From a1372f1d5561a5a5072f9ceffc541085c5e7ce39 Mon Sep 17 00:00:00 2001 From: Christian Weichel Date: Wed, 23 Jun 2021 18:06:06 +0000 Subject: [PATCH] [github-integration] Add /werft run annotations --- plugins/github-integration/go.mod | 1 + plugins/github-integration/main.go | 101 +++++++++++++++++------- plugins/github-integration/main_test.go | 43 ++++++++++ 3 files changed, 116 insertions(+), 29 deletions(-) create mode 100644 plugins/github-integration/main_test.go diff --git a/plugins/github-integration/go.mod b/plugins/github-integration/go.mod index b88efb1..e0979a5 100644 --- a/plugins/github-integration/go.mod +++ b/plugins/github-integration/go.mod @@ -7,6 +7,7 @@ replace github.com/csweichel/werft => ../.. require ( github.com/bradleyfalzon/ghinstallation v1.1.1 github.com/csweichel/werft v0.0.0-00010101000000-000000000000 + github.com/google/go-cmp v0.5.2 // indirect github.com/google/go-github/v35 v35.2.0 github.com/sirupsen/logrus v1.8.1 ) diff --git a/plugins/github-integration/main.go b/plugins/github-integration/main.go index 8371c25..f7b3454 100644 --- a/plugins/github-integration/main.go +++ b/plugins/github-integration/main.go @@ -370,11 +370,6 @@ func (p *githubTriggerPlugin) processIssueCommentEvent(ctx context.Context, even feedback.Message = "cannot find corresponding PR" return } - segs = strings.Split(pr.GetHead().GetRepo().GetFullName(), "/") - var ( - prSrcOwner = segs[0] - prSrcRepo = segs[1] - ) var ( sender = event.GetSender().GetLogin() @@ -409,27 +404,67 @@ func (p *githubTriggerPlugin) processIssueCommentEvent(ctx context.Context, even return } - var run bool lines := strings.Split(event.GetComment().GetBody(), "\n") for _, l := range lines { - l = strings.TrimSpace(l) - if !strings.HasPrefix(l, "/werft") { + cmd, args, err := parseCommand(l) + if err != nil { + feedback.Success = false + feedback.Message = fmt.Sprintf("cannot parse %s: %v", l, err) + continue + } + if cmd == "" { continue } - l = strings.TrimPrefix(l, "/werft") - l = strings.TrimSpace(l) - fmt.Println(l) - if l == "run" { - run = true - break - } else { + var resp string + switch cmd { + case "run": + resp, err = p.handleCommandRun(ctx, event, pr, args) + default: + err = fmt.Errorf("unknown command: %s", cmd) + } + if err != nil { + log.WithError(err).Warn("GitHub webhook error") feedback.Success = false - feedback.Message = fmt.Sprintf("unknown command `%s` - only `run` is supported", l) + feedback.Message = err.Error() + return } + + feedback.Success = true + feedback.Message = resp } - if !run { - return +} + +func (p *githubTriggerPlugin) handleCommandRun(ctx context.Context, event *github.IssueCommentEvent, pr *github.PullRequest, args []string) (msg string, err error) { + segs := strings.Split(pr.GetHead().GetRepo().GetFullName(), "/") + var ( + prSrcOwner = segs[0] + prSrcRepo = segs[1] + ) + segs = strings.Split(event.GetRepo().GetFullName(), "/") + var ( + prDstOwner = segs[0] + prDstRepo = segs[1] + ) + + argm := make(map[string]string) + for _, arg := range args { + var key, value string + if segs := strings.Split(arg, "="); len(segs) == 1 { + key = arg + } else { + key, value = segs[0], strings.Join(segs[1:], "=") + } + argm[key] = value + } + argm[annotationStatusUpdate] = prDstOwner + "/" + prDstRepo + + annotations := make([]*v1.Annotation, 0, len(argm)) + for k, v := range argm { + annotations = append(annotations, &v1.Annotation{ + Key: k, + Value: v, + }) } ref := pr.GetHead().GetRef() @@ -446,13 +481,8 @@ func (p *githubTriggerPlugin) processIssueCommentEvent(ctx context.Context, even Ref: ref, Revision: pr.GetHead().GetSHA(), }, - Trigger: v1.JobTrigger_TRIGGER_MANUAL, - Annotations: []*v1.Annotation{ - { - Key: annotationStatusUpdate, - Value: prDstOwner + "/" + prDstRepo, - }, - }, + Trigger: v1.JobTrigger_TRIGGER_MANUAL, + Annotations: annotations, } var nameSuffix string if prDstOwner != prSrcOwner { @@ -464,11 +494,24 @@ func (p *githubTriggerPlugin) processIssueCommentEvent(ctx context.Context, even }) if err != nil { log.WithError(err).Warn("GitHub webhook error") - feedback.Success = false - feedback.Message = "cannot start job - please talk to whoever's in charge of your Werft installation" + return "", fmt.Errorf("cannot start job - please talk to whoever's in charge of your Werft installation") + } + + return fmt.Sprintf("started the job as [%s](%s/job/%s)", resp.Status.Name, p.Config.BaseURL, resp.Status.Name), nil +} + +func parseCommand(l string) (cmd string, args []string, err error) { + l = strings.TrimSpace(l) + if !strings.HasPrefix(l, "/werft") { return } + l = strings.TrimPrefix(l, "/werft") + l = strings.TrimSpace(l) + + segs := strings.Fields(l) + if len(segs) < 1 { + return "", nil, fmt.Errorf("missing command") + } - feedback.Success = true - feedback.Message = fmt.Sprintf("started the job as [%s](%s/job/%s)", resp.Status.Name, p.Config.BaseURL, resp.Status.Name) + return segs[0], segs[1:], nil } diff --git a/plugins/github-integration/main_test.go b/plugins/github-integration/main_test.go new file mode 100644 index 0000000..32a3817 --- /dev/null +++ b/plugins/github-integration/main_test.go @@ -0,0 +1,43 @@ +package main + +import ( + "testing" + + "github.com/google/go-cmp/cmp" +) + +func TestParseCommand(t *testing.T) { + type Expectation struct { + Cmd string + Args []string + Err string + } + tests := []struct { + Name string + Input string + Expectation Expectation + }{ + {Name: "empty line", Input: ""}, + {Name: "ignore line", Input: "something\nsomethingelse"}, + {Name: "no command", Input: "/werft", Expectation: Expectation{Err: "missing command"}}, + {Name: "no arg", Input: "/werft foo", Expectation: Expectation{Cmd: "foo", Args: []string{}}}, + {Name: "one arg", Input: "/werft foo bar", Expectation: Expectation{Cmd: "foo", Args: []string{"bar"}}}, + {Name: "two args", Input: "/werft foo bar=baz something", Expectation: Expectation{Cmd: "foo", Args: []string{"bar=baz", "something"}}}, + } + for _, test := range tests { + t.Run(test.Name, func(t *testing.T) { + var ( + act Expectation + err error + ) + act.Cmd, act.Args, err = parseCommand(test.Input) + if err != nil { + act.Err = err.Error() + } + + if diff := cmp.Diff(test.Expectation, act); diff != "" { + t.Errorf("MakeGatewayInfo() mismatch (-want +got):\n%s", diff) + } + }) + } +}