Skip to content

Spec: release-plz checkout the pipeline commit (v0.10.6)

  • Repository: gitlab.com/phpboyscout/cicd
  • Component touched: release-plz
  • Release: patch — fix: → v0.10.6

Problem

The release-plz component's .release-plz-base before_script does:

git checkout "$CI_COMMIT_BRANCH"

GitLab CI checks out a detached HEAD at $CI_COMMIT_SHA; the checkout re-attaches to the branch so release-plz can resolve its upstream. But a bare git checkout <branch> moves to whatever commit the local branch ref points at. On a runner that reuses its build directory (GIT_STRATEGY=fetch, common on self-hosted runners) that local ref can be stale from a previous job — git fetch updates refs/remotes/origin/<branch> but not the local refs/heads/<branch>. So release-plz ends up analysing an older commit than the one the pipeline is for.

Observed

On phpboyscout/rust-tool-base, the v0.5.3 publish pipeline merged the Release MR (Cargo.toml at 0.5.3) but release-plz:release logged Previous HEAD position was <sha> chore: release v0.5.3 (the bare checkout moving away from the correct commit) followed by rtb-* 0.5.2: Already published for every crate — it ran against a 0.5.2 tree and published nothing. The publish only succeeded after the consumer added a git update-ref refs/heads/<branch> $CI_COMMIT_SHA guard to its own extra_before_script. This spec moves that fix into the component so every consumer is covered and the workaround can be dropped.

Decision

Force the local branch to the pipeline's commit, and fetch tags:

git fetch --tags --force --quiet || true
git checkout -B "$CI_COMMIT_BRANCH" "$CI_COMMIT_SHA"

checkout -B creates-or-resets the branch to $CI_COMMIT_SHA (always present — it is the detached HEAD CI checked out) and switches to it, so a stale local ref cannot survive. The tag fetch ensures release-plz sees the per-crate release tags it keys off, independent of what the reused workspace had. git branch --set-upstream-to and the token remote swap that follow are unchanged.

Why not rely on GIT_STRATEGY: clone

Forcing a full clone per job would also avoid stale refs but is far more expensive on every release pipeline; consumers should not have to change their git strategy to get a correct release. The two-line fix is self-contained in the component.

Scope & non-goals

  • In scope: the checkout in .release-plz-base (shared by both release-plz:pr and release-plz:release). No input-shape changes.
  • Non-goals: the v0.10.4 pr-after-release ordering (unchanged); the v0.10.3 two-job split (unchanged); tokens / forge / bootstrap.

Downstream

rust-tool-base bumps its pin to v0.10.6 and removes the git update-ref + tag-fetch workaround from its .release-plz-setup anchor (now redundant). Its next release pipeline must publish on the correct tree with no spurious same-version MR.

Testing

tests/release-plz/.gitlab-ci.yml includes the component against a repo with no Cargo workspace; both jobs still hit the documented non-zero exit and are allow_failure-tolerated. checkout -B <branch> $CI_COMMIT_SHA behaves identically to the bare checkout on a fresh clone (the local ref already equals the SHA), so the self-test is unaffected; the self-test:release-plz trigger stays green.