about summary refs log tree commit diff
path: root/tools/gerrit-hook/buildkite.go
diff options
context:
space:
mode:
authorFranck Cuny <franck@fcuny.net>2022-05-30 13:32:43 -0700
committerFranck Cuny <franck@fcuny.net>2022-06-04 15:25:46 -0700
commit83a38a6da9ef99bc6596f6cfb53395a89f0165c7 (patch)
treec808d9dd826757c440f1632fd758503f563c0403 /tools/gerrit-hook/buildkite.go
parentmeta: remove pre-commit checks (diff)
downloadworld-83a38a6da9ef99bc6596f6cfb53395a89f0165c7.tar.gz
feat(gerrit-hook): a small tool to act as a dispatcher for gerrit
When a patchset is created, gerrit will call this tool with a number of
arguments.

This hook triggers a build with buildKite for the given patchset, and
add a comment to gerrit with a link to the build.

We do not wait for the build to be successful to update gerrit. This
will be done by another hook which the buildKite agents will call once
they are done with the build.

Change-Id: Iaa221765f3c52875ec37c5d282ba0557291eb5a4
Reviewed-on: https://cl.fcuny.net/c/world/+/171
Reviewed-by: Franck Cuny <franck@fcuny.net>
Diffstat (limited to '')
-rw-r--r--tools/gerrit-hook/buildkite.go81
1 files changed, 81 insertions, 0 deletions
diff --git a/tools/gerrit-hook/buildkite.go b/tools/gerrit-hook/buildkite.go
new file mode 100644
index 0000000..d8723b6
--- /dev/null
+++ b/tools/gerrit-hook/buildkite.go
@@ -0,0 +1,81 @@
+package main
+
+import (
+	"bytes"
+	"context"
+	"encoding/json"
+	"fmt"
+	"io/ioutil"
+	"log/syslog"
+	"net/http"
+	"time"
+)
+
+// https://buildkite.com/docs/apis/rest-api/builds#create-a-Build
+type Build struct {
+	Commit string `json:"commit"`
+	Branch string `json:"branch"`
+}
+
+type buildResponse struct {
+	WebUrl string `json:"web_url"`
+}
+
+func triggerBuild(cfg *config, log *syslog.Writer, trigger *buildTrigger) error {
+	b := Build{
+		Commit: trigger.commit,
+		Branch: trigger.ref,
+	}
+
+	body, _ := json.Marshal(b)
+	reader := ioutil.NopCloser(bytes.NewReader(body))
+
+	bkUrl := fmt.Sprintf("https://api.buildkite.com/v2/organizations/%s/pipelines/%s/builds", cfg.BuildKiteOrganization, trigger.project)
+	req, err := http.NewRequest("POST", bkUrl, reader)
+	if err != nil {
+		return fmt.Errorf("failed to create an HTTP request: %v", err)
+	}
+
+	req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", cfg.BuildKiteToken))
+	req.Header.Add("Content-Type", "application/json")
+
+	// Let's budget this to 10 seconds maximum, this should be more
+	// than enough, as we're only triggering the build, we're not
+	// waiting on the status of the build
+	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
+	defer cancel()
+
+	resp, err := http.DefaultClient.Do(req.WithContext(ctx))
+	if err != nil {
+		return fmt.Errorf("failed to send buildKite request: %v", err)
+	}
+	defer resp.Body.Close()
+
+	respBody, err := ioutil.ReadAll(resp.Body)
+	if err != nil {
+		return fmt.Errorf("failed to parse buildKite response: %v", err)
+	}
+
+	if resp.StatusCode != http.StatusCreated {
+		return fmt.Errorf("received a non-success response from buildKite: %s (%v)", respBody, resp.Status)
+	}
+
+	var buildResp buildResponse
+	err = json.Unmarshal(respBody, &buildResp)
+	if err != nil {
+		return fmt.Errorf("failed to unmarshal build response: %v", err)
+	}
+
+	// Report the status back to the Gerrit CL so that users can click
+	// through to the running build.
+	msg := fmt.Sprintf("started build for patchset #%s on: %s", trigger.patchset, buildResp.WebUrl)
+	review := reviewInput{
+		Message:                        msg,
+		OmitDuplicateComments:          true,
+		Tag:                            "autogenerated:buildkite~trigger",
+		IgnoreDefaultAttentionSetRules: true,
+		Notify:                         "NONE",
+	}
+	updateGerrit(cfg, review, trigger.changeId, trigger.patchset)
+	return nil
+}