2

I have a project in GitLab, and would like to run a pre-merge CI test on in that verifies that every commit created by the merge request will compile and pass the testsuite, so that if I have to run git-bisect a year later, this will not fail because some intermediate commit does not even build.

Is there a way to create additional jobs for commits other than the branch tip?

Simon Richter
  • 28,572
  • 1
  • 42
  • 64
  • Maybe consider using the "squash commits" option when merging? Then you only have to worry about the MR being in a green state at the time it is merged. It's probably also easier than rewriting history to fix intermediate commits that fail. Obviously, squash&merge has other implications, but if it works for you, it will probably be a lighter touch than enforcing every commit in an MR pass tests and fixing those that don't. – sytech Jul 10 '23 at 17:20

1 Answers1

2

run a pre-merge CI test on in that verifies that every commit created by the merge request will compile and pass the testsuite

That looks... extremely resource-intensive and time-consuming!
If the branch you want to merge has many commits, or if your build and test process is long, this could take a considerable amount of time.

GitLab CI/CD, by default, is designed to run on the latest commit of a merge request (MR). However, if you want to run the pipeline for every single commit in the MR, there is not an out-of-the-box feature that would allow you to do so directly.

However, if you insist on running the pipeline on every commit, you might need to set up a custom script in your GitLab CI configuration.

Here is an example of what that would look like:

test_all_commits:
  script: |
    #! /bin/bash
    # Start by fetching all the branches
    git fetch --all

    # Get the commit hash of the branch to merge
    branch_hash=$(git rev-parse $CI_COMMIT_REF_NAME)

    # Get the commit hash of the target branch to merge into
    target_branch_hash=$(git rev-parse $CI_MERGE_REQUEST_TARGET_BRANCH_NAME)

    # Find the common ancestor of the two branches
    common_ancestor=$(git merge-base $branch_hash $target_branch_hash)

    # Get the list of all commits between the common ancestor and the branch to merge
    commit_list=$(git rev-list $common_ancestor..$branch_hash)

    # Loop over each commit
    for commit in $commit_list; do
      # Check out the commit
      git checkout $commit

      # Run your build and test commands
      make test

      # If the build or test fails, exit with an error code
      if [ $? -ne 0 ]; then
        exit 1
      fi
    done
  only:
    - merge_requests

Do replace make test with the commands you need to run to build and test your project.

That will checkout each commit between the branch you want to merge and its common ancestor with the branch you want to merge into (CI_MERGE_REQUEST_TARGET_BRANCH_NAME, but only in merge request pipeline, as mentioned here), and then run your build and test commands.
If any commit fails to build or pass the tests, the script will exit with an error code, causing the pipeline to fail.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • Yes, it is resource-intensive, but being able to `git bisect run` to find a bug is so worth it. – Simon Richter Jul 10 '23 at 12:13
  • @SimonRichter No problem, as long as your infrastructure and build time are compatible (powerful enough, and not too long), go for it. – VonC Jul 10 '23 at 13:30