Skip to content

feat: command flag to override parallel pool size #5422

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

Open
wants to merge 4 commits into
base: main
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
6 changes: 5 additions & 1 deletion server/events/apply_command_runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,11 @@ func (a *ApplyCommandRunner) Run(ctx *command.Context, cmd *CommentCommand) {
var result command.Result
if a.isParallelEnabled(projectCmds) {
ctx.Log.Info("Running applies in parallel")
result = runProjectCmdsParallelGroups(ctx, projectCmds, a.prjCmdRunner.Apply, a.parallelPoolSize)
parallelPoolSize := a.parallelPoolSize
if cmd.ParallelPoolSize > 0 {
parallelPoolSize = cmd.ParallelPoolSize
}
result = runProjectCmdsParallelGroups(ctx, projectCmds, a.prjCmdRunner.Apply, parallelPoolSize)
} else {
result = runProjectCmds(projectCmds, a.prjCmdRunner.Apply)
}
Expand Down
12 changes: 11 additions & 1 deletion server/events/comment_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ const (
verboseFlagShort = ""
clearPolicyApprovalFlagLong = "clear-policy-approval"
clearPolicyApprovalFlagShort = ""
ParallelPoolSizeFlagLong = "parallel-pool-size"
ParallelPoolSizeFlagShort = "P"
)

// multiLineRegex is used to ignore multi-line comments since those aren't valid
Expand Down Expand Up @@ -232,6 +234,7 @@ func (e *CommentParser) Parse(rawComment string, vcsHost models.VCSHostType) Com
var verbose bool
var autoMergeDisabled bool
var autoMergeMethod string
var parallelPoolSize int
var flagSet *pflag.FlagSet
var name command.Name

Expand All @@ -245,6 +248,7 @@ func (e *CommentParser) Parse(rawComment string, vcsHost models.VCSHostType) Com
flagSet.StringVarP(&dir, dirFlagLong, dirFlagShort, "", "Which directory to run plan in relative to root of repo, ex. 'child/dir'.")
flagSet.StringVarP(&project, projectFlagLong, projectFlagShort, "", "Which project to run plan for. Refers to the name of the project configured in a repo config file. Cannot be used at same time as workspace or dir flags.")
flagSet.BoolVarP(&verbose, verboseFlagLong, verboseFlagShort, false, "Append Atlantis log to comment.")
flagSet.IntVarP(&parallelPoolSize, ParallelPoolSizeFlagLong, ParallelPoolSizeFlagShort, 0, "Override default parallel pool size for this command")
case command.Apply.String():
name = command.Apply
flagSet = pflag.NewFlagSet(command.Apply.String(), pflag.ContinueOnError)
Expand All @@ -255,6 +259,7 @@ func (e *CommentParser) Parse(rawComment string, vcsHost models.VCSHostType) Com
flagSet.BoolVarP(&autoMergeDisabled, autoMergeDisabledFlagLong, autoMergeDisabledFlagShort, false, "Disable automerge after apply.")
flagSet.StringVarP(&autoMergeMethod, autoMergeMethodFlagLong, autoMergeMethodFlagShort, "", "Specifies the merge method for the VCS if automerge is enabled. (Currently only implemented for GitHub)")
flagSet.BoolVarP(&verbose, verboseFlagLong, verboseFlagShort, false, "Append Atlantis log to comment.")
flagSet.IntVarP(&parallelPoolSize, ParallelPoolSizeFlagLong, ParallelPoolSizeFlagShort, 0, "Override default parallel pool size for this command")
case command.ApprovePolicies.String():
name = command.ApprovePolicies
flagSet = pflag.NewFlagSet(command.ApprovePolicies.String(), pflag.ContinueOnError)
Expand Down Expand Up @@ -335,8 +340,13 @@ func (e *CommentParser) Parse(rawComment string, vcsHost models.VCSHostType) Com
}
}

if parallelPoolSize < 0 {
err := fmt.Sprintf("invalid value for --%s: %d, must be >= 0", ParallelPoolSizeFlagLong, parallelPoolSize)
return CommentParseResult{CommentResponse: e.errMarkdown(err, cmd, flagSet)}
}

return CommentParseResult{
Command: NewCommentCommand(dir, extraArgs, name, subName, verbose, autoMergeDisabled, autoMergeMethod, workspace, project, policySet, clearPolicyApproval),
Command: NewCommentCommand(dir, extraArgs, name, subName, verbose, autoMergeDisabled, autoMergeMethod, workspace, project, parallelPoolSize, policySet, clearPolicyApproval),
}
}

Expand Down
88 changes: 81 additions & 7 deletions server/events/comment_parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -750,6 +750,78 @@ func TestParse_Parsing(t *testing.T) {
}
}

func TestParse_ParallelPoolSize(t *testing.T) {
cases := []struct {
command command.Name
flags string
expParallelSize int
expError string
}{
// Test flag works for plan/apply
{
command: command.Plan,
flags: "-P 5",
expParallelSize: 5,
},
{
command: command.Plan,
flags: "--parallel-pool-size 10",
expParallelSize: 10,
},
{
command: command.Apply,
flags: "-P 3",
expParallelSize: 3,
},
{
command: command.Apply,
flags: "--parallel-pool-size 8",
expParallelSize: 8,
},
// Test flag is ignored for other commands
{
command: command.ApprovePolicies,
flags: "-P 5",
expError: fmt.Sprintf("```\nError: unknown shorthand flag: 'P' in -P.\n%s```", ApprovePolicyUsage),
},
{
command: command.ApprovePolicies,
flags: "-p project --parallel-pool-size 5",
expError: fmt.Sprintf("```\nError: unknown flag: --parallel-pool-size.\n%s```", ApprovePolicyUsage),
},
// // Test invalid values
{
command: command.Plan,
flags: "-P fail",
expError: fmt.Sprintf("```\nError: invalid argument \"fail\" for \"-P, --parallel-pool-size\" flag: strconv.ParseInt: parsing \"fail\": invalid syntax.\n%s```", PlanUsage),
},
{
command: command.Apply,
flags: "--parallel-pool-size -1",
expError: fmt.Sprintf("```\nError: invalid value for --parallel-pool-size: -1, must be >= 0.\n%s```", ApplyUsage),
},
}

for _, test := range cases {
comment := fmt.Sprintf("atlantis %s %s", test.command.String(), test.flags)
t.Run(comment, func(t *testing.T) {
r := commentParser.Parse(comment, models.Github)

if test.expError != "" {
Equals(t, test.expError, r.CommentResponse)
return
}

Assert(t, r.CommentResponse == "",
"expected no error but got %q for comment %q",
r.CommentResponse, comment)
Assert(t, test.expParallelSize == r.Command.ParallelPoolSize,
"exp parallel pool size to equal %v but was %v for comment %q",
test.expParallelSize, r.Command.ParallelPoolSize, comment)
})
}
}

func TestBuildPlanApplyVersionComment(t *testing.T) {
cases := []struct {
repoRelDir string
Expand Down Expand Up @@ -1048,13 +1120,14 @@ func TestParse_VCSUsername(t *testing.T) {
}

var PlanUsage = `Usage of plan:
-d, --dir string Which directory to run plan in relative to root of repo,
ex. 'child/dir'.
-p, --project string Which project to run plan for. Refers to the name of the
project configured in a repo config file. Cannot be used
at same time as workspace or dir flags.
--verbose Append Atlantis log to comment.
-w, --workspace string Switch to this Terraform workspace before planning.
-d, --dir string Which directory to run plan in relative to root of
repo, ex. 'child/dir'.
-P, --parallel-pool-size int Override default parallel pool size for this command
-p, --project string Which project to run plan for. Refers to the name
of the project configured in a repo config file.
Cannot be used at same time as workspace or dir flags.
--verbose Append Atlantis log to comment.
-w, --workspace string Switch to this Terraform workspace before planning.
`

var ApplyUsage = `Usage of apply:
Expand All @@ -1064,6 +1137,7 @@ var ApplyUsage = `Usage of apply:
for GitHub)
-d, --dir string Apply the plan for this directory, relative to
root of repo, ex. 'child/dir'.
-P, --parallel-pool-size int Override default parallel pool size for this command
-p, --project string Apply the plan for this project. Refers to the
name of the project configured in a repo config
file. Cannot be used at same time as workspace or
Expand Down
5 changes: 4 additions & 1 deletion server/events/event_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ type CommentCommand struct {
// project specified in an atlantis.yaml file.
// If empty then the comment specified no project.
ProjectName string
// ParallelPoolSize allows changing parallel pool size for a plan/apply specific command.
ParallelPoolSize int
// PolicySet is the name of a policy set to run an approval on.
PolicySet string
// ClearPolicyApproval is true if approvals should be cleared out for specified policies.
Expand Down Expand Up @@ -184,7 +186,7 @@ func (c CommentCommand) String() string {
}

// NewCommentCommand constructs a CommentCommand, setting all missing fields to defaults.
func NewCommentCommand(repoRelDir string, flags []string, name command.Name, subName string, verbose, autoMergeDisabled bool, autoMergeMethod string, workspace string, project string, policySet string, clearPolicyApproval bool) *CommentCommand {
func NewCommentCommand(repoRelDir string, flags []string, name command.Name, subName string, verbose, autoMergeDisabled bool, autoMergeMethod string, workspace string, project string, parallelPoolSize int, policySet string, clearPolicyApproval bool) *CommentCommand {
// If repoRelDir was empty we want to keep it that way to indicate that it
// wasn't specified in the comment.
if repoRelDir != "" {
Expand All @@ -203,6 +205,7 @@ func NewCommentCommand(repoRelDir string, flags []string, name command.Name, sub
AutoMergeDisabled: autoMergeDisabled,
AutoMergeMethod: autoMergeMethod,
ProjectName: project,
ParallelPoolSize: parallelPoolSize,
PolicySet: policySet,
ClearPolicyApproval: clearPolicyApproval,
}
Expand Down
21 changes: 11 additions & 10 deletions server/events/event_parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -751,14 +751,14 @@ func TestNewCommand_CleansDir(t *testing.T) {

for _, c := range cases {
t.Run(c.RepoRelDir, func(t *testing.T) {
cmd := events.NewCommentCommand(c.RepoRelDir, nil, command.Plan, "", false, false, "", "workspace", "", "", false)
cmd := events.NewCommentCommand(c.RepoRelDir, nil, command.Plan, "", false, false, "", "workspace", "", 0, "", false)
Equals(t, c.ExpDir, cmd.RepoRelDir)
})
}
}

func TestNewCommand_EmptyDirWorkspaceProject(t *testing.T) {
cmd := events.NewCommentCommand("", nil, command.Plan, "", false, false, "", "", "", "", false)
cmd := events.NewCommentCommand("", nil, command.Plan, "", false, false, "", "", "", 0, "", false)
Equals(t, events.CommentCommand{
RepoRelDir: "",
Flags: nil,
Expand All @@ -770,15 +770,16 @@ func TestNewCommand_EmptyDirWorkspaceProject(t *testing.T) {
}

func TestNewCommand_AllFieldsSet(t *testing.T) {
cmd := events.NewCommentCommand("dir", []string{"a", "b"}, command.Plan, "", true, false, "", "workspace", "project", "policyset", false)
cmd := events.NewCommentCommand("dir", []string{"a", "b"}, command.Plan, "", true, false, "", "workspace", "project", 5, "policyset", false)
Equals(t, events.CommentCommand{
Workspace: "workspace",
RepoRelDir: "dir",
Verbose: true,
Flags: []string{"a", "b"},
Name: command.Plan,
ProjectName: "project",
PolicySet: "policyset",
Workspace: "workspace",
RepoRelDir: "dir",
Verbose: true,
Flags: []string{"a", "b"},
Name: command.Plan,
ProjectName: "project",
PolicySet: "policyset",
ParallelPoolSize: 5,
}, *cmd)
}

Expand Down
6 changes: 5 additions & 1 deletion server/events/plan_command_runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,11 @@ func (p *PlanCommandRunner) run(ctx *command.Context, cmd *CommentCommand) {
var result command.Result
if p.isParallelEnabled(projectCmds) {
ctx.Log.Info("Running plans in parallel")
result = runProjectCmdsParallelGroups(ctx, projectCmds, p.prjCmdRunner.Plan, p.parallelPoolSize)
parallelPoolSize := p.parallelPoolSize
if cmd.ParallelPoolSize > 0 {
parallelPoolSize = cmd.ParallelPoolSize
}
result = runProjectCmdsParallelGroups(ctx, projectCmds, p.prjCmdRunner.Plan, parallelPoolSize)
} else {
result = runProjectCmds(projectCmds, p.prjCmdRunner.Plan)
}
Expand Down