Automatic versioning for GitHub Actions authors
Source: Dev.to
Overview
As a maintainer of three GitHub Actions, I’ve always struggled a bit with versioning. GitHub’s documentation gives guidance, but there’s no easy way to verify that everything is correct. A quick scan of the Marketplace shows I’m not alone—some of GitHub’s own actions have inconsistencies, too.
That’s why I cobbled together v1 of the Actions Semver Checker a couple of years ago. It served me well, but the initial implementation had a few bugs, was hard to maintain, and any change felt risky because I couldn’t easily test whether I’d broken something.
From v1 to v2
I asked Copilot Agent to use the v1 code as a blueprint and refactor it with the following constraints:
| Constraint | Description |
|---|---|
| Side‑by‑side | Keep the old and new implementations callable together for easy comparison. |
| Modular validation | Extract validation rules into separate scripts for easier maintenance and testing. |
| Manual remediation | Provide manual remediation options wherever possible. |
| Autofix | Implement an autofix that attempts the manual remediation steps automatically. |
| Unit tests | Add unit tests for everything. |
| Integration tests | Add integration tests for everything. |
| Backwards compatibility | Preserve v1 input signatures as much as possible. |
I fed Copilot links to the relevant GitHub docs and blogs (CLI release commands, Releases REST API, Tags REST API, GraphQL API, immutable releases, Actions versioning). Claude Opus helped generate a detailed plan, which I tweaked before letting Copilot spend ~45 minutes coding.
The result was a first‑vibe‑coded GitHub Action that mostly did what was needed, surfacing a few gaps in the plan and creating some interesting interweaving between the two implementations.
After building a test suite of 90+ tests, I felt confident tweaking the behavior. Following several back‑and‑forth sessions with Copilot and hands‑on work in VS Code, I’m proud to release v2 of the GitHub Actions Semver Checker.
What the Action Does
The action is intended to be installed inside the repository that hosts a GitHub Action (e.g., actions/checkout or jessehouwing/actions-semver-checker). It analyzes all branches, tags, and releases and validates them against a set of rules.
Core validation rules (v1)
| Rule | Description |
|---|---|
| vX tag/branch | A configurable vX tag or branch must point to the latest vX.y.z tag. |
| vX.Y tag/branch | A configurable vX.Y tag or branch must point to the latest vX.Y.z tag. |
| vx.y.z tag | Must exist. |
| vx.y.z branch | Must not exist. |
New validation rules (v2)
| Rule | Description |
|---|---|
| Release for every vx.y.z tag | There should be a release for each vx.y.z tag. |
| Immutable releases | Releases must be immutable. |
| Latest release | The release for the highest vx.y.z should be marked as “latest”. |
| No releases for vX / vX.Y | Releases must not exist for the vX and vX.Y tags/branches. |
| Marketplace publishing | The action must be published to the Marketplace. |
| action.yml metadata | action.yml must contain the correct metadata elements. |
| Immutable‑release setting | Immutable releases must be turned on. |
For almost all of these validations, an autofix option automatically corrects any issues found. If the action cannot fix a problem, it logs manual remediation steps to the workflow’s summary page.
Autofix Capabilities
| Capability | What it does |
|---|---|
| Branches | Delete / update / create branches. |
| Tags | Delete / update / create tags. |
| Convert | Convert a branch to a tag or a tag to a branch. |
| Releases | Delete / update / create / publish releases. |
| Latest version | Automatically set the latest version. |
| Immutable releases | Republish releases to make them immutable. |
Additional Improvements
- Configurable rule suites – Choose which groups of rules to run.
- No full checkout needed – The action no longer requires checking out the entire repository.
- Retry & rate‑limit handling – Built‑in retry logic for API rate limits.
- PowerShell Gallery module – Available as a module on the PowerShell Gallery.
Breaking change (v1 → v2)
You must now pass the secret ${{ secrets.GITHUB_TOKEN }} to the token: input of the action.
| Permission needed | Reason |
|---|---|
contents: write | Required for some validations (e.g., reading draft releases). |
contents: write (autofix) | Required for autofix functionality. |
Additional permissions (e.g., workflows: write) | Some fixes need permissions that cannot be granted to GitHub Actions. Use a GitHub App or a fine‑grained Personal Access Token instead. |
Getting Started
-
Install the action in your action repository with the default settings. It will analyze the repo and report any rule violations.
-
Adjust settings to match your desired behavior:
| Input | Options | Description |
|---|---|---|
floating-versions-use | tags | branches | Choose how to manage vx and vx.y versions. |
check-minor-version | none | warning | error | Validate the existence of vx.y versions. |
check-releases | none | warning | error | Validate the existence of releases for vx.y.z tags. |
check-release-immutability | none | warning | error | Validate whether releases are immutable. |
ignore-preview-releases | true | false | Exclude preview releases when checking floating versions (vx and vx.y). |
ignore-versions | comma‑separated list | Exclude specific versions from validation (e.g., very old versions or ones that were accidentally made immutable). |
Example Workflow
name: Check SemVer
on:
push:
branches: ['main']
tags:
- '*'
workflow_dispatch:
permissions: {}
jobs:
check-semver:
permissions:
contents: write # needed for validations & autofix
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
runs-on: ubuntu-latest
steps:
- name: Checkout repository (shallow)
uses: actions/checkout@v4
with:
fetch-depth: 1 # no need for full history
- name: Run SemVer Checker (v2)
uses: jessehouwing/actions-semver-checker@v2
with:
token: ${{ secrets.GITHUB_TOKEN }}
floating-versions-use: tags
check-minor-version: warning
check-releases: error
check-release-immutability: warning
ignore-preview-releases: true
ignore-versions: |
0.0.1
1.0.0-beta
Summary
- v2 adds many new validation rules and a robust autofix system.
- The action is fully configurable, doesn’t require a full checkout, and includes retry & rate‑limit handling.
- It’s available as a PowerShell Gallery module and can run side‑by‑side with v1 for easy comparison.
Feel free to try it out, tweak the inputs to suit your workflow, and let the action keep your GitHub Action releases clean, consistent, and immutable!
GitHub Workflow Example
# Example job fragment
{{ github.workflow }}:
cancel-in-progress: true
runs-on: ubuntu-latest
steps:
- uses: jessehouwing/actions-semver-checker@v2
with:
token: ${{ secrets.GITHUB_TOKEN }}
check-release-immutability: none
⚠️ Important:
Be extra careful with thecheck-release-immutabilitysetting prior to turning on autofix. Most automatic fixes can be easily undone using the Git command line, but once a release is made immutable, there is no way back.
1️⃣ Clean up existing tags
Once your existing tags have been cleaned up and you understand the implications, enable release‑immutability checks:
steps:
- uses: jessehouwing/actions-semver-checker@v2
with:
token: ${{ secrets.GITHUB_TOKEN }}
check-release-immutability: error
2️⃣ Run in read‑only mode
Use the action in read‑only mode for a while, manually performing the suggested remediation steps.
3️⃣ Enable autofix (optional)
When you’re confident the action does what you want, consider turning on autofix:
steps:
- uses: jessehouwing/actions-semver-checker@v2
with:
token: ${{ secrets.GITHUB_TOKEN }}
autofix: true
How it works with autofix
With autofix turned on, the only thing you need to do to release a new version and update all tags and releases is to push a new tag (e.g., vX.Y.Z). This will trigger the action to:
- Create a new release with the correct name.
- Update all relevant tags automatically.
That’s it—no further manual steps required!