-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement a new policy check workflow (#1317)
* Adding policy_check support into yaml config * Added policy check model and runtime structs * Adding BuildPolicyCheckCommand to ProjectCommandBuilder * Return incorrectly deleted code * Remove BuildAutoPolicyPlanCommand from ProjectCommandBuilder * Split runAutoCommand into two functions runAutoPlanCommand - does what originally RunAutoplancommand was doing except now it returns CommandResult and []models.ProjectCommandContext runAutoPolicyCheckCommand - accepts CommandContext, CommandResult, and []models.ProjectCommandContext as arguments and runs PolicyCheckStep runner * Refactor RunCommentCommand * Remove BuildPolicyCheckCommand and rename StepCmdExec back to TerraformExec * Add policy step runner logic and conftest interfaces. * Add show step runner to policy check stage. * Adding models.PolicyCheckCommand to buildCtx This also means buildPlanAllCommands call buildCtx twice once with models.PlanCommand and once with models.PolicyCheckCommand * Adding new project_command_builder that supports policy_check * Refactoring PolicyCheck specific logic into a PolicyCheckProjectCommandBuilder * Moving events.CommandContext to models.CommandContext this will allow me to remove buildCtx method and move ProjectCommandContext creation into models package * Policy Owners might be different types, for that reason we are refactoring Owners into its own struct with specific keys defining different owner types Co-authored-by: Nish Krishnan <[email protected]> Co-authored-by: Nish Krishnan <[email protected]>
- Loading branch information
1 parent
10d7b28
commit af2a806
Showing
126 changed files
with
7,635 additions
and
1,176 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,6 @@ | ||
FROM runatlantis/atlantis:latest | ||
COPY atlantis /usr/local/bin/atlantis | ||
# TODO: remove this once we get this in the base image | ||
ENV DEFAULT_CONFTEST_VERSION=0.21.0 | ||
|
||
WORKDIR /atlantis/src |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,186 @@ | ||
package events | ||
|
||
import ( | ||
"github.com/runatlantis/atlantis/server/events/db" | ||
"github.com/runatlantis/atlantis/server/events/models" | ||
"github.com/runatlantis/atlantis/server/events/vcs" | ||
) | ||
|
||
func NewApplyCommandRunner( | ||
vcsClient vcs.Client, | ||
disableApplyAll bool, | ||
disableApply bool, | ||
commitStatusUpdater CommitStatusUpdater, | ||
prjCommandBuilder ProjectApplyCommandBuilder, | ||
prjCmdRunner ProjectApplyCommandRunner, | ||
autoMerger *AutoMerger, | ||
pullUpdater *PullUpdater, | ||
dbUpdater *DBUpdater, | ||
db *db.BoltDB, | ||
parallelPoolSize int, | ||
) *ApplyCommandRunner { | ||
return &ApplyCommandRunner{ | ||
vcsClient: vcsClient, | ||
DisableApplyAll: disableApplyAll, | ||
DisableApply: disableApply, | ||
commitStatusUpdater: commitStatusUpdater, | ||
prjCmdBuilder: prjCommandBuilder, | ||
prjCmdRunner: prjCmdRunner, | ||
autoMerger: autoMerger, | ||
pullUpdater: pullUpdater, | ||
dbUpdater: dbUpdater, | ||
DB: db, | ||
parallelPoolSize: parallelPoolSize, | ||
} | ||
} | ||
|
||
type ApplyCommandRunner struct { | ||
DisableApplyAll bool | ||
DisableApply bool | ||
DB *db.BoltDB | ||
vcsClient vcs.Client | ||
commitStatusUpdater CommitStatusUpdater | ||
prjCmdBuilder ProjectApplyCommandBuilder | ||
prjCmdRunner ProjectApplyCommandRunner | ||
autoMerger *AutoMerger | ||
pullUpdater *PullUpdater | ||
dbUpdater *DBUpdater | ||
parallelPoolSize int | ||
} | ||
|
||
func (a *ApplyCommandRunner) Run(ctx *CommandContext, cmd *CommentCommand) { | ||
var err error | ||
baseRepo := ctx.Pull.BaseRepo | ||
pull := ctx.Pull | ||
|
||
if a.DisableApply { | ||
ctx.Log.Info("ignoring apply command since apply disabled globally") | ||
if err := a.vcsClient.CreateComment(baseRepo, pull.Num, applyDisabledComment, models.ApplyCommand.String()); err != nil { | ||
ctx.Log.Err("unable to comment on pull request: %s", err) | ||
} | ||
|
||
return | ||
} | ||
|
||
if a.DisableApplyAll && !cmd.IsForSpecificProject() { | ||
ctx.Log.Info("ignoring apply command without flags since apply all is disabled") | ||
if err := a.vcsClient.CreateComment(baseRepo, pull.Num, applyAllDisabledComment, models.ApplyCommand.String()); err != nil { | ||
ctx.Log.Err("unable to comment on pull request: %s", err) | ||
} | ||
|
||
return | ||
} | ||
|
||
// Get the mergeable status before we set any build statuses of our own. | ||
// We do this here because when we set a "Pending" status, if users have | ||
// required the Atlantis status checks to pass, then we've now changed | ||
// the mergeability status of the pull request. | ||
ctx.PullMergeable, err = a.vcsClient.PullIsMergeable(baseRepo, pull) | ||
if err != nil { | ||
// On error we continue the request with mergeable assumed false. | ||
// We want to continue because not all apply's will need this status, | ||
// only if they rely on the mergeability requirement. | ||
ctx.PullMergeable = false | ||
ctx.Log.Warn("unable to get mergeable status: %s. Continuing with mergeable assumed false", err) | ||
} | ||
|
||
// TODO: This needs to be revisited and new PullMergeable like conditions should | ||
// be added to check against it. | ||
if a.anyFailedPolicyChecks(pull) { | ||
ctx.PullMergeable = false | ||
ctx.Log.Warn("when using policy checks all policies have to be approved or pass. Continuing with mergeable assumed false") | ||
} | ||
|
||
ctx.Log.Info("pull request mergeable status: %t", ctx.PullMergeable) | ||
|
||
if err = a.commitStatusUpdater.UpdateCombined(baseRepo, pull, models.PendingCommitStatus, cmd.CommandName()); err != nil { | ||
ctx.Log.Warn("unable to update commit status: %s", err) | ||
} | ||
|
||
var projectCmds []models.ProjectCommandContext | ||
projectCmds, err = a.prjCmdBuilder.BuildApplyCommands(ctx, cmd) | ||
|
||
if err != nil { | ||
if statusErr := a.commitStatusUpdater.UpdateCombined(ctx.Pull.BaseRepo, ctx.Pull, models.FailedCommitStatus, cmd.CommandName()); statusErr != nil { | ||
ctx.Log.Warn("unable to update commit status: %s", statusErr) | ||
} | ||
a.pullUpdater.updatePull(ctx, cmd, CommandResult{Error: err}) | ||
return | ||
} | ||
|
||
// Only run commands in parallel if enabled | ||
var result CommandResult | ||
if a.isParallelEnabled(projectCmds) { | ||
ctx.Log.Info("Running applies in parallel") | ||
result = runProjectCmdsParallel(projectCmds, a.prjCmdRunner.Apply, a.parallelPoolSize) | ||
} else { | ||
result = runProjectCmds(projectCmds, a.prjCmdRunner.Apply) | ||
} | ||
|
||
a.pullUpdater.updatePull( | ||
ctx, | ||
cmd, | ||
result) | ||
|
||
pullStatus, err := a.dbUpdater.updateDB(ctx, pull, result.ProjectResults) | ||
if err != nil { | ||
ctx.Log.Err("writing results: %s", err) | ||
return | ||
} | ||
|
||
a.updateCommitStatus(ctx, pullStatus) | ||
|
||
if a.autoMerger.automergeEnabled(projectCmds) { | ||
a.autoMerger.automerge(ctx, pullStatus) | ||
} | ||
} | ||
|
||
func (a *ApplyCommandRunner) isParallelEnabled(projectCmds []models.ProjectCommandContext) bool { | ||
return len(projectCmds) > 0 && projectCmds[0].ParallelApplyEnabled | ||
} | ||
|
||
func (a *ApplyCommandRunner) updateCommitStatus(ctx *CommandContext, pullStatus models.PullStatus) { | ||
var numSuccess int | ||
var numErrored int | ||
status := models.SuccessCommitStatus | ||
|
||
numSuccess = pullStatus.StatusCount(models.AppliedPlanStatus) | ||
numErrored = pullStatus.StatusCount(models.ErroredApplyStatus) | ||
|
||
if numErrored > 0 { | ||
status = models.FailedCommitStatus | ||
} else if numSuccess < len(pullStatus.Projects) { | ||
// If there are plans that haven't been applied yet, we'll use a pending | ||
// status. | ||
status = models.PendingCommitStatus | ||
} | ||
|
||
if err := a.commitStatusUpdater.UpdateCombinedCount( | ||
ctx.Pull.BaseRepo, | ||
ctx.Pull, | ||
status, | ||
models.ApplyCommand, | ||
numSuccess, | ||
len(pullStatus.Projects), | ||
); err != nil { | ||
ctx.Log.Warn("unable to update commit status: %s", err) | ||
} | ||
} | ||
|
||
func (a *ApplyCommandRunner) anyFailedPolicyChecks(pull models.PullRequest) bool { | ||
policyCheckPullStatus, _ := a.DB.GetPullStatus(pull) | ||
if policyCheckPullStatus != nil && policyCheckPullStatus.StatusCount(models.ErroredPolicyCheckStatus) > 0 { | ||
return true | ||
} | ||
|
||
return false | ||
|
||
} | ||
|
||
// applyAllDisabledComment is posted when apply all commands (i.e. "atlantis apply") | ||
// are disabled and an apply all command is issued. | ||
var applyAllDisabledComment = "**Error:** Running `atlantis apply` without flags is disabled." + | ||
" You must specify which project to apply via the `-d <dir>`, `-w <workspace>` or `-p <project name>` flags." | ||
|
||
// applyDisabledComment is posted when apply commands are disabled globally and an apply command is issued. | ||
var applyDisabledComment = "**Error:** Running `atlantis apply` is disabled." |
Oops, something went wrong.