Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support arbitrary prerelease strings #342

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,15 @@ differences:
on digest).
</td>
</tr>
<tr>
<td><code>tag_regex</code> <em>(Optional)</em></td>
<td>
Monitor semver tags that match the provided regular expression.
Results are sorted in semver order.
<br>
Takes precedence over <code>pre_releases</code>
</td>
</tr>
<tr>
<td><code>variant</code> <em>(Optional)</em></td>
<td>
Expand Down Expand Up @@ -111,8 +120,14 @@ differences:
Note however that variants and pre-releases both use the same syntax:
`1.2.3-alpine` is technically also valid syntax for a Semver prerelease. For
this reason, the resource will only consider prerelease data starting with
`alpha`, `beta`, or `rc` as a proper prerelease, treating anything else as
a variant.
`alpha`, `beta`, or `rc` as a proper prerelease, or values provided by
`pre_release_prefixes`, treating anything else as a variant.
</td>
</tr>
<tr>
<td><code>pre_release_prefixes</code> <em>(Optional)</em></td>
<td>
Opt in to additional pre-release prefixes (e.g. `build.3`)
</td>
</tr>
<tr>
Expand Down
119 changes: 115 additions & 4 deletions check_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -854,6 +854,30 @@ var _ = DescribeTable("tracking semver tags",
},
},
),
Entry("prerelease prefixes opted in",
SemverTagCheckExample{
Tags: map[string]string{
"1.0.0-alpha.1": "random-0",
"1.0.0": "random-1",
"1.2.1-beta.1": "random-2",
"1.2.1": "random-3",
"2.0.0-rc.1": "random-4",
"2.0.0": "random-5",
"2.0.0-build.1": "random-6",
},
PreReleases: true,
PreReleasePrefixes: []string{"build"},
Versions: []string{
"1.0.0-alpha.1",
"1.0.0",
"1.2.1-beta.1",
"1.2.1",
"2.0.0-build.1",
"2.0.0-rc.1",
"2.0.0",
},
},
),
Entry("prereleases do not include 'variants'",
SemverTagCheckExample{
Tags: map[string]string{
Expand Down Expand Up @@ -1032,6 +1056,34 @@ var _ = DescribeTable("tracking semver tags",
},
},
),
Entry("opting in to prereleases allows additional '-' suffixes before variant",
SemverTagCheckExample{
Tags: map[string]string{
"1.0.0-build-foo": "random-1",
"1.0.0-rc.1-foo": "random-2",
"1.0.0-alpha.1-foo": "random-3",
"1.0.0-beta.1-foo": "random-4",
"1.0.0-bar-foo": "random-5",
"1.0.0-rc.1-bar-foo": "random-6",
"1.0.0-alpha.1-bar-foo": "random-7",
"1.0.0-beta.1-bar-foo": "random-8",
},

Variant: "foo",
PreReleases: true,
PreReleasePrefixes: []string{"build"},

Versions: []string{
"1.0.0-alpha.1-foo",
"1.0.0-alpha.1-bar-foo",
"1.0.0-beta.1-foo",
"1.0.0-beta.1-bar-foo",
"1.0.0-build-foo",
"1.0.0-rc.1-foo",
"1.0.0-rc.1-bar-foo",
},
},
),
Entry("tries mirror and falls back on original repository",
SemverTagCheckExample{
Tags: map[string]string{
Expand Down Expand Up @@ -1059,16 +1111,73 @@ var _ = DescribeTable("tracking semver tags",
Versions: []string{"1.0.0", "1.2.1", "2.0.0"},
},
),
Entry("tag regex for final versions",
SemverTagCheckExample{
Tags: map[string]string{
"1.0.0": "random-1",
"1.0.0-alpha.1": "random-2",
"1.2.1": "random-3",
"2.0.0": "random-5",
},

TagRegex: "^[0-9].[0-9].[0-9]$",

Versions: []string{
"1.0.0",
"1.2.1",
"2.0.0",
},
},
),
Entry("tag regex for arbitrary prerelease",
SemverTagCheckExample{
Tags: map[string]string{
"1.0.0": "random-1",
"1.0.0-alpha.1": "random-2",
"1.2.0-dev.1-built.123": "random-3",
"1.2.1": "random-4",
"2.0.0": "random-5",
},

TagRegex: "^[0-9]\\.[0-9]\\.[0-9]-dev\\.[0-9]+.built\\.[0-9]+$",

Versions: []string{
"1.2.0-dev.1-built.123",
},
},
),
Entry("combine tag regex, semver constraint, and variant",
SemverTagCheckExample{
Tags: map[string]string{
"1.1.0-dev.1-built.123-foo": "random-1",
"1.2.0-dev.1-built.123-foo": "random-2",
"1.3.0-dev.1-built.123-foo": "random-3",
"1.3.0-dev.1-built.123-bar": "random-4",
},

TagRegex: "^[0-9]\\.[0-9]\\.[0-9]-dev\\.[0-9]+.built\\.[0-9]+.*$",
Variant: "foo",
SemverConstraint: ">= 1.2.0-0",

Versions: []string{
"1.2.0-dev.1-built.123-foo",
"1.3.0-dev.1-built.123-foo",
},
},
),
)

type SemverTagCheckExample struct {
Tags map[string]string

PreReleases bool
PreReleasePrefixes []string
Variant string

SemverConstraint string

TagRegex string

Repository string
RegistryMirror string
WorkingMirror bool
Expand Down Expand Up @@ -1101,10 +1210,12 @@ func (example SemverTagCheckExample) Run() {

req := resource.CheckRequest{
Source: resource.Source{
Repository: repo.Name(),
PreReleases: example.PreReleases,
Variant: example.Variant,
SemverConstraint: example.SemverConstraint,
Repository: repo.Name(),
PreReleases: example.PreReleases,
PreReleasePrefixes: example.PreReleasePrefixes,
Variant: example.Variant,
SemverConstraint: example.SemverConstraint,
TagRegex: example.TagRegex,
},
}

Expand Down
54 changes: 39 additions & 15 deletions commands/check.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"net/http"
"sort"
"strings"
"regexp"

"github.com/Masterminds/semver/v3"
resource "github.com/concourse/registry-image-resource"
Expand Down Expand Up @@ -137,6 +138,14 @@ func checkRepository(repo name.Repository, source resource.Source, from *resourc
}
}

var regex *regexp.Regexp
if source.TagRegex != "" {
regex, err = regexp.Compile(source.TagRegex)
if err != nil {
return resource.CheckResponse{}, fmt.Errorf("parse tag regex: %w", err)
}
}

for _, identifier := range tags {
var ver *semver.Version
if identifier == bareTag {
Expand All @@ -162,23 +171,38 @@ func checkRepository(repo name.Repository, source resource.Source, from *resourc
continue
}

pre := ver.Prerelease()
if pre != "" {
// pre-releases not enabled; skip
if !source.PreReleases {
if regex != nil {
if ! regex.MatchString(identifier) {
continue
}

// contains additional variant
if strings.Contains(pre, "-") {
continue
}

if !strings.HasPrefix(pre, "alpha") &&
!strings.HasPrefix(pre, "beta") &&
!strings.HasPrefix(pre, "rc") {
// additional variant, not a prerelease segment
continue
} else {
pre := ver.Prerelease()
if pre != "" {
// pre-releases not enabled; skip
if !source.PreReleases {
continue
}

preReleasePrefixes := []string{"alpha", "beta", "rc"}
if source.PreReleasePrefixes != nil && len(source.PreReleasePrefixes) > 0 {
preReleasePrefixes = append(preReleasePrefixes, source.PreReleasePrefixes...)
} else {
if strings.Contains(pre, "-") {
// contains additional variant
continue
}
}

match := false
for _, prefix := range preReleasePrefixes {
if strings.HasPrefix(pre, prefix) {
match = true
}
}
if ! match {
// additional variant, not a prerelease segment
continue
}
}
}

Expand Down
6 changes: 4 additions & 2 deletions types.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,14 @@ type Source struct {

Insecure bool `json:"insecure"`

PreReleases bool `json:"pre_releases,omitempty"`
Variant string `json:"variant,omitempty"`
PreReleases bool `json:"pre_releases,omitempty"`
PreReleasePrefixes []string `json:"pre_release_prefixes,omitempty"`
Variant string `json:"variant,omitempty"`

SemverConstraint string `json:"semver_constraint,omitempty"`

Tag Tag `json:"tag,omitempty"`
TagRegex string `json:"tag_regex,omitempty"`

BasicCredentials
AwsCredentials
Expand Down