Run it in GitHub Actions¶
Goal: every push to your default branch keeps a release pull request up to date, and merging that pull request tags the commit that actually landed.
This guide satisfies what colophon needs from a pipeline item by item. Where a step rests on GitHub's documentation rather than on a run of colophon against GitHub, it says so.
1. Provide a token that is not GITHUB_TOKEN¶
GitHub states that "events triggered by the GITHUB_TOKEN will not create a
new workflow run", apart from workflow_dispatch and repository_dispatch. A
tag colophon pushed with it would never start your release build. Create a
fine-grained personal access token or a GitHub App installation token with
contents and pull requests read/write on the repository, and store it as a
repository secret named COLOPHON_TOKEN. If tags are protected, the token's
owner must be allowed to create them.
2. Check out the full history¶
actions/checkout fetches one commit by default. colophon needs every commit
back to the last release tag and the tags themselves, and fails with
reading commits: iterating commits: object not found on a shallow checkout.
fetch-depth: 0 is defined by the action as "all history for all branches and
tags".
3. Add the workflow¶
# .github/workflows/release.yml
name: release
on:
push:
branches: [main]
permissions:
contents: write
pull-requests: write
concurrency:
group: colophon-${{ github.ref }}
cancel-in-progress: false
env:
COLOPHON_VERSION: v0.3.0
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.COLOPHON_TOKEN }}
- uses: actions/setup-go@v5
with:
go-version: stable
- run: go install gitlab.com/phpboyscout/colophon/cmd/colophon@${COLOPHON_VERSION}
- run: colophon --ci publish --target main --author-name colophon --author-email [email protected]
env:
GITHUB_TOKEN: ${{ secrets.COLOPHON_TOKEN }}
propose:
needs: publish
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.COLOPHON_TOKEN }}
- uses: actions/setup-go@v5
with:
go-version: stable
- run: go install gitlab.com/phpboyscout/colophon/cmd/colophon@${COLOPHON_VERSION}
- run: colophon --ci propose --target main --author-name colophon --author-email [email protected]
env:
GITHUB_TOKEN: ${{ secrets.COLOPHON_TOKEN }}
What each part is for:
- Two jobs,
proposeafterpublish. After the release pull request merges, the release commit is onmainand the tag is not there yet, so a single job running both verbs would re-open a pull request for the release just tagged.proposesees the new tag because its checkout happens afterpublishpushed. Do not fold them. concurrencywithout cancellation. Two pushes in quick succession must not runpublishat the same time; the second waits.token:on the checkout. The checkout's remote is then authenticated with the same token colophon pushes with. colophon supplies the token itself fromGITHUB_TOKENin the environment, sent as thex-access-tokenbasic-auth user; the checkout token matters only foractions/checkoutitself.- A pinned colophon version. colophon decides what ships, so
@latestwould let that decision change without a commit saying so. --ci. Marks the run as unattended.
4. Settings on the repository¶
- Allow rebase merging for pull requests, so the release commit lands as
itself. colophon resolves the landed commit against
mainrather than from the pull request, so squash merging also works; merge commits are best left off. - Require the status checks you care about before merging. The release pull
request will run this workflow's
pull_requesttriggers if you add them; it needs nothing of its own beyond what proves it is what colophon wrote. - Protect
v*tags if you protect anything, and allow the token's owner to create them.
5. Try the safe half first¶
propose alone opens and updates a pull request and cuts no tag. Run the
workflow with only that job while you compare its proposals against whatever
released the project before. colophon plan is the even safer check and runs
on your laptop against any full clone.
Releases with assets¶
A repository whose releases carry binaries publishes with --tag-only, builds
on the tag, and creates the release afterwards with colophon release --tag:
# .github/workflows/tag.yml
on:
push:
tags: ['v*']
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 0 }
# build and upload with goreleaser here; it must not create the release itself
- run: colophon --ci release --tag "${GITHUB_REF_NAME}" --target main --assets dist --asset-base "<where goreleaser uploaded>"
env:
GITHUB_TOKEN: ${{ secrets.COLOPHON_TOKEN }}
Not yet exercised on GitHub, stated from colophon's forge contract rather than
from a run: on GitHub a release is created as a draft and published last, so a
job killed between the two leaves a draft to delete by hand
(go/forge#20); and
GitHub release assets are uploaded bytes, which colophon does not send, so
--asset-base links become a footer in the notes rather than attached files.
Treat this section as the shape to start from and check the first release by
hand. Publish a release with its assets has
the GitLab path that is exercised daily.
If it fails¶
| symptom | cause |
|---|---|
reading commits: iterating commits: object not found |
shallow checkout; set fetch-depth: 0 |
| the tag exists but no tag workflow ran | the tag was pushed with GITHUB_TOKEN; use a PAT or App token |
publish opened a second pull request for the version just tagged |
propose ran before or alongside publish; make it a separate job with needs: publish |
| a push is rejected on the tag | the token's owner cannot create protected tags |