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: add version command #1691

Merged
merged 1 commit into from
Jul 12, 2021
Merged
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
9 changes: 9 additions & 0 deletions server/controllers/events/events_controller_e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -858,11 +858,20 @@ func setupE2E(t *testing.T, repoDir string) (events_controllers.VCSEventsControl
silenceNoProjects,
)

versionCommandRunner := events.NewVersionCommandRunner(
pullUpdater,
projectCommandBuilder,
projectCommandRunner,
parallelPoolSize,
silenceNoProjects,
)

commentCommandRunnerByCmd := map[models.CommandName]events.CommentCommandRunner{
models.PlanCommand: planCommandRunner,
models.ApplyCommand: applyCommandRunner,
models.ApprovePoliciesCommand: approvePoliciesCommandRunner,
models.UnlockCommand: unlockCommandRunner,
models.VersionCommand: versionCommandRunner,
}

commandRunner := &events.DefaultCommandRunner{
Expand Down
25 changes: 25 additions & 0 deletions server/core/runtime/version_step_runner.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package runtime

import (
"path/filepath"

"github.com/hashicorp/go-version"
"github.com/runatlantis/atlantis/server/events/models"
)

// VersionStepRunner runs a version command given a ctx
type VersionStepRunner struct {
TerraformExecutor TerraformExec
DefaultTFVersion *version.Version
}

// Run ensures a given version for the executable, builds the args from the project context and then runs executable returning the result
func (v *VersionStepRunner) Run(ctx models.ProjectCommandContext, extraArgs []string, path string, envs map[string]string) (string, error) {
tfVersion := v.DefaultTFVersion
if ctx.TerraformVersion != nil {
tfVersion = ctx.TerraformVersion
}

versionCmd := []string{"version"}
return v.TerraformExecutor.RunCommandWithVersion(ctx.Log, filepath.Clean(path), versionCmd, envs, tfVersion, ctx.Workspace)
}
50 changes: 50 additions & 0 deletions server/core/runtime/version_step_runner_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package runtime

import (
"testing"

"github.com/hashicorp/go-version"
. "github.com/petergtz/pegomock"
"github.com/runatlantis/atlantis/server/core/terraform/mocks"
"github.com/runatlantis/atlantis/server/events/models"
"github.com/runatlantis/atlantis/server/logging"
. "github.com/runatlantis/atlantis/testing"
)

func TestRunVersionStep(t *testing.T) {
RegisterMockTestingT(t)
logger := logging.NewNoopLogger(t)
workspace := "default"

context := models.ProjectCommandContext{
Log: logger,
EscapedCommentArgs: []string{"comment", "args"},
Workspace: workspace,
RepoRelDir: ".",
User: models.User{Username: "username"},
Pull: models.PullRequest{
Num: 2,
},
BaseRepo: models.Repo{
FullName: "owner/repo",
Owner: "owner",
Name: "repo",
},
}

terraform := mocks.NewMockClient()
tfVersion, _ := version.NewVersion("0.15.0")
tmpDir, cleanup := TempDir(t)
defer cleanup()

s := &VersionStepRunner{
TerraformExecutor: terraform,
DefaultTFVersion: tfVersion,
}

t.Run("ensure runs", func(t *testing.T) {
_, err := s.Run(context, []string{}, tmpDir, map[string]string(nil))
terraform.VerifyWasCalledOnce().RunCommandWithVersion(logger, tmpDir, []string{"version"}, map[string]string(nil), tfVersion, "default")
Ok(t, err)
})
}
9 changes: 9 additions & 0 deletions server/events/command_runner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,11 +162,20 @@ func setup(t *testing.T) *vcsmocks.MockClient {
SilenceNoProjects,
)

versionCommandRunner := events.NewVersionCommandRunner(
pullUpdater,
projectCommandBuilder,
projectCommandRunner,
parallelPoolSize,
SilenceNoProjects,
)

commentCommandRunnerByCmd := map[models.CommandName]events.CommentCommandRunner{
models.PlanCommand: planCommandRunner,
models.ApplyCommand: applyCommandRunner,
models.ApprovePoliciesCommand: approvePoliciesCommandRunner,
models.UnlockCommand: unlockCommandRunner,
models.VersionCommand: versionCommandRunner,
}

preWorkflowHooksCommandRunner = mocks.NewMockPreWorkflowHooksCommandRunner()
Expand Down
18 changes: 17 additions & 1 deletion server/events/comment_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ type CommentBuilder interface {
BuildPlanComment(repoRelDir string, workspace string, project string, commentArgs []string) string
// BuildApplyComment builds an apply comment for the specified args.
BuildApplyComment(repoRelDir string, workspace string, project string, autoMergeDisabled bool) string
// BuildVersionComment builds a version comment for the specified args.
BuildVersionComment(repoRelDir string, workspace string, project string) string
}

// CommentParser implements CommentParsing
Expand Down Expand Up @@ -165,7 +167,7 @@ func (e *CommentParser) Parse(comment string, vcsHost models.VCSHostType) Commen
}

// Need to have a plan, apply, approve_policy or unlock at this point.
if !e.stringInSlice(command, []string{models.PlanCommand.String(), models.ApplyCommand.String(), models.UnlockCommand.String(), models.ApprovePoliciesCommand.String()}) {
if !e.stringInSlice(command, []string{models.PlanCommand.String(), models.ApplyCommand.String(), models.UnlockCommand.String(), models.ApprovePoliciesCommand.String(), models.VersionCommand.String()}) {
return CommentParseResult{CommentResponse: fmt.Sprintf("```\nError: unknown command %q.\nRun 'atlantis --help' for usage.\n```", command)}
}

Expand Down Expand Up @@ -204,6 +206,13 @@ func (e *CommentParser) Parse(comment string, vcsHost models.VCSHostType) Commen
name = models.UnlockCommand
flagSet = pflag.NewFlagSet(models.UnlockCommand.String(), pflag.ContinueOnError)
flagSet.SetOutput(ioutil.Discard)
case models.VersionCommand.String():
name = models.VersionCommand
flagSet = pflag.NewFlagSet(models.VersionCommand.String(), pflag.ContinueOnError)
flagSet.StringVarP(&workspace, workspaceFlagLong, workspaceFlagShort, "", "Switch to this Terraform workspace before running version.")
flagSet.StringVarP(&dir, dirFlagLong, dirFlagShort, "", "Which directory to run version in relative to root of repo, ex. 'child/dir'.")
flagSet.StringVarP(&project, projectFlagLong, projectFlagShort, "", fmt.Sprintf("Print the version for this project. Refers to the name of the project configured in %s.", yaml.AtlantisYAMLFilename))
flagSet.BoolVarP(&verbose, verboseFlagLong, verboseFlagShort, false, "Append Atlantis log to comment.")
default:
return CommentParseResult{CommentResponse: fmt.Sprintf("Error: unknown command %q – this is a bug", command)}
}
Expand Down Expand Up @@ -285,6 +294,12 @@ func (e *CommentParser) BuildApplyComment(repoRelDir string, workspace string, p
return fmt.Sprintf("%s %s%s", atlantisExecutable, models.ApplyCommand.String(), flags)
}

// BuildVersionComment builds a version comment for the specified args.
func (e *CommentParser) BuildVersionComment(repoRelDir string, workspace string, project string) string {
flags := e.buildFlags(repoRelDir, workspace, project, false)
return fmt.Sprintf("%s %s%s", atlantisExecutable, models.VersionCommand.String(), flags)
}

func (e *CommentParser) buildFlags(repoRelDir string, workspace string, project string, autoMergeDisabled bool) string {
// Add quotes if dir has spaces.
if strings.Contains(repoRelDir, " ") {
Expand Down Expand Up @@ -389,6 +404,7 @@ Commands:
{{- end }}
unlock Removes all atlantis locks and discards all plans for this PR.
To unlock a specific plan you can use the Atlantis UI.
version Print the output of 'terraform version'
help View help.

Flags:
Expand Down
158 changes: 87 additions & 71 deletions server/events/comment_parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -576,7 +576,7 @@ func TestParse_Parsing(t *testing.T) {
}
}

func TestBuildPlanApplyComment(t *testing.T) {
func TestBuildPlanApplyVersionComment(t *testing.T) {
cases := []struct {
repoRelDir string
workspace string
Expand All @@ -585,77 +585,87 @@ func TestBuildPlanApplyComment(t *testing.T) {
commentArgs []string
expPlanFlags string
expApplyFlags string
expVersionFlags string
}{
{
repoRelDir: ".",
workspace: "default",
project: "",
commentArgs: nil,
expPlanFlags: "-d .",
expApplyFlags: "-d .",
},
{
repoRelDir: "dir",
workspace: "default",
project: "",
commentArgs: nil,
expPlanFlags: "-d dir",
expApplyFlags: "-d dir",
},
{
repoRelDir: ".",
workspace: "workspace",
project: "",
commentArgs: nil,
expPlanFlags: "-w workspace",
expApplyFlags: "-w workspace",
},
{
repoRelDir: "dir",
workspace: "workspace",
project: "",
commentArgs: nil,
expPlanFlags: "-d dir -w workspace",
expApplyFlags: "-d dir -w workspace",
},
{
repoRelDir: ".",
workspace: "default",
project: "project",
commentArgs: nil,
expPlanFlags: "-p project",
expApplyFlags: "-p project",
},
{
repoRelDir: "dir",
workspace: "workspace",
project: "project",
commentArgs: nil,
expPlanFlags: "-p project",
expApplyFlags: "-p project",
},
{
repoRelDir: ".",
workspace: "default",
project: "",
commentArgs: []string{`"arg1"`, `"arg2"`},
expPlanFlags: "-d . -- arg1 arg2",
expApplyFlags: "-d .",
},
{
repoRelDir: "dir",
workspace: "workspace",
project: "",
commentArgs: []string{`"arg1"`, `"arg2"`, `arg3`},
expPlanFlags: "-d dir -w workspace -- arg1 arg2 arg3",
expApplyFlags: "-d dir -w workspace",
},
{
repoRelDir: "dir with spaces",
workspace: "default",
project: "",
expPlanFlags: "-d \"dir with spaces\"",
expApplyFlags: "-d \"dir with spaces\"",
repoRelDir: ".",
workspace: "default",
project: "",
commentArgs: nil,
expPlanFlags: "-d .",
expApplyFlags: "-d .",
expVersionFlags: "-d .",
},
{
repoRelDir: "dir",
workspace: "default",
project: "",
commentArgs: nil,
expPlanFlags: "-d dir",
expApplyFlags: "-d dir",
expVersionFlags: "-d dir",
},
{
repoRelDir: ".",
workspace: "workspace",
project: "",
commentArgs: nil,
expPlanFlags: "-w workspace",
expApplyFlags: "-w workspace",
expVersionFlags: "-w workspace",
},
{
repoRelDir: "dir",
workspace: "workspace",
project: "",
commentArgs: nil,
expPlanFlags: "-d dir -w workspace",
expApplyFlags: "-d dir -w workspace",
expVersionFlags: "-d dir -w workspace",
},
{
repoRelDir: ".",
workspace: "default",
project: "project",
commentArgs: nil,
expPlanFlags: "-p project",
expApplyFlags: "-p project",
expVersionFlags: "-p project",
},
{
repoRelDir: "dir",
workspace: "workspace",
project: "project",
commentArgs: nil,
expPlanFlags: "-p project",
expApplyFlags: "-p project",
expVersionFlags: "-p project",
},
{
repoRelDir: ".",
workspace: "default",
project: "",
commentArgs: []string{`"arg1"`, `"arg2"`},
expPlanFlags: "-d . -- arg1 arg2",
expApplyFlags: "-d .",
expVersionFlags: "-d .",
},
{
repoRelDir: "dir",
workspace: "workspace",
project: "",
commentArgs: []string{`"arg1"`, `"arg2"`, `arg3`},
expPlanFlags: "-d dir -w workspace -- arg1 arg2 arg3",
expApplyFlags: "-d dir -w workspace",
expVersionFlags: "-d dir -w workspace",
},
{
repoRelDir: "dir with spaces",
workspace: "default",
project: "",
expPlanFlags: "-d \"dir with spaces\"",
expApplyFlags: "-d \"dir with spaces\"",
expVersionFlags: "-d \"dir with spaces\"",
},
{
repoRelDir: "dir",
Expand All @@ -665,19 +675,23 @@ func TestBuildPlanApplyComment(t *testing.T) {
commentArgs: []string{`"arg1"`, `"arg2"`, `arg3`},
expPlanFlags: "-d dir -w workspace -- arg1 arg2 arg3",
expApplyFlags: "-d dir -w workspace --auto-merge-disabled",
expVersionFlags: "-d dir -w workspace",
},
}

for _, c := range cases {
t.Run(c.expPlanFlags, func(t *testing.T) {
for _, cmd := range []models.CommandName{models.PlanCommand, models.ApplyCommand} {
for _, cmd := range []models.CommandName{models.PlanCommand, models.ApplyCommand, models.VersionCommand} {
switch cmd {
case models.PlanCommand:
actComment := commentParser.BuildPlanComment(c.repoRelDir, c.workspace, c.project, c.commentArgs)
Equals(t, fmt.Sprintf("atlantis plan %s", c.expPlanFlags), actComment)
case models.ApplyCommand:
actComment := commentParser.BuildApplyComment(c.repoRelDir, c.workspace, c.project, c.autoMergeDisabled)
Equals(t, fmt.Sprintf("atlantis apply %s", c.expApplyFlags), actComment)
case models.VersionCommand:
actComment := commentParser.BuildVersionComment(c.repoRelDir, c.workspace, c.project)
Equals(t, fmt.Sprintf("atlantis version %s", c.expVersionFlags), actComment)
}
}
})
Expand Down Expand Up @@ -715,6 +729,7 @@ Commands:
To only apply a specific plan, use the -d, -w and -p flags.
unlock Removes all atlantis locks and discards all plans for this PR.
To unlock a specific plan you can use the Atlantis UI.
version Print the output of 'terraform version'
help View help.

Flags:
Expand All @@ -741,6 +756,7 @@ Commands:
To plan a specific project, use the -d, -w and -p flags.
unlock Removes all atlantis locks and discards all plans for this PR.
To unlock a specific plan you can use the Atlantis UI.
version Print the output of 'terraform version'
help View help.

Flags:
Expand Down
Loading