Skip to content

Commit a9ab1b3

Browse files
authored
add: Support multiple version numbers pattern #11 (#12)
add: Support multiple version numbers pattern #11
1 parent af1e4b6 commit a9ab1b3

File tree

5 files changed

+178
-97
lines changed

5 files changed

+178
-97
lines changed
Lines changed: 0 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,10 @@
11
package docker
22

33
import (
4-
"fmt"
5-
"os"
64
"strings"
75
"testing"
8-
9-
"github.com/google/go-containerregistry/pkg/authn"
10-
"github.com/joho/godotenv"
116
)
127

13-
type testenv struct {
14-
host string
15-
image string
16-
tag string
17-
auth string
18-
username string
19-
password string
20-
}
21-
22-
var privateenv = testenv{}
23-
var ecrenv = testenv{}
24-
25-
func init() {
26-
if err := godotenv.Load("../../.env"); err != nil {
27-
fmt.Printf("error loading .env file - %s", err)
28-
}
29-
30-
privateenv.host = os.Getenv("TEST_DOCKER_PRIVATE_HOST")
31-
privateenv.image = os.Getenv("TEST_DOCKER_PRIVATE_IMAGE")
32-
privateenv.tag = os.Getenv("TEST_DOCKER_PRIVATE_TAG")
33-
privateenv.auth = os.Getenv("TEST_DOCKER_PRIVATE_AUTH")
34-
privateenv.username = os.Getenv("TEST_DOCKER_PRIVATE_USERNAME")
35-
privateenv.password = os.Getenv("TEST_DOCKER_PRIVATE_PASSWORD")
36-
37-
ecrenv.host = os.Getenv("TEST_DOCKER_ECR_HOST")
38-
ecrenv.image = os.Getenv("TEST_DOCKER_ECR_IMAGE")
39-
ecrenv.tag = os.Getenv("TEST_DOCKER_ECR_TAG")
40-
}
41-
428
func TestGetImageStringAsterisk(t *testing.T) {
439
r := NewRemoteRegistry()
4410

@@ -50,50 +16,3 @@ func TestGetImageStringAsterisk(t *testing.T) {
5016
t.Logf("success: %s", s)
5117
}
5218
}
53-
54-
func TestGetImageFromPrivateRegistry(t *testing.T) {
55-
if os.Getenv("TEST_DOCKER_PRIVATE_SKIP") != "" {
56-
t.Log("skipping test")
57-
return
58-
}
59-
60-
r := NewRemoteRegistry()
61-
62-
if privateenv.auth != "" {
63-
r.WithImageAuthMap(map[string]authn.Authenticator{
64-
privateenv.host: NewPrivateAuthenticatorWithAuth(privateenv.host, privateenv.auth),
65-
})
66-
} else if privateenv.username != "" && privateenv.password != "" {
67-
r.WithImageAuthMap(map[string]authn.Authenticator{
68-
privateenv.host: NewPrivateAuthenticator(privateenv.host, privateenv.username, privateenv.password),
69-
})
70-
} else {
71-
t.Fatalf("env not set")
72-
}
73-
74-
if s, err := r.GetImageString(privateenv.host+"/"+privateenv.image, privateenv.tag, "linux/amd64"); err != nil {
75-
t.Fatalf("err: %v", err)
76-
} else {
77-
t.Logf("success: %s", s)
78-
}
79-
}
80-
81-
func TestGetImageFromECR(t *testing.T) {
82-
83-
if os.Getenv("TEST_DOCKER_ECR_SKIP") != "" {
84-
t.Log("skipping test")
85-
return
86-
}
87-
88-
r := NewRemoteRegistry()
89-
90-
if ecrenv.host == "" || ecrenv.image == "" || ecrenv.tag == "" {
91-
t.Fatalf("env not set")
92-
}
93-
94-
if s, err := r.GetImageString(ecrenv.host+"/"+ecrenv.image, ecrenv.tag, "linux/amd64"); err != nil {
95-
t.Fatalf("err: %v, %+v", err, ecrenv)
96-
} else {
97-
t.Logf("success: %s", s)
98-
}
99-
}

remoteRegistry/docker/ecr_test.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package docker
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"testing"
7+
8+
"github.com/joho/godotenv"
9+
)
10+
11+
type testEcrEnv struct {
12+
host string
13+
image string
14+
tag string
15+
}
16+
17+
var ecrenv = testEcrEnv{}
18+
19+
func init() {
20+
if err := godotenv.Load("../../.env"); err != nil {
21+
fmt.Printf("error loading .env file - %s", err)
22+
}
23+
24+
ecrenv.host = os.Getenv("TEST_DOCKER_ECR_HOST")
25+
ecrenv.image = os.Getenv("TEST_DOCKER_ECR_IMAGE")
26+
ecrenv.tag = os.Getenv("TEST_DOCKER_ECR_TAG")
27+
}
28+
29+
func TestGetImageFromECR(t *testing.T) {
30+
31+
if os.Getenv("TEST_DOCKER_ECR_SKIP") != "" {
32+
t.Log("skipping test")
33+
return
34+
}
35+
36+
r := NewRemoteRegistry()
37+
38+
if ecrenv.host == "" || ecrenv.image == "" || ecrenv.tag == "" {
39+
t.Fatalf("env not set")
40+
}
41+
42+
if s, err := r.GetImageString(ecrenv.host+"/"+ecrenv.image, ecrenv.tag, "linux/amd64"); err != nil {
43+
t.Fatalf("err: %v, %+v", err, ecrenv)
44+
} else {
45+
t.Logf("success: %s", s)
46+
}
47+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package docker
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"testing"
7+
8+
"github.com/google/go-containerregistry/pkg/authn"
9+
"github.com/joho/godotenv"
10+
)
11+
12+
type testPrivateEnv struct {
13+
host string
14+
image string
15+
tag string
16+
auth string
17+
username string
18+
password string
19+
}
20+
21+
var privateenv = testPrivateEnv{}
22+
23+
func init() {
24+
if err := godotenv.Load("../../.env"); err != nil {
25+
fmt.Printf("error loading .env file - %s", err)
26+
}
27+
28+
privateenv.host = os.Getenv("TEST_DOCKER_PRIVATE_HOST")
29+
privateenv.image = os.Getenv("TEST_DOCKER_PRIVATE_IMAGE")
30+
privateenv.tag = os.Getenv("TEST_DOCKER_PRIVATE_TAG")
31+
privateenv.auth = os.Getenv("TEST_DOCKER_PRIVATE_AUTH")
32+
privateenv.username = os.Getenv("TEST_DOCKER_PRIVATE_USERNAME")
33+
privateenv.password = os.Getenv("TEST_DOCKER_PRIVATE_PASSWORD")
34+
}
35+
36+
func TestGetImageFromPrivateRegistry(t *testing.T) {
37+
if os.Getenv("TEST_DOCKER_PRIVATE_SKIP") != "" {
38+
t.Log("skipping test")
39+
return
40+
}
41+
42+
r := NewRemoteRegistry()
43+
44+
if privateenv.auth != "" {
45+
r.WithImageAuthMap(map[string]authn.Authenticator{
46+
privateenv.host: NewPrivateAuthenticatorWithAuth(privateenv.host, privateenv.auth),
47+
})
48+
} else if privateenv.username != "" && privateenv.password != "" {
49+
r.WithImageAuthMap(map[string]authn.Authenticator{
50+
privateenv.host: NewPrivateAuthenticator(privateenv.host, privateenv.username, privateenv.password),
51+
})
52+
} else {
53+
t.Fatalf("env not set")
54+
}
55+
56+
if s, err := r.GetImageString(privateenv.host+"/"+privateenv.image, privateenv.tag, "linux/amd64"); err != nil {
57+
t.Fatalf("err: %v", err)
58+
} else {
59+
t.Logf("success: %s", s)
60+
}
61+
}

util/version.go

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,38 +10,53 @@ import (
1010

1111
var ErrNotFound = errors.New("not found")
1212

13+
// GetHighestVersionWithFilter versions는 version 목록이다.
14+
// filter는 *(asterisk)를 숫자(\d+)로 대입하는 regexp로 변환된다.
15+
// 예를 들어, filter가 "1.2.*"이면, 1.2.3이나 1.2.4라는 버전을 찾는다.
16+
// 그리고 그 중 *의 위치에 해당하는 숫자가 가장 큰 버전을 반환한다.
17+
// *은 여럿일 수 있으며 왼쪽에서 오른쪽으로 동일 위치에서 더 큰 버전을 찾는다.
18+
// 예를 들어, filter가 "1.*.*"이면, 1.1.5와 1.2.0 중 1.2.0을 반환한다.
1319
func GetHighestVersionWithFilter(versions []string, filter string) (string, error) {
14-
targetTag := ""
15-
targetVer := int64(0)
20+
highestTag := ""
21+
highestNumbers := []int64{}
22+
regexString := fmt.Sprintf("^%s$", strings.Replace(regexp.QuoteMeta(filter), `\*`, `(\d+)`, -1))
23+
patt, err := regexp.Compile(regexString)
1624

17-
patt, err := regexp.Compile(fmt.Sprintf("^%s$", strings.Replace(regexp.QuoteMeta(filter), "\\*", "(\\d+)", 1)))
1825
if nil != err {
1926
return "", err
2027
}
2128

22-
for _, v := range versions {
23-
// fmt.Println(v)
24-
matches := patt.FindStringSubmatch(v)
29+
for _, tag := range versions {
30+
matches := patt.FindStringSubmatch(tag)
2531

26-
if len(matches) == 0 {
32+
if tag == "" || len(matches) < 2 {
2733
continue
2834
}
2935

30-
ver, err := strconv.ParseInt(matches[1], 10, 64)
31-
if nil != err {
32-
continue
36+
numbers := []int64{}
37+
38+
for idx, match := range matches {
39+
if idx == 0 { // 첫번째 매치는 무시한다.
40+
continue
41+
}
42+
if number, err := strconv.ParseInt(match, 10, 64); err != nil {
43+
return "", err
44+
} else {
45+
numbers = append(numbers, number)
46+
}
3347
}
3448

35-
if targetVer > ver {
36-
continue
49+
for idx, number := range numbers { // 각 자릿수를 비교해 더 큰 값이 발견되면 교체
50+
if idx >= len(highestNumbers) || highestNumbers[idx] <= number {
51+
highestTag, highestNumbers = tag, numbers
52+
break
53+
}
3754
}
38-
39-
targetTag, targetVer = v, ver
4055
}
4156

42-
if targetTag == "" {
57+
if highestTag == "" {
4358
return "", ErrNotFound
4459
}
4560

46-
return targetTag, nil
61+
return highestTag, nil
4762
}

util/version_test.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package util
2+
3+
import (
4+
"testing"
5+
)
6+
7+
var versions []string = []string{"v1.0.0", "v1.0.1", "v1.0.2", "v1.0.9", "v1.0.10", "v1.0.11", "v2.0.99", "v2.0.9", "v3.1.999", "v3.1.998", "v4.0.999", "v4.1.0", "v5.0.0", "v6.0.0", "v6.0.1.0"}
8+
9+
func TestGetHighestVersionWithFilter(t *testing.T) {
10+
if highestVersion, _ := GetHighestVersionWithFilter(versions, "v1.0.*"); highestVersion != "v1.0.11" {
11+
t.Errorf("Expected: v1.0.11, Got: %s", highestVersion)
12+
}
13+
14+
if highestVersion, _ := GetHighestVersionWithFilter(versions, "v2.0.*"); highestVersion != "v2.0.99" {
15+
t.Errorf("Expected: v2.0.99, Got: %s", highestVersion)
16+
}
17+
18+
if highestVersion, _ := GetHighestVersionWithFilter(versions, "v3.1.*"); highestVersion != "v3.1.999" {
19+
t.Errorf("Expected: v3.1.999, Got: %s", highestVersion)
20+
}
21+
}
22+
23+
func TestGetHighestVersionWithFilterSingleVersion(t *testing.T) {
24+
if highestVersion, _ := GetHighestVersionWithFilter(versions, "v5.*.*"); highestVersion != "v5.0.0" {
25+
t.Errorf("Expected: v5.0.0, Got: %s", highestVersion)
26+
}
27+
}
28+
29+
func TestGetHighestVersionWithFilterMultipleAsterisk(t *testing.T) {
30+
if highestVersion, _ := GetHighestVersionWithFilter(versions, "v4.*.*"); highestVersion != "v4.1.0" {
31+
t.Errorf("Expected: v4.1.0, Got: %s", highestVersion)
32+
}
33+
}
34+
35+
func TestGetHighestVersionWithFilterAsteriskNotMatch(t *testing.T) {
36+
if highestVersion, _ := GetHighestVersionWithFilter(versions, "v6.*.*"); highestVersion != "v6.0.0" {
37+
t.Errorf("Expected: v6.0.0, Got: %s", highestVersion)
38+
}
39+
}

0 commit comments

Comments
 (0)