Force pipeline on tag push when commit message contains `[skip ci]`

Hello,

I’m using semantic-release to automatically create new releases after updating CHANGELOG.md and I would like to run some jobs when the tag is pushed

  1. Merge a contribution in the master branch
  2. The CI run the build and release stages against the master branch
    1. semantic-release update CHANGELOG.md and add a commit with the subject containing chore(release): X.Y.Z [skip ci]
    2. semantic-release create a tag with the new version
    3. semantic-release create the new release in gitlab
  • What are you seeing, and how does that differ from what you expect to see?

The pipeline for the tag is Skipped

skipped-pipeline-for-tags

  • What version are you on? Are you using self-managed or GitLab.com?

    • GitLab (Hint: /help): 13.9.4-ee (fb7eeedfaf4) self hosted
    • Runner (Hint: /admin/runners): 14.2.0
  • Add the CI configuration from .gitlab-ci.yml and other configuration if relevant (e.g. docker-compose.yml)

gitlab-ci.yml
# -*- coding: utf-8 -*-
# vim: ft=yaml
---
###############################################################################
# Define stages and global variables
###############################################################################
stages:
  - lint
  - build
  - release

variables:
  DOCKER_DRIVER: overlay2

###############################################################################
# `lint` stage: `commitlint`
###############################################################################
commitlint:
  stage: lint
  rules:
    - if: $CI_COMMIT_BRANCH
  image: 'hub.eole.education/eole/commitlint:latest'
  before_script:
    # Add `upstream` remote to get access to `upstream/${CI_DEFAULT_BRANCH}`
    - "git remote show upstream 2> /dev/null || git remote add upstream ${CI_REPOSITORY_URL}"
    - 'git fetch --all'
  after_script:
    # Remove `upstream` to avoid caching `CI_JOB_TOKEN`
    - "git remote remove upstream"
  script:
    # Set default commit hashes for `--from` and `--to`
    - 'export COMMITLINT_FROM="$(git merge-base upstream/${CI_DEFAULT_BRANCH} HEAD)"'
    - 'export COMMITLINT_TO="${CI_COMMIT_SHA}"'
    # Run `commitlint`
    - 'commitlint --from "${COMMITLINT_FROM}"
                  --to   "${COMMITLINT_TO}"
                  --verbose'

###############################################################################
# `build` stage: `*-docker-build`
###############################################################################
# Suffix all jobs to avoid conflict with other jobs names
foo-docker-build: {extends: '.build-docker-image'}
bar-docker-build: {extends: '.build-docker-image'}

# Define `build_docker_image` template used by `*-docker-build` jobs
.build-docker-image:
  stage: build
  rules:
    - if: $CI_COMMIT_BRANCH
  image:
    name: gcr.io/kaniko-project/executor:debug
    entrypoint: [""]
  before_script:
    - export NAME=${CI_JOB_NAME%-docker-build}
    - mkdir -p /kaniko/.docker
    - echo "{\"auths\":{\"${CI_REGISTRY}\":{\"auth\":\"$(echo -n ${CI_REGISTRY_USER}:${CI_REGISTRY_PASSWORD} | base64 | tr -d '\n')\"}}}" > /kaniko/.docker/config.json
  script:
    - /kaniko/executor --context ${CI_PROJECT_DIR} --dockerfile $CI_PROJECT_DIR/Dockerfile.${NAME} --destination ${CI_REGISTRY_IMAGE}/${NAME}:git-${CI_COMMIT_SHORT_SHA}

###############################################################################
# `release` stage: `semantic-release`, `*-docker-tag`
###############################################################################
semantic-release:
  stage: release
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
  image: 'hub.eole.education/eole/semantic-release:latest'
  script:
    - 'semantic-release'

# Suffix all jobs to avoid conflict with other jobs names
foo-docker-tag: {extends: '.tag-docker-image'}
bar-docker-tag: {extends: '.tag-docker-image'}

# Define `tag_docker_image` template used by `*-docker-tag` jobs
.tag-docker-image:
  stage: release
  rules:
    # Only for protected release tags
    - if: $CI_COMMIT_TAG =~ /^release\// && $CI_COMMIT_REF_PROTECTED
  image:
    name: gcr.io/go-containerregistry/crane:debug
    entrypoint: [""]
  variables:
    GIT_STRATEGY: none
  before_script:
    - export NAME=${CI_JOB_NAME%-docker-tag}
    - export RELEASE=${CI_COMMIT_TAG#release/}
  script:
    - crane auth login -u ${CI_REGISTRY_USER} -p ${CI_REGISTRY_PASSWORD} ${CI_REGISTRY}
    - crane tag ${CI_REGISTRY_IMAGE}/${NAME}:git-${CI_COMMIT_SHORT_SHA} ${RELEASE}
    - crane tag ${CI_REGISTRY_IMAGE}/${NAME}:git-${CI_COMMIT_SHORT_SHA} latest
  • What troubleshooting steps have you already taken? Can you link to any docs or other resources so we know where you have been?

It’s the same as the old post Run pipeline on tag after ci skip (maven release) which don’t have a solution.

Does someone have a hint on how to do?

Regards.

1 Like

I work around the issue by:

  1. configure semantic-release/git plugin to not use the [skip ci] in the commit message

          ['@semantic-release/git', {
            assets: ['docs'],
            message: 'chore(release): ${nextRelease.version}\n\n${nextRelease.notes}'
          }],
    
  2. modify the .gitlab-ci.yml to manually exclude some jobs

    diff -u .gitlab.ci.yml.org .gitlab.ci.yml
    --- .gitlab-ci.yml.orig	2021-10-20 10:56:35.379442520 +0200
    +++ .gitlab-ci.yml	2021-10-20 10:58:55.707257280 +0200
    @@ -18,6 +18,9 @@
     commitlint:
       stage: lint
       rules:
    +    # Exclude $CI_DEFAULT_BRANCH of semantic-release commits
    +    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_COMMIT_MESSAGE =~ /^chore\(release\):/
    +      when: never
         - if: $CI_COMMIT_BRANCH
       image: 'hub.eole.education/eole/commitlint:latest'
       before_script:
    @@ -47,7 +50,11 @@
     .build-docker-image:
       stage: build
       rules:
    +    # Exclude $CI_DEFAULT_BRANCH of semantic-release commits
    +    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_COMMIT_MESSAGE =~ /^chore\(release\):/
    +      when: never
         - if: $CI_COMMIT_BRANCH
    +    - if: $CI_COMMIT_TAG =~ /^release\// && $CI_COMMIT_REF_PROTECTED
       image:
         name: gcr.io/kaniko-project/executor:debug
         entrypoint: [""]
    @@ -64,6 +71,9 @@
     semantic-release:
       stage: release
       rules:
    +    # Exclude $CI_DEFAULT_BRANCH of semantic-release commits
    +    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_COMMIT_MESSAGE =~ /^chore\(release\):/
    +      when: never
         - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
       image: 'hub.eole.education/eole/semantic-release:latest'
       script:
    

As a result:

  • for all branches
    • commitlint
    • build docker images
  • on $CI_DEFAULT_BRANCH when merging
    • commitlint
    • build docker images
    • semantic-release to create the release commit, tag and gitlab release
  • on $CI_DEFAULT_BRANCH with release commit starting with message chore(release):
    • nothing is done
  • on tag release/*
    • build docker images
    • tag docker images
2 Likes

Hi, @baby-gnu.

  1. Merge a contribution in the master branch
  2. The CI run the build and release stages against the master branch
    1. semantic-release update CHANGELOG.md and add a commit with the subject containing chore(release): X.Y.Z [skip ci]
    2. semantic-release create a tag with the new version
    3. semantic-release create the new release in gitlab

We do a slight variation of the above on the container scanning CI configuration.

Instead of getting the pipeline to tag on merge, we manually create the tag (using the interface or pushing to the remote). Then, GitLab triggers a pipeline (example) that:

  1. Creates the build artifacts
  2. Updates the changelog
  3. Creates a new release in GitLab

Maybe our configuration can give you some ideas? Let me know if you have questions.

2 Likes

Thanks a lot @thiagocsf, it’s a complete example of what I want to do, except that the CHANGELOG.md should be updated in the source of the release (I checked and the latest entry in 4.3.18 is for 4.3.17).

Note that we want to stick with semantic-release instead of manual tag creation, this way, the tag point to the proper ref where the CHANGELOG.md is updated.

I’ll keep your .gitlab-ci.yml as a reference, thanks.

1 Like

As a final comment, here is our actual setup:

A successful dev pipeline can be seen for this use.

Regards.

1 Like