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

Post implementation for gateway #201

Merged
merged 4 commits into from
Mar 4, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
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_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/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
166 changes: 166 additions & 0 deletions server/lyft/gateway/autoplan_builder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
package gateway

import (
"fmt"
"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"
)

//go:generate pegomock generate -m --use-experimental-model-gen --package mocks -o mocks/mock_autoplan_validator.go AutoplanValidator
type AutoplanValidator interface {
PullRequestHasTerraformChanges(baseRepo models.Repo, headRepo models.Repo, pull models.PullRequest, user models.User) bool
}
samrabelachew marked this conversation as resolved.
Show resolved Hide resolved

// AutoplanBuilder handles setting up repo cloning and checking to verify of any terraform files have changed
type AutoplanBuilder struct {
Logger logging.SimpleLogging
Scope tally.Scope
VCSClient vcs.Client
PreWorkflowHooksCommandRunner events.PreWorkflowHooksCommandRunner
DisableAutoplan bool
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 *AutoplanBuilder) PullRequestHasTerraformChanges(baseRepo models.Repo, headRepo models.Repo, pull models.PullRequest, user models.User) bool {
samrabelachew marked this conversation as resolved.
Show resolved Hide resolved
if opStarted := r.Drainer.StartOp(); !opStarted {
if commentErr := r.VCSClient.CreateComment(baseRepo, pull.Num, ShutdownComment, command.Plan.String()); commentErr != nil {
r.Logger.Log(logging.Error, "unable to comment that Atlantis is shutting down: %s", commentErr)
}
samrabelachew marked this conversation as resolved.
Show resolved Hide resolved
return false
}
defer r.Drainer.OpDone()
samrabelachew marked this conversation as resolved.
Show resolved Hide resolved

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

scope := r.Scope.SubScope("gateway-autoplan")
samrabelachew marked this conversation as resolved.
Show resolved Hide resolved
timer := scope.Timer(metrics.ExecutionTimeMetric).Start()
defer timer.Stop()

ctx := &command.Context{
User: user,
Log: log,
Scope: scope,
Pull: pull,
HeadRepo: headRepo,
Trigger: command.AutoTrigger,
}
if !r.validateCtxAndComment(ctx) {
return false
}
if r.DisableAutoplan {
return false
}
err := r.PreWorkflowHooksCommandRunner.RunPreHooks(ctx)
if err != nil {
ctx.Log.Err("Error running pre-workflow hooks %s. Proceeding with %s command.", err, command.Plan)
samrabelachew marked this conversation as resolved.
Show resolved Hide resolved
}

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
}
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")
if err := r.CommitStatusUpdater.UpdateCombinedCount(baseRepo, pull, models.SuccessCommitStatus, command.Plan, 0, 0); err != nil {
ctx.Log.Warn("unable to update commit status: %s", err)
}
if err := r.CommitStatusUpdater.UpdateCombinedCount(baseRepo, pull, models.SuccessCommitStatus, command.PolicyCheck, 0, 0); err != nil {
ctx.Log.Warn("unable to update commit status: %s", err)
}
if err := r.CommitStatusUpdater.UpdateCombinedCount(baseRepo, pull, models.SuccessCommitStatus, command.Apply, 0, 0); err != nil {
ctx.Log.Warn("unable to update commit status: %s", err)
}
}
samrabelachew marked this conversation as resolved.
Show resolved Hide resolved
ctx.Scope.Counter("tf_projects_found").Inc(1)
return false
}
ctx.Scope.Counter("tf_projects_not_found").Inc(1)
return true
}

func (r *AutoplanBuilder) logPanics(baseRepo models.Repo, pullNum int, logger logging.SimpleLogging) {
if err := recover(); err != nil {
stack := recovery.Stack(3)
logger.Err("PANIC: %s\n%s", err, stack)
if commentErr := r.VCSClient.CreateComment(
baseRepo,
pullNum,
fmt.Sprintf("**Error: goroutine panic. This is a bug.**\n```\n%s\n%s```", err, stack),
"",
); commentErr != nil {
logger.Err("unable to comment: %s", commentErr)
}
}
}

func (r *AutoplanBuilder) 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")
if err := r.VCSClient.CreateComment(ctx.Pull.BaseRepo, ctx.Pull.Num, fmt.Sprintf("Atlantis commands can't be run on fork pull requests. To enable, set --%s or, to disable this message, set --%s", r.AllowForkPRsFlag, r.SilenceForkPRErrorsFlag), ""); err != nil {
ctx.Log.Err("unable to comment: %s", err)
}
return false
}

if ctx.Pull.State != models.OpenPullState {
ctx.Log.Info("command was run on closed pull request")
if err := r.VCSClient.CreateComment(ctx.Pull.BaseRepo, ctx.Pull.Num, "Atlantis commands can't be run on closed pull requests", ""); err != nil {
ctx.Log.Err("unable to comment: %s", err)
}
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