{"id":13452357,"url":"https://github.com/smarkets/marge-bot","last_synced_at":"2026-04-07T07:48:23.885Z","repository":{"id":39800869,"uuid":"95782585","full_name":"smarkets/marge-bot","owner":"smarkets","description":"A merge-bot for GitLab","archived":false,"fork":false,"pushed_at":"2023-07-26T19:54:30.000Z","size":637,"stargazers_count":735,"open_issues_count":116,"forks_count":133,"subscribers_count":22,"default_branch":"master","last_synced_at":"2026-04-07T07:48:16.571Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/smarkets.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2017-06-29T13:50:25.000Z","updated_at":"2026-04-06T14:45:34.000Z","dependencies_parsed_at":"2024-01-15T13:36:01.787Z","dependency_job_id":null,"html_url":"https://github.com/smarkets/marge-bot","commit_stats":null,"previous_names":[],"tags_count":23,"template":false,"template_full_name":null,"purl":"pkg:github/smarkets/marge-bot","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smarkets%2Fmarge-bot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smarkets%2Fmarge-bot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smarkets%2Fmarge-bot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smarkets%2Fmarge-bot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/smarkets","download_url":"https://codeload.github.com/smarkets/marge-bot/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smarkets%2Fmarge-bot/sbom","scorecard":{"id":832571,"data":{"date":"2025-08-11","repo":{"name":"github.com/smarkets/marge-bot","commit":"91b23058afbec984aa23d3981fa0fca63159e5ca"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.4,"checks":[{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Code-Review","score":6,"reason":"Found 19/28 approved changesets -- score normalized to 6","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/deploy.yml:1","Warn: no topLevel permission defined: .github/workflows/test.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/deploy.yml:15: update your workflow using https://app.stepsecurity.io/secureworkflow/smarkets/marge-bot/deploy.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/deploy.yml:16: update your workflow using https://app.stepsecurity.io/secureworkflow/smarkets/marge-bot/deploy.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/deploy.yml:17: update your workflow using https://app.stepsecurity.io/secureworkflow/smarkets/marge-bot/deploy.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/test.yml:21: update your workflow using https://app.stepsecurity.io/secureworkflow/smarkets/marge-bot/test.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/test.yml:22: update your workflow using https://app.stepsecurity.io/secureworkflow/smarkets/marge-bot/test.yml/master?enable=pin","Warn: pipCommand not pinned by hash: .github/workflows/test.yml:27","Info:   0 out of   4 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   1 third-party GitHubAction dependencies pinned","Info:   0 out of   1 pipCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: BSD 3-Clause \"New\" or \"Revised\" License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":0,"reason":"16 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: PYSEC-2021-142 / GHSA-8q59-q68h-6hv4","Warn: Project is vulnerable to: PYSEC-2018-49 / GHSA-rprw-h62v-c2w7","Warn: Project is vulnerable to: PYSEC-2014-14 / GHSA-652x-xj99-gmcc","Warn: Project is vulnerable to: GHSA-9hjg-9r4m-mvj7","Warn: Project is vulnerable to: GHSA-9wx4-h78v-vm56","Warn: Project is vulnerable to: PYSEC-2014-13 / GHSA-cfj3-7x9c-4p3h","Warn: Project is vulnerable to: PYSEC-2018-28 / GHSA-x84v-xcm2-53pg","Warn: Project is vulnerable to: PYSEC-2022-42986 / GHSA-43fp-rhv2-5gv8","Warn: Project is vulnerable to: PYSEC-2023-135 / GHSA-xqr8-7jwr-rhp7","Warn: Project is vulnerable to: PYSEC-2024-60 / GHSA-jjg7-2v4v-x38h","Warn: Project is vulnerable to: PYSEC-2022-42969","Warn: Project is vulnerable to: PYSEC-2023-74 / GHSA-j8r2-6x86-q33q","Warn: Project is vulnerable to: GHSA-34jh-p97f-mpxf","Warn: Project is vulnerable to: PYSEC-2023-212 / GHSA-g4mx-q9vg-27p4","Warn: Project is vulnerable to: GHSA-pq67-6m6q-mj2v","Warn: Project is vulnerable to: PYSEC-2023-192 / GHSA-v845-jxx5-vc9f"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 25 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-23T18:07:20.095Z","repository_id":39800869,"created_at":"2025-08-23T18:07:20.095Z","updated_at":"2025-08-23T18:07:20.095Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31504897,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-07T03:10:19.677Z","status":"ssl_error","status_checked_at":"2026-04-07T03:10:13.982Z","response_time":105,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":[],"created_at":"2024-07-31T07:01:21.727Z","updated_at":"2026-04-07T07:48:23.852Z","avatar_url":"https://github.com/smarkets.png","language":"Python","funding_links":[],"categories":["Python"],"sub_categories":[],"readme":"# Marge-bot [![Test](https://github.com/smarkets/marge-bot/actions/workflows/test.yml/badge.svg)](https://github.com/smarkets/marge-bot/actions/workflows/test.yml)\n\nMarge-bot is a merge-bot for GitLab that, beside other goodies,\nimplements\n[the Not Rocket Science Rule Of Software Engineering:](http://graydon2.dreamwidth.org/1597.html)\n\n\u003e automatically maintain a repository of code that always passes all the tests.\n\n— Graydon Hoare, main author of Rust\n\nThis simple rule of thumb is still nowadays surprisingly difficult to implement\nwith the state-of-the-art tools, and more so in a way that scales with team size\n(also see our [blog\npost](https://smarketshq.com/marge-bot-for-gitlab-keeps-master-always-green-6070e9d248df)).\n\nTake, for instance, GitHub's well-known\n[pull-request workflow](https://help.github.com/categories/collaborating-with-issues-and-pull-requests).\nHere, CI needs to pass on the branch before the pull request can be accepted but\nafter that, the branch is immediately merged (or rebased) into master. By the\ntime this happens, enough changes may have occurred to induce test breakage, but\nthis is only to be found out when the commits have already landed.\n\nGitLab (in their [enterprise edition](https://about.gitlab.com/products/)),\noffers an important improvement here with\ntheir\n[semi-linear history and fast-forward](https://docs.gitlab.com/ee/user/project/merge_requests/) merge\nrequest methods: in both cases a merge request can only be accepted if the\nresulting master branch will be effectively the same as the merge request branch\non which CI has passed. If master has changed since the tests were last run, it\nis the *user's responsibility* to rebase the changes and retry. But this just\ndoesn't scale: if you have, a mono-repo, a large team working on short-lived\nbranches, a CI pipeline that takes 5-10 minutes to complete... then the number\nof times one need's to rebase-and-try-to-accept starts to become unbearable.\n\nMarge-bot offers the simplest of workflows: when a merge-request is ready, just\nassign it to its user, and let her do all the rebase-wait-retry for you. If\nanything goes wrong (merge conflicts, tests that fail, etc.) she'll leave a\nmessage on the merge-request, so you'll get notified. Marge-bot can handle an\nadversarial environment where some developers prefer to merge their own changes,\nso the barrier for adoption is really low.\n\nWhether marge-bot will or not wait for pipeline to succeed depends on the value of \"✓\nPipelines must succeed\" checkbox in your repo. It is available in all Gitlab\nversions, so should not be a barrier.\n\nSince she is at it, she can optionally provide some other goodies like tagging\nof commits (e.g. `Reviewed-by: ...`) or preventing merges during certain hours.\n\n\n## Configuring\n\nArgs that start with '--' (eg. `--auth-token`) can also be set in a config file\n(specified via `--config-file`). The config file uses YAML syntax and must\nrepresent a YAML 'mapping' (for details, see\nhttp://learn.getgrav.org/advanced/yaml). If an arg is specified in more than one\nplace, then commandline values override environment variables which override\nconfig file values which override defaults.\n\n```bash\noptional arguments:\n  -h, --help            show this help message and exit\n  --config-file CONFIG_FILE\n                        config file path   [env var: MARGE_CONFIG_FILE] (default: None)\n  --auth-token TOKEN    Your GitLab token.\n                        DISABLED because passing credentials on the command line is insecure:\n                        You can still set it via ENV variable or config file, or use \"--auth-token-file\" flag.\n                           [env var: MARGE_AUTH_TOKEN] (default: None)\n  --auth-token-file FILE\n                        Path to your GitLab token file.\n                           [env var: MARGE_AUTH_TOKEN_FILE] (default: None)\n  --gitlab-url URL      Your GitLab instance, e.g. \"https://gitlab.example.com\".\n                           [env var: MARGE_GITLAB_URL] (default: None)\n  --use-https           use HTTP(S) instead of SSH for GIT repository access\n                           [env var: MARGE_USE_HTTPS] (default: False)\n  --ssh-key KEY         The private ssh key for marge so it can clone/push.\n                        DISABLED because passing credentials on the command line is insecure:\n                        You can still set it via ENV variable or config file, or use \"--ssh-key-file\" flag.\n                           [env var: MARGE_SSH_KEY] (default: None)\n  --ssh-key-file FILE   Path to the private ssh key for marge so it can clone/push.\n                           [env var: MARGE_SSH_KEY_FILE] (default: None)\n  --embargo INTERVAL[,..]\n                        Time(s) during which no merging is to take place, e.g. \"Friday 1pm - Monday 9am\".\n                           [env var: MARGE_EMBARGO] (default: None)\n  --use-merge-strategy  Use git merge instead of git rebase to update the *source* branch (EXPERIMENTAL)\n                        If you need to use a strict no-rebase workflow (in most cases\n                        you don't want this, even if you configured gitlab to use merge requests\n                        to use merge commits on the *target* branch (the default).)\n                           [env var: MARGE_USE_MERGE_STRATEGY] (default: False)\n  --rebase-remotely     Instead of rebasing in a local clone of the repository, use GitLab's\n                        built-in rebase functionality, via their API. Note that Marge can't add\n                        information in the commits in this case.\n                           [env var: MARGE_REBASE_REMOTELY] (default: False)\n  --add-tested          Add \"Tested: marge-bot \u003c$MR_URL\u003e\" for the final commit on branch after it passed CI.\n                           [env var: MARGE_ADD_TESTED] (default: False)\n  --batch               Enable processing MRs in batches\n                           [env var: MARGE_BATCH] (default: False)\n  --add-part-of         Add \"Part-of: \u003c$MR_URL\u003e\" to each commit in MR.\n                           [env var: MARGE_ADD_PART_OF] (default: False)\n  --add-reviewers       Add \"Reviewed-by: $approver\" for each approver of MR to each commit in MR.\n                           [env var: MARGE_ADD_REVIEWERS] (default: False)\n  --impersonate-approvers\n                        Marge-bot pushes effectively don't change approval status.\n                           [env var: MARGE_IMPERSONATE_APPROVERS] (default: False)\n  --merge-order {created_at,updated_at,assigned_at}\n                        Order marge merges assigned requests. created_at (default), updated_at or assigned_at.\n                           [env var: MARGE_MERGE_ORDER] (default: created_at)\n  --approval-reset-timeout APPROVAL_RESET_TIMEOUT\n                        How long to wait for approvals to reset after pushing.\n                        Only useful with the \"new commits remove all approvals\" option in a project's settings.\n                        This is to handle the potential race condition where approvals don't reset in GitLab\n                        after a force push due to slow processing of the event.\n                           [env var: MARGE_APPROVAL_RESET_TIMEOUT] (default: 0s)\n  --project-regexp PROJECT_REGEXP\n                        Only process projects that match; e.g. 'some_group/.*' or '(?!exclude/me)'.\n                           [env var: MARGE_PROJECT_REGEXP] (default: .*)\n  --ci-timeout CI_TIMEOUT\n                        How long to wait for CI to pass.\n                           [env var: MARGE_CI_TIMEOUT] (default: 15min)\n  --max-ci-time-in-minutes MAX_CI_TIME_IN_MINUTES\n                        Deprecated; use --ci-timeout.\n                           [env var: MARGE_MAX_CI_TIME_IN_MINUTES] (default: None)\n  --git-timeout GIT_TIMEOUT\n                        How long a single git operation can take.\n                           [env var: MARGE_GIT_TIMEOUT] (default: 120s)\n  --git-reference-repo GIT_REFERENCE_REPO\n                        A reference repo to be used when git cloning.\n                           [env var: MARGE_GIT_REFERENCE_REPO] (default: None)\n  --branch-regexp BRANCH_REGEXP\n                        Only process MRs whose target branches match the given regular expression.\n                           [env var: MARGE_BRANCH_REGEXP] (default: .*)\n  --source-branch-regexp SOURCE_BRANCH_REGEXP\n                        Only process MRs whose source branches match the given regular expression.\n                           [env var: MARGE_SOURCE_BRANCH_REGEXP] (default: .*)\n  --debug               Debug logging (includes all HTTP requests etc).\n                           [env var: MARGE_DEBUG] (default: False)\n  --cli                 Run marge-bot as a single CLI command, not as a long-running service.\n                        This may be used to run marge-bot in scheduled CI pipelines or cronjobs.\n                           [env var: MARGE_CLI] (default: False)\n  --use-no-ff-batches   Disable fast forwarding when merging MR batches   [env var: MARGE_USE_NO_FF_BATCHES] (default: False)\n  --use-merge-commit-batches\n                        Use merge commit when creating batches, so that the commits in the batch MR will be the same with in individual MRs. Requires sudo scope in the access token.\n                           [env var: MARGE_USE_MERGE_COMMIT_BATCHES] (default: False)\n  --skip-ci-batches     Skip CI when updating individual MRs when using batches   [env var: MARGE_SKIP_CI_BATCHES] (default: False)\n```\nHere is a config file example\n```yaml\nadd-part-of: true\nadd-reviewers: true\nadd-tested: true\n# choose one way of specifying the Auth token\n#auth-token: TOKEN\nauth-token-file: token.FILE\nbranch-regexp: .*\nci-timeout: 15min\nembargo: Friday 1pm - Monday 9am\nbatch: false\ngit-timeout: 120s\ngitlab-url: \"https://gitlab.example.com\"\nimpersonate-approvers: true\nproject-regexp: .*\n# choose one way of specifying the SSH key\n#ssh-key: KEY\nssh-key-file: token.FILE\n# OR use HTTPS instead of SSH\n#use-https: true\n```\nFor more information about configuring marge-bot see `--help`\n\n\n## Running\n\nFirst, create a user for Marge-bot on your GitLab. We'll use `marge-bot` as\nusername here as well. GitLab sorts users by Name, so we recommend you pick one\nthat starts with a space, e.g. ` Marge Bot`, so it is quicker to assign to (our\ncode strips trailing whitespace in the name, so it won't show up elsewhere).\nThen add `marge-bot` to your projects as `Developer` or `Maintainer`, the latter\nbeing required if she will merge to protected branches.\n\nFor certain features, namely, `--impersonate-approvers`, and `--add-reviewers`,\nyou will need to grant `marge-bot` admin privileges as well. In the latter, so\nthat she can query the email of the reviewers to include it in the commit. Note\nthat if you're trying to run marge-bot against a GitLab instance you don't have\nyourself admin access to (e.g. https://www.gitlab.com), you won't be able to use\nfeatures that require admin for marge-bot.\n\nSecond, you need an authentication token for the `marge-bot` user. You will need\nto select the `api` and `read_user` scopes in all cases.\n\nIf marge-bot was made an admin to handle approver impersonation and/or adding a\nreviewed-by field, then you will also need to add **`sudo`** scope under\n`Impersonation Tokens` in the User Settings. Assuming your GitLab install is\ninstall is `https://your-gitlab.example.com` the link will be at\n`https://your-gitlab.example.com/admin/users/marge-bot/impersonation_tokens`).\n\nOn older GitLab installs, to be able to use impersonation features if marge-bot\nwas made an admin, use the **PRIVATE TOKEN** found in marge-bot's `Profile\nSettings`; otherwise just use a personal token (you will need to impersonate the\nmarge-bot user via the admin UI to get the private token, it should then be at\n`http://my-gitlab.example.com/profile/personal_access_tokens` reachable via\n`Profile Settings -\u003e Acess Tokens`).\n\nOnce you have the token, put it in a file, e.g. `marge-bot.token`.\n\nFinally, create a new ssh key-pair, e.g like so\n\n```bash\nssh-keygen -t ed25519 -C marge-bot@invalid -f marge-bot-ssh-key -P ''\n```\n\nAdd the public key (`marge-bot-ssh-key.pub`) to the user's `SSH Keys` in GitLab\nand keep the private one handy.\n\n### Running marge-bot in docker using SSH (what we do)\n\nAssuming you have already got docker installed, the quickest and most minimal\nway to run marge is like so (*but see note about passing secrets on the\ncommandline below*):\n\n```bash\ndocker run --restart=on-failure \\ # restart if marge crashes because GitLab is flaky\n  -e MARGE_AUTH_TOKEN=\"$(cat marge-bot.token)\" \\\n  -e MARGE_SSH_KEY=\"$(cat marge-bot-ssh-key)\" \\\n  smarkets/marge-bot \\\n  --gitlab-url='http://your.gitlab.instance.com'\n```\n\nNote that other users on the machine can see the secrets in `ps`, because\nalthough they are env vars *inside* docker, we used a commandline switch to set\nthem for docker run.\n\nTo avoid that you have several options. You can just use a yaml file and mount\nthat into the container, for example this is how we actually run marge-bot at\nSmarkets ourselves:\n\n```yaml\n# marge-bot-config.yml\nadd-part-of: true\nadd-reviewers: true\nadd-tested: true\nimpersonate-approvers: true\ngitlab-url: \"https://git.corp.smarkets.com\"\nproject-regexp: \"smarkets/smarkets$\"\nauth-token: \"WoNtTelly0u\"\nssh-key: |\n    -----BEGIN OPENSSH PRIVATE KEY-----\n    [...]\n    -----END OPENSSH PRIVATE KEY-----\n```\n\n```bash\ndocker run --restart=on-failure \\\n  -v \"$(pwd)\":/configuration \\\n  smarkets/marge-bot \\\n  --config-file=/configuration/marge-bot-config.yaml\n```\n\nBy default docker will use the `latest` tag, which corresponds to the latest\nstable version. You can also use the `stable` tag to make this more explicit.\nIf you want a development version, you can use the `master` tag to obtain an\nimage built from the HEAD commit of the `master` branch. Note that this image\nmay contain bugs.\n\nYou can also specify a particular version as a tag, e.g.\n`smarkets/marge-bot:0.7.0`.\n\n### Running marge-bot in docker using HTTPS\n\nIt is also possible to use Git over HTTPS instead of Git over SSH. To use HTTPS instead of SSH,\nadd the `--use-https` flag and do not provide any SSH keys. Alternatively you can set the\nenvironment variable `MARGE_USE_HTTPS` or the config file property `use-https`.\n\n```bash\ndocker run --restart=on-failure \\ # restart if marge crashes because GitLab is flaky\n  -e MARGE_AUTH_TOKEN=\"$(cat marge-bot.token)\" \\\n  smarkets/marge-bot \\\n  --use-https \\\n  --gitlab-url='http://your.gitlab.instance.com'\n```\n\nHTTPS can be used using any other deployment technique as well.\n\n### Running marge-bot in kubernetes\nIt's also possible to run marge in kubernetes, e.g. here's how you use a ktmpl\ntemplate:\n\n```bash\nktmpl ./deploy.yml \\\n--parameter APP_NAME \"marge-bot\" \\\n--parameter APP_IMAGE \"smarkets/marge-bot\" \\\n--parameter KUBE_NAMESPACE \"marge-bot\" \\\n--parameter MARGE_GITLAB_URL 'http://your.gitlab.instance.com' \\\n--parameter MARGE_AUTH_TOKEN \"$(cat marge-bot.token)\" \\\n--parameter MARGE_SSH_KEY \"$(cat marge-bot-ssh-key)\" \\\n--parameter REPLICA_COUNT 1 | kubectl -n=${KUBE_NAMESPACE} apply --force -f -\n```\n\nOnce running, the bot will continuously monitor all projects that have its user as a member and\nwill pick up any changes in membership at runtime.\n\n### Running marge-bot in Swarm\nOr you can run marge in Docker Swarm, e.g. here's how you use a compose file:\n\n```yaml\nversion: '3.8'\nservices:\n  marge-bot:\n    image: smarkets/marge-bot:latest\n    configs:\n      - source: marge_bot_config\n        target: /configuration/marge-bot-config.yaml\n    command:\n      - \"--config-file=/configuration/marge-bot-config.yaml\"\n    deploy:\n      mode: replicated\n      replicas: 1\n      restart_policy:\n        condition: on-failure\n      resources:\n        limits:\n          memory: 256M\n\nconfigs:\n  marge_bot_config:\n    file: ./marge-bot-config.yaml\n    name: marge_bot_config\n```\n\n### Running marge-bot in CI\n\nYou can also run marge-bot directly in your existing CI via scheduled pipelines\nif you'd like to avoid setting up any additional infrastructure.\n\nThis way, you can inject secrets for marge-bot's credentials at runtime\ninside the ephemeral container for each run by adding them to protected CI/CD\nvariables in a dedicated marge-bot runner project, as well as store execution\nlogs as artifacts for evidence.\n\nYou can also configure multiple setups in different CI schedules by supplying\n`MARGE_*` environment variables per-schedule, such as running a different set\nof projects or settings at different times.\n\nNote that in this case, marge-bot will be slower than when run as a service,\ndepending on the frequency of your pipeline schedules.\n\nCreate a marge-bot runner project, and add the variables `MARGE_AUTH_TOKEN`\n(of type Variable) and `MARGE_SSH_KEY_FILE` (of type File) in your CI/CD\nVariables settings.\n\nThen add a scheduled pipeline run to your project with the following minimal\n`.gitlab-ci.yml` config:\n\n```yaml\nrun:\n  image:\n    name: smarkets/marge-bot:latest\n    entrypoint: [\"\"]\n  only:\n    - schedules\n  variables:\n    MARGE_CLI: \"true\"\n    MARGE_GITLAB_URL: \"$CI_SERVER_URL\"\n  script: marge.app\n```\n\n### Running marge-bot as a plain python app\n\n#### Installing marge-bot with nix\n\nAlternatively, if you prefer not to use docker, you can also directly run marge.\nIf you use [nix](https://nixos.org/nix/) do `nix-env --install -f default.nix`.\n\nThe nix install should be fully reproducible on any version of linux (and also\nwork on OS X, although this is not something we properly test). If you don't\nwant to use docker we recommend you give nix a try.\n\n#### Installing marge-bot the old-fashioned way\n\nFinally, although this is our least preferred alternative, you can always do\n`python3 setup.py install` (note that you can use python3.6 to python3.9).\n\nAfterwards, the minimal way to run marge is as follows.\n\n```bash\nmarge.app --auth-token-file marge-bot.token \\\n          --gitlab-url 'http://your.gitlab.instance.com' \\\n          --ssh-key-file marge-bot-ssh-key\n```\n\nHowever, we suggest you use a systemd unit file or some other mechanism to\nautomatically restart marge-bot in case of intermittent GitLab problems.\n\n## Suggested workflow\n1. Alice creates a new merge request and assigns Bob and Charlie as reviewers\n\n2. Both review the code and after all issues they raise are resolved by Alice,\n   they approve the merge request and assign it to `marge-bot` for merging.\n\n3. Marge-bot rebases the latest target branch (typically master) into the\n   merge-request branch and pushes it. Once the tests have passed and there is a\n   sufficient number of approvals (if a minimal approvals limit has been set on\n   the project), Marge-bot will merge (or rebase, depending on project settings)\n   the merge request via the GitLab API. It can also add some headers to all\n   commits in the merge request as described in the next section.\n\n\n## Adding Reviewed-by:, Tested: and Part-of: to commit messages\n\nMarge-bot supports automated addition of the following\ntwo [standardized git commit trailers](https://www.kernel.org/doc/html/v4.11/process/submitting-patches.html#using-reported-by-tested-by-reviewed-by-suggested-by-and-fixes):\n`Reviewed-by` and `Tested-by`. For the latter it uses `Marge Bot\n\u003c$MERGE_REQUEST_URL\u003e` as a slight abuse of the convention (here `Marge Bot` is\nthe name of the `marge-bot` user in GitLab).\n\nIf you pass `--add-reviewers` and the list of approvers is non-empty and you\nhave enough approvers to meet the required approver count, Marge will add the\nfollowing header to each commit message and each reviewer as it rebases the\ntarget branch into your PR branch:\n\n```\nReviewed-by: A. Reviewer \u003ca.reviewer@example.com\u003e\n```\n\nAll existing `Reviewed-by:` trailers on commits in the branch will be stripped. This\nfeature requires marge to run with admin privileges due to a peculiarity of the\nGitLab API: only admin users can obtain email addresses of other users, even\nones explicitly declared as public (strangely this limitation is particular to\nemail, Skype handles etc. are visible to everyone).\n\nIf you pass `--add-tested` the final commit message in a PR will be tagged with\n`Tested-by: marge-bot \u003c$MERGE_REQUEST_URL\u003e` trailer. This can be very useful for\ntwo reasons:\n\n1. Seeing where stuff \"came from\" in a rebase-based workflow\n2. Knowing that a commit has been tested, which is e.g. important for bisection\n   so you can easily and automatically `git bisect --skip` untested commits.\n\nAdditionally, by using `--add-part-of`, all commit messages will be tagged with\na `Part-of: \u003c$MERGE_REQUEST_URL\u003e` trailer to the merge request on which they\nwere merged. This is useful, for example, to go from a commit shown in `git\nblame` to the merge request on which it was introduced or to easily revert a all\ncommits introduced by a single Merge Request when using a fast-forward/rebase\nbased merge workflow.\n\n## Impersonating approvers\nIf you want a full audit trail, you will configure GitLab\n[require approvals](https://docs.gitlab.com/ee/user/project/merge_requests/merge_request_approvals.html#approvals-required)\nfor PRs and also turn on\n[reset approvals on push](https://docs.gitlab.com/ee/user/project/merge_requests/merge_request_approvals.html#reset-approvals-on-push).\nUnfortunately, since Marge-bot's flow is based on pushing to the source branch, this\nmeans it will reset the approval status if the latter option is enabled.\nHowever, if you have given Marge-bot admin privileges and turned on\n`--impersonate-approvers`, she will re-approve the merge request assuming after its own\npush, but by impersonating the existing approvers.\n\n## Merge embargoes\n\nMarge-bot can be configured not to merge during certain periods. E.g., to prevent\nher from merging during weekends, add `--embargo 'Friday 6pm - Monday 9am'`.\nThis is useful for example if you automatically deploy from master and want to\nprevent shipping late on a Friday, but still want to allow marking merge requests as\n\"to be merged on Monday\": just assign them to `marge-bot` as any other day.\n\nMore than one embargo period can be specified, separated by commas. Any merge\nrequest assigned to her during an embargo period, will be merged in only once all\nembargoes are over.\n\n\n## Batching Merge Requests\n\nThe flag `--batch` enables testing and merging merge requests in batches. This can\nsignificantly speed up the rate at which marge-bot processes jobs - not just\nbecause merge requests can be tested together, but because marge-bot will ensure\nthe whole set of merge requests is mergeable first. This includes, for example,\nchecking if a merge request is marked as WIP, or does not have enough approvals.\nEssentially, users get faster feedback if there is an issue. Note that you\nprobably won't need this unless you have tens of merge requests a day (or\nextremely slow CI).\n\n### How it works\n\nIf marge-bot finds multiple merge requests to deal with, she attempts to create\na batch job. She filters the merge requests such that they have all have a\ncommon target branch, and eliminates those that have not yet passed CI (a\nheuristic to help guarantee the batch will pass CI later).\n\nOnce the merge requests have been gathered, a batch branch is created using the\ncommits from each merge request in sequence. Any merge request that cannot be\nmerged to this branch (e.g. due to a rebase conflict) is filtered out. A new\nmerge request is then created for this branch, and tested in CI.\n\nIf CI passes, the original merge requests will be merged one by one.\n\nIf the batch job fails for any reason, we fall back to merging the first merge\nrequest, before attempting a new batch job.\n\n### Limitations\n\n* Currently we still add the tested-by trailer for each merge request's final\n  commit in the batch, but it would probably be more correct to add the trailer\n  only to the last commit in the whole batch request (since that's the only one\n  we know passed for sure in that combination). We might change this in the\n  future or make it configurable, but note that there's still a much stronger\n  chance all intermittent final commits also passed then when just testing on\n  each source branch, because we know the final linearization of all commits\n  passes in that all MRs passed individually on their branches.\n\n* As trailers are added to the original merge requests only, their branches\n  would need to be pushed to in order to reflect this change. This would trigger\n  CI in each of the branches again that would have to be passed before merging,\n  which effectively defeats the point of batching. To workaround this, the\n  current implementation merges to the target branch through git, instead of the\n  GitLab API. GitLab will detect the merge request as having been merged, and\n  update the merge request status accordingly, regardless of whether it has\n  passed CI. This does still mean the triggered CI jobs will be running even\n  though the merge requests are merged. marge-bot will attempt to cancel these\n  pipelines, although this doesn't work too effectively if external CI is used.\n\n* There is what can be considered to be a flaw in this implementation that could\n  potentially result in a non-green master; consider the following situation:\n\n  1. A batch merge request is created, and passes CI.\n  2. Several merge requests are then merged to master, but one could fail\n     (perhaps due to someone pushing directly to master in between).\n  3. At this point, marge-bot will abort the batch job, resulting in a subset of\n     the batch merge requests having been merged.\n\n  We've guaranteed that individually, each of these merge requests pass CI, and\n  together with some extra merge requests they also pass CI, but this does not\n  guarantee that the subset will. However, this would only happen in a rather\n  convoluted situation that can be considered to be very rare.\n\n## Restricting the list of projects marge-bot considers\n\nBy default marge-bot will work on all projects that she is a member of.\nSometimes it is useful to restrict a specific instance of marge-bot to a subset\nof projects. You can specify a regexp that projects must match (anchored at the\nstart of the string) with `--project-regexp`.\n\nOne use-case is if you want to use different configurations (e.g.\n`--add-reviewers` on one project, but not the others). A simple way of doing is\nrun two instances of marge-bot passing `--add-reviewers --project-regexp\nproject/with_reviewers` to the first instance and `--project-regexp\n(?!project/with_reviewers)` to the second ones. The latter regexp is a negative\nlook-ahead and will match any string not starting with `project/with_reviewers`.\n\n## Restricting the list of branches marge-bot considers\n\nIt is also possible to restrict the branches marge-bot watches for incoming\nmerge requests. By default, marge-bot will process MRs targeted for any branch.\nYou may specify a regexp that target branches must match with `--branch-regexp`.\n\nThis could be useful, if for instance, you wanted to set a regular freeze\ninterval on your master branches for releases. You could have one instance of\nmarge-bot with `--embargo \"Friday 1pm - Monday 9am\" --branch-regexp master` and\nthe other with `--branch-regexp (?!master)`. This would allow development to\ncontinue on other branches during the embargo on master.\n\nIt is possible to restrict the source branches with `--source-branch-regexp`.\n\n## Some handy git aliases\n\nOnly `git bisect run` on commits that have passed CI (requires running marge-bot with `--add-tested`):\n```\ngit config --global alias.bisect-run-tested \\\n 'f() { git bisect run /bin/sh -c \"if !(git log -1 --format %B | fgrep -q \\\"Tested-by: Marge Bot\\\"); then exit 125; else \"$@\"; fi\"; }; f'\n```\nE.g. `git bisect-run-tested ./test-for-some-bug.sh`.\n\nRevert a whole MR, in a rebase based workflow (requires running marge-bot with `--add-part-of`):\n```\ngit config --global alias.mr-revs '!f() { git log --grep \"^Part-of.*/\"\"$1\"\"\u003e\" --pretty=\"%H\"; }; f'\ngit config --global alias.mr-url '!f() { git log -1 --grep \"^Part-of.*/\"\"$1\"\"\u003e\" --pretty=\"%b\" | grep \"^Part-of.*/\"\"$1\"\"\u003e\"  | sed \"s/.*\u003c\\\\(.*\\\\)\u003e/\\\\1/\"; }; f'\ngit config --global alias.revert-mr '!f() { REVS=$(git mr-revs \"$1\"); URL=\"$(git mr-url \"$1\")\";  git revert --no-commit $REVS;  git commit -m \"Revert \u003c$URL\u003e$(echo;echo; echo \"$REVS\" | xargs -I% echo \"This reverts commit %.\")\"; }; f'\n```\n\nE.g. `git revert-mr 123`. This will create a single commit reverting all commits\nthat are part of MR 123 with a commit message that looks like this:\n\n```\nRevert \u003chttp://gitlab.example.com/mygropup/myproject/merge_requests/123\u003e\n\nThis reverts commit 86a3d35d9bc12e735efbf72f3e2fb895c0158713.\nThis reverts commit e862330a6df463e36137664f316c18b5836a4df7.\nThis reverts commit 0af5b70a98858c9509c895da2a673ebdb31e20b1.\n```\n\nE.g. `git revert-mr 123`.\n\n\n## Troubleshooting\n\nMarge-bot continuously logs what she is doing, so this is a good place to look\nin case of issues. In addition, by passing the `--debug` flag, additional info\nsuch as REST requests and responses will be logged. When opening an issue,\nplease include a relevant section of the log, ideally ran with `--debug` enabled.\n\nThe most common source of issues is the presence of git-hooks that reject\nMarge-bot as a committer. These may have been explicitly installed by someone in\nyour organization or they may come from the project configuration. E.g., if you\nare using `Settings -\u003e Repository -\u003e Commit author's email`, you may need to\nwhitelist `marge-bot`'s email.\n\nSome versions of GitLab are not good at reporting merge failures due to hooks\n(the REST API may even claim the merge operation succeeded), you can find\nthis in `gitlab-rails/githost.log`, under GitLab's logs directory.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsmarkets%2Fmarge-bot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsmarkets%2Fmarge-bot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsmarkets%2Fmarge-bot/lists"}