Cogito (COncourse GIT status resOurce) is a Concourse resource to update the GitHub commit status during a build. The name is a humble homage to RenΓ© Descartes.
It can also send a message to a chat system (currently supported: Google Chat). This allows to reduce the verbosity of a Concourse pipeline and especially to reduce the number of resource containers in a Concourse deployment, thus reducing load. Chat and GitHub commit status update can be used independently (see examples below).
Written in Go, it has the following characteristics:
- As lightweight as possible (Docker Alpine image).
- Extensive test suite.
- Autodiscovery of configuration parameters.
- No assumptions on the git repository (for example, doesn't assume that the default branch is
main
or that branchmain
even exists). - Supports Concourse instanced pipelines.
- Helpful error messages when something goes wrong with the GitHub API.
- Retryable GitHub HTTP API requests due to rate limiting or transient server errors.
- Configurable logging for the three steps (check, in, out) to help troubleshooting.
This document explains how to use this resource. See CONTRIBUTING for how to build the Docker image, develop, test and contribute to this resource.
Please, before opening a PR, open a ticket to discuss your use case. This allows to better understand the why of a new feature and not to waste your time (and ours) developing a feature that for some reason doesn't fit well with the spirit of the project or could be implemented differently. This is in the spirit of Talk, then code.
We care about code quality, readability and tests, so please follow the current style and provide adequate test coverage. In case of doubts about how to tackle testing something, feel free to ask.
This project follows Semantic Versioning and has a CHANGELOG.
NOTE Following semver, no backwards compatibility is guaranteed as long as the major version is 0.
Releases are tagged in the git repository with the semver format vMAJOR.MINOR.PATCH
(note the v
prefix). The corresponding Docker image has tag MAJOR.MINOR.PATCH
and is available from DockerHub.
- The
latest
tag always points to the latest release, not to the tip of master, so it is quite stable. - Alternatively, you can pin the resource to a specific release tag
MAJOR.MINOR.PATCH
.
See also pipelines/cogito.yml for a bigger example and for how to use YAML anchors to reduce as much as possible YAML verbosity.
resource_types:
- name: cogito
type: registry-image
check_every: 24h
source:
repository: pix4d/cogito
resources:
- name: gh-status
type: cogito
check_every: never
source:
owner: ((github-owner))
repo: ((your-repo-name))
access_token: ((github-PAT))
- name: the-repo
type: git
source:
uri: https://github.com/((github-owner))/((your-repo-name))
branch: ((branch))
jobs:
- name: autocat
on_success:
put: gh-status
inputs: [the-repo]
params: {state: success}
on_failure:
put: gh-status
inputs: [the-repo]
params: {state: failure}
on_error:
put: gh-status
inputs: [the-repo]
params: {state: error}
on_abort:
put: gh-status
inputs: [repo.git]
params: {state: abort}
plan:
- get: the-repo
trigger: true
- put: gh-status
inputs: [the-repo]
params: {state: pending}
- task: maybe-fail
config:
platform: linux
image_resource:
type: registry-image
source: { repository: alpine }
run:
path: /bin/sh
args:
- -c
- |
set -o errexit
echo "Hello world!"
The absolute minimum is adding key gchat_webhook
to the source
configuration of the previous example:
- name: gh-status
type: cogito
check_every: never
source:
owner: ((github-owner))
repo: ((your-repo-name))
access_token: ((github-PAT))
gchat_webhook: ((gchat_webhook))
The absolute minimum is setting keys gchat_webhook
and sinks
in the source
configuration:
- name: chat-notify
type: cogito
check_every: never
source:
sinks:
- gchat
gchat_webhook: ((gchat_webhook))
There is only a partial matching between Concourse and GitHub Commit status API, so we map as good as we can according to this table:
Concourse State |
Color and meaning | GitHub Commit status API |
Chat notification |
---|---|---|---|
running | π‘ - running | pending | pending |
success | π’ - task exited 0 | success | success |
failure | π΄ - task exited non 0 | failure | failure |
error | π - any other error besides failure or abort (pipeline configuration error, network error, timeout, ...) | error | error |
abort | π€ - human-initiated abort | error | abort |
The colors are taken from the Concourse UI and are replicated to the chat message.
With reference to the GitHub Commit status API, the POST
parameters (state
, target_url
, description
, context
) are set by Cogito and rendered by GitHub as follows:
- Create a Gchat space per pipeline or per group of related pipelines.
- At space creation time (cannot be changed afterwards) select threaded messages.
- In the upper left, click on the drop-down menu with the name of the space.
- Click on Manage webhooks.
- Create a webhook and securely store it in your Concourse secret management system.
-
owner
The GitHub user or organization. -
repo
The GitHub repository name. -
access_token
The OAuth access token.
See also: section GitHub OAuth token.
-
context_prefix
The prefix for the GitHub Commit status API "context" (see section Effects on GitHub). If present, the context will be set ascontext_prefix/job_name
.
Default: empty.
See also: the optionalcontext
in the put step. -
log_level
:
The log level (one ofdebug
,info
,warn
,error
).
Default:info
, recommended for normal operation. -
github_hostname
:
GitHub hostname. This allows to post commit statuses to repositories hosted by GitHub Enterprise (GHE) instances. For example: github.mycompany.org will be expanded by cogito to https://github.mycompany.org/api/v3
Default:github.com
-
log_url
. DEPRECATED, no-op, will be removed
A Google Hangout Chat webhook. Useful to obtain logging for thecheck
step for Concourse < v7.x
-
The keys required for Only GitHub commit status
-
gchat_webhook
URL of a Google Chat webhook. A notification about the build status will be sent to the associated chat space, using a thread key composed by the pipeline name and commit hash.
See also:chat_notify_on_states
and section Effects on Google Chat.
-
The optional keys for Only GitHub commit status
-
chat_notify_on_states
The build states that will cause a chat notification. One or more ofabort
,error
,failure
,pending
,success
.
Default:[abort, error, failure]
.
See also: section Build states mapping. -
chat_append_summary
One of:true
,false
. Iftrue
, append the default build summary to the customput.params.chat_message
and/orput.params.chat_message_file
.
Default:true
.
See also: the default build summary in Effects on Google Chat.
-
sinks
The sinks list for chat notification. Acceptable values:[gchat]
. -
gchat_webhook
URL of a Google Chat webhook. A notification will be sent to the associated chat space.
See also:chat_notify_on_states
and section Effects on Google Chat.
-
chat_notify_on_states
The build states that will cause a chat notification. One or more ofabort
,error
,failure
,pending
,success
.
Default:[abort, error, failure]
.
See also: section Build states mapping. -
chat_append_summary
One of:true
,false
. Iftrue
, append the default build summary to the customput.params.chat_message
and/orput.params.chat_message_file
.
Default:true
.
See also: the default build summary in Effects on Google Chat.
We suggest to set a long interval for check_interval
, for example 24 hours, as shown in the example above. This helps to reduce the number of check containers in a busy Concourse deployment and, for this resource, has no adverse effects.
No-op. Will always return the same version, dummy
.
No-op.
Sets the GitHub commit status for a given commit, following the GitHub Commit status API.
The same commit can have multiple statuses, differentiated by parameter context
.
If the source
block has the optional key gchat_webhook
, then it will also send a message to the configured chat space, based on the state
parameter.
state
The state to set. One oferror
,failure
,pending
,success
,abort
.
See also: the mapping explained in section Effects.
context
The value of the non-prefix part of the GitHub Commit status API "context"
Default: the job name.
See also: Effects on GitHub,source.context_prefix
.
-
sinks
If present, overridessource.sinks
. This allows to run stepput
for example to send to chat only. Default:source.sinks
. -
gchat_webhook
If present, overridessource.gchat_webhook
. This allows to use the same Cogito resource for multiple chat spaces.
Default:source.gchat_webhook
. -
chat_message
Custom chat message; overrides the build summary. Its presence is enough for the chat message to be sent, overridingsource.chat_notify_on_states
.
Default: empty. -
chat_message_file
Path to file containing a custom chat message; overrides the build summary. Appended tochat_message
. Its presence is enough for the chat message to be sent, overridingsource.chat_notify_on_states
.
Default: empty. -
chat_append_summary
Overridessource.chat_append_summary
.
Default:source.chat_append_summary
.
If using only GitHub commit status (no chat), the put step requires only one "put inputs". For example:
on_success:
put: gh-status
inputs: [the-repo] # name of the git resource corresponding to the GitHub repo to be updated.
params: {state: success}
If using both GitHub Commit status and the chat_message_file
parameter, the put step requires only two "put inputs". For example:
on_success:
put: gh-status
# the-repo: git resource; the-message-dir: "output" of a previous task
inputs: [the-repo, the-message-dir]
params:
state: success
chat_message_file: the-message-dir/msg.txt
If using send to chat only and the chat_message_file
parameter, the put step requires only one "put inputs". For example:
on_success:
put: chat-only
# the-message-dir: "output" of a previous task
inputs: [the-message-dir]
params:
state: success
chat_message_file: the-message-dir/msg.txt
If using send to chat only without chat_message_file
parameter, inputs
may be left empty.
on_success:
put: gh-status
inputs: []
params:
state: success
chat_message: "This is the custom chat message."
The reasons of this strictness is to help you have an efficient pipeline, since if the "put inputs" list is not set explicitly, then Concourse will stream all inputs used by the job to this resource, which can have a big performance impact. From the "put inputs" documentation:
inputs: [string]
Optional. If specified, only the listed artifacts will be provided to the container. If not specified, all artifacts will be provided.
Follow the instructions at GitHub personal access token to create a personal access token.
Give to it the absolute minimum permissions to get the job done. This resource only needs the repo:status
scope, as explained at GitHub Commit status API.
NOTE: The token is security-sensitive. Treat it as you would treat a password. Do not encode it in the pipeline YAML and do not store it in a YAML file. Use one of the Concourse-supported credentials managers, see Concourse credential managers.
See also the section Integration tests for how to securely store the token to run the end-to-end tests.
From GitHub REST API:
Rate limiting
For API requests using Basic Authentication or OAuth, you can make up to 5000 requests per hour. All OAuth applications authorized by a user share the same quota of 5000 requests per hour when they authenticate with different tokens owned by the same user.
For unauthenticated requests, the rate limit allows for up to 60 requests per hour. Unauthenticated requests are associated with the originating IP address, and not the user making requests.
GitHub resets the limit once per hour (no sliding window). If rate limited, cogito will wait up to 15 minutes for the limit to clear, or fail immediately if it would have to wait more. The error message in the output of the put
step will mention the cause.
This code is licensed according to the MIT license (see file LICENSE).