diff --git a/README.md b/README.md index d00c1ea..73661d0 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,10 @@ differences: would be used for tags like `1.2.3-stretch`. This is typically used *without* `tag` - if it is set, this value will only used for pushing, not checking. +* `semver_constraint`: *Optional.* Constrain the returned semver tags according + to a semver constraint, e.g. `"~1.2.x"`, `">= 1.2 < 3.0.0 || >= 4.2.3"`. + Follows the rules outlined in https://github.com/Masterminds/semver#checking-version-constraints. + * `username` and `password`: *Optional.* A username and password to use when authenticating to the registry. Must be specified for private repos or when using `put`. diff --git a/check_test.go b/check_test.go index b13eeca..869d26e 100644 --- a/check_test.go +++ b/check_test.go @@ -862,6 +862,20 @@ var _ = DescribeTable("tracking semver tags", Versions: []string{"1.0.0", "1.2.1", "2.0.0"}, }, ), + Entry("semver constraint", + SemverTagCheckExample{ + Tags: map[string]string{ + "1.0.0": "random-1", + "1.2.1": "random-3", + "1.2.2": "random-4", + "2.0.0": "random-5", + // Does not include bare tag + "latest": "random-6", + }, + SemverConstraint: "1.2.x", + Versions: []string{"1.2.1", "1.2.2"}, + }, + ), Entry("prereleases ignored by default", SemverTagCheckExample{ Tags: map[string]string{ @@ -1109,6 +1123,8 @@ type SemverTagCheckExample struct { PreReleases bool Variant string + SemverConstraint string + Repository string RegistryMirror string WorkingMirror bool @@ -1141,9 +1157,10 @@ func (example SemverTagCheckExample) Run() { req := resource.CheckRequest{ Source: resource.Source{ - Repository: repo.Name(), - PreReleases: example.PreReleases, - Variant: example.Variant, + Repository: repo.Name(), + PreReleases: example.PreReleases, + Variant: example.Variant, + SemverConstraint: example.SemverConstraint, }, } diff --git a/commands/check.go b/commands/check.go index 477fb04..646ffba 100644 --- a/commands/check.go +++ b/commands/check.go @@ -129,6 +129,14 @@ func checkRepository(repo name.Repository, source resource.Source, from *resourc }) } + var constraint *semver.Constraints + if source.SemverConstraint != "" { + constraint, err = semver.NewConstraint(source.SemverConstraint) + if err != nil { + return resource.CheckResponse{}, fmt.Errorf("parse semver constraint: %w", err) + } + } + for _, identifier := range tags { var ver *semver.Version if identifier == bareTag { @@ -149,6 +157,11 @@ func checkRepository(repo name.Repository, source resource.Source, from *resourc continue } + if constraint != nil && !constraint.Check(ver) { + // semver constraint not met + continue + } + pre := ver.Prerelease() if pre != "" { // pre-releases not enabled; skip @@ -246,7 +259,7 @@ func checkRepository(repo name.Repository, source resource.Source, from *resourc digest := tagDigests[latestTag] _, existsAsSemver := digestVersions[digest] - if !existsAsSemver { + if !existsAsSemver && constraint == nil { response = append(response, resource.Version{ Tag: latestTag, Digest: digest, diff --git a/types.go b/types.go index f129697..e9aade4 100644 --- a/types.go +++ b/types.go @@ -80,6 +80,8 @@ type Source struct { PreReleases bool `json:"pre_releases,omitempty"` Variant string `json:"variant,omitempty"` + SemverConstraint string `json:"semver_constraint,omitempty"` + Tag Tag `json:"tag,omitempty"` BasicCredentials