/
stream_worker.go
132 lines (115 loc) · 4.29 KB
/
stream_worker.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
package hooks
import (
"context"
"errors"
"fmt"
gogithub "github.com/google/go-github/v49/github"
"github.com/rs/zerolog/log"
"github.com/zapier/tfbuddy/pkg/allow_list"
"github.com/zapier/tfbuddy/pkg/comment_actions"
"github.com/zapier/tfbuddy/pkg/tfc_trigger"
"github.com/zapier/tfbuddy/pkg/utils"
"github.com/zapier/tfbuddy/pkg/vcs/github"
"go.opentelemetry.io/otel"
)
func (h *GithubHooksHandler) processIssueCommentEvent(msg *GithubIssueCommentEventMsg) error {
ctx, span := otel.Tracer("hooks").Start(msg.Context, "processIssueCommentEvent")
defer span.End()
var commentErr error
defer func() {
if r := recover(); r != nil {
log.Error().Msgf("Unrecoverable error in issue comment event processing %v", r)
commentErr = nil
}
}()
commentErr = h.processIssueComment(ctx, msg)
return utils.EmitPermanentError(commentErr, func(err error) {
log.Error().Msgf("got a permanent error attempting to process comment event: %s", err.Error())
})
}
func (h *GithubHooksHandler) processIssueComment(ctx context.Context, msg *GithubIssueCommentEventMsg) error {
ctx, span := otel.Tracer("hooks").Start(ctx, "processIssueComment")
defer span.End()
if msg == nil || msg.Payload == nil {
return errors.New("msg is nil")
}
event := msg.Payload
// Check if fullName is allowed
log.Debug().Str("repo", *event.Repo.FullName).Msg("processIssueCommentEvent")
fullName := event.Repo.FullName
if !allow_list.IsGithubRepoAllowed(*fullName) {
return nil
}
// Parse comment
opts, err := comment_actions.ParseCommentCommand(*event.Comment.Body)
if err != nil {
if err == comment_actions.ErrOtherTFTool {
h.postPullRequestComment(ctx, event, "Use 'tfc' to interact with TFBuddy")
}
if err == comment_actions.ErrNotTFCCommand || err == comment_actions.ErrOtherTFTool {
githubWebHookIgnored.WithLabelValues(
"issue_comment_created",
*fullName,
"not-tfc-command",
).Inc()
return nil
}
return err
}
pr, err := h.vcs.GetMergeRequest(ctx, *event.Issue.Number, event.GetRepo().GetFullName())
if err != nil {
log.Error().Err(err).Msg("could not process GitHub IssueCommentEvent")
return err
}
pullReq := pr.(*github.GithubPR)
opts.TriggerOpts.Branch = pr.GetSourceBranch()
opts.TriggerOpts.CommitSHA = pullReq.GetBase().GetSHA()
opts.TriggerOpts.ProjectNameWithNamespace = event.GetRepo().GetFullName()
opts.TriggerOpts.MergeRequestIID = *event.Issue.Number
opts.TriggerOpts.TriggerSource = tfc_trigger.CommentTrigger
opts.TriggerOpts.VcsProvider = "github"
cfg, err := tfc_trigger.NewTFCTriggerConfig(opts.TriggerOpts)
if err != nil {
log.Error().Err(err).Msg("could not create TFCTriggerConfig")
return err
}
trigger := h.triggerCreation(h.vcs, h.tfc, h.runstream, cfg)
//// TODO: support additional commands and arguments (e.g. destroy, refresh, lock, unlock)
//// TODO: this should be refactored and be agnostic to the VCS type
switch opts.Args.Command {
case "apply":
log.Info().Msg("Got TFC apply command")
if !pullReq.IsApproved() {
h.postPullRequestComment(ctx, event, ":no_entry: Apply failed. Pull Request requires approval.")
return nil
}
if pullReq.HasConflicts() {
h.postPullRequestComment(ctx, event, ":no_entry: Apply failed. Pull Request has conflicts that need to be resolved.")
return nil
}
case "lock":
log.Info().Msg("Got TFC lock command")
case "plan":
log.Info().Msg("Got TFC plan command")
case "unlock":
log.Info().Msg("Got TFC unlock command")
default:
return fmt.Errorf("could not parse command")
}
executedWorkspaces, tfError := trigger.TriggerTFCEvents(ctx)
if tfError == nil && len(executedWorkspaces.Errored) > 0 {
for _, failedWS := range executedWorkspaces.Errored {
h.postPullRequestComment(ctx, event, fmt.Sprintf(":no_entry: %s could not be run because: %s", failedWS.Name, failedWS.Error))
}
return nil
}
return tfError
}
func (h *GithubHooksHandler) postPullRequestComment(ctx context.Context, event *gogithub.IssueCommentEvent, body string) error {
ctx, span := otel.Tracer("hooks").Start(ctx, "postPullRequestComment")
defer span.End()
log.Debug().Msg("postPullRequestComment")
prID := event.GetIssue().GetNumber()
log.Debug().Str("repo", event.GetRepo().GetFullName()).Int("PR", prID).Msg("postPullRequestComment")
return h.vcs.CreateMergeRequestComment(ctx, prID, event.GetRepo().GetFullName(), body)
}