Skip to content

Commit

Permalink
Support regexp in command builder on the project name (#1419)
Browse files Browse the repository at this point in the history
  • Loading branch information
bewie authored Mar 6, 2021
1 parent 471646b commit d2ef277
Show file tree
Hide file tree
Showing 10 changed files with 287 additions and 28 deletions.
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

0 comments on commit d2ef277

Please sign in to comment.