Skip to content

GitLab CI/CD

Two CI/CD components record one run event per pipeline execution. Add an include and the value report builds itself from your pipelines.

Which one to use

report-run adds its own job, in the .post stage, running an image that has curl and jq. Use it when you want reporting that doesn't care what your other jobs run in, or when you want the pipeline's outcome rather than one job's.

after-script contributes a hidden job you extend from the job you want measured. Reporting happens in that job's after_script, where $CI_JOB_STATUS holds the real outcome, so one include covers success and failure together. The job's own image needs curl and jq.

Every GitLab pipeline can also report through plain HTTP with a curl step, and the components mostly save you writing that curl.

The API key

Set LUMATRACK_API_KEY under Settings, CI/CD, Variables, masked. Protect it too if you only report from protected branches.

Neither component takes the key as an input. include: inputs are part of the pipeline configuration, so anyone who can read the config would be able to read the key.

An ingest-only key is enough to record runs and is the one to use in a pipeline: if it leaks, an attacker can post junk runs, and they cannot read or restate your ledger.

report-run

include:
  - component: $CI_SERVER_FQDN/lumatrack/gitlab-components/report-run@1.0.0
    inputs:
      base-url: https://lumatrack.io
      automation: deploy-pipeline
      job-name: lumatrack-success
      when: on_success
      status: success
  - component: $CI_SERVER_FQDN/lumatrack/gitlab-components/report-run@1.0.0
    inputs:
      base-url: https://lumatrack.io
      automation: deploy-pipeline
      job-name: lumatrack-failure
      when: on_failure
      status: failure
Input Notes
base-url Your LumaTrack host, e.g. https://lumatrack.example.com
automation The slug this pipeline reports as; create it in the app or over the API
status success, failure, skipped or cancelled. GitLab's own failed and canceled are accepted and mapped
when on_success, on_failure or always
job-name Name of the generated job. Each include needs its own
stage Defaults to .post, which runs after everything else
failure-reason Root cause, e.g. deploy/timeout. Powers the failure-reason Pareto
duration-seconds Wall-clock runtime. Leave it empty rather than sending a guess
units Records the run processed; drives per-unit valuation. Empty leaves the server default of 1
external-id Defaults to the pipeline id and job id, which makes a retried job idempotent
metadata JSON object kept with the run
source Stored on the run, gitlab-ci by default
image Needs curl and jq
fail-on-error false by default, so a LumaTrack outage never fails a deploy that worked

after-script

include:
  - component: $CI_SERVER_FQDN/lumatrack/gitlab-components/after-script@1.0.0
    inputs:
      base-url: https://lumatrack.io
      automation: deploy-pipeline

deploy:
  extends: .lumatrack-report-run
  stage: deploy
  script:
    - ./deploy.sh

$CI_JOB_STATUS maps to a status of its own: failed books as failure and canceled books as cancelled. Neither skipped nor cancelled earns value, and neither is ever reported as a failure. A cancelled job was interrupted part way; whether it carries the automation's per-run cost is set per automation in LumaTrack. Each keeps its own reason, ci/failed or ci/cancelled, so the Pareto can tell them apart.

Reporting from after_script can't fail the job it measures. Every failure path prints what went wrong and exits 0, because an after_script that exits non-zero marks a green deploy red.

Wire the failure path too

One include on the success path is half the integration. Failed pipelines cost money and save nothing, and reporting them is what makes the reliability chart and the net numbers credible. With report-run that means the second include with when: on_failure. With after-script you get it for free, since $CI_JOB_STATUS reports whatever actually happened.

Batches and loops

A pipeline that processes 240 records should report one run with units: 240, not 240 runs. The ledger prices per-unit work as fixed setup plus marginal minutes per record, which is the number that survives a CFO's review. Separate runs would each consume an event against your plan's monthly cap and tell you the same thing.

If a parallel matrix job runs 8 times, each instance has its own $CI_JOB_ID, so the default external id books 8 runs. That's usually right, because each one genuinely succeeded or failed on its own. Set external-id to $CI_PIPELINE_ID if you'd rather have one run for the whole matrix; the first job records it and the other 7 dedupe.

Many pipelines, one automation?

Map them the way your accounting works. If three pipelines together replace one manual task, point all three at the same slug. If one pipeline does two unrelated jobs, either split it or pick the slug per include.

Terraform pipelines

If the pipeline runs Terraform, the Terraform provider reports from inside the config instead, which lets a single apply report the units it actually touched. The two work together: the component reports the job, and the provider reports what the apply did.