forked from coop-cloud/tagcmp
Compare commits
2 Commits
0fed62dc8e
...
3cac15cba2
Author | SHA1 | Date |
---|---|---|
decentral1se | 3cac15cba2 | |
knoflook | 4f27c74467 |
56
godoc.md
56
godoc.md
|
@ -12,7 +12,6 @@ Package tagcmp provides image tag comparison operations\.
|
||||||
|
|
||||||
- [Variables](<#variables>)
|
- [Variables](<#variables>)
|
||||||
- [func IsParsable(tag string) bool](<#func-isparsable>)
|
- [func IsParsable(tag string) bool](<#func-isparsable>)
|
||||||
- [func UpgradeType(t Tag) int](<#func-upgradetype>)
|
|
||||||
- [type ByTagAsc](<#type-bytagasc>)
|
- [type ByTagAsc](<#type-bytagasc>)
|
||||||
- [func (t ByTagAsc) Len() int](<#func-bytagasc-len>)
|
- [func (t ByTagAsc) Len() int](<#func-bytagasc-len>)
|
||||||
- [func (t ByTagAsc) Less(i, j int) bool](<#func-bytagasc-less>)
|
- [func (t ByTagAsc) Less(i, j int) bool](<#func-bytagasc-less>)
|
||||||
|
@ -28,7 +27,11 @@ Package tagcmp provides image tag comparison operations\.
|
||||||
- [func (t Tag) IsGreaterThan(tag Tag) bool](<#func-tag-isgreaterthan>)
|
- [func (t Tag) IsGreaterThan(tag Tag) bool](<#func-tag-isgreaterthan>)
|
||||||
- [func (t Tag) IsLessThan(tag Tag) bool](<#func-tag-islessthan>)
|
- [func (t Tag) IsLessThan(tag Tag) bool](<#func-tag-islessthan>)
|
||||||
- [func (t Tag) String() string](<#func-tag-string>)
|
- [func (t Tag) String() string](<#func-tag-string>)
|
||||||
- [func (curTag Tag) UpgradeElement(newTag Tag) (Tag, error)](<#func-tag-upgradeelement>)
|
- [func (curTag Tag) UpgradeDelta(newTag Tag) (TagDelta, error)](<#func-tag-upgradedelta>)
|
||||||
|
- [type TagDelta](<#type-tagdelta>)
|
||||||
|
- [func ParseDelta(delta string) (TagDelta, error)](<#func-parsedelta>)
|
||||||
|
- [func (t TagDelta) String() string](<#func-tagdelta-string>)
|
||||||
|
- [func (d TagDelta) UpgradeType() int](<#func-tagdelta-upgradetype>)
|
||||||
|
|
||||||
|
|
||||||
## Variables
|
## Variables
|
||||||
|
@ -71,14 +74,6 @@ func IsParsable(tag string) bool
|
||||||
|
|
||||||
IsParsable determines if a tag is supported by this library
|
IsParsable determines if a tag is supported by this library
|
||||||
|
|
||||||
## func UpgradeType
|
|
||||||
|
|
||||||
```go
|
|
||||||
func UpgradeType(t Tag) int
|
|
||||||
```
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
## type ByTagAsc
|
## type ByTagAsc
|
||||||
|
|
||||||
ByTagAsc sorts tags in ascending order where the last element is the latest tag\.
|
ByTagAsc sorts tags in ascending order where the last element is the latest tag\.
|
||||||
|
@ -140,8 +135,9 @@ type Tag struct {
|
||||||
MissingMinor bool // whether or not the minor semver part was left out
|
MissingMinor bool // whether or not the minor semver part was left out
|
||||||
Patch string `json:",omitempty"` // patch semver part
|
Patch string `json:",omitempty"` // patch semver part
|
||||||
MissingPatch bool // whether or not he patch semver part was left out
|
MissingPatch bool // whether or not he patch semver part was left out
|
||||||
Suffix string // tag suffix (e.g. "-alpine")
|
Suffix string // tag suffix (e.g. "-alpine") [would be release candidate in semver]
|
||||||
UsesV bool // whether or not the tag uses the "v" prefix
|
UsesV bool // whether or not the tag uses the "v" prefix
|
||||||
|
Metadata string // metadata: what's after + and after the first "-"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -193,13 +189,45 @@ func (t Tag) String() string
|
||||||
|
|
||||||
String formats a Tag correctly in string representation
|
String formats a Tag correctly in string representation
|
||||||
|
|
||||||
### func \(Tag\) UpgradeElement
|
### func \(Tag\) UpgradeDelta
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func (curTag Tag) UpgradeElement(newTag Tag) (Tag, error)
|
func (curTag Tag) UpgradeDelta(newTag Tag) (TagDelta, error)
|
||||||
```
|
```
|
||||||
|
|
||||||
UpgradeElement returns a Tag object which is the difference between an old and new tag It can contain negative numbers if comparing with an older 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\.
|
||||||
|
|
||||||
|
## type TagDelta
|
||||||
|
|
||||||
|
```go
|
||||||
|
type TagDelta struct {
|
||||||
|
Major int // major semver difference
|
||||||
|
Minor int // minor semver difference
|
||||||
|
Patch int // patch semver difference
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### func ParseDelta
|
||||||
|
|
||||||
|
```go
|
||||||
|
func ParseDelta(delta string) (TagDelta, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
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 \(TagDelta\) String
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (t TagDelta) String() string
|
||||||
|
```
|
||||||
|
|
||||||
|
### func \(TagDelta\) UpgradeType
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (d TagDelta) UpgradeType() int
|
||||||
|
```
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
182
tagcmp_test.go
182
tagcmp_test.go
|
@ -345,15 +345,38 @@ var supported = []string{
|
||||||
"v6.2.1-alpine",
|
"v6.2.1-alpine",
|
||||||
"v6.2.1-alpine",
|
"v6.2.1-alpine",
|
||||||
|
|
||||||
|
// semver with '+'
|
||||||
|
"5+SDFJ_-2l4x.",
|
||||||
|
"2.6+SDFJ_-2l4x.",
|
||||||
|
"4.3.5+SDFJ_-2l4x.",
|
||||||
|
|
||||||
|
// semver with '+' and 'v'
|
||||||
|
"v5+SDFJ_-2l4x.",
|
||||||
|
"v2.6+SDFJ_-2l4x.",
|
||||||
|
"v4.3.5+SDFJ_-2l4x.",
|
||||||
|
|
||||||
|
// semver with '+' and suffix
|
||||||
|
"5-alpine+SDFJ_-2l4x.",
|
||||||
|
"2.6-alpine+SDFJ_-2l4x.",
|
||||||
|
"4.3.5-alpine+SDFJ_-2l4x.",
|
||||||
|
|
||||||
|
// semver with 'v', '+' and suffix
|
||||||
|
"v5-alpine+SDFJ_-2l4x.",
|
||||||
|
"v2.6-alpine+SDFJ_-2l4x.",
|
||||||
|
"v4.3.5-alpine+SDFJ_-2l4x.",
|
||||||
|
|
||||||
// semver with multiple suffix values
|
// semver with multiple suffix values
|
||||||
"v6.2.1-alpine-foo",
|
"v6.2.1-alpine-foo",
|
||||||
|
|
||||||
|
// semver with multiple suffix values and '+'
|
||||||
|
"v6.2.1-alpine-foo+68BC1E",
|
||||||
}
|
}
|
||||||
|
|
||||||
var unsupported = []string{
|
var unsupported = []string{
|
||||||
// empty
|
// empty
|
||||||
"",
|
"",
|
||||||
|
|
||||||
// patametrized
|
// parametrized
|
||||||
"${MAILU_VERSION:-master}",
|
"${MAILU_VERSION:-master}",
|
||||||
"${PHP_VERSION}-fpm-alpine3.13",
|
"${PHP_VERSION}-fpm-alpine3.13",
|
||||||
|
|
||||||
|
@ -369,6 +392,9 @@ var unsupported = []string{
|
||||||
"r1295",
|
"r1295",
|
||||||
"version-r1070",
|
"version-r1070",
|
||||||
|
|
||||||
|
// too much dots
|
||||||
|
"1.0.0.0.0",
|
||||||
|
|
||||||
// prerelease
|
// prerelease
|
||||||
"3.7.0b1",
|
"3.7.0b1",
|
||||||
"3.8.0b1-alpine",
|
"3.8.0b1-alpine",
|
||||||
|
@ -389,6 +415,12 @@ var unsupported = []string{
|
||||||
// multiple - delimters
|
// multiple - delimters
|
||||||
"apache-debian-1.8-prod",
|
"apache-debian-1.8-prod",
|
||||||
"version-znc-1.8.2",
|
"version-znc-1.8.2",
|
||||||
|
|
||||||
|
// unparsable major/minor/patch parts:
|
||||||
|
"a.0.0",
|
||||||
|
"1.a",
|
||||||
|
"1.a.0",
|
||||||
|
"1.0.a",
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParseUnsupported(t *testing.T) {
|
func TestParseUnsupported(t *testing.T) {
|
||||||
|
@ -498,6 +530,22 @@ func TestPatchPart(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIsParsableSupported(t *testing.T) {
|
||||||
|
for _, tag := range supported {
|
||||||
|
if !tagcmp.IsParsable(tag) {
|
||||||
|
t.Errorf("'%s' should be parsable but IsParsable returned false", tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsParsableUnsupported(t *testing.T) {
|
||||||
|
for _, tag := range unsupported {
|
||||||
|
if tagcmp.IsParsable(tag) {
|
||||||
|
t.Errorf("'%s' should not be parsable but IsParsable returned true", tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestIsGreaterThan(t *testing.T) {
|
func TestIsGreaterThan(t *testing.T) {
|
||||||
pairs := []struct {
|
pairs := []struct {
|
||||||
t1 string
|
t1 string
|
||||||
|
@ -505,6 +553,7 @@ func TestIsGreaterThan(t *testing.T) {
|
||||||
expected bool
|
expected bool
|
||||||
}{
|
}{
|
||||||
{"1.2.3", "1.2", false},
|
{"1.2.3", "1.2", false},
|
||||||
|
{"1.2.3", "1.2.4", false},
|
||||||
{"18.04", "18.1", true},
|
{"18.04", "18.1", true},
|
||||||
{"10.1", "10.1.2", true},
|
{"10.1", "10.1.2", true},
|
||||||
{"3", "2", true},
|
{"3", "2", true},
|
||||||
|
@ -564,10 +613,15 @@ func TestEquals(t *testing.T) {
|
||||||
expected bool
|
expected bool
|
||||||
}{
|
}{
|
||||||
{"1.2.3", "1.2.3", true},
|
{"1.2.3", "1.2.3", true},
|
||||||
|
{"1.2.3", "1.2", false},
|
||||||
|
{"1.2.3", "1", false},
|
||||||
{"18.04", "18.4", true},
|
{"18.04", "18.4", true},
|
||||||
{"10.0", "10.0.4", false},
|
{"10.0", "10.0.4", false},
|
||||||
{"3", "4.0", false},
|
{"3", "4.0", false},
|
||||||
{"1.2", "1.2.3", false},
|
{"1.2", "1.2.3", false},
|
||||||
|
{"3", "4", false},
|
||||||
|
{"1.3", "1.4", false},
|
||||||
|
{"3+FF812B", "3", false},
|
||||||
}
|
}
|
||||||
for _, p := range pairs {
|
for _, p := range pairs {
|
||||||
p1, err := tagcmp.Parse(p.t1)
|
p1, err := tagcmp.Parse(p.t1)
|
||||||
|
@ -730,7 +784,7 @@ func TestSortDesc(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestString(t *testing.T) {
|
func TestTagString(t *testing.T) {
|
||||||
for _, tag := range supported {
|
for _, tag := range supported {
|
||||||
p, err := tagcmp.Parse(tag)
|
p, err := tagcmp.Parse(tag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -775,3 +829,127 @@ func TestGiteaFilterCompatible(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDeltaParse(t *testing.T) {
|
||||||
|
supportedDeltas := []string{
|
||||||
|
"1",
|
||||||
|
"1.0",
|
||||||
|
"1.0.0",
|
||||||
|
"-1",
|
||||||
|
"-1.0",
|
||||||
|
"-1.0.0",
|
||||||
|
"-1.0.5",
|
||||||
|
"-1.2.5",
|
||||||
|
"1.-2",
|
||||||
|
}
|
||||||
|
unsupportedDeltas := []string{
|
||||||
|
"AAAAAAAAAAAAAAAA",
|
||||||
|
"1.2.3.4",
|
||||||
|
"1.ab.2",
|
||||||
|
"1.2.a",
|
||||||
|
}
|
||||||
|
for _, delta := range supportedDeltas {
|
||||||
|
if _, err := tagcmp.ParseDelta(delta); err != nil {
|
||||||
|
t.Errorf("'%s' wasn't parsed but it is supported: %s", delta, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, delta := range unsupportedDeltas {
|
||||||
|
if _, err := tagcmp.ParseDelta(delta); err == nil {
|
||||||
|
t.Errorf("'%s' was parsed but it is not supported", delta)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeltaString(t *testing.T) {
|
||||||
|
supportedDeltas := []struct {
|
||||||
|
in string
|
||||||
|
out string
|
||||||
|
}{
|
||||||
|
{"1", "1.0.0"},
|
||||||
|
{"1.0", "1.0.0"},
|
||||||
|
{"1.0.0", "1.0.0"},
|
||||||
|
{"-1", "-1.0.0"},
|
||||||
|
{"-1.0", "-1.0.0"},
|
||||||
|
{"-1.0.0", "-1.0.0"},
|
||||||
|
{"-1.0.5", "-1.0.5"},
|
||||||
|
{"-1.2.5", "-1.2.5"},
|
||||||
|
{"1.-2", "1.-2.0"},
|
||||||
|
}
|
||||||
|
for _, test := range supportedDeltas {
|
||||||
|
parsedDelta, err := tagcmp.ParseDelta(test.in)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("'%s' was not parsed but it is supported", test.in)
|
||||||
|
}
|
||||||
|
if parsedDelta.String() != test.out {
|
||||||
|
t.Errorf("String() of '%s' didn't render properly: %s", test.in, parsedDelta.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpgradeDelta(t *testing.T) {
|
||||||
|
pairs := []struct {
|
||||||
|
t1 string
|
||||||
|
t2 string
|
||||||
|
expected string
|
||||||
|
throwsErr bool
|
||||||
|
}{
|
||||||
|
{"v1.0.0", "1.0.0", "", true},
|
||||||
|
{"1", "2", "1.0.0", false},
|
||||||
|
{"1.0", "1.1", "0.1.0", false},
|
||||||
|
{"1.1.0", "1.1.1", "0.0.1", false},
|
||||||
|
{"2", "1", "-1.0.0", false},
|
||||||
|
{"1.1", "1.0", "0.-1.0", false},
|
||||||
|
{"1.1.1", "1.1.0", "0.0.-1", false},
|
||||||
|
}
|
||||||
|
for _, p := range pairs {
|
||||||
|
p1, err := tagcmp.Parse(p.t1)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("'%s' should have parsed", p.t1)
|
||||||
|
}
|
||||||
|
p2, err := tagcmp.Parse(p.t2)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("'%s' should have parsed", p.t2)
|
||||||
|
}
|
||||||
|
pexpected, _ := tagcmp.ParseDelta(p.expected)
|
||||||
|
res, err := p1.UpgradeDelta(p2)
|
||||||
|
if p.throwsErr && (err == nil) {
|
||||||
|
t.Errorf("(%s).UpgradeDelta(%s) didn't throw an error but should have", p.t1, p.t2)
|
||||||
|
} else if !p.throwsErr && (err != nil) {
|
||||||
|
t.Errorf("(%s).UpgradeDelta(%s) threw an error but shouldn't have", p.t1, p.t2)
|
||||||
|
}
|
||||||
|
if res != pexpected {
|
||||||
|
t.Errorf("(%s).UpgradeDelta(%s) gave %s but expected %s", p.t1, p.t2, res.String(), p.expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpgradeType(t *testing.T) {
|
||||||
|
testSet := []struct {
|
||||||
|
in string
|
||||||
|
out int
|
||||||
|
}{
|
||||||
|
{"1.0.0", 4},
|
||||||
|
{"-1.0.0", -4},
|
||||||
|
{"1.2.0", 4},
|
||||||
|
{"-1.2.0", -4},
|
||||||
|
{"0.1.0", 2},
|
||||||
|
{"0.-1.0", -2},
|
||||||
|
{"0.1.2", 2},
|
||||||
|
{"0.-1.2", -2},
|
||||||
|
{"0.0.1", 1},
|
||||||
|
{"0.0.-1", -1},
|
||||||
|
{"0.0.0", 0},
|
||||||
|
{"-0.-0.-0", 0},
|
||||||
|
}
|
||||||
|
for _, test := range testSet {
|
||||||
|
tagDelta, err := tagcmp.ParseDelta(test.in)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("tagcmp.ParseDelta couldn't parse '%s': '%s'", test.in, err)
|
||||||
|
}
|
||||||
|
upType := tagDelta.UpgradeType()
|
||||||
|
if upType != test.out {
|
||||||
|
t.Errorf("(%s).UpgradeType() returned '%d', expected '%d'", test.in, upType, test.out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue