A GitHub Action that generates a semantic version number based on an input
version (or package.json), the current branch, and the number of commits
since package.json last changed.
It appends a preid suffix (e.g. dev.5) on designated branches and emits
both semver and non-semver variants as outputs.
- If the
versioninput is not provided, the action readsversionfrom the repository'spackage.json. - Any existing pre-release suffix on the incoming version is stripped before
processing (e.g.
1.0.0-rc.0→ base1.0.0), so re-running on the same base version never produces a double-preid like1.0.0-rc.0-rc.5. - The branch is checked against the following rules in order:
force-stable: true→ always stable, regardless of branch.force-preid: true→ always pre-release, uses the mapped preid for the branch or falls back topreid.- Exact match in
preid-branches→ pre-release with the mapped preid (e.g.main→rc,develop→dev). - Matches a
stable-branchesregex pattern (e.g.v1,1.x) → stable. - All other branches → pre-release with the default
preid(e.g.feature/foo→dev).
- When pre-release, the commit count since the last
package.jsonchange is appended:1.5.6→1.5.6-dev.5. The counter resets to0on every version bump. - When stable, the version is emitted unchanged:
1.5.6 - A
tagoutput is always emitted: pre-release builds use the preid label (e.g.rc,dev); stable builds emitlatestfor the highest semver branch andv{major}-ltsfor older ones (detected viagit ls-remote).
| Input | Required | Default | Description |
|---|---|---|---|
version |
No | (reads package.json) |
Base version to use (e.g. 1.5.6). Any existing preid suffix is stripped automatically. |
preid |
No | dev |
Default prerelease identifier used when no branch-specific mapping is defined. |
preid-branches |
No | main:rc,master:rc,develop:dev,vnext:next |
Comma-separated list of branches (with optional branch:preid mapping) that trigger preid versioning. Plain name uses the global preid. |
stable-branches |
No | ^v\d+$,^\d+\.x$ |
Comma-separated regex patterns for branches that are always stable (e.g. v1, 2.x). Any branch not in preid-branches and not matching here falls back to preid. |
preid-num-delimiter |
No | . |
Delimiter between the preid and the counter (e.g. dev.5 or dev-5). |
force-preid |
No | false |
Forces preid versioning regardless of the current branch. |
force-stable |
No | false |
Forces stable versioning regardless of the current branch. |
| Output | Example | Description |
|---|---|---|
version |
1.5.6-dev.5 |
Full semver with preid, or plain version when stable. |
baseVersion |
1.5.6 |
Base version without any pre-release suffix (from the version input or package.json). |
fileVersion |
1.5.6.5 |
4-part numeric version for non-semver consumers (e.g. .NET assembly version); plain version when stable. |
majorVersion |
1 |
Major version segment. |
minorVersion |
5 |
Minor version segment. |
patchVersion |
6 |
Patch version segment. |
preid |
dev |
The preid string when pre-release, otherwise an empty string. |
preidCounter |
5 |
The numeric counter appended after the preid (e.g. 5 for -dev.5), otherwise an empty string. |
isPrerelease |
true |
Whether the generated version is a prerelease. |
tag |
latest |
Dist-tag for the build: preid label when pre-release (e.g. rc), latest or v{major}-lts when stable. |
| Branch | Result |
|---|---|
main |
1.5.6-rc.5 (explicit map) |
master |
1.5.6-rc.5 (explicit map) |
develop |
1.5.6-dev.5 (explicit map) |
vnext |
1.5.6-next.5 (explicit map) |
feature/my-feat |
1.5.6-dev.5 (fallback) |
workflow |
1.5.6-dev.5 (fallback) |
v1, v2 |
1.5.6 (stable pattern) |
1.x, 12.x |
1.5.6 (stable pattern) |
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0 # required for accurate commit counting
- name: Build version
id: version
uses: sketch7/version-builder-action@v3
with:
version: "1.5.6" # optional — omit to read from package.json
preid: "dev" # optional, default fallback preid
preid-branches: "main:rc,master:rc,develop:dev,vnext:next" # optional
stable-branches: "^v\\d+$,^\\d+\\.x$" # optional
- name: Use outputs
run: |
echo "Version: ${{ steps.version.outputs.version }}"
echo "File version: ${{ steps.version.outputs.fileVersion }}"
echo "Preid: ${{ steps.version.outputs.preid }}"
echo "Preid counter: ${{ steps.version.outputs.preidCounter }}"
echo "Tag: ${{ steps.version.outputs.tag }}"
echo "Is pre-release: ${{ steps.version.outputs.isPrerelease }}"- name: Build version (stable)
uses: sketch7/version-builder-action@v3
with:
force-stable: "true"- name: Build version (always preid)
uses: sketch7/version-builder-action@v3
with:
force-preid: "true"
preid: "rc"- name: Build version
uses: sketch7/version-builder-action@v3
with:
stable-branches: "^v\\d+$,^\\d+\\.x$,^hotfix/.*$"Releases are handled entirely by the Release workflow — no local tooling needed.
- Bump the version — update
versioninpackage.json, commit, and push tomain. - Trigger the workflow — go to Actions → Release → Run workflow and click Run.
The workflow will automatically:
- Read the version from
package.jsonon the triggered branch. - Create the exact semver tag (e.g.
v1.2.3) and update the floating major tag (e.g.v1). - Create the
v1branch if it doesn't exist yet, or update it for minor/patch releases within the same major. - Publish a GitHub Release with auto-generated release notes.