From 0fed62dc8e3a8d4004152c90633d9d8032c24adb Mon Sep 17 00:00:00 2001 From: knoflook Date: Mon, 11 Oct 2021 14:29:22 +0200 Subject: [PATCH] refactor!: create and use TagDelta struct et al add a TagDelta struct with accompanying function String() rename UpgradeElement() to UpgradeDelta() and change the return type move UpgradeType() to be a function of TagDelta add ParseDelta() that returns a TagDelta from string --- tagcmp.go | 121 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 72 insertions(+), 49 deletions(-) diff --git a/tagcmp.go b/tagcmp.go index cee2e48..090e115 100644 --- a/tagcmp.go +++ b/tagcmp.go @@ -19,6 +19,12 @@ type Tag struct { Metadata string // metadata: what's after + and after the first "-" } +type TagDelta struct { + Major int // major semver difference + Minor int // minor semver difference + Patch int // patch semver difference +} + // ByTagAsc sorts tags in ascending order where the last element is the latest tag. type ByTagAsc []Tag @@ -148,6 +154,12 @@ func (t Tag) String() string { return repr } +func (t TagDelta) String() string { + var repr string + repr = fmt.Sprintf("%d.%d.%d", t.Major, t.Minor, t.Patch) + return repr +} + // IsCompatible determines if two tags can be compared together func (t Tag) IsCompatible(tag Tag) bool { if t.UsesV && !tag.UsesV || tag.UsesV && !t.UsesV { @@ -175,43 +187,30 @@ func (t Tag) IsCompatible(tag Tag) bool { return true } -// UpgradeElement returns a Tag object which is the difference between an old and new tag +// UpgradeDelta returns a TagDelta object which is the difference between an old and new tag // It can contain negative numbers if comparing with an older tag. -func (curTag Tag) UpgradeElement(newTag Tag) (Tag, error) { +func (curTag Tag) UpgradeDelta(newTag Tag) (TagDelta, error) { if !curTag.IsCompatible(newTag) { - return Tag{}, fmt.Errorf("%s and %s are not compatible with each other", curTag.String(), newTag.String()) + return TagDelta{}, fmt.Errorf("%s and %s are not compatible with each other", curTag.String(), newTag.String()) } - diff := curTag - curMajor, err := strconv.Atoi(curTag.Major) - if err != nil { - return Tag{}, err + diff := TagDelta{ + Major: 0, + Minor: 0, + Patch: 0, } - newMajor, err := strconv.Atoi(newTag.Major) - if err != nil { - return Tag{}, err - } - diff.Major = strconv.Itoa(newMajor - curMajor) + // assuming tags are correctly formatted + curMajor, _ := strconv.Atoi(curTag.Major) + newMajor, _ := strconv.Atoi(newTag.Major) + diff.Major = newMajor - curMajor if !curTag.MissingMinor { - curMinor, err := strconv.Atoi(curTag.Minor) - if err != nil { - return Tag{}, err - } - newMinor, err := strconv.Atoi(newTag.Minor) - if err != nil { - return Tag{}, err - } - diff.Minor = strconv.Itoa(newMinor - curMinor) + curMinor, _ := strconv.Atoi(curTag.Minor) + newMinor, _ := strconv.Atoi(newTag.Minor) + diff.Minor = newMinor - curMinor } if !curTag.MissingPatch { - curPatch, err := strconv.Atoi(curTag.Patch) - if err != nil { - return Tag{}, err - } - newPatch, err := strconv.Atoi(newTag.Patch) - if err != nil { - return Tag{}, err - } - diff.Patch = strconv.Itoa(newPatch - curPatch) + curPatch, _ := strconv.Atoi(curTag.Patch) + newPatch, _ := strconv.Atoi(newTag.Patch) + diff.Patch = newPatch - curPatch } return diff, nil @@ -219,35 +218,23 @@ func (curTag Tag) UpgradeElement(newTag Tag) (Tag, error) { // UpgradeType takes exit from UpgradeElemene and returns a numeric representation of upgrade or downgrade // 1/-1: patch 2/-2: minor 4/-4: major 0: no change -func UpgradeType(t Tag) int { - var major, minor, patch int - major, _ = strconv.Atoi(t.Major) - if t.MissingMinor { - minor = 0 - } else { - minor, _ = strconv.Atoi(t.Minor) - } - if t.MissingPatch { - patch = 0 - } else { - patch, _ = strconv.Atoi(t.Patch) - } - if major > 0 { +func (d TagDelta) UpgradeType() int { + if d.Major > 0 { return 4 } - if major < 0 { + if d.Major < 0 { return -4 } - if minor > 0 { + if d.Minor > 0 { return 2 } - if minor < 0 { + if d.Minor < 0 { return -2 } - if patch > 0 { + if d.Patch > 0 { return 1 } - if patch < 0 { + if d.Patch < 0 { return -1 } return 0 @@ -306,6 +293,42 @@ func parseVersionPart(part string) (int, error) { return p, nil } +// ParseDelta converts a tag difference in the format of X, X.Y or X.Y.Z where +// X, Y, Z are positive or negative integers or 0 +func ParseDelta(delta string) (TagDelta, error) { + tagDelta := TagDelta{ + Major: 0, + Minor: 0, + Patch: 0, + } + + splits := strings.Split(delta, ".") + if len(splits) > 3 { + return TagDelta{}, fmt.Errorf("'%s' has too much dots", delta) + } + major, err := strconv.Atoi(splits[0]) + if err != nil { + return TagDelta{}, fmt.Errorf("Major part of '%s' is not an integer", delta) + } + tagDelta.Major = major + + if len(splits) > 1 { + minor, err := strconv.Atoi(splits[1]) + if err != nil { + return TagDelta{}, fmt.Errorf("Minor part of '%s' is not an integer", delta) + } + tagDelta.Minor = minor + } + if len(splits) > 2 { + patch, err := strconv.Atoi(splits[2]) + if err != nil { + return TagDelta{}, fmt.Errorf("Minor part of '%s' is not an integer", delta) + } + tagDelta.Patch = patch + } + return tagDelta, nil +} + // Parse converts an image tag into a structured data format. It aims to to // support the general case of tags which are "semver-like" and/or stable and // parseable by heuristics. Image tags follow no formal specification and