Skip to content

Mergebot

Rémy Voet edited this page Jul 9, 2024 · 52 revisions

Introduction

The merge bot is a tool to orchestrate the integration of pull requests (PR) into the reference branches of Odoo. Its goal is to ensure every PR is tested, approved, and cleanly integrates, although it does rely on tests and code being deterministic to work correctly.

The mergebot works by tracking the progress of PRs through a validation pipeline, then staging them by merging a bunch of PRs into a staging branch, testing that, and merging those PRs into the branch on success.

If the staging fails, the mergebot will split the staging and stage the splits to try to find out if there is a specific PR at issue, and put it in the error state.

Odoo workflow

For a developer

  1. Create your PR
  2. Squash appropriate commits to keep only meaningful ones
  3. Write commit messages respecting the commit guidelines
  4. If your PR contains more than one commit, clean the pull request description to match the commit guidelines too (it may be used as the merge commit message)
  5. Ask a review to one of the authorized reviewers (see with your team gooroo for the reviewers for your team and tasks)

For a reviewer

  1. Review the pull request (actually a mandatory step).
  2. If there are multiple reviews requested, you can use Github's "Approve", otherwise skip to next step.
  3. If all reviewers have approved, either use review+ or delegate, to start the merging process.
  4. If the PR contains multiple commits, configure its integration mode

Available Commands

A command string is a line starting with the mergebot's name (robodoo, @ prefix optional) and followed by various commands.

For Authors and reviewers

  • retry

    If the mergebot attempts to integrate the PR and gets an error, it will put the PR in error state.

    If you determine that the failure was not related to your PR e.g. it was caused by a flaky test (a test which is partially non-deterministic and may succeed or fail for reasons unrelated code changes), then you can retry it to remove the error status and make it ready for staging again.

    Note: if you need to update the PR, it will automatically be reset and does not need to be reset.

  • r(eview)-

    Removes approval from a PR. Most useful after noticing an error or issue with the PR, to ensure it does not get needlessly staged (or worse incorrectly merged).

    Can be used to remove a PR from staging after noticing that it causes the staging to fail deterministically. In that case it is recommended to warn the runbot team to validate the findings and reset stagings.

For reviewers and delegates

  • r(eview)+

    Approves a PR.

  • delegate+

    Shortcut for delegate=<pr-author>, the most common form of delegation. Can be used to request a few fixes from an author but then let them merge the PR at their convenience.

  • delegate=<users>

    Gives these rights to the specified users (as a comma-separated list of github usernames).

merge method

When a PR contains more than one commit, a merge method has to be selected to tell the mergebot how to integrate it, these methods are:

  • rebase-merge

    Rebases the PR then integrates it via a regular merge commit, the PR title and body are used to create the message of the merge commit.

  • merge

    Integrates the PR via a regular merge commit, without rebasing, the PR title and body are used to create the message of the merge commit.

  • rebase-ff

    Rebases the PR then integrates it via a fast-forward (all the commits of the PR are copied to the target).

  • squash

    Squashes the entire PR to a single commit, using the PR title and body to create the commit message.

For Reviewers

Note that these commands affect all employees significantly and should be used with care, ideally not at all or after concertation with the runbot team

  • cancel=staging

    Configures the pull request to cancel stagings any time it becomes ready. Avoids having to wait for PRs which require haste, but will severely impact others if the PR has to be retried multiple times.

Priorities

By default, ready PRs are selected for staging arbitrarily. Priority commands allow tuning this behaviour:

  • default

    Resets a PR to its default behaviour of being picked whenever it is picked.

  • priority

    Tries to stage this PR first (alongside other priority PRs). If the staging still has room when all priority PRs have been staged, fills it with default PRs.

  • alone

    Tries to stage this PR first (alongside other alone PRs). Does not fill stagings with non-alone PRs afterwards. This should be reserved for urgent PRs.

Other

  • override=<status name>

    Allows overriding whatever status was sent by the runbot or CI.

    The override is persistently linked to the pull request, updates to the pull request (status or code) will not reset them. Example: override=ci/style

    Override rights are orthogonal from general review rights and are configured separately, so it is possible to have override rights on a status without even being a reviewer, and the other way around.

Examples

Simple

  1. @alice creates a PR, write a good commit message and asks a review to @bob

  2. @bob writes a message to approve the PR

    robodoo review+

  3. @robodoo rebases and merges the PR

Delegation

  1. @alice creates a PR, write a good commit message and asks a review to @bob

  2. @bob is not certain of the content and would like a second opinion from @carol (who is not an authorized reviewer)

    robodoo delegate=carol

  3. @carol agrees with the PR and approves

    robodoo r+ 👍

  4. @robodoo rebases and merges the PR

Error

  1. @alice creates a PR, writes a good commit message and asks a review to @bob

  2. @bob approves the PR with r+

  3. @robodoo tries to merge it but it fails (e.g. test fail or conflict after rebase); it posts a message on PR

    Staging failed: ci/runbot failed on 4a0b13ed923

  4. @alice corrects the PR

  5. As the content has changed, @bob validates again the PR

    robodoo r+ please

  6. @robodoo rebases and merges the PR

Merge a community's contribution

  1. @alice (community member) creates a PR and asks a review to @bob

  2. @bob (reviewer) wants to slightly clean up the PR to apply code/commit guidelines

  3. As @alice, by default, allows commits in her branch when creating a PR, @bob can add the remote, fetch and checkout the branch (or, if he is lazy, use an alias to set in his ~/.gitconfig to do the same)

    $ git get-br alice:11.0-awesome-fix
    $ git commit --amend
    $ git push --force-with-lease alice 11.0-awesome-fix
    
  4. Once the PR is ready, @bob approves the amended version

    robodoo review+

  5. @robodoo rebases and merges the PR

Multiple commits with a regular merge

  1. @alice creates a PR containing multiple commits, writes a good PR title and body and asks a review to @bob

  2. @bob writes the following message to approve the PR

    robodoo r+

  3. @robodoo sends a feedback message on the github PR like this one:

    Because this PR has multiple commits, I need to know how to merge it:

    merge to merge directly, using the PR as merge commit message rebase-merge to rebase and merge, using the PR as merge commit message rebase-ff to rebase and fast-forward

  4. @alice sets the merge method to merge

    robodoo merge

  5. @robodoo creates a merge commit with the PR title and body as commit message

Multiple commits with a rebase and a merge commit

  1. @alice creates a PR containing multiple commits, writes a good PR title and body and asks a review to @bob

  2. @bob writes the following message to set the merge method and approves the PR

    robodoo rebase-merge r+

  3. @robodoo rebases and creates a merge commit with the PR title and body as commit message

Multiple commits with a rebase and fast-forward

  1. @alice creates a PR with multiple commits and good commit messages. She asks a review to @bob

  2. @alice wants the commits to be fast-forwarded, she sets the merge method

    robodoo rebase-ff

  3. @bob writes a message to set the merge method and approves the PR

    robodoo review+

  4. @robodoo rebases and fast-forwards the PR commits

Forward-port

Most pull requests will be merged to the development branch (usually "master" or "main"). However for some changes, or for bug fixes, the pull request should target the lowest version where the bug is reproducible.

Once merged, the change will then be automatically forward-ported (copied to the next branch) up to a limit (the development branch by default).

Commands

Unless otherwise specified, forward-port commands have to be specified on the original ("source") pull request, and can be used by the author of that PR.

  • up to <version>

    To use on the original PR before it is merged.

    Allows setting a forward port limit (e.g. up to 12.0): by default a pull request is forward-ported to all still-supported later versions. The limit is inclusive.

    Forward-port can be disabled by providing the original PR's target as limit e.g. if the PR was created targeting 10.0, specifying up to 10.0 will not do any forward-porting.

  • r(eview)+

    Can be used on any forward-port. Will approve that forward-port and any non-detached ancestor (predecessor in the forward-port sequence). This allows authors to merge changes as-forward-ported since the original was properly validated.

    A forward-port is detached if it is in conflict or has been updated since it was created. In that case it has to be approved the normal way.

    Note: delegation partially persists through approval, if a user is delegated on a source PR then they have approval rights on all forward ports.

  • fw=no

    Alias for up to <target branch>, disables the forward-port of this PR.

  • fw=skipci

    By default, once a PR is forward-ported the mergebot will wait for its required statuses to be valid before creating the next forward-port. This limits the number of active invalid pull requests and the number of builds required.

    This setting instructs the mergebot to create all the forward-ports eagerly without waiting.

  • fw=default

    Resets the previous setting back to waiting for statuses for each forward-port.

  • close

    As the author of the original pull request may not have write access to the repository where forward-ports are created, this requests the mergebot close their PR on their behalf.

Example:

  1. Create a branch in v16, create a PR.

  2. Follow the usual review process with @robodoo and with an optional forward-port command

    @robodoo up to saas-17.2 r+

  3. As soon as the PR is merged, the @robodoo will create a PR in version N + 1 (sticky version), in this case v17

  4. If the v17 runbot is green, a PR is created in v17.1.

  5. If the v17.1 runbot is green, a PR is created in v17.2 (the specified limit).

  6. When the v17.2 runbot is green, you can proceed on the PR for v17.2: "@robodoo r+"

  7. Every forward port PR, from v17 to v17.2 will be merged

Interrupted chain

If runbot fails on a forward-port PR, the chain will get interrupted as the bot awaits further action.

If this is a false-positive runbot failure, you can just rebuild, as soon as runbot succeeds the forward-port will continue as if nothing had happened.

If this is a real failure, you will need to edit the pull-request.

Conflict

If a conflict occurs while creating a forward-port PR, the chain will get broken, you will have to edit it to resolve the conflict, either in-place if there is a single commit or doing your own cherry-pick to re-do the forward-port resolving the conflicts.

Alternatively, the pull request can be closed (and ignored) if it turns out redundant or unnecessary from this point onwards.

Edition

A forward-port pull-request can be edited by pushing commits to it (either pushing new commits or editing and force-pushing commits). This puts the pull-request into a semi-manual mode:

  • the pull-request will have to be approved via the normal mergebot workflow
  • the forward-port process will then resume up to the limit originally configured (if any)
  • if the edited pull-request already has forward-port descendants, those descendants will automatically get updated to match

Example:

  1. Create a branch in v16, create a PR and r+ it
  2. As soon as the PR is merged, the @robodoo will create a PR in version N + 1 (sticky version), in this case v17
  3. If the v17 runbot is green, a PR is created in v17.1.
  4. If the v17.1 PR fails because of a merge conflict, solve the conflict manually and ask @robodoo to merge it when ready. You will also need to @robodoo r+ the v17 PR (so all PRs of the chain up to v17 are merged)
  5. The @robodoo will create a PR in version v17.2 based on the v17.1 port (in essence, it's the v17.1 PR that is now being forward-ported, the v16 PR is closed).