{"id":14966204,"url":"https://github.com/rocq-prover/bot","last_synced_at":"2025-10-19T09:31:06.340Z","repository":{"id":39996633,"uuid":"131505583","full_name":"coq/bot","owner":"coq","description":"A (Coq Development Team) bot written in OCaml","archived":false,"fork":false,"pushed_at":"2024-09-17T01:29:52.000Z","size":5861,"stargazers_count":23,"open_issues_count":113,"forks_count":14,"subscribers_count":8,"default_branch":"master","last_synced_at":"2024-09-30T20:41:03.853Z","etag":null,"topics":["bot","github","github-api","github-app","gitlab","gitlab-api","ocaml","webhook"],"latest_commit_sha":null,"homepage":"","language":"OCaml","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/coq.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":".github/CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":"CITATION.cff","codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-04-29T15:20:42.000Z","updated_at":"2024-09-17T01:29:55.000Z","dependencies_parsed_at":"2024-01-16T21:42:54.347Z","dependency_job_id":"a34400c4-788a-4c25-a778-6ab735350e38","html_url":"https://github.com/coq/bot","commit_stats":{"total_commits":819,"total_committers":15,"mean_commits":54.6,"dds":0.7081807081807081,"last_synced_commit":"850d39ce90bafff9e41a61ff70bc2fce80c2b7a2"},"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coq%2Fbot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coq%2Fbot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coq%2Fbot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coq%2Fbot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/coq","download_url":"https://codeload.github.com/coq/bot/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":219869245,"owners_count":16555571,"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":["bot","github","github-api","github-app","gitlab","gitlab-api","ocaml","webhook"],"created_at":"2024-09-24T13:36:00.031Z","updated_at":"2025-10-19T09:31:06.334Z","avatar_url":"https://github.com/coq.png","language":"OCaml","readme":"[![Zulip][zulip-badge]][zulip-link]\n\n[zulip-badge]: https://img.shields.io/badge/chat-on%20Zulip-informational.svg\n[zulip-link]: https://rocq-prover.zulipchat.com/#narrow/stream/243318-coqbot-devs.20.26.20users\n\n# A multi-function bot, written in OCaml #\n\nMost of the functions of this bot are used in the development of the Rocq Prover.\nA subset of functions (most notably the ability to synchronize GitHub\npull requests to GitLab branches and report back the results of\ncontinuous integration) are used in dozens of additional projects.\n\nThis is a work in progress and your help is welcome, both in the form\nof issues and pull requests.  When reporting a bug or requesting a\nfeature, please be as specific as possible, and be ready to follow up.\nIf you are not ready to follow up to make your needs more explicit, or\nto help with testing, don't bother requesting a new feature in the\nfirst place.\n\n## Contents ##\n1. [Features](#features)\n2. [How to use the **@coqbot** instance](#how-to-use-the-coqbot-instance)\n3. [Architecture](#architecture)\n4. [How to deploy a new instance](#how-to-deploy-a-new-instance)\n5. [Building locally](#building-locally)\n\n## Features ##\n\n### Synchronization between GitHub and GitLab ###\n\nGitLab is not just a development platform similar to GitHub, it is\nalso one of the best CI providers there is today.  Consequently, it is\nno surprise that many projects that are developed on GitHub want to\nuse GitLab for CI/CD.  Since 2018, [GitLab CI/CD supports\nGitHub][gitlab-github-support], but this only means mirroring the\nrepository's branches and reporting status checks back.  Pull requests\noriginating from forks get no testing, even though this has been a\n[feature request][gitlab-fork-issue] for more than two years.\n\n[gitlab-github-support]: https://about.gitlab.com/solutions/github/\n[gitlab-fork-issue]: https://gitlab.com/gitlab-org/gitlab-ee/issues/5667\n\n#### Synchronize pull requests from forks ####\n\nThis bot works around this issue by pushing new and updated pull\nrequests to branches on the GitLab mirror.  Note that depending on\nyour settings this could result in a security risk.  In particular, if\nyou have secret variables, you should restrict them to protected\nbranches.  Otherwise, anyone could instrument pull request testing to\nget access to their values.\n\n![pushed branch screenshot](screenshots/pushed-branch.png)\n\n#### Automatic merge commits for testing ####\n\nLike Travis, the bot always create a merge commit of the pull request\nhead with the head of the base branch, which is very convenient when\nthe pull request is not up-to-date with the base branch.  If the\nautomatic merge fails, then the bot will push a failed status check on\nthe PR and set a \"needs: rebase\" label (if this labels exists).  It\nalso removes the label when an updated version without conflicts is\npushed.\n\n![needs rebase label screenshot](screenshots/needs-rebase.png)\n\n#### Detailed failure reporting ####\n\nIn the reverse direction, the bot will substitute itself to the status\ncheck reporting that GitLab supports, and report more detailed\ninformation on failing pipelines (with a direct link to the failed\njobs).\n\n![detailed reporting screenshot](screenshots/detailed-reporting.png)\n\nUsing the status check reporting provided by this bot rather than the\none provided by GitLab is essential, because GitLab wouldn't know how\nto report the status back for automatic merge commits.\n\n#### GitHub Checks features ####\n\nWhen the bot is installed as a [GitHub App](#as-a-github-app), it uses\nthe GitHub Checks tab for the status reporting.  You get some\nadditional benefits, like having a snippet of the failed build logs\nand the ability to restart failed jobs and pipelines by clicking on\nthe \"Re-run\" button.\n\n![re-run button](screenshots/re-run.png)\n\nThe GitHub App is also able to report failed jobs in `allow_failure`\nmode as \"neutral\" status checks.\n\n![neutral check](screenshots/neutral-check.png)\n\n#### Other GitHub-GitLab synchronization features ####\n\nThe bot can also add direct link to artifacts generated by the CI to\nease reviewing.  For now, this feature is only activated on the Rocq Prover\nrepository.  Please open an issue if you would like to use it on your\nrepository too.\n\n![direct link to CI artifact](screenshots/link-to-artifact.png)\n\nThe bot will delete branches corresponding to pull requests when the\npull requests are merged or closed.\n\n![branch deletion screenshot](screenshots/deleted-branch.png)\n\nFinally, the bot handles some cases of spurious failures by\nrelaunching the failed job automatically, for instance in case of\nrunner failure.  At some point in the past, shared runner failures\nwere very frequent and this feature was absolutely necessary to make\nGitLab CI/CD usable in practice.\n\nPlease open an issue if you would like any of the behaviors described\nabove to be configurable.\n\n### Clear milestone of unmerged pull requests ###\n\nWhen a pull request is closed without being merged, the bot will\nremove any milestone that had been set.\n\n![milestone removal screenshot](screenshots/removed-milestone.png)\n\nPlease open an issue if you would like this behavior to be\nconfigurable.\n\n### Mark pull request as stale and automatically close them ###\n\nIf this feature is used, the bot will mark pull requests as stale when\nthey have not been rebased for more than 30 days, with a comment\ngiving another 30 days to rebase the pull request before it is\nautomatically closed.\n\n![stale pull request](screenshots/stale-pull-request.png)\n\nTo use the feature, create the `needs: rebase` and the `stale` labels\nand set up a cron job (e.g. a scheduled GitHub Action) to call the\n`/check-stale-pr` endpoint every day with `owner:repo` in the body.\n\nThis feature is best used in combination with a GitHub Action to\nautomatically add the `needs: rebase` label when a conflict appears\nafter the base branch has been updated.  Example:\n\n```yml\nname: \"Check conflicts\"\non: [push]\n# Only on push because @coqbot already takes care of checking for\n# conflicts when PRs are opened or synchronized\n\njobs:\n  main:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: eps1lon/actions-label-merge-conflict@b8bf8341285ec9a4567d4318ba474fee998a6919\n        with:\n          dirtyLabel: \"needs: rebase\"\n          repoToken: \"${{ secrets.GITHUB_TOKEN }}\"\n```\n\n### Synchronize closed issue's milestone with the one of the pull request that closed it ###\n\nIf an issue is closed automatically when merging a pull request, and\nthis pull request had a milestone set, then the bot will add the issue\nto the same milestone.  If the issue was already in a different\nmilestone, the bot will change the milestone and post a comment\nalerting of the change.\n\n![updated milestone screenshot](screenshots/changed-milestone.png)\n\nThis feature won't be activated if you don't select the \"issue\" event\nwhen configuring the GitHub webhook.  However, it is activated if you\ninstalled the bot as a [GitHub App](#as-a-github-app).  Please open an\nissue if you would like this behavior to be configurable.\n\n### Post comment when a pull request does not respect certain standards ###\n\nThis feature is only activated on the Rocq Prover repository.  Please open an\nissue if you would like to use it on your repository too.\n\nWhen someone opens a pull request but the name of the branch that was\nused to open the pull request is the same as the base branch, the bot\nposts a comment recommending to do differently next time, and suggests\nreading the contributing guide.\n\n![pull request recommendation screenshot](screenshots/pr-recommendation.png)\n\n### Manage the backporting process ###\n\nThis is a complex feature that is not activated by default, and that\nwould deserve a whole document to present it.  Please open an issue if\nyou are interested in hearing about it.\n\n![backport management screenshot](screenshots/backport-management.png)\n\n![backport rejection screenshot](screenshots/reject-backport.png)\n\n## How to use the **@coqbot** instance ##\n\n### As a GitHub App\n\nThis is the recommended installation method, as this is both easier to\nset up and it gives access to new features (related to GitHub Checks).\n\nNotes:\n\n- Installation as a GitHub App is still in an experimental stage\nand you may frequently receive requests to expand permissions.\n\n- All the repositories that use the bot and belong to the same\nowner must install the bot using the same method (GitHub App or\nregular user).\n\n- If you were previously using the legacy installation method,\nmake sure you disable any previously set up GitHub webhooks when\nswitching to the GitHub App, otherwise the bot will receive every\nrequest twice.\n\nThe bot can be installed as a GitHub App to either your account or\norganization ([link to app](https://github.com/apps/coqbot-app)).\nOnce you finish the installation, follow these steps:\n\n- Create a repository on GitLab.com which will be used to run CI jobs.\n\n  By default, the bot will only take care of mirroring the PRs and\n  reporting status checks back. So you may still want to activate:\n\n  - either GitLab's mirroring feature for the main branches.\n    (A drawback is the\n    [sync lag](https://docs.gitlab.com/ee/user/project/repository/mirror/#update-a-mirror)\n    (between 5' and 30') that occurs with this pull-based mirroring.)\n    If you do so, the easiest way is to choose the \"CI/CD for external\n    repo\" option when creating the GitLab repository.  However, you\n    should opt to give the repo by URL rather than with the GitHub\n    button, because we won't need GitLab's own status check reporting\n    feature. (If it is already activated, you can disable this\n    integration in the \"Settings\" / \"Integration\" menu).\n\n  - or **@coqbot**'s mirroring feature (it is a push-based mirroring).\n    For now, this requires hardcoding the GitHub / GitLab mapping in\n    the bot's source code.  Please open an issue if you would like to\n    use this feature. We plan to make this configurable in the future.\n\n- In your GitLab repository:\n\n  - go to \"Members\" to add\n    [**@coqbot**](https://gitlab.com/coqbot) as a project member with\n    \"Developer\" role (so that it can push new branches).\n\n  - go to \"Settings\" / \"Webhooks\" and create one webhook that will be\n    triggered by pipeline events and job events. Set its URL to\n    \u003chttps://coqbot.herokuapp.com/gitlab\u003e.\n\n  By default, **@coqbot** considers that both GitHub and GitLab repositories\n  share the same URL except for the \"lab\" replacing the \"hub\" part. If\n  that is not the case, assuming you created a GitLab repository whose\n  URL is \u003chttps://mygitlab.example.com/owner/repo/\u003e, add a file `coqbot.toml` at\n  the root of your GitHub repository and in its default branch (most often\n  named `master`), containing:\n  ```\n  [mapping]\n  gitlab = \"owner/repo\"\n  gitlab_domain = \"mygitlab.example.com\"\n  ```\n  If omitted, the `gitlab_domain` value defaults to `\"gitlab.com\"`.\n  Note that the value of `gitlab_domain` must be a supported GitLab\n  instance, i.e., it needs to be defined in the bot's own configuration\n  file (check [coqbot-config.toml](coqbot-config.toml) for the coqbot\n  instance configuration).\n\n  If you use another instance of **@coqbot**, this repository-specific\n  configuration file becomes `BOT_NAME.toml` where `BOT_NAME` is the name\n  of the bot.\n\n### As a regular user account (legacy)\n\nThe bot used to be given access to each of your GitHub repositories as a\nregular GitHub user account (**@coqbot**). This installation method is\nstill supported for repositories that haven't migrated to the GitHub App\nyet. Here are the steps to follow in addition to those described in the \n`As GitHub App` section:\n\n- In your GitHub repository:\n\n  - go to \"Settings\" / \"Manage access\" to add\n    [**@coqbot**](https://github.com/coqbot) as a collaborator with\n    the \"Write\" role (so that it can push status checks, and set\n    labels).\n\n    Currently, every invitation requires a manual validation, so there\n    may be some lag before **@coqbot** can push status checks\n    to your repository.\n\n  - go to \"Settings\" / \"Webhooks\" and add one webhook with URL\n    \u003chttps://coqbot.herokuapp.com/github\u003e that will only be triggered\n    at least by pull request events, and if you want to use the issue\n    milestone feature, by issue events as well.  Make sure you change\n    the \"content/type\" value to \"application/json\".\n\n  \n\n## Architecture ##\n\nThe bot has grown according to the needs for automation in the Rocq\nProver, initially as a single file, and is now incrementally being\nrearchitected around the idea of providing a library of base bot\ncomponents that can be used in a trigger-action programming model.\n\nThe most popular trigger-action programming platforms as of today are\nIFTTT and Zapier.  Interestingly both of them provide a GitHub\nintegration, and Zapier provides a GitLab integration as well, but\ntheir integrations do not include sufficiently advanced triggers nor\nactions to perform the kind of things that this bot does.\n\nThe bot components are of three types (the naming follows [GraphQL's\nterminology][graphql-terms] of the corresponding GraphQL requests,\nGraphQL requests are preferred to REST requests whenever possible):\n\n- **Subscriptions** are the events that the bot listens to (currently\n  GitHub and GitLab webhooks).  See for instance\n  `bot-components/GitHub_subscriptions.ml`.\n\n- **Queries** are the requests that are sent to gather additional\n  necessary information, and to decide whether the conditions to\n  perform an action are met.  See for instance\n  `bot-components/GitHub_queries.ml`.\n\n- **Mutations** are the state-changing actions that are performed by\n  the bot, in response to some event and some conditions being met.\n  See for instance `bot-components/GitHub_mutations.ml`.\n\n[graphql-terms]: https://graphql.github.io/graphql-spec/June2018/#sec-Language.Operations\n\nWhen this architecture is sufficiently stable, the goal is to publish\nthe `bot-components` folder as an independent library of building\nblocks to create a personalized bot in OCaml.  In the meantime, if you\ndeploy your own instance, the `callback` function in the `bot.ml` file\nis the main entry point, where you can decide of your business\nlogic by choosing the subscriptions you listen to, and by triggering\nthe relevant queries and mutations on demand.\n\n## How to deploy a new instance ##\n\nCreating an instance of the bot requires to create a\n[GitHub App](https://docs.github.com/en/developers/apps/creating-a-github-app) and set up a server.\n\n### Deploying the server\n\nWe provide a Docker image at each release, which can be easily deployed\nto [Heroku](https://www.heroku.com/). Simply follow the official\n[instructions](https://devcenter.heroku.com/articles/container-registry-and-runtime).\n\nThe bot will need to read a few environment variables so make sure\nthese are configured in your Heroku app:\n\n- `GITHUB_ACCESS_TOKEN` (can also be defined in the configuration file as `github.api_token`)\n- `GITLAB_ACCESS_TOKEN` (can also be defined for each GitLab instance through the configuration file as `api_token` or through an environment variable whose name is defined in the configuration file as `api_token_env_var`)\n- `GITHUB_WEBHOOK_SECRET` (can also be defined in the configuration file as `github.webhook_secret`)\n- `GITLAB_WEBHOOK_SECRET` (can also be defined in the configuration file as `gitlab.webhook_secret`, will default to `GITHUB_WEBHOOK_SECRET` if not defined)\n- `DAILY_SCHEDULE_SECRET` (can also be defined in the configuration file as `github.daily_schedule_secret`, will default to `GITHUB_WEBHOOK_SECRET` if not defined)\n- `GITHUB_APP_ID` (can also be defined in the configuration file as `github.app_id`)\n- `GITHUB_PRIVATE_KEY` (a private key of your GitHub app)\n- `PORT` (can also be defined in the configuration file as `server.port`)\n\nThen, you must configure the bot with a configuration file. Here is an example\nto adapt to your needs [`example-config.toml`](example-config.toml).\n\nHere is an example of Dockerfile to build a personalized image based\non a release image from GitHub packages, using a custom `bot_config.toml`\nconfiguration file:\n```dockerfile\nFROM docker.pkg.github.com/coq/bot/coqbot:v0.2.0\n\nCOPY path/to/bot_config.toml ./\n\nEXPOSE 8000 # The port you specified in bot_config.toml\n            # (this command is ignored if you deploy to Heroku)\n\nCMD [\"./bot.exe\", \"bot_config.toml\"]\n```\nKeep in mind that you should login first to GitHub packages with your\nGitHub credentials.\n\n### Create a GitHub App\n\nPlease follow the [instructions](https://docs.github.com/en/developers/apps/creating-a-github-app)\nfor creating a GitHub App.\n\nMake sure to enter the address of your instance of the server followed by `/github` in the\n`Webhook URL` entry. It typically looks like `https://myapp.herokuapp.com/github` if you\ndeployed the server to Heroku.\n\nYou can also specify the `Webhook Secret`, which should correspond to the `GITHUB_WEBHOOK_SECRET`\nenvironment variable.\n\nThen, you need to set the following permissions:\n\n- Repository permissions:\n  - Checks: read \u0026 write\n  - Contents: read \u0026 write\n  - Issues: read \u0026 write\n  - Metadata: read-only\n  - Pull requests: read \u0026 write\n  - Projects: read \u0026 write\n  - Commit statuses: read \u0026 write\n\n- Organization permissions:\n  - Members: read-only\n  - Projects: read \u0026 write\n\n- Subscribe to events (check the following events):\n  - Check run\n  - Commit comment\n  - Create\n  - Issue comment\n  - Issues\n  - Project\n  - Project card\n  - Project column\n  - Pull request\n  - Pull request review\n  - Push\n\n## Building locally ##\n\nInstructions for building and testing locally can be found in the\n[contributing guide](.github/CONTRIBUTING.md).\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frocq-prover%2Fbot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frocq-prover%2Fbot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frocq-prover%2Fbot/lists"}