Ensure matching modules with metadata when requested (#21640)
When a constraint is defined including build metadata, go-version ignores this, and if a user explicitly requests a build version, this will now return that version. Also covers cases when a user adds build metadata to a non-equality constraint, or in a constraint with multiple conditions (ex. >0.8.0+abc, <1.0.0), and gives and error when this occurs.
This commit is contained in:
parent
f4e27ca480
commit
f1541adfad
|
@ -3,7 +3,9 @@ package module
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
version "github.com/hashicorp/go-version"
|
||||
"github.com/hashicorp/terraform/registry/response"
|
||||
|
@ -11,6 +13,8 @@ import (
|
|||
|
||||
const anyVersion = ">=0.0.0"
|
||||
|
||||
var explicitEqualityConstraint = regexp.MustCompile("^=[0-9]")
|
||||
|
||||
// return the newest version that satisfies the provided constraint
|
||||
func newest(versions []string, constraint string) (string, error) {
|
||||
if constraint == "" {
|
||||
|
@ -21,6 +25,30 @@ func newest(versions []string, constraint string) (string, error) {
|
|||
return "", err
|
||||
}
|
||||
|
||||
// Find any build metadata in the constraints, and
|
||||
// store whether the constraint is an explicit equality that
|
||||
// contains a build metadata requirement, so we can return a specific,
|
||||
// if requested, build metadata version
|
||||
var constraintMetas []string
|
||||
var equalsConstraint bool
|
||||
for i := range cs {
|
||||
constraintMeta := strings.SplitAfterN(cs[i].String(), "+", 2)
|
||||
if len(constraintMeta) > 1 {
|
||||
constraintMetas = append(constraintMetas, constraintMeta[1])
|
||||
}
|
||||
}
|
||||
|
||||
if len(cs) == 1 {
|
||||
equalsConstraint = explicitEqualityConstraint.MatchString(cs.String())
|
||||
}
|
||||
|
||||
// If the version string includes metadata, this is valid in go-version,
|
||||
// However, it's confusing as to what expected behavior should be,
|
||||
// so give an error so the user can do something more logical
|
||||
if (len(cs) > 1 || !equalsConstraint) && len(constraintMetas) > 0 {
|
||||
return "", fmt.Errorf("Constraints including build metadata must have explicit equality, or are otherwise too ambiguous: %s", cs.String())
|
||||
}
|
||||
|
||||
switch len(versions) {
|
||||
case 0:
|
||||
return "", errors.New("no versions found")
|
||||
|
@ -58,6 +86,12 @@ func newest(versions []string, constraint string) (string, error) {
|
|||
continue
|
||||
}
|
||||
if cs.Check(v) {
|
||||
// Constraint has metadata and is explicit equality
|
||||
if equalsConstraint && len(constraintMetas) > 0 {
|
||||
if constraintMetas[0] != v.Metadata() {
|
||||
continue
|
||||
}
|
||||
}
|
||||
return versions[i], nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,3 +58,33 @@ func TestNewestInvalidModuleVersion(t *testing.T) {
|
|||
t.Fatalf("expected version %q, got %q", expected, m.Version)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewestModulesWithMetadata(t *testing.T) {
|
||||
mpv := &response.ModuleProviderVersions{
|
||||
Source: "registry/test/module",
|
||||
Versions: []*response.ModuleVersion{
|
||||
{Version: "0.9.0"},
|
||||
{Version: "0.9.0+def"},
|
||||
{Version: "0.9.0+abc"},
|
||||
{Version: "0.9.0+xyz"},
|
||||
},
|
||||
}
|
||||
|
||||
// with metadata and explicit version request
|
||||
expected := "0.9.0+def"
|
||||
m, _ := newestVersion(mpv.Versions, "=0.9.0+def")
|
||||
if m.Version != expected {
|
||||
t.Fatalf("expected version %q, got %q", expected, m.Version)
|
||||
}
|
||||
|
||||
// respect explicit equality, but >/</~, or metadata in multiple constraints, will give an error
|
||||
_, err := newestVersion(mpv.Versions, "~>0.9.0+abc")
|
||||
if err == nil {
|
||||
t.Fatalf("expected an error, but did not get one")
|
||||
}
|
||||
|
||||
_, err = newestVersion(mpv.Versions, ">0.8.0+abc, <1.0.0")
|
||||
if err == nil {
|
||||
t.Fatalf("expected an error, but did not get one")
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue