CI/CD pipeline - "changes" inside "rules" are not working

Hi guys,

I have this code on my gitlab-ci.yml:

stages:
  - setup
  - train

.rules_non_prod:
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
      when: never
    - if: "$CI_COMMIT_BRANCH !~ /^(development|staging|main)$/"
      variables:
        ENVIRONMENT: "feature"
    - if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH

.rules_prod:
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
      when: never
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
      variables:
        ENVIRONMENT: prod

.tags_non_prod:
  - dev
  - mll

.tags_prod:
  - prod
  - mll

#======= BUILD
.build: &build
  stage: setup
  image: $DOCKER_IMAGE
  dependencies: []
  environment:
    name: $ENVIRONMENT
  services:
    - docker:dind
  before_script:
    - cd scripts/docker && sh login.sh
  script:
    - sh build.sh $CI_PROJECT_NAME $DOCKER_FOLDER

build:non-prod:
  <<: *build
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
      when: never
    - if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH
      changes:
        - docker/**/*
      when: never
    - !reference [.rules_non_prod, rules]
  tags: !reference [.tags_non_prod]

build:prod:
  <<: *build
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
      when: never
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
      changes:
        - docker/**/*
      when: never
    - !reference [.rules_prod, rules]
  tags: !reference [.tags_prod]

I would like to ensure that the “build” job only appears when there are changes in the files within the docker folder. To achieve this, I attempted to incorporate the “changes” parameter into the rules of the job, as you can see. However, this approach is not working as the “build” job consistently appears.

What I’m doing wrong?

Thank you.

NOTE: I have many other jobs that use that general rules.

@andrequintino It looks as if the when: never can be removed

1 Like

I tried that too, but unfortunately it doesn’t work :(.

I just noticed that a pipeline in my project does not work anymore. It worked until yesterday (last execution about 11h ago) but new commits with a changed file monitored by a changes-rule do not trigger pipeline execution anymore. The pipeline definition itself was not changed.
I assume there must be some general issue with the gitlab.com pipelines at the moment.

@olivergregorius yes, there is ongoing issue, check status.gitlab.com

@andrequintino

rules are evaluated in the order defined. If you want the build:* jobs to run only when there are changes to docker folder, you need to include that in all rule entries that would be evaluated as true, not just one.

In your setup build:prod job is executed, because of this rule:

    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
      variables:
        ENVIRONMENT: prod

In order to run only if changes in docker folder, you need to add that to the rule:

    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
      changes:
        - docker/**/*
      variables:
        ENVIRONMENT: prod

Also you are duplicating rules in jobs and reference.

2 Likes

First of all, thanks for the answer.

That way works, but I’d like to use just the references and add the “changes”, so I don’t have duplicate code.

But at least I’m left with a version that works, until I find a solution that allows me to use the references.

Something like this:

#======= BUILD
.build: &build
  stage: setup
  image: $DOCKER_IMAGE
  dependencies: []
  environment:
    name: $ENVIRONMENT
  services:
    - docker:dind
  before_script:
    - cd scripts/docker && sh login.sh
  script:
    - sh build.sh $CI_PROJECT_NAME $DOCKER_FOLDER

build:non-prod:
  <<: *build
  rules:
      - !reference [.rules_non_prod, rules]
        changes:
          - docker/**/*
  tags: !reference [.tags_non_prod]

build:prod:
  <<: *build
  rules:
      - !reference [.rules_prod, rules]
        changes:
          - docker/**/*
  tags: !reference [.tags_prod]

I understand, unfortunately that is currently not possible using the reference. It would be awesome, tho.

1 Like

This was my best solution until now, but maybe there is a way not to have so many if/else.

stages:
  - build
  - auth
  - train

.variables_non_prod: &variables_non_prod
  variables:
    ENVIRONMENT: "feature"

.variables_prod: &variables_prod
  variables:
    ENVIRONMENT: prod

.rules_non_prod:
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
      when: never
      # if branch is not development, staging or main, set ENVIRONMENT to feature
    - if: $CI_COMMIT_BRANCH !~ /^(development|staging|main)$/ && $CI_JOB_STAGE != "build"
      <<: *variables_non_prod
    - if: $CI_COMMIT_BRANCH !~ /^(development|staging|main)$/ && $CI_JOB_STAGE == "build"
      changes:
        - docker/**/*
      <<: *variables_non_prod
    - if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH && $CI_JOB_STAGE != "build"
    - if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH && $CI_JOB_STAGE == "build"
      changes:
        - docker/**/*

.rules_prod:
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
      when: never
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_JOB_STAGE != "build"
      <<: *variables_prod
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_JOB_STAGE == "build"
      changes:
        - docker/**/*
      <<: *variables_prod

#======= BUILD
.build: &build
  stage: build
  image: $DOCKER_IMAGE
  dependencies: []
  environment:
    name: $ENVIRONMENT
  services:
    - docker:dind
  before_script:
    - cd scripts/docker && sh login.sh
  script:
    - sh build.sh $CI_PROJECT_NAME $DOCKER_FOLDER

build:non-prod:
  <<: *build
  rules: !reference [.rules_non_prod, rules]
  tags: !reference [.tags_non_prod]

build:prod:
  <<: *build
  rules: !reference [.rules_prod, rules]
  tags: !reference [.tags_prod]

I have a similar issue but my pipeline is not fired when I change a Dockerfile inside a sub folder. My config is something like this. Some parts were omitted (vars used to tag image, etc)

.build: &build_config
stage: build
rules:
- changes:
- ./${CONTEXT}/Dockerfile
image: docker:20.10.8
services:
- docker:20.10.8-dind
before_script:
//export vars. Tags, registry and so on
script:
//build image and push

service_image:
<<: *build_config
variables:
DOCKER_FILE: ./service/Dockerfile
CONTEXT: ./service

./ is in the variable value as well as before the variable in changes: