Testing rule $CI_COMMIT_MESSAGE with regex - not working

Hello,

Hello, I’m trying to use a pipeline rule where, if a commit contains the word ‘crap’ at the end of the commit message, the pipeline shouldn’t run.

This is what the gitlab-ci looks like:

image: docker:24.0.2-dind

stages:
  - build
  - test
  - compliance

variables:
  NGINX_VERSION: 1.24.0-bullseye

build:
  stage: build
  script:
    - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
    - docker build --build-arg VERSION=$NGINX_VERSION -t $CI_REGISTRY_IMAGE/nginx:$NGINX_VERSION .
    - docker push $CI_REGISTRY_IMAGE/nginx:$NGINX_VERSION
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'

test:
  stage: test
  image: curlimages/curl:8.1.2
  services:
    - name: $CI_REGISTRY_IMAGE/nginx:$NGINX_VERSION
      alias: nginx
  script:
    - curl nginx

workflow:
  rules:
    - if: $CI_COMMIT_MESSAGE =~ /crap$/
      when: never
    - if: $CI_COMMIT_BRANCH == "main"

I’ve added the following commit message:

git commit -m "some other crap"

and pushed it, but the pipeline still ran. I’m not sure what I’m doing wrong. Any ideas?

I’m using gitlab-ee:16.1.1-ee.0 on Ubuntu 22.04.2

Have you tried removing the rules from the build job?

build:
  stage: build
  script:
    - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
    - docker build --build-arg VERSION=$NGINX_VERSION -t $CI_REGISTRY_IMAGE/nginx:$NGINX_VERSION .
    - docker push $CI_REGISTRY_IMAGE/nginx:$NGINX_VERSION

Thanks for pointing this out, that was silly, indeed :slight_smile: But unfortunately it still doesn’t work, the pipeline still runs. This is what the gitlab-ci looks like now:

image: docker:24.0.2-dind

stages:
  - build
  - test
  - compliance

variables:
  NGINX_VERSION: 1.24.0-bullseye

build:
  stage: build
  script:
    - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
    - docker build --build-arg VERSION=$NGINX_VERSION -t $CI_REGISTRY_IMAGE/nginx:$NGINX_VERSION .
    - docker push $CI_REGISTRY_IMAGE/nginx:$NGINX_VERSION

test:
  stage: test
  image: curlimages/curl:8.1.2
  services:
    - name: $CI_REGISTRY_IMAGE/nginx:$NGINX_VERSION
      alias: nginx
  script:
    - curl nginx

workflow:
  rules:
    - if: '$CI_COMMIT_MESSAGE =~ /crap$/'
      when: never
    - if: '$CI_COMMIT_BRANCH == "main"'

The latest commit message is:

git commit -m "yet another crap"

Maybe it isn’t identifying ‘workflow’ as a keyword or something?

I’ve also tried with this pipeline where the rules are added for each job:

image: docker:24.0.2-dind

stages:
  - build
  - test

variables:
  NGINX_VERSION: 1.24.0-bullseye

build:
  stage: build
  script:
    - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
    - docker build --build-arg VERSION=$NGINX_VERSION -t $CI_REGISTRY_IMAGE/nginx:$NGINX_VERSION .
    - docker push $CI_REGISTRY_IMAGE/nginx:$NGINX_VERSION
  rules:
    - if: '$CI_COMMIT_MESSAGE =~ /crap$/'
      when: never
    - if: '$CI_COMMIT_BRANCH == "main"'

test:
  stage: test
  image: curlimages/curl:8.1.2
  services:
    - name: $CI_REGISTRY_IMAGE/nginx:$NGINX_VERSION
      alias: nginx
  script:
    - curl nginx
  rules:
    - if: '$CI_COMMIT_MESSAGE =~ /crap$/'
      when: never
    - if: '$CI_COMMIT_BRANCH == "main"'

Pushing commit with message “some crap” still runs.

Try it without encapsulating the rule in ' single quotes.
if: $CI_COMMIT_MESSAGE =~ /crap$/

1 Like

I’ve tried it before too to no avail. Now I’ve tried it again. Updated gitlab-ci:

 image: docker:24.0.2-dind

stages:
  - build
  - test

variables:
  NGINX_VERSION: 1.24.0-bullseye

build:
  stage: build
  script:
    - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
    - docker build --build-arg VERSION=$NGINX_VERSION -t $CI_REGISTRY_IMAGE/nginx:$NGINX_VERSION .
    - docker push $CI_REGISTRY_IMAGE/nginx:$NGINX_VERSION
  rules:
    - if: $CI_COMMIT_MESSAGE =~ /crap$/
      when: never
    - if: $CI_COMMIT_BRANCH == "main"

test:
  stage: test
  image: curlimages/curl:8.1.2
  services:
    - name: $CI_REGISTRY_IMAGE/nginx:$NGINX_VERSION
      alias: nginx
  script:
    - curl nginx
  rules:
    - if: $CI_COMMIT_MESSAGE =~ /crap$/
      when: never
    - if: $CI_COMMIT_BRANCH == "main"
git commit -m "removed some crap"

Same thing unfortunately. The pipeline runs.

Not sure if the regex is correct for the re2 standard mentioned in Choose when to run jobs | GitLab It says it matches on regex101.com but that page supports a wide range of regex testing.

/.*crap$/ might be worth a try.

Enabling debugging could also shed more light. GitLab CI/CD variables | GitLab

Storing the regex pattern in a variable - does it change the behavior?

New gitlab-ci:

image: docker:24.0.2-dind

stages:
  - build
  - test

variables:
  NGINX_VERSION: 1.24.0-bullseye

build:
  variables:
    CI_DEBUG_TRACE: "true"
  stage: build
  script:
    - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
    - docker build --build-arg VERSION=$NGINX_VERSION -t $CI_REGISTRY_IMAGE/nginx:$NGINX_VERSION .
    - docker push $CI_REGISTRY_IMAGE/nginx:$NGINX_VERSION
  rules:
    - if: $CI_COMMIT_MESSAGE =~ /.*crap$/
      when: never
    - if: $CI_COMMIT_BRANCH == "main"

test:
  variables:
    CI_DEBUG_TRACE: "true"
  stage: test
  image: curlimages/curl:8.1.2
  services:
    - name: $CI_REGISTRY_IMAGE/nginx:$NGINX_VERSION
      alias: nginx
  script:
    - curl nginx
  rules:
    - if: $CI_COMMIT_MESSAGE =~ /.*crap$/
      when: never
    - if: $CI_COMMIT_BRANCH == "main"

I’m not seeing any if conditionals related to the rules. I see this written exactly like this, which looks suspicious:

++ export 'CI_COMMIT_MESSAGE=crap
'
++ CI_COMMIT_MESSAGE='crap
'

This is the result of:

git commit -m "crap"

Later in the debug trace:

export CI_COMMIT_MESSAGE=$'"'"'crap\n'"'"'

So I guess there’s a new line there.

Changing it to:

/.*crap\n$/

Seems to be working. But it looks like a bug to me at first sight. Where does the newline come from? I’m just using git on a mac os and I’m nothing doing anything out of the ordinary other than commit and push.

Later Edit:
This also seems to be working:

/crap\n$/

so without the regex for everything.

Odd, I have never seen that before. (but also never tested for line endings with regex)

Searched for ci_commit_message, and google auto completed to CI_COMMIT_MESSAGE regex examples in `rules` should not use prefix matching due to trailing new line (#348254) · Issues · GitLab.org / GitLab · GitLab

Seems that the Git CLI always appends a newline when using the -m flag.

2 Likes

Ok, to be honest, I don’t think I’ll ever use this, unless maybe I’d be playing around in dev and maybe switch between various builds/stages, whatever, but even then I’d probably choose some other criteria.

I really just wanted to have a better understanding of the rules and how they’re interpreted, but on this occasion I’ve come across this, so I’ll keep it in mind.

ChatGPT did mention something along these lines, but it said quite the reverse. Funny interpretation though :smiley:

GitLab uses Ruby-style regular expressions in its if conditions. In Ruby, the correct syntax to match the end of a string is \z, not $ So you might want to try changing your rule to - if: $CI_COMMIT_MESSAGE =~ /crap\z/.

Indeed, this is the documentation I started from, the one linked in the issue:

(probably should be fixed, but yeah, I’m guessing not a lot of people actually use it).

1 Like

Great learning curve :slight_smile: I have seen use cases where folks check for context in git commits, and build a custom logic similar to [skip ci].