-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
Copy pathpending_plan_finder.go
100 lines (89 loc) · 2.94 KB
/
pending_plan_finder.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
package events
import (
"os"
"os/exec"
"path/filepath"
"strings"
"github.com/pkg/errors"
"github.com/runatlantis/atlantis/server/core/runtime"
"github.com/runatlantis/atlantis/server/utils"
)
//go:generate pegomock generate --package mocks -o mocks/mock_pending_plan_finder.go PendingPlanFinder
type PendingPlanFinder interface {
Find(pullDir string) ([]PendingPlan, error)
DeletePlans(pullDir string) error
}
// DefaultPendingPlanFinder finds unapplied plans.
type DefaultPendingPlanFinder struct{}
// PendingPlan is a plan that has not been applied.
type PendingPlan struct {
// RepoDir is the absolute path to the root of the repo that holds this
// plan.
RepoDir string
// RepoRelDir is the relative path from the repo to the project that
// the plan is for.
RepoRelDir string
// Workspace is the workspace this plan should execute in.
Workspace string
ProjectName string
}
// Find finds all pending plans in pullDir. pullDir should be the working
// directory where Atlantis will operate on this pull request. It's one level
// up from where Atlantis clones the repo for each workspace.
func (p *DefaultPendingPlanFinder) Find(pullDir string) ([]PendingPlan, error) {
plans, _, err := p.findWithAbsPaths(pullDir)
return plans, err
}
func (p *DefaultPendingPlanFinder) findWithAbsPaths(pullDir string) ([]PendingPlan, []string, error) {
workspaceDirs, err := os.ReadDir(pullDir)
if err != nil {
return nil, nil, err
}
var plans []PendingPlan
var absPaths []string
for _, workspaceDir := range workspaceDirs {
workspace := workspaceDir.Name()
repoDir := filepath.Join(pullDir, workspace)
// Any generated plans should be untracked by git since Atlantis created
// them.
lsCmd := exec.Command("git", "ls-files", ".", "--others") // nolint: gosec
lsCmd.Dir = repoDir
lsOut, err := lsCmd.CombinedOutput()
if err != nil {
return nil, nil, errors.Wrapf(err, "running 'git ls-files . --others' in '%s' directory: %s", repoDir, string(lsOut))
}
for _, file := range strings.Split(string(lsOut), "\n") {
if filepath.Ext(file) == ".tfplan" {
// Ignore .terragrunt-cache dirs (#487)
if strings.Contains(file, ".terragrunt-cache/") {
continue
}
projectName, err := runtime.ProjectNameFromPlanfile(workspace, filepath.Base(file))
if err != nil {
return nil, nil, err
}
plans = append(plans, PendingPlan{
RepoDir: repoDir,
RepoRelDir: filepath.Dir(file),
Workspace: workspace,
ProjectName: projectName,
})
absPaths = append(absPaths, filepath.Join(repoDir, file))
}
}
}
return plans, absPaths, nil
}
// deletePlans deletes all plans in pullDir.
func (p *DefaultPendingPlanFinder) DeletePlans(pullDir string) error {
_, absPaths, err := p.findWithAbsPaths(pullDir)
if err != nil {
return err
}
for _, path := range absPaths {
if err := utils.RemoveIgnoreNonExistent(path); err != nil {
return errors.Wrapf(err, "delete plan at %s", path)
}
}
return nil
}