Skip to content

rust-release

The Rust half of a colophon release. Colophon proposes the release MR, writes the new version into Cargo.toml and Cargo.lock, and tags when the MR merges. It never touches a registry. This component does the two things a Rust release needs beyond that:

  • rust-semver runs cargo semver-checks on colophon's release MR, against the versions on crates.io. If the API change needs a bigger bump than the version colophon wrote, the job is red and so is the release MR.
  • rust-publish runs on the tag pipeline. It checks that every crate that publishes carries the tag's version, then publishes once: the whole workspace in dependency order, or the single crate.

It is a separate component from colophon so that a Go or Node project including colophon never gets a Rust job. Wiki spec 0116 records the design; colophon's side is its spec 0027.

Jobs

Job Runs on What it does
rust-semver the release MR (colophon/release/*) cargo semver-checks check-release, one --package per publishing member that crates.io has. A crate never published, or with publish = false, is skipped, because there is no baseline.
rust-publish a tag matching tag_pattern Reads the version from the tag, then stops red if any publishing member has another version. Asks crates.io for each one: all present exits 0 having done nothing, some present stops red naming both lists, none present publishes with --locked (and --workspace when the root Cargo.toml has a [workspace]).

A re-run is safe. If the tag pipeline is retried after a complete publish, rust-publish finds every crate on crates.io and is green. If a workspace publish stopped part-way, the job does not guess: it names what is published and what is missing, and finishing it is a person's call.

The semver gate only runs on the release MR. On any other MR the version in Cargo.toml is still the last release's, so every API change would read as unreleased and the check would always fail.

The version a tag carries is the trailing X.Y.Z (and any pre-release suffix) after the last v, -v, /v or @. v0.9.1 and rtb-error-v0.6.5 both work, which are the estate's two shapes. The colophon component's colophon-release job derives $COLOPHON_VERSION the same way.

Inputs

Input Type Default Description
image string rust-tools:v0.2.5 Needs cargo, jq, curl and cargo-semver-checks. rust-tools has cargo-semver-checks from v0.2.0. A project's rust-toolchain.toml still picks the toolchain.
semver_stage string test Stage for rust-semver.
semver_if string '$CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_SOURCE_BRANCH_NAME =~ /^colophon\/release\//' Gating rules:if: for rust-semver. Matches the branch the colophon component derives. Change it only alongside colophon's release_branch.
stage string release Stage for rust-publish.
tag_pattern string v root tags and <crate>-v tags RE2 pattern a tag must match for rust-publish to run.
token string $CARGO_REGISTRY_TOKEN crates.io API token. Read only by rust-publish, and only when there is something to publish.
cache_prune_days number 7 As for the other rust-* components: when the runner exports RUST_CACHE_DIR, the target directory is keyed by compiler and libc, and unused keys are pruned after this many days. Wiki spec 0106. A key last used before a newer key appeared goes after one idle day regardless (wiki spec 0119).
extra_before_script string "" Shell snippet run first in both jobs, for native build dependencies. Both jobs compile.
resource_group string "$CI_PROJECT_PATH_SLUG-rust-compile" Serialises rust-semver with the project's other compile jobs. rust-publish has its own group, so two tag pipelines never publish at once.

Protect the release tags

CARGO_REGISTRY_TOKEN is a protected variable, so it only reaches pipelines for protected refs. Protect the tag shapes the project releases (v*, or <crate>-v*). An unprotected tag runs rust-publish without a token, which stops red before cargo runs.

Usage

A single crate keeping its <crate>-v tags. .colophon.yaml:

versioning:
  tag: "rtb-error-v{version}"
  files:
    - cargo: Cargo.toml

.gitlab-ci.yml:

include:
  - component: gitlab.com/phpboyscout/cicd/colophon@main
    inputs:
      release_files: "CHANGELOG.md **/CHANGELOG.md Cargo.toml **/Cargo.toml Cargo.lock"
  - component: gitlab.com/phpboyscout/cicd/rust-release@main

A lockstep workspace leaves out versioning.tag and releases on a v root tag. The includes are the same.

release_files has to admit the manifests and the lock file, because colophon writes the version into them. Its default admits changelogs only, and would fail every release MR.

See also

  • colophon, which proposes, tags and announces
  • release-plz, which this replaces and is deprecated