Skip to content

image-release

Decides, on a tag pipeline, whether a release can be a retag of the image the default-branch pipeline already published for that commit — and triggers one of two child pipelines, named for the answer.

It publishes nothing itself. It chooses a path and makes that choice visible.

Why a retag is correct, not merely faster

Every image in phpboyscout/images builds reproducibly: SOURCE_DATE_EPOCH comes from the commit, so a rebuild of a commit is byte-identical to the first build of it. Verified in the registry — ci-base v0.2.1 and its sha- tag carry the same digest, as do go-tools v0.4.0 and its own.

Rebuilding on a tag is therefore an expensive way to obtain bytes that are already in the registry.

The child config is generated, and it has to be

release:resolve probes the registry and then writes the child config, naming either retag_file or rebuild_file. release:publish includes that artifact.

The obvious alternative — two trigger jobs gated on a variable the probe sets — cannot work, and it is worth knowing why because it fails silently. rules: are evaluated when the pipeline is created, before any job has run, so a dotenv variable written by the probe is empty at that moment. Both triggers are dropped, and the tag pipeline goes green having published nothing. That shipped once: release-tools v0.1.13 was tagged in git with no image behind it.

The path taken is visible in the child pipeline's jobs — retag:semver on one side, the build and scan jobs on the other — and stated in release:resolve's log.

The fallback has never fired in normal use — 0 of 22 semver tags lacked a sha- tag when this was measured — which is exactly why it would go unnoticed when it does.

What gates a release

Not this pipeline. Colophon's release merge request builds, scans and runs the reproducibility check against the exact commit that gets tagged: under fast-forward merge the release MR's head becomes the default branch's head, and colophon tags that.

A hand-cut tag has no release MR and therefore no gate. That is the emergency path, and it is what the rebuild child covers.

Inputs

Input Type Default Description
stage string release Stage for the resolve job and both triggers. You must declare it.
image string $CI_REGISTRY_IMAGE Registry repository holding the image, without a tag.
sha_tag string sha-$CI_COMMIT_SHORT_SHA Tag the default branch publishes for this commit.
retag_file string .gitlab-ci-retag.yml Child pipeline run when sha_tag is present.
rebuild_file string .gitlab-ci-rebuild.yml Child pipeline run when it is not.
wait_seconds integer 180 How long to keep probing before concluding the tag is absent. See below.
crane_image string digest-pinned crane:debug Probe image. crane:debug publishes no version tag, so the digest is the only stable handle.
registry_user string $CI_REGISTRY_USER Registry username for the probe.
registry_password string $CI_REGISTRY_PASSWORD Registry password for the probe.

Jobs produced

Job Runs when
release:resolve any tag pipeline — probes the registry and generates the child config
release:publish any tag pipeline — triggers the generated child

The probe uses crane manifest, which is a HEAD against the registry: no layer is pulled, so it costs a request rather than a download.

The probe waits, and your stage order matters

Colophon cuts the tag from the release stage. If your pipeline pushes the sha- image in a later stage, the tag — and therefore the tag pipeline — exists before the image does. Measured before this was handled: tag pipelines were created 2m45s and 11m50s ahead of publish:sha finishing on two repos.

Left alone, the probe would find nothing every time, take the rebuild path every time, and look exactly like a feature that works.

The fix is to publish the sha- image in a stage that runs BEFORE the one colophon tags from — stages: [lint, build, scan, publish, release] rather than [..., release, publish]. wait_seconds is what makes the failure loud rather than silent if you have not: the job says so in its log instead of quietly rebuilding.

Usage

stages: [lint, build, scan, release, publish]

include:
  - component: gitlab.com/phpboyscout/cicd/[email protected]
    inputs:
      stage: release

with .gitlab-ci-retag.yml in the repository:

include:
  - component: gitlab.com/phpboyscout/cicd/[email protected]
    inputs:
      stage: publish

and .gitlab-ci-rebuild.yml carrying that repository's existing build, scan and publish jobs.

See also

  • image-retag — the child pipeline this triggers on the retag path
  • Spec 0094