mirror of
https://git.vectorsigma.ru/public/atlantis.git
synced 2026-07-29 19:58:33 +00:00
* Moved CommandContext and CommandResult to models (#193) * Moved CommandContext and CommandResult to models * move from models to command rename CommandContext -> Context rename CommandResult -> Result * moved command related helpers into command package * move ProjectCommandContext and ProjectResult to command/project package * move project command context and project result * revert unrelated code * move tests * fix left over * fix linting * fix tests * remove unused import * fix project context dependencies * fix depenedecies * fix typo
812 lines
19 KiB
Go
812 lines
19 KiB
Go
// Copyright 2017 HootSuite Media Inc.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the License);
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an AS IS BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
// Modified hereafter by contributors to runatlantis/atlantis.
|
|
|
|
package db_test
|
|
|
|
import (
|
|
"os"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/runatlantis/atlantis/server/core/db"
|
|
|
|
"github.com/pkg/errors"
|
|
"github.com/runatlantis/atlantis/server/events/command"
|
|
"github.com/runatlantis/atlantis/server/events/models"
|
|
. "github.com/runatlantis/atlantis/testing"
|
|
bolt "go.etcd.io/bbolt"
|
|
)
|
|
|
|
var lockBucket = "bucket"
|
|
var configBucket = "configBucket"
|
|
var project = models.NewProject("owner/repo", "parent/child")
|
|
var workspace = "default"
|
|
var pullNum = 1
|
|
var lock = models.ProjectLock{
|
|
Pull: models.PullRequest{
|
|
Num: pullNum,
|
|
},
|
|
User: models.User{
|
|
Username: "lkysow",
|
|
},
|
|
Workspace: workspace,
|
|
Project: project,
|
|
Time: time.Now(),
|
|
}
|
|
|
|
func TestLockCommandNotSet(t *testing.T) {
|
|
t.Log("retrieving apply lock when there are none should return empty LockCommand")
|
|
db, b := newTestDB()
|
|
defer cleanupDB(db)
|
|
exists, err := b.CheckCommandLock(command.Apply)
|
|
Ok(t, err)
|
|
Assert(t, exists == nil, "exp nil")
|
|
}
|
|
|
|
func TestLockCommandEnabled(t *testing.T) {
|
|
t.Log("setting the apply lock")
|
|
db, b := newTestDB()
|
|
defer cleanupDB(db)
|
|
timeNow := time.Now()
|
|
_, err := b.LockCommand(command.Apply, timeNow)
|
|
Ok(t, err)
|
|
|
|
config, err := b.CheckCommandLock(command.Apply)
|
|
Ok(t, err)
|
|
Equals(t, true, config.IsLocked())
|
|
}
|
|
|
|
func TestLockCommandFail(t *testing.T) {
|
|
t.Log("setting the apply lock")
|
|
db, b := newTestDB()
|
|
defer cleanupDB(db)
|
|
timeNow := time.Now()
|
|
_, err := b.LockCommand(command.Apply, timeNow)
|
|
Ok(t, err)
|
|
|
|
_, err = b.LockCommand(command.Apply, timeNow)
|
|
ErrEquals(t, "db transaction failed: lock already exists", err)
|
|
}
|
|
|
|
func TestUnlockCommandDisabled(t *testing.T) {
|
|
t.Log("unsetting the apply lock")
|
|
db, b := newTestDB()
|
|
defer cleanupDB(db)
|
|
timeNow := time.Now()
|
|
_, err := b.LockCommand(command.Apply, timeNow)
|
|
Ok(t, err)
|
|
|
|
config, err := b.CheckCommandLock(command.Apply)
|
|
Ok(t, err)
|
|
Equals(t, true, config.IsLocked())
|
|
|
|
err = b.UnlockCommand(command.Apply)
|
|
Ok(t, err)
|
|
|
|
config, err = b.CheckCommandLock(command.Apply)
|
|
Ok(t, err)
|
|
Assert(t, config == nil, "exp nil object")
|
|
}
|
|
|
|
func TestUnlockCommandFail(t *testing.T) {
|
|
t.Log("setting the apply lock")
|
|
db, b := newTestDB()
|
|
defer cleanupDB(db)
|
|
err := b.UnlockCommand(command.Apply)
|
|
ErrEquals(t, "db transaction failed: no lock exists", err)
|
|
}
|
|
|
|
func TestMixedLocksPresent(t *testing.T) {
|
|
db, b := newTestDB()
|
|
defer cleanupDB(db)
|
|
timeNow := time.Now()
|
|
_, err := b.LockCommand(command.Apply, timeNow)
|
|
Ok(t, err)
|
|
|
|
_, _, err = b.TryLock(lock)
|
|
Ok(t, err)
|
|
ls, err := b.List()
|
|
Ok(t, err)
|
|
Equals(t, 1, len(ls))
|
|
}
|
|
|
|
func TestListNoLocks(t *testing.T) {
|
|
t.Log("listing locks when there are none should return an empty list")
|
|
db, b := newTestDB()
|
|
defer cleanupDB(db)
|
|
ls, err := b.List()
|
|
Ok(t, err)
|
|
Equals(t, 0, len(ls))
|
|
}
|
|
|
|
func TestListOneLock(t *testing.T) {
|
|
t.Log("listing locks when there is one should return it")
|
|
db, b := newTestDB()
|
|
defer cleanupDB(db)
|
|
_, _, err := b.TryLock(lock)
|
|
Ok(t, err)
|
|
ls, err := b.List()
|
|
Ok(t, err)
|
|
Equals(t, 1, len(ls))
|
|
}
|
|
|
|
func TestListMultipleLocks(t *testing.T) {
|
|
t.Log("listing locks when there are multiple should return them")
|
|
db, b := newTestDB()
|
|
defer cleanupDB(db)
|
|
|
|
// add multiple locks
|
|
repos := []string{
|
|
"owner/repo1",
|
|
"owner/repo2",
|
|
"owner/repo3",
|
|
"owner/repo4",
|
|
}
|
|
|
|
for _, r := range repos {
|
|
newLock := lock
|
|
newLock.Project = models.NewProject(r, "path")
|
|
_, _, err := b.TryLock(newLock)
|
|
Ok(t, err)
|
|
}
|
|
ls, err := b.List()
|
|
Ok(t, err)
|
|
Equals(t, 4, len(ls))
|
|
for _, r := range repos {
|
|
found := false
|
|
for _, l := range ls {
|
|
if l.Project.RepoFullName == r {
|
|
found = true
|
|
}
|
|
}
|
|
Assert(t, found, "expected %s in %v", r, ls)
|
|
}
|
|
}
|
|
|
|
func TestListAddRemove(t *testing.T) {
|
|
t.Log("listing after adding and removing should return none")
|
|
db, b := newTestDB()
|
|
defer cleanupDB(db)
|
|
_, _, err := b.TryLock(lock)
|
|
Ok(t, err)
|
|
_, err = b.Unlock(project, workspace)
|
|
Ok(t, err)
|
|
|
|
ls, err := b.List()
|
|
Ok(t, err)
|
|
Equals(t, 0, len(ls))
|
|
}
|
|
|
|
func TestLockingNoLocks(t *testing.T) {
|
|
t.Log("with no locks yet, lock should succeed")
|
|
db, b := newTestDB()
|
|
defer cleanupDB(db)
|
|
acquired, currLock, err := b.TryLock(lock)
|
|
Ok(t, err)
|
|
Equals(t, true, acquired)
|
|
Equals(t, lock, currLock)
|
|
}
|
|
|
|
func TestLockingExistingLock(t *testing.T) {
|
|
t.Log("if there is an existing lock, lock should...")
|
|
db, b := newTestDB()
|
|
defer cleanupDB(db)
|
|
_, _, err := b.TryLock(lock)
|
|
Ok(t, err)
|
|
|
|
t.Log("...succeed if the new project has a different path")
|
|
{
|
|
newLock := lock
|
|
newLock.Project = models.NewProject(project.RepoFullName, "different/path")
|
|
acquired, currLock, err := b.TryLock(newLock)
|
|
Ok(t, err)
|
|
Equals(t, true, acquired)
|
|
Equals(t, pullNum, currLock.Pull.Num)
|
|
}
|
|
|
|
t.Log("...succeed if the new project has a different workspace")
|
|
{
|
|
newLock := lock
|
|
newLock.Workspace = "different-workspace"
|
|
acquired, currLock, err := b.TryLock(newLock)
|
|
Ok(t, err)
|
|
Equals(t, true, acquired)
|
|
Equals(t, newLock, currLock)
|
|
}
|
|
|
|
t.Log("...succeed if the new project has a different repoName")
|
|
{
|
|
newLock := lock
|
|
newLock.Project = models.NewProject("different/repo", project.Path)
|
|
acquired, currLock, err := b.TryLock(newLock)
|
|
Ok(t, err)
|
|
Equals(t, true, acquired)
|
|
Equals(t, newLock, currLock)
|
|
}
|
|
|
|
t.Log("...not succeed if the new project only has a different pullNum")
|
|
{
|
|
newLock := lock
|
|
newLock.Pull.Num = lock.Pull.Num + 1
|
|
acquired, currLock, err := b.TryLock(newLock)
|
|
Ok(t, err)
|
|
Equals(t, false, acquired)
|
|
Equals(t, currLock.Pull.Num, pullNum)
|
|
}
|
|
}
|
|
|
|
func TestUnlockingNoLocks(t *testing.T) {
|
|
t.Log("unlocking with no locks should succeed")
|
|
db, b := newTestDB()
|
|
defer cleanupDB(db)
|
|
_, err := b.Unlock(project, workspace)
|
|
|
|
Ok(t, err)
|
|
}
|
|
|
|
func TestUnlocking(t *testing.T) {
|
|
t.Log("unlocking with an existing lock should succeed")
|
|
db, b := newTestDB()
|
|
defer cleanupDB(db)
|
|
|
|
_, _, err := b.TryLock(lock)
|
|
Ok(t, err)
|
|
_, err = b.Unlock(project, workspace)
|
|
Ok(t, err)
|
|
|
|
// should be no locks listed
|
|
ls, err := b.List()
|
|
Ok(t, err)
|
|
Equals(t, 0, len(ls))
|
|
|
|
// should be able to re-lock that repo with a new pull num
|
|
newLock := lock
|
|
newLock.Pull.Num = lock.Pull.Num + 1
|
|
acquired, currLock, err := b.TryLock(newLock)
|
|
Ok(t, err)
|
|
Equals(t, true, acquired)
|
|
Equals(t, newLock, currLock)
|
|
}
|
|
|
|
func TestUnlockingMultiple(t *testing.T) {
|
|
t.Log("unlocking and locking multiple locks should succeed")
|
|
db, b := newTestDB()
|
|
defer cleanupDB(db)
|
|
|
|
_, _, err := b.TryLock(lock)
|
|
Ok(t, err)
|
|
|
|
new := lock
|
|
new.Project.RepoFullName = "new/repo"
|
|
_, _, err = b.TryLock(new)
|
|
Ok(t, err)
|
|
|
|
new2 := lock
|
|
new2.Project.Path = "new/path"
|
|
_, _, err = b.TryLock(new2)
|
|
Ok(t, err)
|
|
|
|
new3 := lock
|
|
new3.Workspace = "new-workspace"
|
|
_, _, err = b.TryLock(new3)
|
|
Ok(t, err)
|
|
|
|
// now try and unlock them
|
|
_, err = b.Unlock(new3.Project, new3.Workspace)
|
|
Ok(t, err)
|
|
_, err = b.Unlock(new2.Project, workspace)
|
|
Ok(t, err)
|
|
_, err = b.Unlock(new.Project, workspace)
|
|
Ok(t, err)
|
|
_, err = b.Unlock(project, workspace)
|
|
Ok(t, err)
|
|
|
|
// should be none left
|
|
ls, err := b.List()
|
|
Ok(t, err)
|
|
Equals(t, 0, len(ls))
|
|
}
|
|
|
|
func TestUnlockByPullNone(t *testing.T) {
|
|
t.Log("UnlockByPull should be successful when there are no locks")
|
|
db, b := newTestDB()
|
|
defer cleanupDB(db)
|
|
|
|
_, err := b.UnlockByPull("any/repo", 1)
|
|
Ok(t, err)
|
|
}
|
|
|
|
func TestUnlockByPullOne(t *testing.T) {
|
|
t.Log("with one lock, UnlockByPull should...")
|
|
db, b := newTestDB()
|
|
defer cleanupDB(db)
|
|
_, _, err := b.TryLock(lock)
|
|
Ok(t, err)
|
|
|
|
t.Log("...delete nothing when its the same repo but a different pull")
|
|
{
|
|
_, err := b.UnlockByPull(project.RepoFullName, pullNum+1)
|
|
Ok(t, err)
|
|
ls, err := b.List()
|
|
Ok(t, err)
|
|
Equals(t, 1, len(ls))
|
|
}
|
|
t.Log("...delete nothing when its the same pull but a different repo")
|
|
{
|
|
_, err := b.UnlockByPull("different/repo", pullNum)
|
|
Ok(t, err)
|
|
ls, err := b.List()
|
|
Ok(t, err)
|
|
Equals(t, 1, len(ls))
|
|
}
|
|
t.Log("...delete the lock when its the same repo and pull")
|
|
{
|
|
_, err := b.UnlockByPull(project.RepoFullName, pullNum)
|
|
Ok(t, err)
|
|
ls, err := b.List()
|
|
Ok(t, err)
|
|
Equals(t, 0, len(ls))
|
|
}
|
|
}
|
|
|
|
func TestUnlockByPullAfterUnlock(t *testing.T) {
|
|
t.Log("after locking and unlocking, UnlockByPull should be successful")
|
|
db, b := newTestDB()
|
|
defer cleanupDB(db)
|
|
_, _, err := b.TryLock(lock)
|
|
Ok(t, err)
|
|
_, err = b.Unlock(project, workspace)
|
|
Ok(t, err)
|
|
|
|
_, err = b.UnlockByPull(project.RepoFullName, pullNum)
|
|
Ok(t, err)
|
|
ls, err := b.List()
|
|
Ok(t, err)
|
|
Equals(t, 0, len(ls))
|
|
}
|
|
|
|
func TestUnlockByPullMatching(t *testing.T) {
|
|
t.Log("UnlockByPull should delete all locks in that repo and pull num")
|
|
db, b := newTestDB()
|
|
defer cleanupDB(db)
|
|
_, _, err := b.TryLock(lock)
|
|
Ok(t, err)
|
|
|
|
// add additional locks with the same repo and pull num but different paths/workspaces
|
|
new := lock
|
|
new.Project.Path = "dif/path"
|
|
_, _, err = b.TryLock(new)
|
|
Ok(t, err)
|
|
new2 := lock
|
|
new2.Workspace = "new-workspace"
|
|
_, _, err = b.TryLock(new2)
|
|
Ok(t, err)
|
|
|
|
// there should now be 3
|
|
ls, err := b.List()
|
|
Ok(t, err)
|
|
Equals(t, 3, len(ls))
|
|
|
|
// should all be unlocked
|
|
_, err = b.UnlockByPull(project.RepoFullName, pullNum)
|
|
Ok(t, err)
|
|
ls, err = b.List()
|
|
Ok(t, err)
|
|
Equals(t, 0, len(ls))
|
|
}
|
|
|
|
func TestGetLockNotThere(t *testing.T) {
|
|
t.Log("getting a lock that doesn't exist should return a nil pointer")
|
|
db, b := newTestDB()
|
|
defer cleanupDB(db)
|
|
l, err := b.GetLock(project, workspace)
|
|
Ok(t, err)
|
|
Equals(t, (*models.ProjectLock)(nil), l)
|
|
}
|
|
|
|
func TestGetLock(t *testing.T) {
|
|
t.Log("getting a lock should return the lock")
|
|
db, b := newTestDB()
|
|
defer cleanupDB(db)
|
|
_, _, err := b.TryLock(lock)
|
|
Ok(t, err)
|
|
|
|
l, err := b.GetLock(project, workspace)
|
|
Ok(t, err)
|
|
// can't compare against time so doing each field
|
|
Equals(t, lock.Project, l.Project)
|
|
Equals(t, lock.Workspace, l.Workspace)
|
|
Equals(t, lock.Pull, l.Pull)
|
|
Equals(t, lock.User, l.User)
|
|
}
|
|
|
|
// Test we can create a status and then getCommandLock it.
|
|
func TestPullStatus_UpdateGet(t *testing.T) {
|
|
b, cleanup := newTestDB2(t)
|
|
defer cleanup()
|
|
|
|
pull := models.PullRequest{
|
|
Num: 1,
|
|
HeadCommit: "sha",
|
|
URL: "url",
|
|
HeadBranch: "head",
|
|
BaseBranch: "base",
|
|
Author: "lkysow",
|
|
State: models.OpenPullState,
|
|
BaseRepo: models.Repo{
|
|
FullName: "runatlantis/atlantis",
|
|
Owner: "runatlantis",
|
|
Name: "atlantis",
|
|
CloneURL: "clone-url",
|
|
SanitizedCloneURL: "clone-url",
|
|
VCSHost: models.VCSHost{
|
|
Hostname: "github.com",
|
|
Type: models.Github,
|
|
},
|
|
},
|
|
}
|
|
status, err := b.UpdatePullWithResults(
|
|
pull,
|
|
[]command.ProjectResult{
|
|
{
|
|
Command: command.Plan,
|
|
RepoRelDir: ".",
|
|
Workspace: "default",
|
|
Failure: "failure",
|
|
},
|
|
})
|
|
Ok(t, err)
|
|
|
|
maybeStatus, err := b.GetPullStatus(pull)
|
|
Ok(t, err)
|
|
Equals(t, pull, maybeStatus.Pull) // nolint: staticcheck
|
|
Equals(t, []models.ProjectStatus{
|
|
{
|
|
Workspace: "default",
|
|
RepoRelDir: ".",
|
|
ProjectName: "",
|
|
Status: models.ErroredPlanStatus,
|
|
},
|
|
}, status.Projects)
|
|
}
|
|
|
|
// Test we can create a status, delete it, and then we shouldn't be able to getCommandLock
|
|
// it.
|
|
func TestPullStatus_UpdateDeleteGet(t *testing.T) {
|
|
b, cleanup := newTestDB2(t)
|
|
defer cleanup()
|
|
|
|
pull := models.PullRequest{
|
|
Num: 1,
|
|
HeadCommit: "sha",
|
|
URL: "url",
|
|
HeadBranch: "head",
|
|
BaseBranch: "base",
|
|
Author: "lkysow",
|
|
State: models.OpenPullState,
|
|
BaseRepo: models.Repo{
|
|
FullName: "runatlantis/atlantis",
|
|
Owner: "runatlantis",
|
|
Name: "atlantis",
|
|
CloneURL: "clone-url",
|
|
SanitizedCloneURL: "clone-url",
|
|
VCSHost: models.VCSHost{
|
|
Hostname: "github.com",
|
|
Type: models.Github,
|
|
},
|
|
},
|
|
}
|
|
_, err := b.UpdatePullWithResults(
|
|
pull,
|
|
[]command.ProjectResult{
|
|
{
|
|
RepoRelDir: ".",
|
|
Workspace: "default",
|
|
Failure: "failure",
|
|
},
|
|
})
|
|
Ok(t, err)
|
|
|
|
err = b.DeletePullStatus(pull)
|
|
Ok(t, err)
|
|
|
|
maybeStatus, err := b.GetPullStatus(pull)
|
|
Ok(t, err)
|
|
Assert(t, maybeStatus == nil, "exp nil")
|
|
}
|
|
|
|
// Test we can create a status, update a specific project's status within that
|
|
// pull status, and when we getCommandLock all the project statuses, that specific project
|
|
// should be updated.
|
|
func TestPullStatus_UpdateProject(t *testing.T) {
|
|
b, cleanup := newTestDB2(t)
|
|
defer cleanup()
|
|
|
|
pull := models.PullRequest{
|
|
Num: 1,
|
|
HeadCommit: "sha",
|
|
URL: "url",
|
|
HeadBranch: "head",
|
|
BaseBranch: "base",
|
|
Author: "lkysow",
|
|
State: models.OpenPullState,
|
|
BaseRepo: models.Repo{
|
|
FullName: "runatlantis/atlantis",
|
|
Owner: "runatlantis",
|
|
Name: "atlantis",
|
|
CloneURL: "clone-url",
|
|
SanitizedCloneURL: "clone-url",
|
|
VCSHost: models.VCSHost{
|
|
Hostname: "github.com",
|
|
Type: models.Github,
|
|
},
|
|
},
|
|
}
|
|
_, err := b.UpdatePullWithResults(
|
|
pull,
|
|
[]command.ProjectResult{
|
|
{
|
|
RepoRelDir: ".",
|
|
Workspace: "default",
|
|
Failure: "failure",
|
|
},
|
|
{
|
|
RepoRelDir: ".",
|
|
Workspace: "staging",
|
|
ApplySuccess: "success!",
|
|
},
|
|
})
|
|
Ok(t, err)
|
|
|
|
err = b.UpdateProjectStatus(pull, "default", ".", models.DiscardedPlanStatus)
|
|
Ok(t, err)
|
|
|
|
status, err := b.GetPullStatus(pull)
|
|
Ok(t, err)
|
|
Equals(t, pull, status.Pull) // nolint: staticcheck
|
|
Equals(t, []models.ProjectStatus{
|
|
{
|
|
Workspace: "default",
|
|
RepoRelDir: ".",
|
|
ProjectName: "",
|
|
Status: models.DiscardedPlanStatus,
|
|
},
|
|
{
|
|
Workspace: "staging",
|
|
RepoRelDir: ".",
|
|
ProjectName: "",
|
|
Status: models.AppliedPlanStatus,
|
|
},
|
|
}, status.Projects) // nolint: staticcheck
|
|
}
|
|
|
|
// Test that if we update an existing pull status and our new status is for a
|
|
// different HeadSHA, that we just overwrite the old status.
|
|
func TestPullStatus_UpdateNewCommit(t *testing.T) {
|
|
b, cleanup := newTestDB2(t)
|
|
defer cleanup()
|
|
|
|
pull := models.PullRequest{
|
|
Num: 1,
|
|
HeadCommit: "sha",
|
|
URL: "url",
|
|
HeadBranch: "head",
|
|
BaseBranch: "base",
|
|
Author: "lkysow",
|
|
State: models.OpenPullState,
|
|
BaseRepo: models.Repo{
|
|
FullName: "runatlantis/atlantis",
|
|
Owner: "runatlantis",
|
|
Name: "atlantis",
|
|
CloneURL: "clone-url",
|
|
SanitizedCloneURL: "clone-url",
|
|
VCSHost: models.VCSHost{
|
|
Hostname: "github.com",
|
|
Type: models.Github,
|
|
},
|
|
},
|
|
}
|
|
_, err := b.UpdatePullWithResults(
|
|
pull,
|
|
[]command.ProjectResult{
|
|
{
|
|
RepoRelDir: ".",
|
|
Workspace: "default",
|
|
Failure: "failure",
|
|
},
|
|
})
|
|
Ok(t, err)
|
|
|
|
pull.HeadCommit = "newsha"
|
|
status, err := b.UpdatePullWithResults(pull,
|
|
[]command.ProjectResult{
|
|
{
|
|
RepoRelDir: ".",
|
|
Workspace: "staging",
|
|
ApplySuccess: "success!",
|
|
},
|
|
})
|
|
|
|
Ok(t, err)
|
|
Equals(t, 1, len(status.Projects))
|
|
|
|
maybeStatus, err := b.GetPullStatus(pull)
|
|
Ok(t, err)
|
|
Equals(t, pull, maybeStatus.Pull)
|
|
Equals(t, []models.ProjectStatus{
|
|
{
|
|
Workspace: "staging",
|
|
RepoRelDir: ".",
|
|
ProjectName: "",
|
|
Status: models.AppliedPlanStatus,
|
|
},
|
|
}, maybeStatus.Projects)
|
|
}
|
|
|
|
// Test that if we update an existing pull status and our new status is for a
|
|
// the same commit, that we merge the statuses.
|
|
func TestPullStatus_UpdateMerge(t *testing.T) {
|
|
b, cleanup := newTestDB2(t)
|
|
defer cleanup()
|
|
|
|
pull := models.PullRequest{
|
|
Num: 1,
|
|
HeadCommit: "sha",
|
|
URL: "url",
|
|
HeadBranch: "head",
|
|
BaseBranch: "base",
|
|
Author: "lkysow",
|
|
State: models.OpenPullState,
|
|
BaseRepo: models.Repo{
|
|
FullName: "runatlantis/atlantis",
|
|
Owner: "runatlantis",
|
|
Name: "atlantis",
|
|
CloneURL: "clone-url",
|
|
SanitizedCloneURL: "clone-url",
|
|
VCSHost: models.VCSHost{
|
|
Hostname: "github.com",
|
|
Type: models.Github,
|
|
},
|
|
},
|
|
}
|
|
_, err := b.UpdatePullWithResults(
|
|
pull,
|
|
[]command.ProjectResult{
|
|
{
|
|
Command: command.Plan,
|
|
RepoRelDir: "mergeme",
|
|
Workspace: "default",
|
|
Failure: "failure",
|
|
},
|
|
{
|
|
Command: command.Plan,
|
|
RepoRelDir: "projectname",
|
|
Workspace: "default",
|
|
ProjectName: "projectname",
|
|
Failure: "failure",
|
|
},
|
|
{
|
|
Command: command.Plan,
|
|
RepoRelDir: "staythesame",
|
|
Workspace: "default",
|
|
PlanSuccess: &models.PlanSuccess{
|
|
TerraformOutput: "tf out",
|
|
LockURL: "lock-url",
|
|
RePlanCmd: "plan command",
|
|
ApplyCmd: "apply command",
|
|
},
|
|
},
|
|
})
|
|
Ok(t, err)
|
|
|
|
updateStatus, err := b.UpdatePullWithResults(pull,
|
|
[]command.ProjectResult{
|
|
{
|
|
Command: command.Apply,
|
|
RepoRelDir: "mergeme",
|
|
Workspace: "default",
|
|
ApplySuccess: "applied!",
|
|
},
|
|
{
|
|
Command: command.Apply,
|
|
RepoRelDir: "projectname",
|
|
Workspace: "default",
|
|
ProjectName: "projectname",
|
|
Error: errors.New("apply error"),
|
|
},
|
|
{
|
|
Command: command.Apply,
|
|
RepoRelDir: "newresult",
|
|
Workspace: "default",
|
|
ApplySuccess: "success!",
|
|
},
|
|
})
|
|
Ok(t, err)
|
|
|
|
getStatus, err := b.GetPullStatus(pull)
|
|
Ok(t, err)
|
|
|
|
// Test both the pull state returned from the update call *and* the getCommandLock
|
|
// call.
|
|
for _, s := range []models.PullStatus{updateStatus, *getStatus} {
|
|
Equals(t, pull, s.Pull)
|
|
Equals(t, []models.ProjectStatus{
|
|
{
|
|
RepoRelDir: "mergeme",
|
|
Workspace: "default",
|
|
Status: models.AppliedPlanStatus,
|
|
},
|
|
{
|
|
RepoRelDir: "projectname",
|
|
Workspace: "default",
|
|
ProjectName: "projectname",
|
|
Status: models.ErroredApplyStatus,
|
|
},
|
|
{
|
|
RepoRelDir: "staythesame",
|
|
Workspace: "default",
|
|
Status: models.PlannedPlanStatus,
|
|
},
|
|
{
|
|
RepoRelDir: "newresult",
|
|
Workspace: "default",
|
|
Status: models.AppliedPlanStatus,
|
|
},
|
|
}, updateStatus.Projects)
|
|
}
|
|
}
|
|
|
|
// newTestDB returns a TestDB using a temporary path.
|
|
func newTestDB() (*bolt.DB, *db.BoltDB) {
|
|
// Retrieve a temporary path.
|
|
f, err := os.CreateTemp("", "")
|
|
if err != nil {
|
|
panic(errors.Wrap(err, "failed to create temp file"))
|
|
}
|
|
path := f.Name()
|
|
f.Close() // nolint: errcheck
|
|
|
|
// Open the database.
|
|
boltDB, err := bolt.Open(path, 0600, nil)
|
|
if err != nil {
|
|
panic(errors.Wrap(err, "could not start bolt DB"))
|
|
}
|
|
if err := boltDB.Update(func(tx *bolt.Tx) error {
|
|
if _, err := tx.CreateBucketIfNotExists([]byte(lockBucket)); err != nil {
|
|
return errors.Wrap(err, "failed to create bucket")
|
|
}
|
|
if _, err := tx.CreateBucketIfNotExists([]byte(configBucket)); err != nil {
|
|
return errors.Wrap(err, "failed to create bucket")
|
|
}
|
|
return nil
|
|
}); err != nil {
|
|
panic(errors.Wrap(err, "could not create bucket"))
|
|
}
|
|
b, _ := db.NewWithDB(boltDB, lockBucket, configBucket)
|
|
return boltDB, b
|
|
}
|
|
|
|
func newTestDB2(t *testing.T) (*db.BoltDB, func()) {
|
|
tmp, cleanup := TempDir(t)
|
|
boltDB, err := db.New(tmp)
|
|
Ok(t, err)
|
|
return boltDB, func() {
|
|
cleanup()
|
|
}
|
|
}
|
|
|
|
func cleanupDB(db *bolt.DB) {
|
|
os.Remove(db.Path()) // nolint: errcheck
|
|
db.Close() // nolint: errcheck
|
|
}
|