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

Orca 679 global atlantis lock new release branch #49

23 changes: 19 additions & 4 deletions server/events/apply_command_runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@ package events

import (
"github.com/runatlantis/atlantis/server/events/db"
"github.com/runatlantis/atlantis/server/events/locking"
"github.com/runatlantis/atlantis/server/events/models"
"github.com/runatlantis/atlantis/server/events/vcs"
)

func NewApplyCommandRunner(
vcsClient vcs.Client,
disableApplyAll bool,
disableApply bool,
applyCommandLocker locking.ApplyLockChecker,
commitStatusUpdater CommitStatusUpdater,
prjCommandBuilder ProjectApplyCommandBuilder,
prjCmdRunner ProjectApplyCommandRunner,
Expand All @@ -22,7 +23,7 @@ func NewApplyCommandRunner(
return &ApplyCommandRunner{
vcsClient: vcsClient,
DisableApplyAll: disableApplyAll,
DisableApply: disableApply,
locker: applyCommandLocker,
commitStatusUpdater: commitStatusUpdater,
prjCmdBuilder: prjCommandBuilder,
prjCmdRunner: prjCmdRunner,
Expand All @@ -36,8 +37,8 @@ func NewApplyCommandRunner(

type ApplyCommandRunner struct {
DisableApplyAll bool
DisableApply bool
DB *db.BoltDB
locker locking.ApplyLockChecker
vcsClient vcs.Client
commitStatusUpdater CommitStatusUpdater
prjCmdBuilder ProjectApplyCommandBuilder
Expand All @@ -53,7 +54,15 @@ func (a *ApplyCommandRunner) Run(ctx *CommandContext, cmd *CommentCommand) {
baseRepo := ctx.Pull.BaseRepo
pull := ctx.Pull

if a.DisableApply {
locked, err := a.IsLocked()
// CheckApplyLock falls back to DisableApply flag if fetching the lock
// raises an erro r
// We will log failure as warning
if err != nil {
ctx.Log.Warn("checking global apply lock: %s", err)
}

if locked {
ctx.Log.Info("ignoring apply command since apply disabled globally")
if err := a.vcsClient.CreateComment(baseRepo, pull.Num, applyDisabledComment, models.ApplyCommand.String()); err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The applyDisabledComment is very generic, would be good to think about how to make that more useful depending on how the apply command lock is configured. Not in scope for this PR though.

ctx.Log.Err("unable to comment on pull request: %s", err)
Expand Down Expand Up @@ -135,6 +144,12 @@ func (a *ApplyCommandRunner) Run(ctx *CommandContext, cmd *CommentCommand) {
}
}

func (a *ApplyCommandRunner) IsLocked() (bool, error) {
lock, err := a.locker.CheckApplyLock()

return lock.Locked, err
}

func (a *ApplyCommandRunner) isParallelEnabled(projectCmds []models.ProjectCommandContext) bool {
return len(projectCmds) > 0 && projectCmds[0].ParallelApplyEnabled
}
Expand Down
123 changes: 123 additions & 0 deletions server/events/apply_command_runner_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package events_test

import (
"errors"
"testing"

"github.com/google/go-github/v31/github"
stats "github.com/lyft/gostats"
. "github.com/petergtz/pegomock"
"github.com/runatlantis/atlantis/server/events"
"github.com/runatlantis/atlantis/server/events/locking"
"github.com/runatlantis/atlantis/server/events/models"
"github.com/runatlantis/atlantis/server/events/models/fixtures"
)

// func setupApplyCmd(t *testing.T) *events.ApplyCommandRunner {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commented?

// tmp, cleanup := TempDir(t)
// defer cleanup()

// githubGetter = mocks.NewMockGithubPullGetter()
// eventParsing = mocks.NewMockEventParsing()
// vcsClient = vcsmocks.NewMockClient()
// commitUpdater = mocks.NewMockCommitStatusUpdater()
// applyLockChecker = lockingmocks.NewMockApplyLockChecker()

// projectCommandBuilder = mocks.NewMockProjectCommandBuilder()
// projectCommandRunner = mocks.NewMockProjectCommandRunner()

// pullUpdater := &events.PullUpdater{
// HidePrevPlanComments: false,
// VCSClient: vcsClient,
// MarkdownRenderer: &events.MarkdownRenderer{},
// }

// defaultBoltDB, err := db.New(tmp)
// Ok(t, err)

// dbUpdater := &events.DBUpdater{
// DB: defaultBoltDB,
// }

// autoMerger := &events.AutoMerger{
// VCSClient: vcsClient,
// GlobalAutomerge: false,
// }

// scopeNull := stats.NewStore(stats.NewNullSink(), false)
// parallelPoolSize := 1

// return events.NewApplyCommandRunner(
// vcsClient,
// false,
// applyLockChecker,
// commitUpdater,
// projectCommandBuilder,
// projectCommandRunner,
// autoMerger,
// pullUpdater,
// dbUpdater,
// defaultBoltDB,
// parallelPoolSize,
// )

//}

func TestApplyCommandRunner_IsLocked(t *testing.T) {
RegisterMockTestingT(t)

cases := []struct {
Description string
ApplyLocked bool
ApplyLockError error
ExpComment string
}{
{
Description: "When global apply lock is present IsDisabled returns true",
ApplyLocked: true,
ApplyLockError: nil,
ExpComment: "**Error:** Running `atlantis apply` is disabled.",
},
{
Description: "When no global apply lock is present and DisableApply flag is false IsDisabled returns false",
ApplyLocked: false,
ApplyLockError: nil,
ExpComment: "Ran Apply for 0 projects:\n\n\n\n",
},
{
Description: "If ApplyLockChecker returns an error IsDisabled return value of DisableApply flag",
ApplyLockError: errors.New("error"),
ApplyLocked: false,
ExpComment: "Ran Apply for 0 projects:\n\n\n\n",
},
}

for _, c := range cases {
t.Run(c.Description, func(t *testing.T) {
vcsClient := setup(t)

scopeNull := stats.NewStore(stats.NewNullSink(), false)

pull := &github.PullRequest{
State: github.String("open"),
}
modelPull := models.PullRequest{BaseRepo: fixtures.GithubRepo, State: models.OpenPullState, Num: fixtures.Pull.Num}
When(githubGetter.GetPullRequest(fixtures.GithubRepo, fixtures.Pull.Num)).ThenReturn(pull, nil)
When(eventParsing.ParseGithubPull(pull)).ThenReturn(modelPull, modelPull.BaseRepo, fixtures.GithubRepo, nil)

ctx := &events.CommandContext{
User: fixtures.User,
Log: noopLogger,
Pull: modelPull,
HeadRepo: fixtures.GithubRepo,
Trigger: events.Comment,
Scope: scopeNull,
}

When(applyLockChecker.CheckApplyLock()).ThenReturn(locking.ApplyCommandLock{Locked: c.ApplyLocked}, c.ApplyLockError)
applyCommandRunner.Run(ctx, &events.CommentCommand{Name: models.ApplyCommand})

vcsClient.VerifyWasCalledOnce().CreateComment(fixtures.GithubRepo, modelPull.Num, c.ExpComment, "apply")
})
}
}
25 changes: 5 additions & 20 deletions server/events/command_runner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"github.com/google/go-github/v31/github"
. "github.com/petergtz/pegomock"
"github.com/runatlantis/atlantis/server/events"
lockingmocks "github.com/runatlantis/atlantis/server/events/locking/mocks"
"github.com/runatlantis/atlantis/server/events/mocks"
eventmocks "github.com/runatlantis/atlantis/server/events/mocks"
"github.com/runatlantis/atlantis/server/events/mocks/matchers"
Expand Down Expand Up @@ -60,6 +61,7 @@ var autoMerger *events.AutoMerger
var policyCheckCommandRunner *events.PolicyCheckCommandRunner
var approvePoliciesCommandRunner *events.ApprovePoliciesCommandRunner
var planCommandRunner *events.PlanCommandRunner
var applyLockChecker *lockingmocks.MockApplyLockChecker
var applyCommandRunner *events.ApplyCommandRunner
var unlockCommandRunner *events.UnlockCommandRunner
var preWorkflowHooksCommandRunner events.PreWorkflowHooksCommandRunner
Expand All @@ -86,10 +88,12 @@ func setup(t *testing.T) *vcsmocks.MockClient {

drainer = &events.Drainer{}
deleteLockCommand = eventmocks.NewMockDeleteLockCommand()
applyLockChecker = lockingmocks.NewMockApplyLockChecker()
When(logger.GetLevel()).ThenReturn(logging.Info)
When(logger.NewLogger("runatlantis/atlantis#1", true, logging.Info)).
ThenReturn(pullLogger)

scope := stats.NewStore(stats.NewNullSink(), false)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was this added for fixing the tests you thought were broken? lol do we still need it?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, this is to remove the logging warnings about statsd failing to reach the localhost. Just to reduce the noise :)

dbUpdater = &events.DBUpdater{
DB: defaultBoltDB,
}
Expand Down Expand Up @@ -132,7 +136,7 @@ func setup(t *testing.T) *vcsmocks.MockClient {
applyCommandRunner = events.NewApplyCommandRunner(
vcsClient,
false,
false,
applyLockChecker,
commitUpdater,
projectCommandBuilder,
projectCommandRunner,
Expand Down Expand Up @@ -167,8 +171,6 @@ func setup(t *testing.T) *vcsmocks.MockClient {

When(preWorkflowHooksCommandRunner.RunPreHooks(matchers.AnyPtrToEventsCommandContext())).ThenReturn(nil)

scope := stats.NewDefaultStore()

ch = events.DefaultCommandRunner{
VCSClient: vcsClient,
CommentCommandRunnerByCmd: commentCommandRunnerByCmd,
Expand Down Expand Up @@ -296,23 +298,6 @@ func TestRunCommentCommand_DisableApplyAllDisabled(t *testing.T) {
vcsClient.VerifyWasCalledOnce().CreateComment(fixtures.GithubRepo, modelPull.Num, "**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.", "apply")
}

func TestRunCommentCommand_ApplyDisabled(t *testing.T) {
t.Log("if \"atlantis apply\" is run and this is disabled globally atlantis should" +
" comment saying that this is not allowed")
vcsClient := setup(t)
applyCommandRunner.DisableApply = true
defer func() { applyCommandRunner.DisableApply = false }()
pull := &github.PullRequest{
State: github.String("open"),
}
modelPull := models.PullRequest{BaseRepo: fixtures.GithubRepo, State: models.OpenPullState, Num: fixtures.Pull.Num}
When(githubGetter.GetPullRequest(fixtures.GithubRepo, fixtures.Pull.Num)).ThenReturn(pull, nil)
When(eventParsing.ParseGithubPull(pull)).ThenReturn(modelPull, modelPull.BaseRepo, fixtures.GithubRepo, nil)

ch.RunCommentCommand(fixtures.GithubRepo, nil, nil, fixtures.User, modelPull.Num, &events.CommentCommand{Name: models.ApplyCommand})
vcsClient.VerifyWasCalledOnce().CreateComment(fixtures.GithubRepo, modelPull.Num, "**Error:** Running `atlantis apply` is disabled.", "apply")
}

func TestRunCommentCommand_DisableDisableAutoplan(t *testing.T) {
t.Log("if \"DisableAutoplan is true\" are disabled and we are silencing return and do not comment with error")
setup(t)
Expand Down
Loading