Set up the version gate in GitHub Actions¶
Make a pull request fail when a segment's version is behind what its commits warrant, so a change cannot reach the default branch without shipping.
Time: about ten minutes. You need: Admin on the repository.
Why a gate and not an automatic bump¶
The obvious design is to let CI compute the bump, commit it and push it back. GitHub stops that at the last step, and says so plainly:
With the exception of
workflow_dispatchandrepository_dispatch, otherGITHUB_TOKEN-triggered events do not create workflow runs at all.
That is deliberate: it is what stops a workflow that pushes re-triggering itself forever. But it means a bump written by CI arrives as a head commit with no checks of its own, so a branch protection rule requiring status checks blocks the pull request with nothing able to clear it.
You can work around it with a Personal Access Token or a GitHub App, at the cost of a long-lived credential with write access. skillup does not, because the alternative is one command run occasionally.
GitLab's
CI_JOB_TOKENbehaves the same way, for the same reason. See Set up the version gate in GitLab CI.
1. Protect the default branch¶
The gate only means something if nothing can bypass it.
Settings → Branches → Add branch ruleset for main:
| Rule | Value |
|---|---|
| Restrict deletions | on |
| Require a pull request before merging | on |
| Require status checks to pass | on, with version-check selected |
| Block force pushes | on |
The required-status-check entry only appears in the list after the workflow has run at least once, so add the workflow first and come back to it.
2. Add the workflow¶
.github/workflows/version-check.yml:
name: version
on:
pull_request:
jobs:
version-check:
runs-on: ubuntu-latest
permissions:
contents: read # the gate only reads; it never pushes
steps:
- uses: actions/checkout@v4
with:
# skillup reads each manifest's whole history. The default checkout is
# shallow, and a shallow clone yields a confidently wrong answer
# rather than an error.
fetch-depth: 0
- uses: actions/setup-go@v5
with:
go-version: stable
- name: Install skillup
# Pinned, not @latest: this gate decides whether a change ships, so it
# should not change underneath the repository without a commit saying so.
run: go install gitlab.com/phpboyscout/skillup/cmd/skillup@v0.1.0
- name: Check segment versions
run: skillup check --path .
Three details that matter:
fetch-depth: 0. Without it the checkout is shallow, skillup sees a truncated history, and computes a version that is wrong without failing.contents: read. The gate never writes, so do not grant more. If you later add a job that does push, give that jobcontents: writerather than widening this one.- Pin the version; do not track
@latest. This job decides whether a change reaches consumers. On@latestthat decision changes without a commit saying so, and the change lands on whichever pull request happens to run next.
go-version: stable is enough today — skillup needs Go 1.26.5 or newer.
Keep the pin current¶
Nothing bumps this line by default. Dependabot's gomod ecosystem reads
go.mod, and its github-actions ecosystem reads uses: — neither looks at a
run: command, and skillup is not on GitHub anyway. Renovate can, with a custom
manager in renovate.json:
{
"customManagers": [
{
"customType": "regex",
"managerFilePatterns": ["/^\\.github/workflows/.+\\.ya?ml$/"],
"matchStrings": [
"go install gitlab\\.com/phpboyscout/skillup/cmd/skillup@(?<currentValue>v[\\d.]+)"
],
"datasourceTemplate": "gitlab-tags",
"depNameTemplate": "phpboyscout/skillup"
}
]
}
Otherwise the pin stays where you put it — safe, but frozen. Watch the releases page and bump it by hand.
3. Check it bites¶
On a branch, change something inside a segment and commit it as a feat: or
fix: without touching the version. The check should fail with:
my-segment is 0.3.0 but its commits warrant 0.4.0 (minor)
a1b2c3d4 feat(my-segment): add a thing (minor)
To fix, on your branch:
skillup apply --path .
git add -u && git commit --amend --no-edit # or a new commit
Run those two commands, push, and it goes green.
Troubleshooting¶
The check passes but should not. Confirm fetch-depth: 0. A shallow
checkout is the usual cause of a wrong-but-confident answer.
version-check is not offered as a required status check. It has to have
run once before GitHub will list it. Open a throwaway pull request, let it run,
then add the rule.
Every segment wants to go to 0.1.0. skillup is reading a repository whose
manifests have no history, so every segment looks new. Confirm --path points
at the right root.
The check does not run on a fork's pull request. Workflows from forks get a read-only token by default. That is fine here — the gate only reads — but if you add anything that writes, it will fail for external contributors.