Files
galaxy-game/rtmanager/internal/service/patchruntime/semver.go
T
2026-04-28 20:39:18 +02:00

53 lines
1.7 KiB
Go

package patchruntime
import (
"errors"
"fmt"
"strings"
"github.com/distribution/reference"
"golang.org/x/mod/semver"
)
// errImageRefNoTag reports that an image reference does not declare a
// tag. The patch service maps it to `image_ref_not_semver` because a
// digest-only or tagless reference cannot carry a semver-comparable
// version.
var errImageRefNoTag = errors.New("image reference is missing a tag")
// extractSemverTag returns the canonical semver string ("v1.4.7") for
// imageRef, ready to feed into golang.org/x/mod/semver. The leading "v"
// is added when the underlying tag omits it.
//
// Errors returned by this function are pre-formatted for inclusion in
// the patch service's `image_ref_not_semver` failure message.
func extractSemverTag(imageRef string) (string, error) {
parsed, err := reference.ParseNormalizedNamed(imageRef)
if err != nil {
return "", fmt.Errorf("parse image reference %q: %w", imageRef, err)
}
tagged, ok := parsed.(reference.NamedTagged)
if !ok {
return "", fmt.Errorf("%w: %q", errImageRefNoTag, imageRef)
}
tag := strings.TrimSpace(tagged.Tag())
if tag == "" {
return "", fmt.Errorf("%w: %q", errImageRefNoTag, imageRef)
}
candidate := tag
if !strings.HasPrefix(candidate, "v") {
candidate = "v" + candidate
}
if !semver.IsValid(candidate) {
return "", fmt.Errorf("tag %q on image reference %q is not a valid semver", tag, imageRef)
}
return candidate, nil
}
// samePatchSeries reports whether two canonical semver strings (with
// the leading "v") share their major and minor components. The third
// component (patch) and any pre-release / build metadata are ignored.
func samePatchSeries(currentSemver, newSemver string) bool {
return semver.MajorMinor(currentSemver) == semver.MajorMinor(newSemver)
}