Run it in GitLab CI¶
Goal: every merge to your default branch keeps a Release merge request up to date, and merging that request tags the commit that actually landed.
You need a project on GitLab, a stages: list you can add to, and a token.
The component satisfies what colophon needs from a pipeline
for you; this page shows where each requirement lives.
1. Provide a token¶
colophon needs a forge token with api and write_repository. It uses it for
the API calls, the release-branch push and the tag push.
It must not be CI_JOB_TOKEN. A tag pushed with CI_JOB_TOKEN does not
fire downstream tag pipelines, so your goreleaser or publish jobs would never
run.
Set it as a CI/CD variable named COLOPHON_TOKEN, masked and protected.
2. Add the component¶
include:
- component: gitlab.com/phpboyscout/cicd/colophon@main
inputs:
stage: release
branch: main
stages:
- lint
- test
- release
That is the whole setup for the common case. Pin a tag instead of main if you
want releases of the component to reach you deliberately. The component adds:
| Job | Runs on | What it does |
|---|---|---|
colophon-publish |
the default branch | A Release merge request has merged: resolve what landed on the target, tag that commit, create the release. |
colophon-propose-next |
the default branch, after publish | Re-cut the release branch from the target and open or update the Release merge request for the next release. |
colophon-release-check |
the Release merge request's pipeline | Check the merge request carries only the files colophon writes. It is the merge gate's pipeline, so the project's other jobs can stand aside there. |
colophon-release |
the tag pipeline, with assets: true |
Create the release carrying links to what the build uploaded. |
3. Keep the checkout full¶
Every job that runs the colophon binary sets GIT_DEPTH: "0", because
colophon reads the history back to the last release tag, and the tags, from the
checkout. (colophon-release-check runs only git and fetches the depth it
needs itself.) A shallow clone is refused like this:
ERRO this checkout is shallow (depth-limited clone) hints="colophon needs the full history and tags: set GIT_DEPTH: \"0\" on the job in GitLab CI, or fetch-depth: 0 on actions/checkout in GitHub Actions"
GitLab's project default is a depth of 20, which is shallow enough to fail.
The component's setting wins over the project default for its own jobs; do not
override it in a default: or variables: block that reaches them. If you run
colophon outside the component, set GIT_DEPTH: "0" on that job yourself.
4. Leave the order alone¶
publish runs before propose, and the component enforces that with needs:.
It is a correctness constraint rather than a preference.
After a Release merge request merges, the release commit is on the target branch but the tag does not exist yet. In that window colophon computes the same release again. A pipeline that proposed first would re-open a Release merge request for the version about to be tagged, publish would then tag it, and that merge request would sit open forever proposing a release that has already happened.
Inputs¶
Every input has a default; most projects set none of them.
| Input | Default | Notes |
|---|---|---|
image |
registry.gitlab.com/phpboyscout/images/release-tools:vX.Y.Z |
Image carrying the colophon binary; the component's default is the newest the component works with. |
stage |
release |
One stage is enough. Declare it in your own stages:. |
branch |
main |
Target branch to release from. |
token |
$COLOPHON_TOKEN |
Needs api + write_repository. Never CI_JOB_TOKEN. |
if |
$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH |
Gating rule for both jobs. Set it to match if you release from a non-default branch. |
author_name |
colophon |
Identity on the release commit and tag. |
author_email |
[email protected] |
See author_name. |
release_branch |
derived | Empty derives colophon/release/<branch>. |
propose |
true |
Set false to publish only. |
publish |
true |
Set false to propose only, which is the safe half: it opens a merge request and cuts no tag. |
assets |
false |
Releases carry binaries: publish --tag-only on the default branch, create the release on the tag pipeline. See Publish a release with its assets. |
dist |
dist |
goreleaser's output directory; its artifacts.json names what the release should carry. |
asset_base |
$CI_API_V4_URL/projects/$CI_PROJECT_ID/packages/generic/$CI_PROJECT_NAME/$COLOPHON_VERSION |
URL the artefacts were uploaded under, with each asset's name appended. Must match where goreleaser actually uploaded. |
release_files |
CHANGELOG.md **/CHANGELOG.md |
Files a Release merge request may change; colophon-release-check fails it on anything else. |
Try the safe half first¶
If you are migrating a project that already releases some other way, run
propose on its own to begin with. It opens and updates a merge request and
cuts no tag, so you can compare its answer against your existing tool without
either of them acting.
include:
- component: gitlab.com/phpboyscout/cicd/colophon@main
inputs:
stage: release
publish: false
colophon plan is the even safer version of the same comparison, and runs on
your laptop. See Getting started.
Running it outside the component¶
The component is a convenience. The commands underneath it take a token from
<FORGE>_TOKEN in the environment, upper-cased from the forge name, so
GITLAB_TOKEN for GitLab and GITHUB_TOKEN for GitHub.
release:
stage: release
image: registry.gitlab.com/phpboyscout/images/release-tools:vX.Y.Z
variables:
GIT_DEPTH: "0" # a shallow checkout fails; see step 3
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
script:
- export GITLAB_TOKEN="$COLOPHON_TOKEN"
- colophon --ci publish --target main
- colophon --ci propose --target main # in ONE job this re-proposes the release just tagged; keep them separate
The two commands above sit in one job only to show the flags. Run them as two
jobs, publish first, for the reason in step 4.