refactor(ops/besadii): Generalise for use with non-TVL URLs
This makes it possible to use besadii for any TVL-ish setup using Gerrit and Buildkite, with the same hook functionality as for TVL. Change-Id: I1144b68d7ec01c4c8e34f7bee4da590f2ff8c53c
This commit is contained in:
parent
e48ae26e8e
commit
dcb2410982
1 changed files with 30 additions and 46 deletions
|
@ -26,7 +26,6 @@ import (
|
||||||
"path"
|
"path"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Regular expression to extract change ID out of a URL
|
// Regular expression to extract change ID out of a URL
|
||||||
|
@ -135,18 +134,18 @@ func loadConfig() (*config, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// updateGerrit posts a comment on a Gerrit CL to indicate the current build status.
|
// updateGerrit posts a comment on a Gerrit CL to indicate the current build status.
|
||||||
func updateGerrit(review reviewInput, changeId, patchset string) {
|
func updateGerrit(cfg *config, review reviewInput, changeId, patchset string) {
|
||||||
body, _ := json.Marshal(review)
|
body, _ := json.Marshal(review)
|
||||||
reader := ioutil.NopCloser(bytes.NewReader(body))
|
reader := ioutil.NopCloser(bytes.NewReader(body))
|
||||||
|
|
||||||
url := fmt.Sprintf("https://cl.tvl.fyi/a/changes/%s/revisions/%s/review", changeId, patchset)
|
url := fmt.Sprintf("%s/a/changes/%s/revisions/%s/review", cfg.GerritUrl, changeId, patchset)
|
||||||
req, err := http.NewRequest("POST", url, reader)
|
req, err := http.NewRequest("POST", url, reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "failed to create an HTTP request: %w", err)
|
fmt.Fprintf(os.Stderr, "failed to create an HTTP request: %w", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
req.SetBasicAuth("buildkite", gerritPassword())
|
req.SetBasicAuth(cfg.GerritUser, cfg.GerritPassword)
|
||||||
req.Header.Add("Content-Type", "application/json")
|
req.Header.Add("Content-Type", "application/json")
|
||||||
|
|
||||||
resp, err := http.DefaultClient.Do(req)
|
resp, err := http.DefaultClient.Do(req)
|
||||||
|
@ -159,12 +158,12 @@ func updateGerrit(review reviewInput, changeId, patchset string) {
|
||||||
respBody, _ := ioutil.ReadAll(resp.Body)
|
respBody, _ := ioutil.ReadAll(resp.Body)
|
||||||
fmt.Fprintf(os.Stderr, "received non-success response from Gerrit: %s (%v)", respBody, resp.Status)
|
fmt.Fprintf(os.Stderr, "received non-success response from Gerrit: %s (%v)", respBody, resp.Status)
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("Added CI status comment on https://cl.tvl.fyi/c/depot/+/%s/%s", changeId, patchset)
|
fmt.Printf("Added CI status comment on %s/c/%s/+/%s/%s", cfg.GerritUrl, cfg.Repository, changeId, patchset)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trigger a build of a given branch & commit on Buildkite
|
// Trigger a build of a given branch & commit on Buildkite
|
||||||
func triggerBuild(log *syslog.Writer, token string, trigger *buildTrigger) error {
|
func triggerBuild(cfg *config, log *syslog.Writer, trigger *buildTrigger) error {
|
||||||
env := make(map[string]string)
|
env := make(map[string]string)
|
||||||
|
|
||||||
// Pass information about the originating Gerrit change to the
|
// Pass information about the originating Gerrit change to the
|
||||||
|
@ -172,11 +171,11 @@ func triggerBuild(log *syslog.Writer, token string, trigger *buildTrigger) error
|
||||||
//
|
//
|
||||||
// This information is later used by besadii when invoked by Gerrit
|
// This information is later used by besadii when invoked by Gerrit
|
||||||
// to communicate the build status back to Gerrit.
|
// to communicate the build status back to Gerrit.
|
||||||
canonBuild := true
|
headBuild := true
|
||||||
if trigger.changeId != "" && trigger.patchset != "" {
|
if trigger.changeId != "" && trigger.patchset != "" {
|
||||||
env["GERRIT_CHANGE_ID"] = trigger.changeId
|
env["GERRIT_CHANGE_ID"] = trigger.changeId
|
||||||
env["GERRIT_PATCHSET"] = trigger.patchset
|
env["GERRIT_PATCHSET"] = trigger.patchset
|
||||||
canonBuild = false
|
headBuild = false
|
||||||
}
|
}
|
||||||
|
|
||||||
build := Build{
|
build := Build{
|
||||||
|
@ -191,12 +190,13 @@ func triggerBuild(log *syslog.Writer, token string, trigger *buildTrigger) error
|
||||||
body, _ := json.Marshal(build)
|
body, _ := json.Marshal(build)
|
||||||
reader := ioutil.NopCloser(bytes.NewReader(body))
|
reader := ioutil.NopCloser(bytes.NewReader(body))
|
||||||
|
|
||||||
req, err := http.NewRequest("POST", "https://api.buildkite.com/v2/organizations/tvl/pipelines/depot/builds", reader)
|
bkUrl := fmt.Sprintf("https://api.buildkite.com/v2/organizations/%s/pipelines/%s/builds", cfg.BuildkiteOrg, cfg.BuildkiteProject)
|
||||||
|
req, err := http.NewRequest("POST", bkUrl, reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create an HTTP request: %w", err)
|
return fmt.Errorf("failed to create an HTTP request: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
req.Header.Add("Authorization", "Bearer "+token)
|
req.Header.Add("Authorization", "Bearer "+cfg.BuildkiteToken)
|
||||||
req.Header.Add("Content-Type", "application/json")
|
req.Header.Add("Content-Type", "application/json")
|
||||||
|
|
||||||
resp, err := http.DefaultClient.Do(req)
|
resp, err := http.DefaultClient.Do(req)
|
||||||
|
@ -223,8 +223,8 @@ func triggerBuild(log *syslog.Writer, token string, trigger *buildTrigger) error
|
||||||
|
|
||||||
fmt.Fprintf(log, "triggered build for ref %q at commit %q: %s", trigger.ref, trigger.commit, buildResp.WebUrl)
|
fmt.Fprintf(log, "triggered build for ref %q at commit %q: %s", trigger.ref, trigger.commit, buildResp.WebUrl)
|
||||||
|
|
||||||
// For builds of canon there is nothing else to do
|
// For builds of the HEAD branch there is nothing else to do
|
||||||
if canonBuild {
|
if headBuild {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,7 +239,7 @@ func triggerBuild(log *syslog.Writer, token string, trigger *buildTrigger) error
|
||||||
// Do not update the attention set for this comment.
|
// Do not update the attention set for this comment.
|
||||||
IgnoreDefaultAttentionSetRules: true,
|
IgnoreDefaultAttentionSetRules: true,
|
||||||
}
|
}
|
||||||
updateGerrit(review, trigger.changeId, trigger.patchset)
|
updateGerrit(cfg, review, trigger.changeId, trigger.patchset)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -279,7 +279,7 @@ func ignoreFlags(ignore []string) {
|
||||||
// Extract the buildtrigger struct out of the flags passed to besadii
|
// Extract the buildtrigger struct out of the flags passed to besadii
|
||||||
// when invoked as Gerrit's 'patchset-created' hook. This hook is used
|
// when invoked as Gerrit's 'patchset-created' hook. This hook is used
|
||||||
// for triggering CI on in-progress CLs.
|
// for triggering CI on in-progress CLs.
|
||||||
func buildTriggerFromPatchsetCreated() (*buildTrigger, error) {
|
func buildTriggerFromPatchsetCreated(cfg *config) (*buildTrigger, error) {
|
||||||
// Information that needs to be returned
|
// Information that needs to be returned
|
||||||
var trigger buildTrigger
|
var trigger buildTrigger
|
||||||
|
|
||||||
|
@ -299,10 +299,10 @@ func buildTriggerFromPatchsetCreated() (*buildTrigger, error) {
|
||||||
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
// If the patchset is not for depot@canon then we can ignore it. It
|
// If the patchset is not for the HEAD branch of the monorepo, then
|
||||||
// might be some other kind of change (refs/meta/config or
|
// we can ignore it. It might be some other kind of change
|
||||||
// Gerrit-internal), but it is not an error.
|
// (refs/meta/config or Gerrit-internal), but it is not an error.
|
||||||
if trigger.project != "depot" || targetBranch != "canon" {
|
if trigger.project != cfg.Repository || targetBranch != cfg.Branch {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -323,8 +323,8 @@ func buildTriggerFromPatchsetCreated() (*buildTrigger, error) {
|
||||||
|
|
||||||
// Extract the buildtrigger struct out of the flags passed to besadii
|
// Extract the buildtrigger struct out of the flags passed to besadii
|
||||||
// when invoked as Gerrit's 'change-merged' hook. This hook is used
|
// when invoked as Gerrit's 'change-merged' hook. This hook is used
|
||||||
// for triggering canon builds after change submission.
|
// for triggering HEAD builds after change submission.
|
||||||
func buildTriggerFromChangeMerged() *buildTrigger {
|
func buildTriggerFromChangeMerged(cfg *config) *buildTrigger {
|
||||||
// Information that needs to be returned
|
// Information that needs to be returned
|
||||||
var trigger buildTrigger
|
var trigger buildTrigger
|
||||||
|
|
||||||
|
@ -341,12 +341,13 @@ func buildTriggerFromChangeMerged() *buildTrigger {
|
||||||
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
// Skip builds for anything other than depot@canon
|
// If the patchset is not for the HEAD branch of the monorepo, then
|
||||||
if trigger.project != "depot" || targetBranch != "canon" {
|
// we can ignore it.
|
||||||
|
if trigger.project != cfg.Repository || targetBranch != cfg.Branch {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
trigger.ref = "refs/heads/canon"
|
trigger.ref = "refs/heads/" + targetBranch
|
||||||
|
|
||||||
return &trigger
|
return &trigger
|
||||||
}
|
}
|
||||||
|
@ -357,14 +358,7 @@ func gerritHookMain(cfg *config, log *syslog.Writer, trigger *buildTrigger) {
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
buildkiteTokenBytes, err := ioutil.ReadFile("/etc/secrets/buildkite-besadii")
|
err := triggerBuild(cfg, log, trigger)
|
||||||
if err != nil {
|
|
||||||
log.Alert(fmt.Sprintf("buildkite token could not be read: %s", err))
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
buildkiteToken := strings.TrimSpace(string(buildkiteTokenBytes))
|
|
||||||
|
|
||||||
err = triggerBuild(log, buildkiteToken, trigger)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Err(fmt.Sprintf("failed to trigger Buildkite build: %s", err))
|
log.Err(fmt.Sprintf("failed to trigger Buildkite build: %s", err))
|
||||||
|
@ -378,17 +372,7 @@ func gerritHookMain(cfg *config, log *syslog.Writer, trigger *buildTrigger) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func gerritPassword() string {
|
func postCommandMain(cfg *config) {
|
||||||
gerritPassword, err := ioutil.ReadFile("/etc/secrets/buildkite-gerrit")
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "Gerrit password could not be read: %s", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
return string(gerritPassword)
|
|
||||||
}
|
|
||||||
|
|
||||||
func postCommandMain() {
|
|
||||||
changeId := os.Getenv("GERRIT_CHANGE_ID")
|
changeId := os.Getenv("GERRIT_CHANGE_ID")
|
||||||
patchset := os.Getenv("GERRIT_PATCHSET")
|
patchset := os.Getenv("GERRIT_PATCHSET")
|
||||||
|
|
||||||
|
@ -429,7 +413,7 @@ func postCommandMain() {
|
||||||
|
|
||||||
Tag: "autogenerated:buildkite~result",
|
Tag: "autogenerated:buildkite~result",
|
||||||
}
|
}
|
||||||
updateGerrit(review, changeId, patchset)
|
updateGerrit(cfg, review, changeId, patchset)
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
@ -452,17 +436,17 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if bin == "patchset-created" {
|
if bin == "patchset-created" {
|
||||||
trigger, err := buildTriggerFromPatchsetCreated()
|
trigger, err := buildTriggerFromPatchsetCreated(cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Crit("failed to parse 'patchset-created' invocation from args")
|
log.Crit("failed to parse 'patchset-created' invocation from args")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
gerritHookMain(cfg, log, trigger)
|
gerritHookMain(cfg, log, trigger)
|
||||||
} else if bin == "change-merged" {
|
} else if bin == "change-merged" {
|
||||||
trigger := buildTriggerFromChangeMerged()
|
trigger := buildTriggerFromChangeMerged(cfg)
|
||||||
gerritHookMain(cfg, log, trigger)
|
gerritHookMain(cfg, log, trigger)
|
||||||
} else if bin == "post-command" {
|
} else if bin == "post-command" {
|
||||||
postCommandMain()
|
postCommandMain(cfg)
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(os.Stderr, "besadii does not know how to be invoked as %q, sorry!", bin)
|
fmt.Fprintf(os.Stderr, "besadii does not know how to be invoked as %q, sorry!", bin)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
|
Loading…
Add table
Reference in a new issue