A Backstage backend module that adds the webex:webhooks:sendMessage
Scaffolder action. The action sends text or Markdown messages to one or more
Webex incoming webhooks.
- Supports Webex
textandmarkdownmessage formats. - Sends one message to multiple incoming webhooks.
- Continues processing when an individual webhook fails.
- Reports delivery failures through the
failedMessagesaction output. - Integrates with the Backstage new backend system as a Scaffolder module.
- Backstage release line 1.52 or a compatible set of
@backstagepackages. - Node.js 22.22.2, 24.15.0, or a newer supported even-numbered release.
- Corepack with the repository-pinned Yarn 4.8.1 package manager.
- At least one Webex incoming-webhook URL.
Treat webhook URLs as secrets. Do not commit real URLs to templates or source control.
Install the module in the Backstage backend package:
yarn --cwd packages/backend add @coderrob/backstage-plugin-scaffolder-backend-module-webexAdd the module to packages/backend/src/index.ts alongside the Scaffolder
backend plugin:
backend.add(import('@backstage/plugin-scaffolder-backend'));
backend.add(import('@coderrob/backstage-plugin-scaffolder-backend-module-webex'));The package's default export is the webex Scaffolder backend module.
Configure default destinations and the request timeout in app-config.yaml:
webex:
webhooks:
urls:
- ${WEBEX_INCOMING_WEBHOOK_URL}
timeout:
seconds: 15| Configuration key | Type | Required | Default | Description |
|---|---|---|---|---|
webex.webhooks.urls |
string[] |
No | None | Default incoming-webhook destinations. |
webex.webhooks.timeout |
HumanDuration |
No | { seconds: 10 } |
Timeout for each HTTP request. |
The timeout uses Backstage's human-duration object. It accepts one or more of
years, months, weeks, days, hours, minutes, seconds, and
milliseconds:
webex:
webhooks:
timeout:
minutes: 1
seconds: 30webex.webhooks.urls is marked as secret in the package's Backstage
configuration schema. Use environment-variable substitution or another secret
configuration source; do not store real webhook URLs in source control.
Every configured URL must use the format issued by the Webex Incoming Webhooks integration:
https://webexapis.com/v1/webhooks/incoming/<webhook-token>
The module rejects configured URLs with another scheme, host, path, query string, or fragment. Validation errors do not include the secret URL.
The action selects destinations in this order:
- A non-empty
webhooksarray supplied by the Software Template step. - The default
webex.webhooks.urlsarray from Backstage configuration.
When no configured defaults exist, webhooks is required in the action input.
When defaults exist, webhooks is optional and overrides the entire configured
array when supplied.
When webex.webhooks.urls is configured, a template only needs to supply the
message format and content:
- id: send-webex-message
name: Send Webex message
action: webex:webhooks:sendMessage
input:
format: markdown
message: Deployment `${{ parameters.version }}` completed.Supply webhooks to replace the configured defaults for one action invocation:
- id: send-webex-message
name: Send Webex message
action: webex:webhooks:sendMessage
input:
format: text
message: Build completed.
webhooks:
- ${{ secrets.WEBEX_INCOMING_WEBHOOK_URL }}Pass webhook URLs through Backstage secrets rather than ordinary template parameters, because the URL contains a credential.
| Name | Type | Required | Description |
|---|---|---|---|
format |
text | markdown |
Yes | Selects the Webex JSON payload field. |
message |
string |
Yes | Non-empty plain-text or Markdown message. |
webhooks |
non-empty array of URLs | Conditional | Replaces configured destinations when supplied. |
webhooks is required only when webex.webhooks.urls is not configured. Each
input URL must match the Webex Incoming Webhooks URL format shown above.
| Name | Type | Description |
|---|---|---|
failedMessages |
array of strings | Delivery failures; empty when every webhook returns HTTP 200. |
Webhook requests are processed sequentially using the configured timeout. An
HTTP 200 response is considered successful. Other HTTP responses and request
errors are added to failedMessages; a failure does not prevent the remaining
destinations from being attempted.
src/contracts.tsdefines the package's shared public API contracts.src/actions/contains the Scaffolder action implementation.src/config/translates Backstage configuration into action options.src/utils/contains generic internal runtime guards.src/webex/validates Webex Incoming Webhook URLs and delivers messages.src/__tests__/contains cross-cutting package contract tests.scripts/package/contains npm prepack and publication validation tooling.scripts/local-setup.shcreates a disposable Backstage app for integration testing.
Tests for a production module are colocated with that module.
yarn test runs the suite once and exits; use yarn test:watch for an
interactive local watch session. yarn test:leaks runs Jest serially with
memory-leak and open-handle detection.
Install dependencies and run the quality checks:
yarn install
yarn audit
yarn lint
yarn tsc:full
yarn test:coverage
yarn test:leaks
yarn build
yarn publintRun the setup script from a Unix-like shell with Git, a supported Node.js
version, Corepack, and npx available:
bash scripts/local-setup.shSet BACKSTAGE_APP_DIR to override the default sibling application directory.
The target must not already exist.
The script builds and packages the current checkout, creates
../my-backstage-app, installs the package in its backend, registers the
backend module, adds an example Webex scaffolder template, and starts the
Backstage development app. The process remains attached to the terminal; press
Ctrl+C to stop it. Keeping the app beside the plugin repository prevents its
workspace from affecting plugin linting and publication. The packaged plugin is kept under
../my-backstage-app/.local-packages, so subsequent installs do not depend on a
temporary file or an unpublished Git commit.
Disable automatic startup for setup-only or automated checks with:
BACKSTAGE_START=false bash scripts/local-setup.shThe script refuses to overwrite an existing ../my-backstage-app. Move or
remove an earlier disposable application before rerunning it.
The audit fails on high or critical dependency advisories. The test suite enforces at least 95% coverage for statements, branches, functions, and lines. Publint validates the Backstage-transformed npm artifact and its explicit publication allowlist.
Issues and pull requests are welcome. Please include tests for behavioral changes and ensure all development checks pass before opening a pull request.
Licensed under the Apache License 2.0.
