Concourse
Webhook Notification Resource forSend notification messages to any webhook from a Concourse CI pipeline.
This resource provides:
- Pre-formatted markdown messages, with colorful icons, for every Concourse job status.
- Integration with Discord.
- Integration with Gitter activity feeds.
- Extensible design to easily add support for other webhooks. (See Contributing for more information.)
Contents
Background
Concourse is an open-source continuous thing-doer. It's pretty amazing for CI and for more complicated pipelines, you should check it out.
It's pretty common to want to send notification messages somewhere when a job succeeds or fails. Sometimes it's just an HTTP POST or other similarly simple action. This resource tries to make it easy to have a polished-looking informational message for these simple integrations.
For more information on Concourse Resources:
- Concourse Resource - how to configure and use resources
- Concourse Resource Types - how resources work
- Concourse Resource Directory - a collection of Concourse integrations
Source Configuration
These parameters go into the source
fields of the resource.
Required
adapter
: The name of the service adapter you want to use.- Generally these are named after the service they support, and live in
resource/lib/adapters
. - Valid values are:
DiscordAdapter
,GitterActivityFeedAdapter
,MockTeapot
- Generally these are named after the service they support, and live in
url
: The target webhook URL.
Optional
dryrun
: When set totrue
, the resource does not make any HTTP requests. (Defaults tofalse
)
Invocation
check
and in
This resource only supports the put
step, so these are no-ops in this resource.
out
put
will connect to the webhook and send the configured markdown message.
Sending Pre-formatted Messages
This resource comes with some standard pre-formatted messages to reflect typical Concourse job status. You can easily send these messages by setting the following parameter:
status
: Set to one of the states named below to get a sane, well-formatted message.
Valid status
values:
aborted
will post the contents of resource/messages/aborted.mderrored
will post the contents of resource/messages/errored.mdfailed
will post the contents of resource/messages/failed.mdpending
will post the contents of resource/messages/pending.mdstarted
will post the contents of resource/messages/started.mdsucceeded
will post the contents of resource/messages/succeeded.md
Any other value will post the contents of resource/messages/unknown.md.
Sending Custom Messages
To send a custom message, exactly one of the following parameters must be present:
message
: The markdown-formatted text of the notification to be sent.message_file
: Path to a file containing the markdown-formatted text of the notification to be sent.
Any Concourse metadata in the message
string or in the text contents of message_file
will be evaluated prior to sending the message. If the notification text contains newlines then it will be split into multiple IRC message sends.
Additionally, this resource provides a metadatum named BUILD_URL
which should point back to the build's canonical URL. Its value is:
${ATC_EXTERNAL_URL}/teams/${BUILD_TEAM_NAME}/pipelines/${BUILD_PIPELINE_NAME}/jobs/${BUILD_JOB_NAME}/builds/${BUILD_NAME}
Example usage
Discord example
Here's how the resource might be configured to send pre-formatted markdown messages to a Discord channel activity feed in a Concourse pipeline file:
resource_types:
- name: webhook-notification
type: registry-image
source:
repository: flavorjones/webhook-notification-resource
tag: latest
resources:
- name: my-discord-channel
type: webhook-notification
icon: bell
source:
adapter: DiscordAdapter
url: ((webhook_url))
jobs:
- name: build-success
plan:
- task: run-a-test
config: { ... }
on_success: { put: my-discord-channel, params: {status: "succeeded"} }
on_failure: { put: my-discord-channel, params: {status: "failed"} }
on_error: { put: my-discord-channel, params: {status: "errored"} }
on_abort: { put: my-discord-channel, params: {status: "aborted"} }
And here's what the standard notifications look like before any configuration:
Gitter example
See docs/gitter-create-webhook.md for help creating a Gitter webhook.
Here's how the resource might be configured to send pre-formatted markdown messages to a Gitter channel activity feed in a Concourse pipeline file:
resource_types:
- name: webhook-notification
type: docker-image
source:
repository: flavorjones/webhook-notification-resource
resources:
- name: foobar-gitter-channel
type: webhook-notification
source:
adapter: GitterActivityFeedAdapter
url: ((webhook_url))
jobs:
- name: run-some-tests
plan:
- task: run-a-test
config: { ... }
on_success: { put: foobar-gitter-channel, params: {status: "succeeded"} }
on_failure: { put: foobar-gitter-channel, params: {status: "failed"} }
on_error: { put: foobar-gitter-channel, params: {status: "errored"} }
on_abort: { put: foobar-gitter-channel, params: {status: "aborted"} }
And here's what the standard notifications look like before any configuration:
Custom message example
And here's how you can configure a custom message:
resource_types:
- name: webhook-notification
type: docker-image
source:
repository: flavorjones/webhook-notification-resource
resources:
- name: foobar-gitter-channel
type: webhook-notification
source:
adapter: GitterActivityFeedAdapter
url: ((webhook_url))
- name: post-a-message-to-gitter
plan:
- put: foobar-gitter-channel
params:
message: "_This_ is a *markdown* message about [${BUILD_PIPELINE_NAME}/${BUILD_JOB_NAME}/${BUILD_NAME}}](${BUILD_URL})"
Roadmap
The following features seem like reasonable things to implement, but I just haven't gotten around to them yet. If you'd like to help implement these, please do!
- Connecting via HTTP proxy or tunnel
Contributing
Pull requests are welcome, as are Github issues opened to discuss bugs or desired features.
Adding Support For A New Service
If you'd like to integrate with a new service:
- Fork this repo
- Run the tests to ensure you're in a good spot (see below)
- Create a new adapter in
resource/lib/adapters
named after your ClassName in snake_case. - Adapters are modules with one public class method:
.post(url_string, message)
and one optional public class method:.status_message_for(status)
- Write some tests!
It's totally possible that your adapter might need to be a real class (not just a module) and take additional arguments (like the config params). If so, let's talk!
If you have questions, please reach out! I shipped this in a hurry so this section is definitely not as explanatory as I'd like.
Development and Running the tests
Without a local Ruby environment
Requirements:
- make
- docker
To build an OCI image and run the tests in that image:
$ make test
This iteration loop is slightly slower than working with a local Ruby environment (~3 seconds on my laptop).
With a local Ruby environment
Requirements:
- ruby >= 2.7
$ bundle install && bundle exec rake test
This iteration loop is slightly faster than working inside a docker container (~1 second on my laptop).
License
MIT. See the file named LICENSE
in this repository.