GitLab CI/CD component
See which tests a merge request affects, inside your GitLab pipeline.
The DiffCI observer is a GitLab CI/CD Catalog component. It adds one job that analyses each merge request and default-branch push, and writes a report saying which tests the change affects and why. It runs no tests, skips nothing, and cannot change the pipeline result.
Add the observer job
Add this to .gitlab-ci.yml and keep every existing test, build, lint and security job unchanged:
include:
- component: $CI_SERVER_FQDN/diffci/diffci/observe@0.3.38The component version is the exact @diffci.com/diffci CLI version it runs, so one number means one thing. Pin it like any other dependency and update it on purpose.
On the next merge request the pipeline shows a diffci-observe job beside your own jobs. It needs a runner with Docker; gitlab.com shared runners work as they are.
What the job does
- Runs only where a commit range exists: merge request pipelines and pushes to the default branch. It does not run for other branch pushes, schedules, or pipelines started from the web or API, and it runs once per change in projects that have both branch and merge request pipelines.
- Never becomes the pipeline result. It starts at once (
needs: []) and usesallow_failure: true, so a DiffCI problem shows as a warning, not a failed pipeline. - Clones full history (
GIT_DEPTH: "0"). GitLab's default 20-commit clone can drop a merge request's base commit. - Leaves your checkout alone. It installs the pinned CLI outside the project with
--ignore-scriptsand writes the report outside it while observing, so your lockfile andnode_modulesare untouched. - Sends nothing. The report stays in your pipeline as an artifact.
In a merged-results pipeline the observer diffs the source branch head, not the merge commit GitLab creates.
Read the report
The job uploads .diffci/diffci-observation.json as an artifact, linked from the merge request as "DiffCI observation". It records the commit range, the changed files, the tests the change affects with the reason for each, and every reason DiffCI fell back to a full run.
Later jobs can read the outcome. Add needs: [diffci-observe] and use $DIFFCI_STATUS:
DIFFCI_STATUS | Meaning |
|---|---|
OBSERVED | The change was analysed. The report says whether a selective plan was safe or a full run is needed. |
REFUSED | DiffCI could not establish a trustworthy range or graph. Run your normal pipeline; nothing was decided. |
ERROR | The observer itself failed. The pipeline result is unaffected. |
Inputs
| Input | Default | Meaning |
|---|---|---|
stage | test | Stage of the observer job. It starts at once whatever the stage. |
job-name | diffci-observe | Job name. Redefine the job under this name to override rules or allow_failure. |
image | node:22 | Needs Node 22+, Git and Bash. Debian-based Node images qualify; Alpine ones lack Bash. Pin by digest in production. |
cli-version | the component version | Exact published @diffci.com/diffci version. |
redact-paths | false | Replace every file path in the report with a stable 12-character digest. |
artifact-expire-in | 7 days | How long GitLab keeps the report artifact. |
include:
- component: $CI_SERVER_FQDN/diffci/diffci/observe@0.3.38
inputs:
stage: verify
redact-paths: trueWhen it reports a full run
A conservative selection is only useful if it knows when to stop. The observer reports a full run, with the reason named, when:
- Pipeline configuration changed:
.gitlab-ci.yml, a file it includes, or another CI definition. - The dependency graph is incomplete: an import or configuration DiffCI cannot resolve, a lockfile or root configuration change, or a file type it does not model.
- The range is untrustworthy: a missing base commit or a pipeline with no comparable range.
Unknown is never treated as "no tests affected". Review the language and framework support matrix before interpreting an ecosystem-specific fallback.
A measured run on gitlab.com
We imported jshttp/cookie (MIT, Vitest, four spec files) into a private gitlab.com test project and added only the include: above, with no dependency install. Each observer job took 34–40 seconds on shared runners.
| Change | Pipeline | Report |
|---|---|---|
Edit .gitlab-ci.yml on the default branch | Push | OBSERVED, full run: pipeline configuration changed |
| Edit one spec file | Merge request | OBSERVED, 1 of 4 specs affected |
Edit src/index.ts | Merge request | OBSERVED, 4 of 4 specs affected (every spec imports it) |
| Merge the spec change | Default-branch push | OBSERVED, 1 of 4 specs affected |
| Push to another branch | None | No observer job, as intended |
The first version we ran, 0.3.28, reported a full run for every change in this project: its bundled TypeScript rejected the repository's TypeScript 6 options. Version 0.3.29 accepts them. One small repository is a functional check, not a savings claim; the open benchmark covers measurement.
Troubleshooting
| Symptom | Why it happens | What to do |
|---|---|---|
No diffci-observe job | The pipeline is not a merge request or default-branch push, or the project's own workflow:rules exclude merge request pipelines. | Open a merge request, or allow merge_request_event pipelines in workflow:rules. |
Job fails with bash: not found | An Alpine image was set through image. | Use a Debian-based Node 22+ image. |
REFUSED on a merge request | The base commit is missing, usually because a project-level GIT_DEPTH overrides the component's. | Keep GIT_DEPTH: "0" for the observer job. |
| Every report is a full run | A configuration DiffCI cannot resolve marks the graph incomplete. The report's fallback reasons name it. | Read the reasons, check the support matrix, and open an issue with the redacted report if it looks wrong. |
| Pipelines never start on a new gitlab.com account | GitLab asks new accounts to verify before using shared runners. | Complete GitLab's account verification, then rerun. |
What it does not do yet
- It does not skip or reorder jobs. The observer reports; your pipeline runs as before. Enforcement on GitLab, through a generated child pipeline with a full-pipeline fallback, is planned for after design partners.
- It does not plan GitLab jobs. It selects tests, but does not yet read
.gitlab-ci.ymlto say which of your jobs a change affects. Changes to pipeline files already make it report a full run. - It does not send reports to DiffCI Cloud. Cloud accepts GitHub repositories only today.
- Self-managed GitLab: components work there, but the catalog is per instance. Copy the component project to your instance for now.