From 856e53427fc7158a8a71e5cb90111f16a49574be Mon Sep 17 00:00:00 2001 From: Jason Murray Date: Sun, 22 Nov 2020 12:59:53 -0800 Subject: [PATCH] Fix Issue #1217: Use semver constraints --- server/events/project_command_builder.go | 62 ++++++++++++++++++------ 1 file changed, 48 insertions(+), 14 deletions(-) diff --git a/server/events/project_command_builder.go b/server/events/project_command_builder.go index 9341ce8acc..3850a0d7fe 100644 --- a/server/events/project_command_builder.go +++ b/server/events/project_command_builder.go @@ -4,9 +4,10 @@ import ( "fmt" "os" "path/filepath" - "regexp" + "sort" "strings" + semver "github.com/hashicorp/go-version" "github.com/runatlantis/atlantis/server/events/yaml/valid" "github.com/hashicorp/go-version" @@ -15,6 +16,7 @@ import ( "github.com/runatlantis/atlantis/server/events/models" "github.com/runatlantis/atlantis/server/events/vcs" "github.com/runatlantis/atlantis/server/events/yaml" + lib "github.com/warrensbox/terraform-switcher/lib" ) const ( @@ -32,6 +34,10 @@ const ( DefaultParallelPlanEnabled = false ) +const ( + tfReleasesURL = "https://releases.hashicorp.com/terraform/" +) + //go:generate pegomock generate -m --use-experimental-model-gen --package mocks -o mocks/mock_project_command_builder.go ProjectCommandBuilder // ProjectCommandBuilder builds commands that run on individual projects. @@ -471,6 +477,8 @@ func (p *DefaultProjectCommandBuilder) escapeArgs(args []string) []string { return escaped } +// TODO: [chaosaffe]Get correct version of TF + // Extracts required_version from Terraform configuration. // Returns nil if unable to determine version from configuration. func (p *DefaultProjectCommandBuilder) getTfVersion(ctx *CommandContext, absProjDir string) *version.Version { @@ -483,26 +491,52 @@ func (p *DefaultProjectCommandBuilder) getTfVersion(ctx *CommandContext, absProj return nil } - if len(module.RequiredCore) != 1 { - ctx.Log.Info("cannot determine which version to use from terraform configuration, detected %d possibilities.", len(module.RequiredCore)) + if len(module.RequiredCore) == 0 { + ctx.Log.Debug("no version constraints detected from terrafrom configuration.") return nil } - requiredVersionSetting := module.RequiredCore[0] - // We allow `= x.y.z`, `=x.y.z` or `x.y.z` where `x`, `y` and `z` are integers. - re := regexp.MustCompile(`^=?\s*([^\s]+)\s*$`) - matched := re.FindStringSubmatch(requiredVersionSetting) - if len(matched) == 0 { - ctx.Log.Debug("did not specify exact version in terraform configuration, found %q", requiredVersionSetting) + // build constraints + constraintStrings := strings.Join(module.RequiredCore, ",") + + constraints, err := semver.NewConstraint(constraintStrings) + if err != nil { + ctx.Log.Err("trying to build constraints: %s", err) return nil } - ctx.Log.Debug("found required_version setting of %q", requiredVersionSetting) - version, err := version.NewVersion(matched[1]) + + // build versions + includePrerelease := true + + versionStrings, err := lib.GetTFList(tfReleasesURL, includePrerelease) if err != nil { - ctx.Log.Debug(err.Error()) + ctx.Log.Err("trying to get list of terraform versions from %s", tfReleasesURL) return nil } - ctx.Log.Info("detected module requires version: %q", version.String()) - return version + versions := make([]*semver.Version, len(versionStrings)) + for i, versionString := range versionStrings { + version, err := semver.NewVersion(versionString) + if err != nil { + ctx.Log.Err("trying to build version list: %s", err) + return nil + } + + versions[i] = version + } + + // sortVersions + sort.Sort(sort.Reverse(semver.Collection(versions))) + + for _, version := range versions { + if constraints.Check(version) { + ctx.Log.Info("detected module requires version: %q", version) + return version + } + + } + + ctx.Log.Info("no versions matched constraint: %s", constraints) + return nil + }