124 lines
3.3 KiB
Go
124 lines
3.3 KiB
Go
package semver
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
goSemver "github.com/Masterminds/semver/v3"
|
|
|
|
"git.thokra.dev/thokra/stamp/internal/changeset"
|
|
)
|
|
|
|
// Bump computes the next version given the current version string and a bump type.
|
|
// preID is the pre-release identifier (e.g. "alpha", "beta", "rc") used for pre-* bumps.
|
|
func Bump(current string, bump changeset.BumpType, preID string) (string, error) {
|
|
v, err := goSemver.NewVersion(current)
|
|
if err != nil {
|
|
return "", fmt.Errorf("invalid version %q: %w", current, err)
|
|
}
|
|
|
|
if preID == "" {
|
|
preID = "0"
|
|
}
|
|
|
|
switch bump {
|
|
case changeset.BumpMajor:
|
|
next := v.IncMajor()
|
|
return next.Original(), nil
|
|
|
|
case changeset.BumpMinor:
|
|
next := v.IncMinor()
|
|
return next.Original(), nil
|
|
|
|
case changeset.BumpPatch:
|
|
next := v.IncPatch()
|
|
return next.Original(), nil
|
|
|
|
case changeset.BumpPreMajor:
|
|
next := v.IncMajor()
|
|
pre, err := goSemver.NewVersion(fmt.Sprintf("%d.%d.%d-%s.0", next.Major(), next.Minor(), next.Patch(), preID))
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return pre.Original(), nil
|
|
|
|
case changeset.BumpPreMinor:
|
|
next := v.IncMinor()
|
|
pre, err := goSemver.NewVersion(fmt.Sprintf("%d.%d.%d-%s.0", next.Major(), next.Minor(), next.Patch(), preID))
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return pre.Original(), nil
|
|
|
|
case changeset.BumpPrePatch:
|
|
next := v.IncPatch()
|
|
pre, err := goSemver.NewVersion(fmt.Sprintf("%d.%d.%d-%s.0", next.Major(), next.Minor(), next.Patch(), preID))
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return pre.Original(), nil
|
|
|
|
case changeset.BumpPreRelease:
|
|
// If already a pre-release with matching identifier, increment the pre-release number.
|
|
// Otherwise start a fresh pre-release on current patch.
|
|
preStr := v.Prerelease()
|
|
if preStr != "" && strings.HasPrefix(preStr, preID+".") {
|
|
parts := strings.SplitN(preStr, ".", 2)
|
|
var num int
|
|
fmt.Sscanf(parts[1], "%d", &num)
|
|
next, err := goSemver.NewVersion(fmt.Sprintf("%d.%d.%d-%s.%d",
|
|
v.Major(), v.Minor(), v.Patch(), preID, num+1))
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return next.Original(), nil
|
|
}
|
|
// Start a new pre-release on next patch.
|
|
patch := v.IncPatch()
|
|
next, err := goSemver.NewVersion(fmt.Sprintf("%d.%d.%d-%s.0",
|
|
patch.Major(), patch.Minor(), patch.Patch(), preID))
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return next.Original(), nil
|
|
|
|
default:
|
|
return "", fmt.Errorf("unknown bump type %q", bump)
|
|
}
|
|
}
|
|
|
|
// HighestBump returns the highest-priority bump type from a set of bumps.
|
|
// Priority: major > minor > patch > premajor > preminor > prepatch > prerelease.
|
|
func HighestBump(bumps []changeset.BumpType) changeset.BumpType {
|
|
priority := map[changeset.BumpType]int{
|
|
changeset.BumpMajor: 6,
|
|
changeset.BumpMinor: 5,
|
|
changeset.BumpPatch: 4,
|
|
changeset.BumpPreMajor: 3,
|
|
changeset.BumpPreMinor: 2,
|
|
changeset.BumpPrePatch: 1,
|
|
changeset.BumpPreRelease: 0,
|
|
}
|
|
|
|
best := changeset.BumpPreRelease
|
|
bestP := -1
|
|
for _, b := range bumps {
|
|
if p, ok := priority[b]; ok && p > bestP {
|
|
best = b
|
|
bestP = p
|
|
}
|
|
}
|
|
return best
|
|
}
|
|
|
|
// ProjectBumps aggregates bump types per project from a list of changesets.
|
|
func ProjectBumps(changesets []*changeset.Changeset) map[string][]changeset.BumpType {
|
|
result := map[string][]changeset.BumpType{}
|
|
for _, cs := range changesets {
|
|
for project, bump := range cs.Bumps {
|
|
result[project] = append(result[project], bump)
|
|
}
|
|
}
|
|
return result
|
|
}
|