The semverutil package provides shared semantic versioning primitives used across pkg/workflow and pkg/cli. Centralizing these helpers ensures that semver parsing, comparison, and compatibility logic is defined in one place.
This package wraps golang.org/x/mod/semver with additional helpers for:
- Normalizing version strings (adding the required
vprefix). - Validating GitHub Actions version tags (
vmajor,vmajor.minor,vmajor.minor.patch). - Parsing versions into a structured
SemanticVersiontype. - Comparing and checking compatibility between version strings.
A parsed semantic version with individual numeric components.
type SemanticVersion struct {
Major int
Minor int
Patch int
Pre string // Prerelease identifier without leading hyphen (e.g. "beta.1")
Raw string // Original version string without leading "v"
}| Method | Description |
|---|---|
IsPreciseVersion() bool |
Returns true if the version has at least two dots (e.g. v6.0.0 is precise, v6 is not) |
IsNewer(other *SemanticVersion) bool |
Returns true if this version is newer than other |
Adds a leading "v" if v does not already have one. Required because golang.org/x/mod/semver demands the prefix.
semverutil.EnsureVPrefix("1.2.3") // → "v1.2.3"
semverutil.EnsureVPrefix("v1.2.3") // → "v1.2.3"Reports whether s is a valid GitHub Actions version tag. Accepted forms: vmajor, vmajor.minor, vmajor.minor.patch. Prerelease and build-metadata suffixes are not accepted.
semverutil.IsActionVersionTag("v4") // true
semverutil.IsActionVersionTag("v4.1") // true
semverutil.IsActionVersionTag("v4.1.0") // true
semverutil.IsActionVersionTag("v4.1.0-rc") // falseReports whether ref is a valid semantic version string (accepts any valid semver including prerelease/build-metadata, and bare versions without "v").
semverutil.IsValid("1.2.3") // true
semverutil.IsValid("v1.2.3-beta") // true
semverutil.IsValid("not-a-ver") // falseParses v into a SemanticVersion. Returns nil if v is not a valid semver string.
ver := semverutil.ParseVersion("v1.2.3")
if ver != nil {
fmt.Println(ver.Major, ver.Minor, ver.Patch) // 1 2 3
}Compares two semantic versions using golang.org/x/mod/semver. Returns 1 if v1 > v2, -1 if v1 < v2, or 0 if equal. Bare versions (without "v") are accepted.
semverutil.Compare("v2.0.0", "v1.9.9") // 1 (v2 is newer)
semverutil.Compare("v1.0.0", "v1.0.0") // 0 (equal)
semverutil.Compare("v0.9.0", "v1.0.0") // -1 (v0.9 is older)Reports whether v1 should sort ahead of v2 in the action-version specificity ordering. Versions with more dot-separated components sort first (e.g. "v4.3.0" ahead of "v4"), and ties use lexicographic ordering. This is an ordering predicate, not a strict "more precise" check. No validation is performed; callers MUST ensure both inputs are well-formed version tags.
semverutil.IsMorePreciseVersion("v4.3.0", "v4") // true (v4.3.0 is more specific)
semverutil.IsMorePreciseVersion("v4", "v4.3.0") // false
semverutil.IsMorePreciseVersion("v4.3.0", "v4.3.0") // false (equal precision)Reports whether pinVersion is semver-compatible with requestedVersion. Compatibility is defined as sharing the same major version.
semverutil.IsCompatible("v5.0.0", "v5") // true
semverutil.IsCompatible("v5.1.0", "v5.0.0") // true
semverutil.IsCompatible("v6.0.0", "v5") // falseimport "github.com/github/gh-aw/pkg/semverutil"
// Normalize a version string
semverutil.EnsureVPrefix("1.2.3") // → "v1.2.3"
// Parse into structured type
ver := semverutil.ParseVersion("v1.2.3")
if ver != nil {
fmt.Println(ver.Major, ver.Minor, ver.Patch) // 1 2 3
}
// Compare versions
semverutil.Compare("v2.0.0", "v1.9.9") // 1 (v2 is newer)
// Check major-version compatibility
semverutil.IsCompatible("v5.1.0", "v5") // true
semverutil.IsCompatible("v6.0.0", "v5") // falseInternal:
github.com/github/gh-aw/pkg/logger— debug logging
External:
golang.org/x/mod/semver— canonical semver parsing and comparison
- All debug output uses
logger.New("semverutil:semverutil")and is only emitted whenDEBUG=semverutil:*. - The package intentionally delegates to
golang.org/x/mod/semverfor canonical semver logic rather than implementing its own parsing. ParseVersionusessemver.Canonicalbefore splitting into components, ensuring correct handling of short forms likev1(canonicalized tov1.0.0).IsCompatiblereturnsfalsefor invalid versions on either side before comparing majors, preventing two malformed version strings from being treated as compatible.
This specification is automatically maintained by the spec-extractor workflow.