How to distinguish changes in root files from changes in subfolders?

I have a NodeJS monorepo which I’m trying to process with GitLab CI.

I have a job that I want to trigger if the package.json in the root of the repository was changed. If a package.json in any workspace subfolder (/packages/**) of the repository was changed, I do not want to trigger the job.

Initially, I assumed this would be easy and I tried approaches like this:

test:
  script:
    - echo GitLab CI is such a pain sometimes
  rules:
    - if: '$CI_PIPELINE_SOURCE == "push"'
      changes:
        - ${CI_PROJECT_DIR}/package.json
        - ./package.json
        - /package.json
      when: on_success
    - when: never

None of these seemed to work.

I also tried to negate a ruleset with another:

test:
  script:
    - echo GitLab CI is such a pain sometimes
  rules:
    - if: '$CI_PIPELINE_SOURCE == "push"'
      changes:
        - package.json
      when: on_success
    - if: '$CI_PIPELINE_SOURCE == "push"'
      changes:
        - packages/**/package.json
      when: never
    - when: never

This also didn’t seem to have the desired effect, as the job is triggered on any changed package.json. This makes sense to me, as the documentation suggests that only the first successful rule is relevant.

So how can I make this work?

1 Like

This seemed to work for me:

stages:
  - hello
  - test

hello:
  stage: hello
  script:
    - echo HELLO

test:
  stage: test
  script:
    - echo "Testing changes..."
  rules:
    - if: '$CI_PIPELINE_SOURCE == "push"'
      changes:
        - package.json
      when: on_success
    - when: never

I had a file called package.json and one called packages/mydir/package.json in an empty (ish) scratch repo.

I think you want to avoid globbing, it’s a bit more eager than you need!

1 Like

I was certain that I had tried this as well with no success. So I tried to repro that just now in a minimal repo and you are right. This works exactly as expected. I must have done something else in my larger repo that causes me to get unexpected results.

When you’re changing lots of combinations of different things at once, it’s easy to lose track!

1 Like

I feel like my earlier mistakes were a result of not understanding the changes in relation to the specific push event properly. I finally found the article Troubleshooting CI/CD | GitLab which touches on my earlier problem.

For example, changes is always true in certain pipeline types, including scheduled pipelines and pipelines for tags.

Is the key information I was missing earlier. I kept pushing commits that changed only package.json but also accompanying tags, which ultimately resulted in my changes being ineffective, as tag pushes don’t evaluate those.

Right, I think this trips a lot of people up. There’s a few little details like this that are tricky, like after_script runs in a separate shell, but before_script and script are concatenated together!

1 Like

Oh wow. Didn’t know that either. I’m learning so much today :smiley: Thanks again