---
trigger: glob
globs: .gitlab-ci.yml,.gitlab/ci/**/*.yml
---

# GitLab CI/CD

- Validate every change with the CI Lint tool (`glab ci lint`, or the project's Pipeline editor) before committing. Never push changes that trigger deploy jobs to test syntax.
- Use `rules:` on jobs; don't use `only:`/`except:` in new code. Add top-level `workflow: rules:` so branch and merge request pipelines don't both run for the same push.
- Declare `stages:` in order, and use `needs:` to let jobs start as soon as their dependencies finish. Keep `needs` lists accurate when renaming jobs.
- Pin images by version (`node:22-alpine`, not `latest`) and set `default:` for shared `image`, `before_script`, `interruptible: true` and `retry` on flaky infrastructure failures only.
- Cache dependencies keyed on lockfiles: `cache: key: files: [package-lock.json]` with `paths` for the package cache. Use `policy: pull` in jobs that don't update it.
- Artifacts: only what later jobs or reviewers need, with `expire_in`. Test reports via `artifacts: reports: junit/coverage_report` so results show in merge requests.
- Reuse with `include:` (local files under `.gitlab/ci/`, project templates, or CI/CD components with pinned versions) and `extends:`/YAML anchors instead of copy-pasted jobs.
- Secrets live in CI/CD variables: masked, and protected for production. Never echo them, never hardcode tokens, and use `CI_JOB_TOKEN` or OIDC `id_tokens` for cloud auth instead of long-lived keys.
- Deploy jobs use `environment:` with `name` and `url`, `resource_group` to prevent concurrent deploys, and `when: manual` (or protected branches) for production.
- Merge request pipelines run fast checks first (lint, unit tests); long suites can be `rules`-gated by changed paths with `changes:`.
- Keep scripts short in YAML; move logic into versioned scripts in the repo and call them.
