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

Support regexp in command builder on the project name #1419

Merged
merged 4 commits into from
Mar 6, 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
5 changes: 5 additions & 0 deletions cmd/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ const (
DisableMarkdownFoldingFlag = "disable-markdown-folding"
DisableRepoLockingFlag = "disable-repo-locking"
EnablePolicyChecksFlag = "enable-policy-checks"
EnableRegExpCmdFlag = "enable-regexp-cmd"
GHHostnameFlag = "gh-hostname"
GHTokenFlag = "gh-token"
GHUserFlag = "gh-user"
Expand Down Expand Up @@ -300,6 +301,10 @@ var boolFlags = map[string]boolFlag{
description: "Enable atlantis to run user defined policy checks. This is explicitly disabled for TFE/TFC backends since plan files are inaccessible.",
defaultValue: false,
},
EnableRegExpCmdFlag: {
description: "Enable Atlantis to use regular expressions on plan/apply commands when \"-p\" flag is passed with it.",
defaultValue: false,
},
AllowDraftPRs: {
description: "Enable autoplan for Github Draft Pull Requests",
defaultValue: false,
Expand Down
1 change: 1 addition & 0 deletions cmd/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ var testFlags = map[string]interface{}{
WriteGitCredsFlag: true,
DisableAutoplanFlag: true,
EnablePolicyChecksFlag: false,
EnableRegExpCmdFlag: false,
}

func TestExecute_Defaults(t *testing.T) {
Expand Down
11 changes: 11 additions & 0 deletions runatlantis.io/docs/server-configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,17 @@ Values are chosen in this order:
```
Enables atlantis to run server side policies on the result of a terraform plan. Policies are defined in [server side repo config](https://www.runatlantis.io/docs/server-side-repo-config.html#reference).

* ### `--enable-regexp-cmd`
```bash
atlantis server --enable-regexp-cmd
```
Enable Atlantis to use regular expressions on plan/apply commands when \"-p\" flag is passed with it.

::: warning SECURITY WARNING
It's not supposed to be used with `--disable-apply-all`.
The command `atlantis apply -p .*` will bypass the restriction and run apply on every projects
:::

* ### `--gh-hostname`
```bash
atlantis server --gh-hostname="my.github.enterprise.com"
Expand Down
84 changes: 56 additions & 28 deletions server/events/project_command_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ func NewProjectCommandBuilder(
pendingPlanFinder *DefaultPendingPlanFinder,
commentBuilder CommentBuilder,
skipCloneNoChanges bool,
EnableRegExpCmd bool,
) *DefaultProjectCommandBuilder {
projectCommandBuilder := &DefaultProjectCommandBuilder{
ParserValidator: parserValidator,
Expand All @@ -48,6 +49,7 @@ func NewProjectCommandBuilder(
GlobalCfg: globalCfg,
PendingPlanFinder: pendingPlanFinder,
SkipCloneNoChanges: skipCloneNoChanges,
EnableRegExpCmd: EnableRegExpCmd,
ProjectCommandContextBuilder: NewProjectCommandContextBulder(
policyChecksSupported,
commentBuilder,
Expand Down Expand Up @@ -101,6 +103,7 @@ type DefaultProjectCommandBuilder struct {
PendingPlanFinder *DefaultPendingPlanFinder
ProjectCommandContextBuilder ProjectCommandContextBuilder
SkipCloneNoChanges bool
EnableRegExpCmd bool
}

// See ProjectCommandBuilder.BuildAutoplanCommands.
Expand Down Expand Up @@ -303,7 +306,7 @@ func (p *DefaultProjectCommandBuilder) buildProjectPlanCommand(ctx *CommandConte

// getCfg returns the atlantis.yaml config (if it exists) for this project. If
// there is no config, then projectCfg and repoCfg will be nil.
func (p *DefaultProjectCommandBuilder) getCfg(ctx *CommandContext, projectName string, dir string, workspace string, repoDir string) (projectCfg *valid.Project, repoCfg *valid.RepoCfg, err error) {
func (p *DefaultProjectCommandBuilder) getCfg(ctx *CommandContext, projectName string, dir string, workspace string, repoDir string) (projectsCfg []valid.Project, repoCfg *valid.RepoCfg, err error) {
hasConfigFile, err := p.ParserValidator.HasRepoCfg(repoDir)
if err != nil {
err = errors.Wrapf(err, "looking for %s file in %q", yaml.AtlantisYAMLFilename, repoDir)
Expand All @@ -327,8 +330,14 @@ func (p *DefaultProjectCommandBuilder) getCfg(ctx *CommandContext, projectName s
// If they've specified a project by name we look it up. Otherwise we
// use the dir and workspace.
if projectName != "" {
projectCfg = repoCfg.FindProjectByName(projectName)
if projectCfg == nil {
if p.EnableRegExpCmd {
projectsCfg = repoCfg.FindProjectsByName(projectName)
} else {
if p := repoCfg.FindProjectByName(projectName); p != nil {
projectsCfg = append(projectsCfg, *p)
}
}
if len(projectsCfg) == 0 {
err = fmt.Errorf("no project with name %q is defined in %s", projectName, yaml.AtlantisYAMLFilename)
return
}
Expand All @@ -343,7 +352,7 @@ func (p *DefaultProjectCommandBuilder) getCfg(ctx *CommandContext, projectName s
err = fmt.Errorf("must specify project name: more than one project defined in %s matched dir: %q workspace: %q", yaml.AtlantisYAMLFilename, dir, workspace)
return
}
projectCfg = &projCfgs[0]
projectsCfg = projCfgs
return
}

Expand Down Expand Up @@ -418,7 +427,7 @@ func (p *DefaultProjectCommandBuilder) buildProjectApplyCommand(ctx *CommandCont
)
}

// buildProjectCommandCtx builds a context for a single project identified
// buildProjectCommandCtx builds a context for a single or several projects identified
// by the parameters.
func (p *DefaultProjectCommandBuilder) buildProjectCommandCtx(ctx *CommandContext,
cmd models.CommandName,
Expand All @@ -429,47 +438,66 @@ func (p *DefaultProjectCommandBuilder) buildProjectCommandCtx(ctx *CommandContex
workspace string,
verbose bool) ([]models.ProjectCommandContext, error) {

projCfgPtr, repoCfgPtr, err := p.getCfg(ctx, projectName, repoRelDir, workspace, repoDir)
matchingProjects, repoCfgPtr, err := p.getCfg(ctx, projectName, repoRelDir, workspace, repoDir)
if err != nil {
return []models.ProjectCommandContext{}, err
}

var projCtxs []models.ProjectCommandContext
var projCfg valid.MergedProjectCfg
if projCfgPtr != nil {
automerge := DefaultAutomergeEnabled
parallelApply := DefaultParallelApplyEnabled
parallelPlan := DefaultParallelPlanEnabled
if repoCfgPtr != nil {
automerge = repoCfgPtr.Automerge
parallelApply = repoCfgPtr.ParallelApply
parallelPlan = repoCfgPtr.ParallelPlan
}

if len(matchingProjects) > 0 {
// Override any dir/workspace defined on the comment with what was
// defined in config. This shouldn't matter since we don't allow comments
// with both project name and dir/workspace.
repoRelDir = projCfg.RepoRelDir
workspace = projCfg.Workspace
projCfg = p.GlobalCfg.MergeProjectCfg(ctx.Log, ctx.Pull.BaseRepo.ID(), *projCfgPtr, *repoCfgPtr)
for _, mp := range matchingProjects {
ctx.Log.Debug("Merging config for project at dir: %q workspace: %q", mp.Dir, mp.Workspace)
projCfg = p.GlobalCfg.MergeProjectCfg(ctx.Log, ctx.Pull.BaseRepo.ID(), mp, *repoCfgPtr)

projCtxs = append(projCtxs,
p.ProjectCommandContextBuilder.BuildProjectContext(
ctx,
cmd,
projCfg,
commentFlags,
repoDir,
automerge,
parallelApply,
parallelPlan,
verbose,
)...)
}
} else {
projCfg = p.GlobalCfg.DefaultProjCfg(ctx.Log, ctx.Pull.BaseRepo.ID(), repoRelDir, workspace)
projCtxs = append(projCtxs,
p.ProjectCommandContextBuilder.BuildProjectContext(
ctx,
cmd,
projCfg,
commentFlags,
repoDir,
automerge,
parallelApply,
parallelPlan,
verbose,
)...)
}

if err := p.validateWorkspaceAllowed(repoCfgPtr, repoRelDir, workspace); err != nil {
return []models.ProjectCommandContext{}, err
}

automerge := DefaultAutomergeEnabled
parallelApply := DefaultParallelApplyEnabled
parallelPlan := DefaultParallelPlanEnabled
if repoCfgPtr != nil {
automerge = repoCfgPtr.Automerge
parallelApply = repoCfgPtr.ParallelApply
parallelPlan = repoCfgPtr.ParallelPlan
}
return projCtxs, nil

return p.ProjectCommandContextBuilder.BuildProjectContext(
ctx,
cmd,
projCfg,
commentFlags,
repoDir,
automerge,
parallelApply,
parallelPlan,
verbose,
), nil
}

// validateWorkspaceAllowed returns an error if repoCfg defines projects in
Expand Down
Loading