From 019f0a0bf5df086d5190817f4cf2f4ddef6740b2 Mon Sep 17 00:00:00 2001 From: Joakim Hulthe Date: Sat, 7 Nov 2020 14:31:50 +0100 Subject: [PATCH] Parse tags as semver --- go.mod | 1 + go.sum | 2 ++ main.go | 52 +++++++++++++++++++++++-------------------- semver.go | 45 +++++++++++++++++++++++++++++++++++++ versioning_mode.go | 55 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 131 insertions(+), 24 deletions(-) create mode 100644 semver.go create mode 100644 versioning_mode.go diff --git a/go.mod b/go.mod index 1330980..37f8179 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.15 require ( github.com/Microsoft/go-winio v0.4.14 // indirect + github.com/coreos/go-semver v0.3.0 github.com/docker/distribution v2.7.1+incompatible // indirect github.com/docker/docker v1.13.1 github.com/docker/go-connections v0.4.0 // indirect diff --git a/go.sum b/go.sum index 8671483..9750841 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,7 @@ github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU= github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug= diff --git a/main.go b/main.go index 3a706b8..a479e71 100644 --- a/main.go +++ b/main.go @@ -11,22 +11,12 @@ import ( "github.com/docker/docker/client" ) -const ( - versioningModeLabel = "lookbuilding.mode" -) - -type VersioningMode string - -const ( - SemVerAny VersioningMode = "SemVerAny" -) - type labeledContainer struct { container types.Container mode VersioningMode } -type tag struct { +type Tag struct { Creator int `json:"creator"` ID int `json:"id"` LastUpdated string `json:"last_updated"` @@ -39,10 +29,10 @@ type tag struct { TagStatus string `json:"tag_status"` TagLastPulled string `json:"tag_last_pulled"` TagLastPushed string `json:"tag_last_pushed"` - Images []image `json:images` + Images []Image `json:images` } -type image struct { +type Image struct { Architecture string `json:architecture` Features string `json:features` Digest string `json:digest` @@ -82,10 +72,10 @@ func getImageParts(name string) (*string, string, *string) { return owner, repository, tag } -func getDockerRepoTags(maybe_owner *string, repository string) []tag { +func getDockerRepoTags(maybe_owner *string, repository string) []Tag { type dockerPollResponse struct { Count int `json:"count"` - Results []tag `json:"results"` + Results []Tag `json:"results"` } owner := "_" @@ -116,19 +106,26 @@ func getLabeledContainers(cli *client.Client) []labeledContainer { panic(err) } + fmt.Println("scanning running container labels") for _, container := range containers { - fmt.Printf("%s %s\n", container.ID[:10], container.Image) + fmt.Printf("- %s %s\n", container.ID[:10], container.Image) for k, v := range container.Labels { + fmt.Printf(" - \"%s\": \"%s\"\n", k, v) if k == versioningModeLabel { + mode := ParseVersioningMode(v) + if mode == nil { + fmt.Printf("Failed to parse '%s' as a versioning mode\n", v) + continue + } + lc := labeledContainer{ container, - SemVerAny, + *mode, } out = append(out, lc) - continue; + continue } - fmt.Printf(" - %s: %s\n", k, v) } } @@ -142,6 +139,8 @@ func main() { } labeledContainers := getLabeledContainers(cli) + fmt.Println() + for _, lc := range labeledContainers { owner, repository, tag := getImageParts(lc.container.Image) @@ -150,21 +149,26 @@ func main() { } else { fmt.Printf("container image: _/%s\n", repository) } + fmt.Printf(" versioning: %+v\n", lc.mode.Label()) fmt.Printf(" id: %s\n", lc.container.ImageID) if tag != nil { - fmt.Printf(" tag: %s\n", *tag) + fmt.Printf(" current tag: %s\n", *tag) } else { - fmt.Printf(" no tag\n") + fmt.Printf(" no current tag, skipping\n") + continue } repoTags := getDockerRepoTags(owner, repository) - fmt.Println("## tags in registry ##") + fmt.Println(" tags in registry:") for _, tag := range repoTags { - fmt.Printf(" tag: %s\n", tag.Name) + fmt.Printf(" - \"%s\"\n", tag.Name) + svt := parseTagAsSemVer(tag.Name) + if svt != nil { + fmt.Printf(" semver: true\n") + } } - fmt.Println("##") } } diff --git a/semver.go b/semver.go new file mode 100644 index 0000000..129b0d7 --- /dev/null +++ b/semver.go @@ -0,0 +1,45 @@ +package main + +import ( + //"fmt" + "regexp" + + "github.com/coreos/go-semver/semver" +) + +var ( + rxSemVerPrefix = regexp.MustCompile(`^[^\d]*`) +) + +type SemVerTag struct { + prefix string + version semver.Version +} + +// Return a +// Returns nil if the tag did not parse as semver +func parseTagAsSemVer(tag string) *SemVerTag { + var prefix string + loc := rxSemVerPrefix.FindStringIndex(tag) + if loc != nil { + prefix = tag[:loc[1]] + tag = tag[loc[1]:] + } + + version, err := semver.NewVersion(tag) + if err != nil { + return nil + } + + svt := SemVerTag { + prefix, + *version, + } + + return &svt +} + +func (SemVerTag) asTag() string { + return "" +} + diff --git a/versioning_mode.go b/versioning_mode.go new file mode 100644 index 0000000..b6a033f --- /dev/null +++ b/versioning_mode.go @@ -0,0 +1,55 @@ +package main + +const ( + versioningModeLabel = "lookbuilding.mode" +) + +type VersioningMode interface { + Label() string + ShouldUpdate(currentTag string, availableTags []Tag) *Tag +} + +type SameTag struct {} +type SemVerMajor struct {} +type SemVerMinor struct {} +type SemVerPatch struct {} + +var ( + AllModes = [...]VersioningMode{ + SameTag{}, + SemVerMajor{}, + SemVerMinor{}, + SemVerPatch{}, + } +) + +func (SameTag) Label() string { return "same_tag" } +func (SameTag) ShouldUpdate(currentTag string, availableTags []Tag) *Tag { + return nil // TODO: implement me +} + +func (SemVerMajor) Label() string { return "semver_major" } +func (SemVerMajor) ShouldUpdate(currentTag string, availableTags []Tag) *Tag { + return nil // TODO: implement me +} + +func (SemVerMinor) Label() string { return "semver_minor" } +func (SemVerMinor) ShouldUpdate(currentTag string, availableTags []Tag) *Tag { + return nil // TODO: implement me +} + +func (SemVerPatch) Label() string { return "semver_patch" } +func (SemVerPatch) ShouldUpdate(currentTag string, availableTags []Tag) *Tag { + return nil // TODO: implement me +} + + +func ParseVersioningMode(input string) *VersioningMode { + for _, mode := range AllModes { + if mode.Label() == input { + return &mode + } + } + return nil +} +