Skip to content

Commit 7a66347

Browse files
committed
feat: add "exclude-versions" flag and do small code refactor
1 parent 13fd1f1 commit 7a66347

File tree

14 files changed

+495
-271
lines changed

14 files changed

+495
-271
lines changed

README.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@ Checks Docker hub for Docker images tag update. It compares the given Helm chart
55
## Usage
66

77
```text
8-
hcuc <flags>
8+
Usage of hcuc:
99
10-
Flags:
1110
--debug
1211
Enable debug outputs
1312
--docker-hub-repo string
1413
DockHub repo to check tag versions
14+
--exclude-versions string
15+
Versions to exclude from check
1516
--fail-on-update
1617
Return exit code 1, if update is available
1718
--helm-chart-path string
@@ -22,3 +23,5 @@ Flags `--docker-hub-repo string` and `--helm-chart-path` are required.
2223

2324
Per default, it shows a small table with the current version and all available versions.
2425
When `--fail-on-update` is set, the app is exiting with code 1.
26+
27+
`--exclude-versions` can be set, to ignore / exclude version on DockerHub from the check.

go.mod

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ module github.com/pmoscode/helm-chart-update-check
22

33
go 1.22.3 // Update GH Action aswell
44

5-
require github.com/Masterminds/semver/v3 v3.3.0
6-
7-
require gopkg.in/yaml.v3 v3.0.1
5+
require (
6+
github.com/Masterminds/semver/v3 v3.3.0
7+
gopkg.in/yaml.v3 v3.0.1
8+
github.com/pmoscode/go-common v0.10.0
9+
)

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0
22
github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
33
github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0=
44
github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
5+
github.com/pmoscode/go-common v0.10.0 h1:yrllglzwdbozsB2NB7DNTKqrulaLkig9t50+/yZYOf4=
6+
github.com/pmoscode/go-common v0.10.0/go.mod h1:Me/Dh7F7F1fnUeBpmAK0qlZJ4LkVgFMOvznn7g8zcbY=
57
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
68
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
79
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

main.go

Lines changed: 39 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,110 +1,74 @@
11
package main
22

33
import (
4-
"errors"
5-
"flag"
64
"fmt"
75
"github.com/Masterminds/semver/v3"
6+
"github.com/pmoscode/go-common/shutdown"
87
chart2 "github.com/pmoscode/helm-chart-update-check/pkg/chart"
8+
"github.com/pmoscode/helm-chart-update-check/pkg/cli"
99
"github.com/pmoscode/helm-chart-update-check/pkg/dockerhub"
10+
"github.com/pmoscode/helm-chart-update-check/pkg/utils"
1011
"log"
11-
"strings"
1212
)
1313

14-
type CliOptions struct {
15-
dockerHubRepository *string
16-
helmChartPath *string
17-
failOnExistingUpdate *bool
18-
debug *bool
19-
}
20-
21-
func getCliOptionsParameters() *CliOptions {
22-
dockerHubRepository := flag.String("docker-hub-repo", "", "DockHub repo to check tag versions")
23-
helmChartPath := flag.String("helm-chart-path", ".", "Helm chart to check for updates")
24-
failOnExistingUpdate := flag.Bool("fail-on-update", false, "Return exit code 1, if update is available")
25-
debug := flag.Bool("debug", false, "Enable debug outputs")
26-
27-
flag.Parse()
28-
29-
return &CliOptions{
30-
dockerHubRepository: dockerHubRepository,
31-
helmChartPath: helmChartPath,
32-
failOnExistingUpdate: failOnExistingUpdate,
33-
debug: debug,
34-
}
35-
}
36-
3714
func main() {
38-
cliOptions := getCliOptions()
15+
defer shutdown.ExitOnPanic()
3916

40-
dockerVersions := getDockerVersions(cliOptions)
17+
cliOptions := cli.GetCliOptions()
4118

42-
chartVersion := getChartVersion(cliOptions)
19+
dockerVersions := dockerhub.FetchDockerVersions(cliOptions)
20+
chartVersion := chart2.FetchChartVersion(cliOptions)
4321

4422
_, err := checkVersion(chartVersion, dockerVersions, cliOptions)
4523
if err != nil {
4624
log.Fatalln(err)
4725
}
4826
}
4927

50-
func getCliOptions() *CliOptions {
51-
cliOptions := getCliOptionsParameters()
52-
53-
if *cliOptions.dockerHubRepository == "" {
54-
log.Fatal(errors.New("parameter 'docker-hub-repo' is required"))
55-
}
56-
if *cliOptions.helmChartPath == "" {
57-
log.Fatal(errors.New("parameter 'helm-chart-path' is required"))
58-
}
59-
60-
return cliOptions
61-
}
62-
63-
func getDockerVersions(cliOptions *CliOptions) []*semver.Version {
64-
dockerHub := dockerhub.CreateDockerHub(*cliOptions.dockerHubRepository, *cliOptions.debug)
65-
versions := dockerHub.GetVersions()
66-
67-
return versions
68-
}
69-
70-
func getChartVersion(cliOptions *CliOptions) *semver.Version {
71-
chart := chart2.NewChart(*cliOptions.helmChartPath)
72-
73-
appVersion := strings.Trim(chart.AppVersion(), "\"")
74-
fmt.Println("Helm chart AppVersion:")
75-
fmt.Println(appVersion)
76-
77-
v, err := semver.NewVersion(appVersion)
78-
if err != nil {
79-
log.Fatal("Problem creating semver: ", err)
80-
}
81-
return v
82-
}
83-
84-
func checkVersion(chartVersion *semver.Version, dockerVersions []*semver.Version, cliOptions *CliOptions) (int, error) {
85-
constraintStr := fmt.Sprintf("<= %s-0", chartVersion.IncPatch().String())
28+
func checkVersion(chartVersion *semver.Version, dockerVersions []*semver.Version, cliOptions *cli.Options) (int, error) {
8629
// See: https://github.com/Masterminds/semver?tab=readme-ov-file#working-with-prerelease-versions
87-
constraint, err := semver.NewConstraint(constraintStr)
30+
constraint, err := semver.NewConstraint(fmt.Sprintf("<= %s-0", chartVersion.IncPatch().String()))
8831
if err != nil {
8932
log.Fatalln(err)
9033
}
9134

9235
newerVersions := make([]*semver.Version, 0)
36+
excludeVersions := utils.GetExcludedVersionsSimple(*cliOptions.ExcludeVersions)
9337

9438
fmt.Printf("Checking, if some version is > %s\n", chartVersion.String())
9539
for _, item := range dockerVersions {
96-
if *cliOptions.debug {
40+
if *cliOptions.Debug {
9741
fmt.Printf("Checking if Helm chart version %v is >= DockerHub version %v: ", chartVersion.Original(), item.Original())
9842
}
99-
if !constraint.Check(item) {
100-
newerVersions = append(newerVersions, item)
101-
if *cliOptions.debug {
102-
fmt.Println(false)
43+
44+
skipVersion := false
45+
if excludeVersions != nil {
46+
for _, version := range excludeVersions {
47+
constraintExclude, err := semver.NewConstraint(fmt.Sprintf("%s", version))
48+
if err != nil {
49+
log.Fatalln(err)
50+
}
51+
52+
if constraintExclude.Check(item) {
53+
skipVersion = true
54+
break
55+
}
10356
}
104-
} else {
105-
if *cliOptions.debug {
106-
fmt.Println(true)
57+
}
58+
59+
if !skipVersion {
60+
if !constraint.Check(item) {
61+
newerVersions = append(newerVersions, item)
62+
if *cliOptions.Debug {
63+
fmt.Println(false)
64+
}
65+
} else {
66+
if *cliOptions.Debug {
67+
fmt.Println(true)
68+
}
10769
}
70+
} else {
71+
fmt.Println("skipped")
10872
}
10973
}
11074

@@ -116,7 +80,7 @@ func checkVersion(chartVersion *semver.Version, dockerVersions []*semver.Version
11680
fmt.Println(item.Original())
11781
}
11882

119-
if *cliOptions.failOnExistingUpdate {
83+
if *cliOptions.FailOnExistingUpdate {
12084
return newerVersionsCnt, fmt.Errorf("FAIL: Found %d new versions", newerVersionsCnt)
12185
}
12286
} else {

main_test.go

Lines changed: 28 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,10 @@ package main
33
import (
44
"encoding/json"
55
"github.com/Masterminds/semver/v3"
6+
"github.com/pmoscode/helm-chart-update-check/pkg/cli"
67
"github.com/pmoscode/helm-chart-update-check/pkg/dockerhub"
7-
"log"
88
"net/http"
99
"net/http/httptest"
10-
"reflect"
1110
"testing"
1211
)
1312

@@ -17,38 +16,29 @@ type Tests struct {
1716
expectedResult []string
1817
}
1918

20-
func TestGetDockerVersions(t *testing.T) {
21-
tests := []Tests{
22-
{
23-
name: "one",
24-
server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
25-
w.WriteHeader(http.StatusOK)
26-
w.Write(getTestData())
27-
})),
28-
expectedResult: []string{"1.2.3", "1.2.3", "1.2.3-pre.1", "1.2.3-dev", "1.5.0-rc", "1.5.0-rc1", "1.5.0", "1.5.0-nightly.1"},
29-
},
30-
}
19+
func TestCheckVersionNormal(t *testing.T) {
20+
innerTest(t, "")
21+
}
3122

32-
for _, test := range tests {
33-
t.Run(test.name, func(t *testing.T) {
34-
defer test.server.Close()
23+
func TestCheckVersionWithExcludesSimple(t *testing.T) {
24+
innerTest(t, "1.2.3")
25+
}
3526

36-
hub := dockerhub.CreateDockerHubWithUri(test.server.URL, false)
37-
versions := hub.GetVersions()
27+
func TestCheckVersionWithExcludesRangeMajor(t *testing.T) {
28+
innerTest(t, "^1.0.0-0")
29+
}
3830

39-
if !reflect.DeepEqual(convertSemverToStringArray(versions), test.expectedResult) {
40-
t.Errorf("FAILED: expected %v, got %v\n", test.expectedResult, versions)
41-
}
42-
})
43-
}
31+
func TestCheckVersionWithExcludesRangeMinor(t *testing.T) {
32+
innerTest(t, "~3.3.0-0")
4433
}
4534

46-
func TestCheckVersion(t *testing.T) {
35+
func innerTest(t *testing.T, excludeVersions string) {
4736
debug := true
4837
fail := false
49-
cliOptions := &CliOptions{
50-
debug: &debug,
51-
failOnExistingUpdate: &fail,
38+
cliOptions := &cli.Options{
39+
Debug: &debug,
40+
FailOnExistingUpdate: &fail,
41+
ExcludeVersions: &excludeVersions,
5242
}
5343

5444
test := Tests{
@@ -61,27 +51,17 @@ func TestCheckVersion(t *testing.T) {
6151

6252
defer test.server.Close()
6353

64-
hub := dockerhub.CreateDockerHubWithUri(test.server.URL, *cliOptions.debug)
54+
hub := dockerhub.CreateDockerHubWithUri(test.server.URL, *cliOptions.Debug)
6555
dockerVersions := hub.GetVersions()
6656

6757
chartVersion, _ := semver.NewVersion("v1.5.0")
6858

6959
_, err := checkVersion(chartVersion, dockerVersions, cliOptions)
7060
if err != nil {
71-
log.Fatalln(err)
61+
t.Fatalf("Expected no error, got %v", err)
7262
}
7363
}
7464

75-
func convertSemverToStringArray(semverVersions []*semver.Version) []string {
76-
versions := make([]string, len(semverVersions))
77-
78-
for idx, item := range semverVersions {
79-
versions[idx] = item.String()
80-
}
81-
82-
return versions
83-
}
84-
8565
func getTestData() []byte {
8666
var serverResponseBody = &dockerhub.ResponseBody{
8767
Results: []dockerhub.Results{
@@ -109,6 +89,15 @@ func getTestData() []byte {
10989
{
11090
Name: "v1.5.0-nightly.1",
11191
},
92+
{
93+
Name: "v2.2.0",
94+
},
95+
{
96+
Name: "v3.2.1",
97+
},
98+
{
99+
Name: "v3.3.4",
100+
},
112101
},
113102
}
114103

pkg/chart/chart.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package chart
2+
3+
import (
4+
"gopkg.in/yaml.v3"
5+
"strings"
6+
)
7+
8+
type Chart struct {
9+
chartPath string
10+
root *yaml.Node
11+
}
12+
13+
func (c *Chart) Version() string {
14+
return strings.TrimSpace(c.searchNode("version"))
15+
}
16+
17+
func (c *Chart) AppVersion() string {
18+
return strings.TrimSpace(c.searchNode("appVersion"))
19+
}
20+
21+
func (c *Chart) UpdateAppVersion() {
22+
23+
}
24+
25+
func (c *Chart) searchNode(nodeName string) string {
26+
//var keyNode *yaml.Node
27+
var valNode *yaml.Node
28+
29+
for i := 0; i < len(c.root.Content); i += 2 {
30+
node := c.root.Content[i]
31+
if node.Kind == yaml.ScalarNode && node.Value == nodeName {
32+
//keyNode = c.root.Content[i]
33+
valNode = c.root.Content[i+1]
34+
}
35+
}
36+
37+
//locationSectionKey, _ := yaml.Marshal(keyNode)
38+
//fmt.Println(string(locationSectionKey))
39+
locationSectionVal, _ := yaml.Marshal(valNode)
40+
41+
return string(locationSectionVal)
42+
}

0 commit comments

Comments
 (0)