Skip to content

Commit

Permalink
Post implementation for gateway (#201)
Browse files Browse the repository at this point in the history
* post implementation for gateway

* comments

* comments

* nit
  • Loading branch information
samrabelachew committed Mar 4, 2022
1 parent 8ff637a commit 70ffa5f
Show file tree
Hide file tree
Showing 21 changed files with 1,097 additions and 26 deletions.
4 changes: 2 additions & 2 deletions server/events/apply_command_runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ func (a *ApplyCommandRunner) Run(ctx *command.Context, cmd *CommentCommand) {
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, command.Result{Error: err})
a.pullUpdater.UpdatePull(ctx, cmd, command.Result{Error: err})
return
}

Expand Down Expand Up @@ -143,7 +143,7 @@ func (a *ApplyCommandRunner) Run(ctx *command.Context, cmd *CommentCommand) {
result = runProjectCmds(projectCmds, a.prjCmdRunner.Apply)
}

a.pullUpdater.updatePull(
a.pullUpdater.UpdatePull(
ctx,
cmd,
result)
Expand Down
4 changes: 2 additions & 2 deletions server/events/approve_policies_command_runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func (a *ApprovePoliciesCommandRunner) Run(ctx *command.Context, cmd *CommentCom
if statusErr := a.commitStatusUpdater.UpdateCombined(ctx.Pull.BaseRepo, ctx.Pull, models.FailedCommitStatus, command.PolicyCheck); statusErr != nil {
ctx.Log.Warn("unable to update commit status: %s", statusErr)
}
a.pullUpdater.updatePull(ctx, cmd, command.Result{Error: err})
a.pullUpdater.UpdatePull(ctx, cmd, command.Result{Error: err})
return
}

Expand All @@ -72,7 +72,7 @@ func (a *ApprovePoliciesCommandRunner) Run(ctx *command.Context, cmd *CommentCom

result := a.buildApprovePolicyCommandResults(ctx, projectCmds)

a.pullUpdater.updatePull(
a.pullUpdater.UpdatePull(
ctx,
cmd,
result,
Expand Down
3 changes: 1 addition & 2 deletions server/events/mocks/matchers/models_pullrequest.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions server/events/mocks/matchers/models_user.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions server/events/mocks/matchers/ptr_to_events_commentcommand.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions server/events/mocks/matchers/ptr_to_models_pullrequest.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions server/events/mocks/matchers/ptr_to_models_repo.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions server/events/mocks/matchers/time_time.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 2 additions & 3 deletions server/events/mocks/mock_command_runner.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions server/events/plan_command_runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ func (p *PlanCommandRunner) runAutoplan(ctx *command.Context) {
if statusErr := p.commitStatusUpdater.UpdateCombined(baseRepo, pull, models.FailedCommitStatus, command.Plan); statusErr != nil {
ctx.Log.Warn("unable to update commit status: %s", statusErr)
}
p.pullUpdater.updatePull(ctx, AutoplanCommand{}, command.Result{Error: err})
p.pullUpdater.UpdatePull(ctx, AutoplanCommand{}, command.Result{Error: err})
return
}

Expand Down Expand Up @@ -121,7 +121,7 @@ func (p *PlanCommandRunner) runAutoplan(ctx *command.Context) {
result.PlansDeleted = true
}

p.pullUpdater.updatePull(ctx, AutoplanCommand{}, result)
p.pullUpdater.UpdatePull(ctx, AutoplanCommand{}, result)

pullStatus, err := p.dbUpdater.updateDB(ctx, ctx.Pull, result.ProjectResults)
if err != nil {
Expand Down Expand Up @@ -160,7 +160,7 @@ func (p *PlanCommandRunner) run(ctx *command.Context, cmd *CommentCommand) {
if statusErr := p.commitStatusUpdater.UpdateCombined(ctx.Pull.BaseRepo, ctx.Pull, models.FailedCommitStatus, command.Plan); statusErr != nil {
ctx.Log.Warn("unable to update commit status: %s", statusErr)
}
p.pullUpdater.updatePull(ctx, cmd, command.Result{Error: err})
p.pullUpdater.UpdatePull(ctx, cmd, command.Result{Error: err})
return
}

Expand Down Expand Up @@ -195,7 +195,7 @@ func (p *PlanCommandRunner) run(ctx *command.Context, cmd *CommentCommand) {
result.PlansDeleted = true
}

p.pullUpdater.updatePull(
p.pullUpdater.UpdatePull(
ctx,
cmd,
result)
Expand Down
2 changes: 1 addition & 1 deletion server/events/policy_check_command_runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ func (p *PolicyCheckCommandRunner) Run(ctx *command.Context, cmds []command.Proj
result = runProjectCmds(cmds, p.prjCmdRunner.PolicyCheck)
}

p.pullUpdater.updatePull(ctx, PolicyCheckCommand{}, result)
p.pullUpdater.UpdatePull(ctx, PolicyCheckCommand{}, result)

pullStatus, err := p.dbUpdater.updateDB(ctx, ctx.Pull, result.ProjectResults)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion server/events/pull_updater.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ type PullUpdater struct {
GlobalCfg valid.GlobalCfg
}

func (c *PullUpdater) updatePull(ctx *command.Context, cmd PullCommand, res command.Result) {
func (c *PullUpdater) UpdatePull(ctx *command.Context, cmd PullCommand, res command.Result) {
// Log if we got any errors or failures.
if res.Error != nil {
ctx.Log.Err(res.Error.Error())
Expand Down
2 changes: 1 addition & 1 deletion server/events/version_command_runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func (v *VersionCommandRunner) Run(ctx *command.Context, cmd *CommentCommand) {
result = runProjectCmds(projectCmds, v.prjCmdRunner.Version)
}

v.pullUpdater.updatePull(ctx, cmd, result)
v.pullUpdater.UpdatePull(ctx, cmd, result)
}

func (v *VersionCommandRunner) isParallelEnabled(cmds []command.ProjectContext) bool {
Expand Down
147 changes: 147 additions & 0 deletions server/lyft/gateway/autoplan_builder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
package gateway

import (
"github.com/pkg/errors"
"github.com/runatlantis/atlantis/server/core/config/valid"
"github.com/runatlantis/atlantis/server/events"
"github.com/runatlantis/atlantis/server/events/command"
"github.com/runatlantis/atlantis/server/events/metrics"
"github.com/runatlantis/atlantis/server/events/models"
"github.com/runatlantis/atlantis/server/events/vcs"
"github.com/runatlantis/atlantis/server/logging"
"github.com/runatlantis/atlantis/server/recovery"
"github.com/uber-go/tally"
"strconv"
)

// AutoplanValidator handles setting up repo cloning and checking to verify of any terraform files have changed
type AutoplanValidator struct {
Logger logging.SimpleLogging
Scope tally.Scope
VCSClient vcs.Client
PreWorkflowHooksCommandRunner events.PreWorkflowHooksCommandRunner
Drainer *events.Drainer
GlobalCfg valid.GlobalCfg
// AllowForkPRs controls whether we operate on pull requests from forks.
AllowForkPRs bool
// AllowForkPRsFlag is the name of the flag that controls fork PR's. We use
// this in our error message back to the user on a forked PR so they know
// how to enable this functionality.
AllowForkPRsFlag string
// SilenceForkPRErrors controls whether to comment on Fork PRs when AllowForkPRs = False
SilenceForkPRErrors bool
// SilenceForkPRErrorsFlag is the name of the flag that controls fork PR's. We use
// this in our error message back to the user on a forked PR so they know
// how to disable error comment
SilenceForkPRErrorsFlag string
// SilenceVCSStatusNoPlans is whether autoplan should set commit status if no plans
// are found
silenceVCSStatusNoPlans bool
// SilenceVCSStatusNoPlans is whether any plan should set commit status if no projects
// are found
silenceVCSStatusNoProjects bool
CommitStatusUpdater events.CommitStatusUpdater
PrjCmdBuilder events.ProjectPlanCommandBuilder
PullUpdater *events.PullUpdater
}

func (r *AutoplanValidator) isValid(baseRepo models.Repo, headRepo models.Repo, pull models.PullRequest, user models.User) (bool, error) {
if opStarted := r.Drainer.StartOp(); !opStarted {
return false, errors.New("atlantis is shutting down, cannot process current event")
}
defer r.Drainer.OpDone()

log := r.Logger.WithHistory(
"repository", baseRepo.FullName,
"pull-num", strconv.Itoa(pull.Num),
)
defer r.logPanics(log)

ctx := &command.Context{
User: user,
Log: log,
Scope: r.Scope,
Pull: pull,
HeadRepo: headRepo,
Trigger: command.AutoTrigger,
}
if !r.validateCtxAndComment(ctx) {
return false, errors.New("invalid command context")
}
err := r.PreWorkflowHooksCommandRunner.RunPreHooks(ctx)
if err != nil {
ctx.Log.Err("Error running pre-workflow hooks %s. Proceeding with %s command.", err, command.Plan)
}

projectCmds, err := r.PrjCmdBuilder.BuildAutoplanCommands(ctx)
if err != nil {
if statusErr := r.CommitStatusUpdater.UpdateCombined(baseRepo, pull, models.FailedCommitStatus, command.Plan); statusErr != nil {
ctx.Log.Warn("unable to update commit status: %s", statusErr)
}
r.PullUpdater.UpdatePull(ctx, events.AutoplanCommand{}, command.Result{Error: err})
return false, errors.Wrap(err, "Failed building autoplan commands")
}
if len(projectCmds) == 0 {
ctx.Log.Info("determined there was no project to run plan in")
if !(r.silenceVCSStatusNoPlans || r.silenceVCSStatusNoProjects) {
// If there were no projects modified, we set successful commit statuses
// with 0/0 projects planned/policy_checked/applied successfully because some users require
// the Atlantis status to be passing for all pull requests.
ctx.Log.Debug("setting VCS status to success with no projects found")
for _, cmd := range []command.Name{command.Plan, command.Apply, command.PolicyCheck} {
if err := r.CommitStatusUpdater.UpdateCombinedCount(baseRepo, pull, models.SuccessCommitStatus, cmd, 0, 0); err != nil {
ctx.Log.Warn("unable to update commit status: %s", err)
}
}
}
return false, nil
}
return true, nil
}

func (r *AutoplanValidator) InstrumentedIsValid(baseRepo models.Repo, headRepo models.Repo, pull models.PullRequest, user models.User) bool {
timer := r.Scope.Timer(metrics.ExecutionTimeMetric).Start()
defer timer.Stop()
isValid, err := r.isValid(baseRepo, headRepo, pull, user)
if err != nil {
r.Logger.With("repo", baseRepo.FullName, "pull", pull.Num).Err(err.Error())
r.Scope.Counter(metrics.ExecutionErrorMetric).Inc(1)
return false
}
if !isValid {
r.Scope.Counter(metrics.ExecutionFailureMetric).Inc(1)
return false
}
r.Scope.Counter(metrics.ExecutionSuccessMetric).Inc(1)
return true
}

func (r *AutoplanValidator) logPanics(logger logging.SimpleLogging) {
if err := recover(); err != nil {
stack := recovery.Stack(3)
logger.Err("PANIC: %s\n%s", err, stack)
}
}

func (r *AutoplanValidator) validateCtxAndComment(ctx *command.Context) bool {
if !r.AllowForkPRs && ctx.HeadRepo.Owner != ctx.Pull.BaseRepo.Owner {
if r.SilenceForkPRErrors {
return false
}
ctx.Log.Info("command was run on a fork pull request which is disallowed")
return false
}

if ctx.Pull.State != models.OpenPullState {
ctx.Log.Info("command was run on closed pull request")
return false
}

repo := r.GlobalCfg.MatchingRepo(ctx.Pull.BaseRepo.ID())
if !repo.BranchMatches(ctx.Pull.BaseBranch) {
ctx.Log.Info("command was run on a pull request which doesn't match base branches")
// just ignore it to allow us to use any git workflows without malicious intentions.
return false
}
return true
}
Loading

0 comments on commit 70ffa5f

Please sign in to comment.