forked from runatlantis/atlantis
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpre_workflow_hooks_command_runner.go
133 lines (112 loc) · 3.79 KB
/
pre_workflow_hooks_command_runner.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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
package events
import (
"fmt"
"github.com/runatlantis/atlantis/server/events/models"
"github.com/runatlantis/atlantis/server/events/runtime"
"github.com/runatlantis/atlantis/server/events/vcs"
"github.com/runatlantis/atlantis/server/events/yaml/valid"
"github.com/runatlantis/atlantis/server/logging"
"github.com/runatlantis/atlantis/server/recovery"
)
//go:generate pegomock generate -m --use-experimental-model-gen --package mocks -o mocks/mock_pre_workflows_hooks_command_runner.go PreWorkflowHooksCommandRunner
type PreWorkflowHooksCommandRunner interface {
RunPreHooks(
baseRepo models.Repo,
headRepo models.Repo,
pull models.PullRequest,
user models.User,
)
}
// DefaultPreWorkflowHooksCommandRunner is the first step when processing a workflow hook commands.
type DefaultPreWorkflowHooksCommandRunner struct {
VCSClient vcs.Client
Logger logging.SimpleLogging
WorkingDirLocker WorkingDirLocker
WorkingDir WorkingDir
GlobalCfg valid.GlobalCfg
Drainer *Drainer
PreWorkflowHookRunner *runtime.PreWorkflowHookRunner
}
// RunPreHooks runs pre_workflow_hooks when PR is opened or updated.
func (w *DefaultPreWorkflowHooksCommandRunner) RunPreHooks(
baseRepo models.Repo,
headRepo models.Repo,
pull models.PullRequest,
user models.User,
) {
if opStarted := w.Drainer.StartOp(); !opStarted {
if commentErr := w.VCSClient.CreateComment(baseRepo, pull.Num, ShutdownComment, "pre_workflow_hooks"); commentErr != nil {
w.Logger.Log(logging.Error, "unable to comment that Atlantis is shutting down: %s", commentErr)
}
return
}
defer w.Drainer.OpDone()
log := w.buildLogger(baseRepo.FullName, pull.Num)
defer w.logPanics(baseRepo, pull.Num, log)
log.Info("running pre hooks")
preWorkflowHooks := make([]*valid.PreWorkflowHook, 0)
for _, repo := range w.GlobalCfg.Repos {
if repo.IDMatches(baseRepo.ID()) && len(repo.PreWorkflowHooks) > 0 {
preWorkflowHooks = append(preWorkflowHooks, repo.PreWorkflowHooks...)
}
}
if len(preWorkflowHooks) == 0 {
return
}
unlockFn, err := w.WorkingDirLocker.TryLock(baseRepo.FullName, pull.Num, DefaultWorkspace)
if err != nil {
log.Warn("workspace is locked")
return
}
log.Debug("got workspace lock")
defer unlockFn()
repoDir, _, err := w.WorkingDir.Clone(log, headRepo, pull, DefaultWorkspace)
if err != nil {
log.Err("unable to run pre workflow hooks: %s", err)
return
}
ctx := models.PreWorkflowHookCommandContext{
BaseRepo: baseRepo,
HeadRepo: headRepo,
Log: log,
Pull: pull,
User: user,
Verbose: false,
}
err = w.runHooks(ctx, preWorkflowHooks, repoDir)
if err != nil {
log.Err("pre workflow hook run error results: %s", err)
}
}
func (w *DefaultPreWorkflowHooksCommandRunner) runHooks(
ctx models.PreWorkflowHookCommandContext,
preWorkflowHooks []*valid.PreWorkflowHook,
repoDir string,
) error {
for _, hook := range preWorkflowHooks {
_, err := w.PreWorkflowHookRunner.Run(ctx, hook.RunCommand, repoDir)
if err != nil {
return err
}
}
return nil
}
func (w *DefaultPreWorkflowHooksCommandRunner) buildLogger(repoFullName string, pullNum int) *logging.SimpleLogger {
src := fmt.Sprintf("%s#%d", repoFullName, pullNum)
return w.Logger.NewLogger(src, true, w.Logger.GetLevel())
}
// logPanics logs and creates a comment on the pull request for panics.
func (w *DefaultPreWorkflowHooksCommandRunner) 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 := w.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)
}
}
}