Skip to content

Commit

Permalink
fix!: prereleases should not match constraints for previous versions.
Browse files Browse the repository at this point in the history
Signed-off-by: i4k <[email protected]>
  • Loading branch information
i4ki committed May 20, 2024
1 parent 7867235 commit 36eba48
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 6 deletions.
5 changes: 2 additions & 3 deletions stdlib/funcs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -266,12 +266,11 @@ func TestStdlibTmVersionMatch(t *testing.T) {
},
{
expr: `tm_version_match("2.0.0-dev", "~> 1", {allow_prereleases = true})`,
want: true,
want: false,
},
{
expr: `tm_version_match("2.0.0-dev", "~> 1.0", {allow_prereleases = true})`,
// 2.0.0-dev < 2.0.0
want: true,
want: false,
},
{
expr: `tm_version_match("2.0.0-dev", "~> 1.0", {allow_prereleases = false})`,
Expand Down
31 changes: 29 additions & 2 deletions versions/versions.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,35 @@ func Match(version, constraint string, allowPrereleases bool) (bool, error) {
return false, errors.E(ErrCheck, "invalid constraint", err)
}

allowed := versions.MeetingConstraintsExact(spec)
return allowed.Has(semver), nil
// Prereleases for an upcoming breaking change MUST NOT match the previous release.
// In other words, Semantic Version defines the order below:
// 0.9.9 < 1.0.0-alpha < 1.0.0 < 1.0.1
//
// But we want the behavior below:
//
// The constraint `~> 0.5.0` must not match `0.6.0-rc1` release.
// The reasoning is that v0.6.0-rc1 could already introduce some (or all) of
// the v0.6.0 release and then the loose `~> 0.5.0` could put users at risk.

var plainConstraints, rcConstraints constraints.IntersectionSpec
for _, sel := range spec {
if sel.Boundary.Prerelease != "" {
rcConstraints = append(rcConstraints, sel)
} else {
plainConstraints = append(plainConstraints, sel)
}
}

plainAllowed := versions.MeetingConstraintsExact(plainConstraints)
copied := semver
copied.Prerelease = ""
has := plainAllowed.Has(copied)
if !has {
return false, nil
}

rcAllowed := versions.MeetingConstraintsExact(rcConstraints)
return rcAllowed.Has(semver), nil
}

spec, err := hclversion.NewConstraint(constraint)
Expand Down
63 changes: 62 additions & 1 deletion versions/versions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,18 @@ func TestTerramateVersionConstraints(t *testing.T) {
constraint: "> 1.2.2, < 1.2.3",
want: errors.E(versions.ErrCheck),
},
{
version: "1.2.3-alpha",
constraint: "> 1.2.2, < 1.2.3",
prereleases: true,
want: errors.E(versions.ErrCheck),
},
{
version: "1.2.3-alpha",
constraint: "~> 1.2.2",
prereleases: true,
//want: errors.E(versions.ErrCheck),
},
{
version: "1.2.3-dev",
constraint: ">= 1.2.3",
Expand All @@ -201,12 +213,12 @@ func TestTerramateVersionConstraints(t *testing.T) {
version: "1.2.3-dev",
constraint: ">= 1.2.3",
prereleases: true,
want: errors.E(versions.ErrCheck),
},
{
version: "1.2.3-dev",
constraint: "< 1.2.3",
prereleases: true,
want: errors.E(versions.ErrCheck),
},
{
version: "1.2.3-dev",
Expand Down Expand Up @@ -308,6 +320,55 @@ func TestTerramateVersionConstraints(t *testing.T) {
constraint: "< 1.2.3-dev2",
prereleases: true,
},
{
version: "0.6.0-rc1",
constraint: "~> 0.5.0",
want: errors.E(versions.ErrCheck),
},
{
version: "0.6.0-rc1",
constraint: "~> 0.5.0",
prereleases: true,
want: errors.E(versions.ErrCheck),
},
{
version: "0.6.0-rc1",
constraint: "~> 0.6.0-rc1",
},
{
version: "0.6.0-rc1",
constraint: "~> 0.6.0-rc1",
prereleases: true,
},
{
version: "0.6.0-rc1",
constraint: "~> 0.5.0",
want: errors.E(versions.ErrCheck),
},
{
version: "2.0.0-alpha",
constraint: "~> 1",
prereleases: true,
want: errors.E(versions.ErrCheck),
},
{
version: "1.0.0-alpha",
constraint: "< 2",
prereleases: true,
},
{
version: "0.6.0-rc1",
constraint: "> 0.5, ~> 0.5.0",
want: errors.E(versions.ErrCheck),
},
// TODO(i4k): review this with Marius.
// looks broken.
{
version: "1.0.0-alpha",
constraint: "< 1.0.0",
prereleases: true,
want: errors.E(versions.ErrCheck),
},
} {
tc := tc
name := fmt.Sprintf("CheckVersionFor(%q,%q, %t)", tc.version, tc.constraint, tc.prereleases)
Expand Down

0 comments on commit 36eba48

Please sign in to comment.