How does the syntax to specify file type changes in Gitlab's CI rules work?

Viewed 135

My file structure consits of 2 main directories, resources and src, resources has images in a subdirectory, and various json files. src has many nested directories with .ts files in each:

├── package.json
├── package-lock.json
├── README.md
│ 
├── .docker
│   ├── Dockerfile
│   └── aBashScript.sh
│ 
├── resources
│   ├── data.json
│   └── images
│       └── manyimages.png
│
├── src
│   ├── subdirectory1
│   └── NestedDirectories
│
├── .gitlab-ci.yml
├── tsconfig.eslint.json
├── tsconfig.json
├── eslintrc.json
└── prettierrc.json

My gitlab-ci.yml has two stages, build and deploy
What I want:
1- If it's a commit on branches "main" or "dev" and If anything that affects the actual project changes, run build.
That is anything under resources, or src (and their nested directories), the Dockerfile, package.json and package-lock.json
I'd be content with "any .ts file changed" too, since all other criteria is usually only when this happens.
2- If build ran and it's a commit on the default branch ("main") then run the deploy stage.
Also for clarification when I say there's a commit on branch X, I mean as in an accepted merge request, or well an actual change on that branch. At some point in my tinkering it was running on (non accepted) merge requests, but I forgot what I changed to fix that.

What happens:
1- If I specify the changes rule on build then it never runs, however even if build doesn't run deploy always runs (if on branch "main")

.gitlab-ci.yml

variables:
  IMAGE_TAG: project

stages:
  - build
  - deploy

build_image:
    stage: build
    image: docker:20.10.16
    services:
        - docker:20.10.16-dind
    variables:
        DOCKER_TLS_CERTDIR: "/certs"
    before_script:
        - echo $REGISTRY_PASS | docker login -u $REGISTRY_USER --password-stdin
    script:
    - |
        if [[ "$CI_COMMIT_BRANCH" == "$CI_DEFAULT_BRANCH" ]]; then
        tag="latest"
        echo "Running on default branch '$CI_DEFAULT_BRANCH': tag = '$tag'"
        else
        tag="$CI_COMMIT_REF_SLUG"
        echo "Running on branch '$CI_COMMIT_BRANCH': tag = $tag"
        fi
    - docker build -f .docker/Dockerfile -t $REPO_NAME:$IMAGE_TAG-$tag .
    - docker push $REPO_NAME:$IMAGE_TAG-$tag
    rules:
        - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH == "dev"'
          changes:
            - \*.ts
            - \*.json
            - Dockerfile

deploy:
    stage: deploy
    before_script:
    - chmod SSH_KEY
    script:
    - ssh -o StrictHostKeyChecking=no -i $SSH_KEY $VPS "
        echo $REGISTRY_PASS | docker login -u $REGISTRY_USER --password-stdin &&
        cd project &&
        docker-compose pull &&
        docker-compose up -d"
    rules:
        - if: '$CI_COMMIT_BRANCH == "main"'

This is the most basic one I could cobble up, basically excluding just the readme, but the build stage doesn't run (deploy does run even if build didn't)

Normally this is something I'd be able to "brute force" figure out myself, but to avoid uselessly modifying my files to test the changes rule, I've only been able to test this when making actual modifications to the project.
There seems to be a lot of examples from questions and tutorials out there, but I think something is off with my file structure as I've had no luck copying their changes rule

1 Answers

The changes: entries are glob patterns, not regex. So in order for you to match .ts files in any directory, you'll need to use "**/*.ts" not *.ts (which would only match files in the root).

changes:
  - "**/*.ts"
  - "**/*.json"
  # ...

If build ran and it's a commit on the default branch ("main") then run the deploy stage.

To get this effect, you'll want your deploy job to share some of the rules of your build job.

deploy:
  rules:
    - if: "$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH"
      changes:
        - Dockerfile
        - "**/*.ts"
        - "**/*.json"

Or a little fancier way that reduces code duplication:

  rules:
    - if: "$CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH"
      when: never  # only deploy on default branch
    - !reference [build_image, rules]
Related