{"id":26786981,"url":"https://github.com/pix4d/cogito","last_synced_at":"2025-06-29T13:03:24.221Z","repository":{"id":36698113,"uuid":"206025629","full_name":"Pix4D/cogito","owner":"Pix4D","description":"Concourse resource for GitHub Commit Status and Google Chat notifications","archived":false,"fork":false,"pushed_at":"2025-05-05T14:30:07.000Z","size":1163,"stargazers_count":35,"open_issues_count":4,"forks_count":15,"subscribers_count":22,"default_branch":"master","last_synced_at":"2025-06-29T13:03:22.084Z","etag":null,"topics":["cicd","concourse","concourse-resource","github-status","go","google-chat","internal","owner-platform-ci"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Pix4D.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2019-09-03T08:18:23.000Z","updated_at":"2025-05-09T06:18:18.000Z","dependencies_parsed_at":"2024-02-22T08:28:50.742Z","dependency_job_id":"2e5f308c-ea4e-4753-b33a-75c8136eb13f","html_url":"https://github.com/Pix4D/cogito","commit_stats":null,"previous_names":[],"tags_count":23,"template":false,"template_full_name":null,"purl":"pkg:github/Pix4D/cogito","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Pix4D%2Fcogito","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Pix4D%2Fcogito/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Pix4D%2Fcogito/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Pix4D%2Fcogito/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Pix4D","download_url":"https://codeload.github.com/Pix4D/cogito/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Pix4D%2Fcogito/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":262598139,"owners_count":23334667,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cicd","concourse","concourse-resource","github-status","go","google-chat","internal","owner-platform-ci"],"created_at":"2025-03-29T12:17:31.319Z","updated_at":"2025-06-29T13:03:24.201Z","avatar_url":"https://github.com/Pix4D.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# cogito\n\nCogito (**CO**ncourse **GIT** status res**O**urce) is a [Concourse resource] to update the GitHub commit status during a build. The name is a humble homage to [René Descartes].\n\nIt 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](#examples) below).\n\nWritten in Go, it has the following characteristics:\n\n- As lightweight as possible (Docker Alpine image).\n- Extensive test suite.\n- Autodiscovery of configuration parameters.\n- No assumptions on the git repository (for example, doesn't assume that the default branch is `main` or that branch `main` even exists).\n- Supports Concourse [instanced pipelines](https://concourse-ci.org/instanced-pipelines.html).\n- Helpful error messages when something goes wrong with the GitHub API.\n- Retryable GitHub HTTP API requests due to rate limiting or transient server errors.\n- Configurable logging for the three steps (check, in, out) to help troubleshooting.\n\n[Concourse resource]: https://concourse-ci.org/resources.html\n[René Descartes]: https://en.wikipedia.org/wiki/Ren%C3%A9_Descartes\n\n# Contributing and Development\n\nThis document explains how to use this resource. See [CONTRIBUTING](./CONTRIBUTING.md) for how to build the Docker image, develop, test and contribute to this resource.\n\n**Please, before opening a PR, open a ticket to discuss your use case**.\nThis 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.\nThis is in the spirit of [Talk, then code](https://dave.cheney.net/2019/02/18/talk-then-code).\n\nWe care about code quality, readability and tests, so please follow the current style and provide adequate test coverage.\nIn case of doubts about how to tackle testing something, feel free to ask.\n\n# Semver, releases and Docker images\n\nThis project follows [Semantic Versioning](https://semver.org/) and has a [CHANGELOG](./CHANGELOG).\n\n**NOTE** Following semver, no backwards compatibility is guaranteed as long as the major version is 0.\n\nReleases 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](https://hub.docker.com/r/pix4d/cogito).\n\n## Which Docker tag to use?\n\n- The `latest` tag always points to the latest release, not to the tip of master, so it is quite stable.\n- Alternatively, you can pin the resource to a specific release tag `MAJOR.MINOR.PATCH`.\n\n# Examples\n\n## Only GitHub commit status\n\nSee also [pipelines/cogito.yml](pipelines/cogito.yml) for a bigger example and for how to use YAML anchors to reduce as much as possible YAML verbosity.\n\n```yaml\nresource_types:\n- name: cogito\n  type: registry-image\n  check_every: 24h\n  source:\n    repository: pix4d/cogito\n\nresources:\n- name: gh-status\n  type: cogito\n  check_every: never\n  source:\n    owner: ((github-owner))\n    repo: ((your-repo-name))\n    access_token: ((github-PAT))\n\n- name: the-repo\n  type: git\n  source:\n    uri: https://github.com/((github-owner))/((your-repo-name))\n    branch: ((branch))\n\njobs:\n  - name: autocat\n    on_success:\n      put: gh-status\n      inputs: [the-repo]\n      params: {state: success}\n    on_failure:\n      put: gh-status\n      inputs: [the-repo]\n      params: {state: failure}\n    on_error:\n      put: gh-status\n      inputs: [the-repo]\n      params: {state: error}\n    on_abort:\n      put: gh-status\n      inputs: [repo.git]\n      params: {state: abort}\n    plan:\n      - get: the-repo\n        trigger: true\n      - put: gh-status\n        inputs: [the-repo]\n        params: {state: pending}\n      - task: maybe-fail\n        config:\n          platform: linux\n          image_resource:\n            type: registry-image\n            source: { repository: alpine }\n          run:\n            path: /bin/sh\n            args:\n              - -c\n              - |\n                set -o errexit\n                echo \"Hello world!\"\n```\n\n## GitHub commit status plus chat notification\n\nThe absolute minimum is adding key `gchat_webhook` to the `source` configuration of the previous example:\n\n```yaml\n- name: gh-status\n  type: cogito\n  check_every: never\n  source:\n    owner: ((github-owner))\n    repo: ((your-repo-name))\n    access_token: ((github-PAT))\n    gchat_webhook: ((gchat_webhook))\n```\n\n## Chat notification only\n\nThe absolute minimum is setting keys `gchat_webhook` and `sinks` in the `source` configuration:\n\n```yaml\n- name: chat-notify\n  type: cogito\n  check_every: never\n  source:\n    sinks:\n      - gchat\n    gchat_webhook: ((gchat_webhook))\n```\n\n# Effects\n\n## Build states mapping\n\nThere is only a partial matching between Concourse and GitHub Commit status API, so we map as good as we can according to this table: \n\n| Concourse\u003cbr/\u003e State | Color and meaning                                                                                         | GitHub\u003cbr/\u003e Commit status API | Chat notification |\n|----------------------|-----------------------------------------------------------------------------------------------------------|-------------------------------|-------------------|\n| running              | 🟡 - running                                                                                              | pending                       | pending           |\n| success              | 🟢 - task exited 0                                                                                        | success                       | success           |\n| failure              | 🔴 - task exited non 0                                                                                    | failure                       | failure           |\n| error                | 🟠 - any other error besides failure or abort (pipeline configuration error, network error, timeout, ...) | error                         | error             |\n| abort                | 🟤 - human-initiated abort                                                                                | error                         | abort             |\n\nThe colors are taken from the Concourse UI and are replicated to the chat message.\n\n## Effects on GitHub\n\nWith 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:\n\n![Screenshot of GitHub UI](doc/gh-ui-decorated.png)\n\n## Effects on Google Chat\n\n- Create a Gchat space per pipeline or per group of related pipelines.\n- At space creation time (cannot be changed afterwards) select threaded messages.\n- In the upper left, click on the drop-down menu with the name of the space.\n- Click on Manage webhooks.\n- Create a webhook and securely store it in your Concourse secret management system.\n\n![Screenshot of Google Chat UI](doc/cogito-gchat.png)\n\n# Source Configuration\n\n## GitHub commit status only\n\n### Required keys\n\n- `owner`\\\n  The GitHub user or organization.\n\n- `repo`\\\n  The GitHub repository name.\n\n###  Authentication keys\n\nKeys must be provided for one of the following authentication methods:\n1. [Personal Access Token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens)\n2. [GitHub app](https://docs.github.com/en/apps/creating-github-apps/about-creating-github-apps/about-creating-github-apps)\n\n#### Personal Access Token keys\n\n- `access_token`\\\n  The OAuth access token.\\\n  See also: section [GitHub OAuth token](#github-oauth-token).\n\n#### GitHub app keys\n\n- `github_app`\\\n  Github Application object with the required key-value pairs:\n  - `client_id` \\\n    The client id of the GitHub application\n\n  - `installation_id` \\\n    The installation id of the GitHub application. To find out the value go to the application url e.g. https://github.com/settings/apps/\u003cAPP_NAME\u003e/installations and then click the gear icon. The installation id can be found in the URL itself: https://github.com/settings/installations/\u003cINSTALLATION_ID\u003e\n\n  - `private_key` \\\n    The private key generated for the GitHub application\n\nSee also: section [GitHub app auth](#github-app-auth).\n\n### Which authentication method to choose?\n\nThe advantage of using a Personal Access Token is that it is simpler to setup,\nwhile the advantage of a GitHub App is that it has a more generous rate limit.\nSee section [#Caveat: GitHub rate limiting] for details.\n\n### Optional keys\n\n- `context_prefix`\\\n  The prefix for the GitHub Commit status API \"context\" (see section [Effects on GitHub](#effects-on-github)). If present, the context will be set as `context_prefix/job_name`.\\\n  Default: empty.\\\n  See also: the optional `context` in the [put step](#the-put-step).\n\n- `log_level`:\\\n  The log level (one of `debug`, `info`, `warn`, `error`).\\\n  Default: `info`, recommended for normal operation.\n\n- `github_hostname`:\\\n  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 \\\n  Default: `github.com`\n\n- `omit_target_url`:\\\n  If set to true, will omit the GitHub Commit status API `target_url` (the URL to the build on Concourse).\\n\n  Default: `false`.\n\n- `log_url`. **DEPRECATED, no-op, will be removed**\\\n  A Google Hangout Chat webhook. Useful to obtain logging for the `check` step for Concourse \u003c v7.x\n\n\n## GitHub commit status plus chat notifications\n\n### Required keys\n\n- The keys required for [Only GitHub commit status](##github-commit-status-only)\n\n- `gchat_webhook`\\\n  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.\\\n  See also: `chat_notify_on_states` and section [Effects on Google Chat](#effects-on-google-chat).\n\n### Optional keys\n\n- The optional keys for [Only GitHub commit status](##github-commit-status-only)\n\n- `chat_notify_on_states`\\\n  The build states that will cause a chat notification. One or more of `abort`, `error`, `failure`, `pending`, `success`.\\\n  Default: `[abort, error, failure]`.\\\n  See also: section [Build states mapping](#build-states-mapping).\n\n- `chat_append_summary`\\\n  One of: `true`, `false`. If `true`, append the default build summary to the custom `put.params.chat_message` and/or `put.params.chat_message_file`.\\\n  Default: `true`.\\\n  See also: the default build summary in [Effects on Google Chat](#effects-on-google-chat).\n\n## Chat notification only\n\n### Required keys\n\n- `sinks`\\\n  The sinks list for chat notification.\n  Acceptable values: `[gchat]`.\n\n- `gchat_webhook`\\\n  URL of a [Google Chat webhook]. A notification will be sent to the associated chat space.\\\n  See also: `chat_notify_on_states` and section [Effects on Google Chat](#effects-on-google-chat).\n\n### Optional keys\n\n- `chat_notify_on_states`\\\n  The build states that will cause a chat notification. One or more of `abort`, `error`, `failure`, `pending`, `success`.\\\n  Default: `[abort, error, failure]`.\\\n  See also: section [Build states mapping](#build-states-mapping).\n\n- `chat_append_summary`\\\n  One of: `true`, `false`. If `true`, append the default build summary to the custom `put.params.chat_message` and/or `put.params.chat_message_file`.\\\n  Default: `true`.\\\n  See also: the default build summary in [Effects on Google Chat](#effects-on-google-chat).\n\n## Suggestions\n\nWe 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.\n\n# The check step\n\nNo-op. Will always return the same version, `dummy`.\n\n# The get step\n\nNo-op.\n\n# The put step\n\nSets the GitHub commit status for a given commit, following the [GitHub Commit status API].\nThe same commit can have multiple statuses, differentiated by parameter `context`.\n\nIf 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.\n\n## Required params\n\n- `state`\\\n  The state to set. One of `error`, `failure`, `pending`, `success`, `abort`.\\\n  See also: the mapping explained in section [Effects](#effects).\n\n## Optional params for GitHub commit status\n\n- `context`\\\n  The value of the non-prefix part of the GitHub Commit status API \"context\"\\\n  Default: the job name.\\\n  See also: [Effects on GitHub](#effects-on-github), `source.context_prefix`.\n\n## Optional params for chat\n\n- `sinks`\\\n  If present, overrides `source.sinks`. This allows to run step `put` for example to send to chat only.\n  Default: `source.sinks`.\n\n- `gchat_webhook`\\\n  If present, overrides `source.gchat_webhook`. This allows to use the same Cogito resource for multiple chat spaces.\\\n  Default: `source.gchat_webhook`. \n\n- `chat_message`\\\n  Custom chat message; overrides the build summary. Its presence is enough for the chat message to be sent, overriding `source.chat_notify_on_states`.\\\n  Default: empty.\n\n- `chat_message_file`\\\n  Path to file containing a custom chat message; overrides the build summary. Appended to `chat_message`. Its presence is enough for the chat message to be sent, overriding `source.chat_notify_on_states`.\\\n  Default: empty.\n\n- `chat_append_summary`\\\n  Overrides `source.chat_append_summary`.  \n  Default: `source.chat_append_summary`.\n\n## Note on the put inputs\n\nIf using only GitHub commit status (no chat), the put step requires only one [\"put inputs\"]. For example:\n\n```yaml\non_success:\n  put: gh-status\n  inputs: [the-repo] # name of the git resource corresponding to the GitHub repo to be updated.\n  params: {state: success}\n```\n\nIf using both GitHub Commit status and the `chat_message_file` parameter, the put step requires only two [\"put inputs\"]. For example:\n\n```yaml\non_success:\n  put: gh-status\n  # the-repo: git resource; the-message-dir: \"output\" of a previous task\n  inputs: [the-repo, the-message-dir]\n  params:\n    state: success\n    chat_message_file: the-message-dir/msg.txt\n```\n\nIf using send to chat only and the `chat_message_file` parameter, the put step requires only one [\"put inputs\"]. For example:\n\n```yaml\non_success:\n  put: chat-only\n  # the-message-dir: \"output\" of a previous task\n  inputs: [the-message-dir]\n  params:\n    state: success\n    chat_message_file: the-message-dir/msg.txt\n```\n\nIf using send to chat only without `chat_message_file` parameter, `inputs` may be left empty.\n\n```yaml\non_success:\n  put: gh-status\n  inputs: []\n  params:\n    state: success\n    chat_message: \"This is the custom chat message.\"\n```\n\nThe 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:\n\n\u003e inputs: [string]\n\u003e\n\u003e Optional. If specified, only the listed artifacts will be provided to the container. If not specified, all artifacts will be provided.\n\n[\"put inputs\"]: https://concourse-ci.org/put-step.html#put-step-inputs\n\n# GitHub OAuth token\n\nFollow the instructions at [GitHub personal access token] to create a personal access token.\n\nGive 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].\n\nNOTE: 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].\n\nSee also the section [Integration tests](./CONTRIBUTING.md#integration-tests) for how to securely store the token to run the end-to-end tests.\n\n# GitHub App auth\n\n1. Create a new GitHub App  https://github.com/settings/apps/new\n2. Mark webhook as inactive\n3. Add repository permission: Commit Statuses: `Read/write`\n4. Generate a private key and download a copy\n5. Install the app in selected repositories\n\n# Caveat: GitHub rate limiting\n\nFrom [GitHub REST API]:\n\n\u003e Rate limiting\n\u003e\n\u003e For API requests using Basic Authentication or OAuth, you can make up to 5000 requests\n\u003e per hour. All OAuth applications authorized by a user share the same quota of 5000\n\u003e requests per hour when they authenticate with different tokens owned by the same user.\n\u003e\n\u003e For unauthenticated requests, the rate limit allows for up to 60 requests per hour.\n\u003e Unauthenticated requests are associated with the originating IP address, and not the\n\u003e user making requests.\n\n\u003e GitHub Apps authenticating with an installation access token use the installation's\n\u003e minimum rate limit of 5,000 requests per hour. If the installation is on a GitHub\n\u003e Enterprise Cloud organization, the installation has a rate limit of 15,000 requests per\n\u003e hour.\n\n\u003e For installations that are not on a GitHub Enterprise Cloud organization, the rate\n\u003e limit for the installation will scale with the number of users and repositories.\n\u003e Installations that have more than 20 repositories receive another 50 requests per hour\n\u003e for each repository. Installations that are on an organization that have more than 20\n\u003e users receive another 50 requests per hour for each user. The rate limit cannot\n\u003e increase beyond 12,500 requests per hour.\n\nGitHub 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.\n\n# License\n\nThis code is licensed according to the MIT license (see file [LICENSE](./LICENSE)).\n\n[GitHub Commit status API]: https://docs.github.com/en/rest/commits/statuses\n[GitHub REST API]: https://docs.github.com/en/rest\n[GitHub personal access token]: https://help.github.com/en/articles/creating-a-personal-access-token-for-the-command-line\n\n[Concourse credential managers]: https://concourse-ci.org/creds.html.\n\n[Google Chat webhook]: https://developers.google.com/chat/how-tos/webhooks\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpix4d%2Fcogito","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpix4d%2Fcogito","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpix4d%2Fcogito/lists"}