From 80c6680eda2afd2e9899f92d508d1b1907916756 Mon Sep 17 00:00:00 2001 From: Vincent Ambo Date: Thu, 13 Feb 2020 22:38:34 +0000 Subject: [PATCH 01/11] feat(ops/besadii): Refactored tool to trigger sourcehut builds Refactors //ops/sync-gcsr which was previously responsible for synchronising the git repository between GCSR and the git.tazj.in cgit instance to simply be responsible for triggering builds on sourcehut. This program is intended to run as a git post-update hook. Note: Not yet feature complete, as interpolation of concrete git values and also sourcehut secrets is missing. --- ops/besadii/default.nix | 8 ++ ops/besadii/main.go | 119 +++++++++++++++++++++ ops/sync-gcsr/default.nix | 14 --- ops/sync-gcsr/main.go | 202 ------------------------------------ ops/sync-gcsr/manifest.yaml | 23 ---- 5 files changed, 127 insertions(+), 239 deletions(-) create mode 100644 ops/besadii/default.nix create mode 100644 ops/besadii/main.go delete mode 100644 ops/sync-gcsr/default.nix delete mode 100644 ops/sync-gcsr/main.go delete mode 100644 ops/sync-gcsr/manifest.yaml diff --git a/ops/besadii/default.nix b/ops/besadii/default.nix new file mode 100644 index 000000000..fc7b2286c --- /dev/null +++ b/ops/besadii/default.nix @@ -0,0 +1,8 @@ +# This program is used as a git post-update hook to trigger builds on +# sourcehut. +{ depot, ... }: + +depot.buildGo.program { + name = "besadii"; + srcs = [ ./main.go ]; +} diff --git a/ops/besadii/main.go b/ops/besadii/main.go new file mode 100644 index 000000000..e9feadd95 --- /dev/null +++ b/ops/besadii/main.go @@ -0,0 +1,119 @@ +// Copyright 2019 Google LLC. +// SPDX-License-Identifier: Apache-2.0 +// +// besadii is a small CLI tool that triggers depot builds on +// builds.sr.ht +// +// It is designed to run as a post-update git hook on the server +// hosting the depot. +package main + +import ( + "bytes" + "encoding/json" + "fmt" + "io/ioutil" + "log" + "net/http" + "os" +) + +// Represents a builds.sr.ht build object as described on +// https://man.sr.ht/builds.sr.ht/api.md +type Build struct { + Manifest string `json:"manifest"` + Note string `json:"note"` + Tags []string `json:"tags"` +} + +// Represents a build trigger object as described on +type Trigger struct { + Action string `json:"action"` + Condition string `json:"condition"` + To string `json:"to"` +} + +// Represents a build manifest for sourcehut. +type Manifest struct { + Image string `json:"image"` + Sources []string `json:"sources"` + Secrets []string `json:"secrets"` + Tasks [](map[string]string) `json:"tasks"` + Triggers []Trigger `json:"triggers"` +} + +func prepareManifest(commit string) string { + m := Manifest{ + Image: "nixos/latest", + Sources: []string{"https://git.camden.tazj.in/"}, + + // secret for cachix/tazjin + Secrets: []string{"f7f02546-4d95-44f7-a98e-d61fdded8b5b"}, + + Tasks: [](map[string]string){ + {"setup": `# sourcehut does not censor secrets in builds, hence this hack: +echo -n 'export CACHIX_SIGNING_KEY=' >> ~/.buildenv +cat ~/.cachix-tazjin >> ~/.buildenv +nix-env -iA third_party.cachix -f git.tazj.in +cachix use tazjin +cd git.tazj.in +git checkout ` + commit}, + + {"build": `cd git.tazj.in +nix-build ci-builds.nix > built-paths`}, + + {"cache": `cd git.tazj.in +cat built-paths | cachix push tazjin`}, + }, + + Triggers: []Trigger{ + Trigger{Action: "email", Condition: "failure", To: "mail@tazj.in"}, + }, + } + + j, _ := json.Marshal(m) + return string(j) +} + +// Trigger a build of a given branch & commit on builds.sr.ht +func triggerBuild(branch, commit string) { + build := Build{ + Manifest: prepareManifest(commit), + Note: fmt.Sprintf("Build of 'master' at '%s'", commit), + Tags: []string{ + "depot", branch, + }, + } + + body, _ := json.Marshal(build) + reader := ioutil.NopCloser(bytes.NewReader(body)) + + req, err := http.NewRequest("POST", "https://builds.sr.ht/api/jobs", reader) + if err != nil { + log.Fatalln("[ERROR] failed to create an HTTP request:", err) + } + + req.Header.Add("Authorization", fmt.Sprintf("token %s", os.Getenv("SRHT_TOKEN"))) + req.Header.Add("Content-Type", "application/json") + + resp, err := http.DefaultClient.Do(req) + if err != nil { + // This might indicate a temporary error on the SourceHut side, do + // not fail the whole program. + log.Println("failed to send builds.sr.ht request:", err) + return + } + defer resp.Body.Close() + + if resp.StatusCode != 200 { + respBody, err := ioutil.ReadAll(resp.Body) + log.Printf("received non-success response from builds.sr.ht: %s (%v)[%s]", respBody, resp.Status, err) + } else { + log.Println("triggered builds.sr.ht job for commit", commit) + } +} + +func main() { + triggerBuild("master", "c5806a44a728d5a46878f54de7b695321a38559c") +} diff --git a/ops/sync-gcsr/default.nix b/ops/sync-gcsr/default.nix deleted file mode 100644 index ea5d0594a..000000000 --- a/ops/sync-gcsr/default.nix +++ /dev/null @@ -1,14 +0,0 @@ -{ depot, ... }: - -depot.nix.buildGo.program { - name = "sync-gcsr"; - srcs = [ ./main.go ]; - - deps = with depot.third_party; map (p: p.gopkg) [ - gopkgs."gopkg.in".src-d.go-git - ]; - - x_defs = { - "main.BuildManifest" = "${./manifest.yaml}"; - }; -} diff --git a/ops/sync-gcsr/main.go b/ops/sync-gcsr/main.go deleted file mode 100644 index 62c24a92c..000000000 --- a/ops/sync-gcsr/main.go +++ /dev/null @@ -1,202 +0,0 @@ -// Copyright 2019 Google LLC. -// SPDX-License-Identifier: Apache-2.0 -// -// sync-gcsr implements a small utility that periodically mirrors a -// remote Google Cloud Source Repository to a local file path. -// -// This utility is also responsible for triggering depot builds on -// builds.sr.ht if a change is detected on the master branch. -package main - -import ( - "encoding/json" - "fmt" - "io/ioutil" - "log" - "net/http" - "os" - "time" - "bytes" - - git "gopkg.in/src-d/go-git.v4" - "gopkg.in/src-d/go-git.v4/plumbing" - githttp "gopkg.in/src-d/go-git.v4/plumbing/transport/http" -) - -// Path to the build manifest, added by Nix at compile time. -var BuildManifest string - -// Represents a builds.sr.ht build object as described on -// https://man.sr.ht/builds.sr.ht/api.md -type Build struct { - Manifest string `json:"manifest"` - Note string `json:"note"` - Tags []string `json:"tags"` -} - -func EnvOr(key, def string) string { - v := os.Getenv(key) - if v == "" { - return def - } - - return v -} - -// Trigger a build of master on builds.sr.ht -func triggerBuild(commit string) { - manifest, err := ioutil.ReadFile(BuildManifest) - if err != nil { - log.Fatalln("[ERROR] failed to read sr.ht build manifest:", err) - } - - build := Build{ - Manifest: string(manifest), - Note: fmt.Sprintf("Build of 'master' at '%s'", commit), - Tags: []string{ - "depot", "master", - }, - } - - body, _ := json.Marshal(build) - reader := ioutil.NopCloser(bytes.NewReader(body)) - - req, err := http.NewRequest("POST", "https://builds.sr.ht/api/jobs", reader) - if err != nil { - log.Fatalln("[ERROR] failed to create an HTTP request:", err) - } - - req.Header.Add("Authorization", fmt.Sprintf("token %s", os.Getenv("SRHT_TOKEN"))) - req.Header.Add("Content-Type", "application/json") - - resp, err := http.DefaultClient.Do(req) - if err != nil { - // This might indicate a temporary error on the SourceHut side, do - // not fail the whole program. - log.Println("failed to send builds.sr.ht request:", err) - return - } - defer resp.Body.Close() - - if resp.StatusCode != 200 { - respBody, err := ioutil.ReadAll(resp.Body) - log.Printf("received non-success response from builds.sr.ht: %s (%v)[%s]", respBody, resp.Status, err) - } else { - log.Println("triggered builds.sr.ht job for commit", commit) - } -} - -// ensure that all remote branches exist locally & are up to date. -func updateBranches(auth *githttp.BasicAuth, repo *git.Repository) error { - origin, err := repo.Remote("origin") - if err != nil { - return err - } - - refs, err := origin.List(&git.ListOptions{ - Auth: auth, - }) - if err != nil { - return err - } - - for _, ref := range refs { - if !ref.Name().IsBranch() || ref.Type() != plumbing.HashReference { - continue - } - - name := plumbing.NewBranchReferenceName(ref.Name().Short()) - - if current, err := repo.Storer.Reference(name); err == nil { - // Determine whether the reference has changed to skip - // unnecessary modifications. - if current.Hash() == ref.Hash() { - continue - } - } - - branch := plumbing.NewHashReference(name, ref.Hash()) - - err := repo.Storer.SetReference(branch) - if err != nil { - return err - } - - if ref.Name().Short() == "master" { - go triggerBuild(ref.Hash().String()) - } - - log.Println("Updated branch", ref.Name().String()) - } - - return nil -} - -func updateRepo(auth *githttp.BasicAuth, repo *git.Repository, opts *git.FetchOptions) error { - err := repo.Fetch(opts) - - if err == git.NoErrAlreadyUpToDate { - // nothing to do ... - return nil - } else if err != nil { - return err - } - - log.Println("Fetched updates from remote, updating local branches") - return updateBranches(auth, repo) -} - -func cloneRepo(dest, project, repo string, auth *githttp.BasicAuth) (*git.Repository, error) { - var cloneOpts = git.CloneOptions{ - Auth: auth, - URL: fmt.Sprintf("https://source.developers.google.com/p/%s/r/%s", project, repo), - } - - handle, err := git.PlainClone(dest, true, &cloneOpts) - - if err == git.ErrRepositoryAlreadyExists { - handle, err = git.PlainOpen(dest) - } - - return handle, updateBranches(auth, handle) -} - -func main() { - dest := EnvOr("SYNC_DEST", "/git/depot") - project := EnvOr("SYNC_PROJECT", "tazjins-infrastructure") - repo := EnvOr("SYNC_REPO", "depot") - user := os.Getenv("SYNC_USER") - pass := os.Getenv("SYNC_PASS") - - log.Printf("Syncing repository '%s/%s' to destination '%s'", project, repo, dest) - - var auth *githttp.BasicAuth - if user != "" && pass != "" { - auth = &githttp.BasicAuth{ - Username: user, - Password: pass, - } - log.Println("Enabling basic authentication as user", user) - } - - handle, err := cloneRepo(dest, project, repo, auth) - - if err != nil { - log.Fatalf("Failed to clone repository: %s", err) - } else { - log.Println("Initiating update loop") - } - - fetchOpts := git.FetchOptions{ - Auth: auth, - Force: true, - } - - for { - if err = updateRepo(auth, handle, &fetchOpts); err != nil { - log.Fatalf("Failed to pull updated repository: %s", err) - } - - time.Sleep(10 * time.Second) - } -} diff --git a/ops/sync-gcsr/manifest.yaml b/ops/sync-gcsr/manifest.yaml deleted file mode 100644 index 3016c2ca5..000000000 --- a/ops/sync-gcsr/manifest.yaml +++ /dev/null @@ -1,23 +0,0 @@ -image: nixos/latest -sources: - - https://git.tazj.in/ -secrets: - # cachix/tazjin - - f7f02546-4d95-44f7-a98e-d61fdded8b5b -tasks: - - setup: | - # sourcehut does not censor secrets in builds, hence this hack: - echo -n 'export CACHIX_SIGNING_KEY=' > cachix-preamble - cat cachix-preamble ~/.cachix-tazjin >> ~/.buildenv - nix-env -iA third_party.cachix -f git.tazj.in - cachix use tazjin - - build: | - cd git.tazj.in - nix-build ci-builds.nix > built-paths - - cache: | - cd git.tazj.in - cat built-paths | cachix push tazjin -triggers: - - action: email - condition: failure - to: mail@tazj.in From 0a34810e274bb2ca3dc8764733ec23b6b878d5bc Mon Sep 17 00:00:00 2001 From: Vincent Ambo Date: Fri, 21 Feb 2020 22:06:56 +0000 Subject: [PATCH 02/11] chore(ops/besadii): Fail if sourcehut token is unset --- ops/besadii/main.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/ops/besadii/main.go b/ops/besadii/main.go index e9feadd95..c417cb0a1 100644 --- a/ops/besadii/main.go +++ b/ops/besadii/main.go @@ -94,12 +94,17 @@ func triggerBuild(branch, commit string) { log.Fatalln("[ERROR] failed to create an HTTP request:", err) } - req.Header.Add("Authorization", fmt.Sprintf("token %s", os.Getenv("SRHT_TOKEN"))) + token := fmt.Sprintf("token %s", os.Getenv("SRHT_TOKEN")) + if token == "" { + log.Fatalln("[ERROR] sourcehut token is not set") + } + + req.Header.Add("Authorization", ) req.Header.Add("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) if err != nil { - // This might indicate a temporary error on the SourceHut side, do + // This might indicate a temporary error on the sourcehut side, do // not fail the whole program. log.Println("failed to send builds.sr.ht request:", err) return From 5058f3928a13e73a72a86e685519ba8be7ca8714 Mon Sep 17 00:00:00 2001 From: Vincent Ambo Date: Fri, 21 Feb 2020 22:31:57 +0000 Subject: [PATCH 03/11] feat(ops/besadii): Read sourcehut token from secrets file on disk --- ops/besadii/main.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ops/besadii/main.go b/ops/besadii/main.go index c417cb0a1..4bb5c59a1 100644 --- a/ops/besadii/main.go +++ b/ops/besadii/main.go @@ -77,7 +77,7 @@ cat built-paths | cachix push tazjin`}, } // Trigger a build of a given branch & commit on builds.sr.ht -func triggerBuild(branch, commit string) { +func triggerBuild(token, branch, commit string) { build := Build{ Manifest: prepareManifest(commit), Note: fmt.Sprintf("Build of 'master' at '%s'", commit), @@ -94,12 +94,7 @@ func triggerBuild(branch, commit string) { log.Fatalln("[ERROR] failed to create an HTTP request:", err) } - token := fmt.Sprintf("token %s", os.Getenv("SRHT_TOKEN")) - if token == "" { - log.Fatalln("[ERROR] sourcehut token is not set") - } - - req.Header.Add("Authorization", ) + req.Header.Add("Authorization", token) req.Header.Add("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) @@ -121,4 +116,9 @@ func triggerBuild(branch, commit string) { func main() { triggerBuild("master", "c5806a44a728d5a46878f54de7b695321a38559c") + token, err := ioutil.ReadFile("/etc/secrets/srht-token") + if err != nil { + log.Fatalln("[ERROR] sourcehot token could not be read") + } + } From dcbe3d1f9b0c1a4720bd2b9170d302c8ba672f83 Mon Sep 17 00:00:00 2001 From: Vincent Ambo Date: Fri, 21 Feb 2020 22:32:23 +0000 Subject: [PATCH 04/11] feat(ops/besadii): Use post-receive hook input to trigger builds Parses the input passed to besadii from git to extract ref updates and trigger builds. --- ops/besadii/main.go | 50 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/ops/besadii/main.go b/ops/besadii/main.go index 4bb5c59a1..b09e1b929 100644 --- a/ops/besadii/main.go +++ b/ops/besadii/main.go @@ -9,6 +9,7 @@ package main import ( + "bufio" "bytes" "encoding/json" "fmt" @@ -16,8 +17,18 @@ import ( "log" "net/http" "os" + "strings" ) +// Represents an updated reference as passed to besadii by git +// +// https://git-scm.com/docs/githooks#pre-receive +type refUpdate struct { + name string + old string + new string +} + // Represents a builds.sr.ht build object as described on // https://man.sr.ht/builds.sr.ht/api.md type Build struct { @@ -110,15 +121,50 @@ func triggerBuild(token, branch, commit string) { respBody, err := ioutil.ReadAll(resp.Body) log.Printf("received non-success response from builds.sr.ht: %s (%v)[%s]", respBody, resp.Status, err) } else { - log.Println("triggered builds.sr.ht job for commit", commit) + log.Printf("triggered builds.sr.ht job for branch '%s' at commit '%s'", branch, commit) } } +func parseRefUpdates() ([]refUpdate, error) { + var updates []refUpdate + + scanner := bufio.NewScanner(os.Stdin) + for scanner.Scan() { + line := scanner.Text() + fragments := strings.Split(line, " ") + + if len(fragments) != 3 { + return nil, fmt.Errorf("invalid ref update: '%s'", line) + } + + updates = append(updates, refUpdate{ + old: fragments[0], + new: fragments[1], + name: fragments[2], + }) + } + + if err := scanner.Err(); err != nil { + return nil, err + } + + return updates, nil +} + func main() { - triggerBuild("master", "c5806a44a728d5a46878f54de7b695321a38559c") token, err := ioutil.ReadFile("/etc/secrets/srht-token") if err != nil { log.Fatalln("[ERROR] sourcehot token could not be read") } + updates, err := parseRefUpdates() + if err != nil { + log.Fatalln("[ERROR] could not parse updated refs:", err) + } + + log.Printf("triggering builds for %v refs", len(updates)) + + for _, update := range updates { + triggerBuild(string(token), update.name, update.new) + } } From 59d02771b52c36af62c2bdce034648600c338eda Mon Sep 17 00:00:00 2001 From: Vincent Ambo Date: Fri, 21 Feb 2020 22:46:34 +0000 Subject: [PATCH 05/11] refactor(ops/besadii): Log to syslog instead of stdout --- ops/besadii/main.go | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/ops/besadii/main.go b/ops/besadii/main.go index b09e1b929..34b33f9ca 100644 --- a/ops/besadii/main.go +++ b/ops/besadii/main.go @@ -14,7 +14,7 @@ import ( "encoding/json" "fmt" "io/ioutil" - "log" + "log/syslog" "net/http" "os" "strings" @@ -88,7 +88,7 @@ cat built-paths | cachix push tazjin`}, } // Trigger a build of a given branch & commit on builds.sr.ht -func triggerBuild(token, branch, commit string) { +func triggerBuild(log *syslog.Writer, token, branch, commit string) { build := Build{ Manifest: prepareManifest(commit), Note: fmt.Sprintf("Build of 'master' at '%s'", commit), @@ -102,7 +102,8 @@ func triggerBuild(token, branch, commit string) { req, err := http.NewRequest("POST", "https://builds.sr.ht/api/jobs", reader) if err != nil { - log.Fatalln("[ERROR] failed to create an HTTP request:", err) + log.Err(fmt.Sprintf("failed to create an HTTP request: %s", err)) + os.Exit(1) } req.Header.Add("Authorization", token) @@ -112,16 +113,16 @@ func triggerBuild(token, branch, commit string) { if err != nil { // This might indicate a temporary error on the sourcehut side, do // not fail the whole program. - log.Println("failed to send builds.sr.ht request:", err) + log.Err(fmt.Sprintf("failed to send builds.sr.ht request:", err)) return } defer resp.Body.Close() if resp.StatusCode != 200 { respBody, err := ioutil.ReadAll(resp.Body) - log.Printf("received non-success response from builds.sr.ht: %s (%v)[%s]", respBody, resp.Status, err) + log.Err(fmt.Sprintf("received non-success response from builds.sr.ht: %s (%v)[%s]", respBody, resp.Status, err)) } else { - log.Printf("triggered builds.sr.ht job for branch '%s' at commit '%s'", branch, commit) + fmt.Fprintf(log, "triggered builds.sr.ht job for branch '%s' at commit '%s'", branch, commit) } } @@ -152,19 +153,27 @@ func parseRefUpdates() ([]refUpdate, error) { } func main() { + log, err := syslog.New(syslog.LOG_INFO|syslog.LOG_USER, "besadii") + if err != nil { + fmt.Printf("failed to open syslog: %s\n", err) + os.Exit(1) + } + token, err := ioutil.ReadFile("/etc/secrets/srht-token") if err != nil { - log.Fatalln("[ERROR] sourcehot token could not be read") + log.Alert("sourcehot token could not be read") + os.Exit(1) } updates, err := parseRefUpdates() if err != nil { - log.Fatalln("[ERROR] could not parse updated refs:", err) + log.Err(fmt.Sprintf("could not parse updated refs:", err)) + os.Exit(1) } - log.Printf("triggering builds for %v refs", len(updates)) + fmt.Fprintf(log, "triggering builds for %v refs", len(updates)) for _, update := range updates { - triggerBuild(string(token), update.name, update.new) + triggerBuild(log, string(token), update.name, update.new) } } From 28563a747cbfe4483082450dc35ab87347e92d1a Mon Sep 17 00:00:00 2001 From: Vincent Ambo Date: Fri, 21 Feb 2020 22:48:08 +0000 Subject: [PATCH 06/11] chore(build): Build besadii in CI (ironic) --- ci-builds.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-builds.nix b/ci-builds.nix index 624f4893b..e9abcdb61 100644 --- a/ci-builds.nix +++ b/ci-builds.nix @@ -14,13 +14,13 @@ with (import ./default.nix {}); [ nix.buildLisp.example nix.yants.tests ops."posix_mq.rs" + ops.besadii ops.journaldriver ops.kms_pass ops.kontemplate ops.mq_cli ops.nixos.camdenSystem ops.nixos.nuggetSystem - ops.sync-gcsr third_party.cgit third_party.git third_party.guile From 8377fd48f51df43b2c2376b5be34d1d63e72185d Mon Sep 17 00:00:00 2001 From: Vincent Ambo Date: Fri, 21 Feb 2020 22:51:40 +0000 Subject: [PATCH 07/11] fix(ops/besadii): Send auth token in correct format --- ops/besadii/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ops/besadii/main.go b/ops/besadii/main.go index 34b33f9ca..438dd91f5 100644 --- a/ops/besadii/main.go +++ b/ops/besadii/main.go @@ -106,7 +106,7 @@ func triggerBuild(log *syslog.Writer, token, branch, commit string) { os.Exit(1) } - req.Header.Add("Authorization", token) + req.Header.Add("Authorization", "token " + token) req.Header.Add("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) From 21b76cb0238319c7fd58d7522fd42ca8c314ff8b Mon Sep 17 00:00:00 2001 From: Vincent Ambo Date: Fri, 21 Feb 2020 22:57:34 +0000 Subject: [PATCH 08/11] feat(ops/besadii): Run 'git update-server-info' at startup Since besadii is effectively the entire post-receive hook, it also needs to do the entire job of the hook. --- ops/besadii/main.go | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/ops/besadii/main.go b/ops/besadii/main.go index 438dd91f5..36e0b6e59 100644 --- a/ops/besadii/main.go +++ b/ops/besadii/main.go @@ -17,9 +17,12 @@ import ( "log/syslog" "net/http" "os" + "os/exec" "strings" ) +var gitBin = "git" + // Represents an updated reference as passed to besadii by git // // https://git-scm.com/docs/githooks#pre-receive @@ -106,7 +109,7 @@ func triggerBuild(log *syslog.Writer, token, branch, commit string) { os.Exit(1) } - req.Header.Add("Authorization", "token " + token) + req.Header.Add("Authorization", "token "+token) req.Header.Add("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) @@ -159,6 +162,15 @@ func main() { os.Exit(1) } + // Before triggering builds, it is important that git + // update-server-info is run so that cgit correctly serves the + // repository. + err := exec.Command(gitBin, "update-server-info").Run() + if err != nil { + log.Alert("failed to run 'git update-server-info' for depot!") + os.Exit() + } + token, err := ioutil.ReadFile("/etc/secrets/srht-token") if err != nil { log.Alert("sourcehot token could not be read") From c689df0dc721b766dfc4c0820238646a9e3fe815 Mon Sep 17 00:00:00 2001 From: Vincent Ambo Date: Fri, 21 Feb 2020 23:01:42 +0000 Subject: [PATCH 09/11] fix(ops/besadii): Replace slashes in branch names Submitting a build with a branch containing a slash (which is common for my branches) returns this error: Invalid tag name, tags must use lowercase alphanumeric characters, underscores, dashes, or dots This commit replaces all slashes with underscores to work around that. --- ops/besadii/main.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/ops/besadii/main.go b/ops/besadii/main.go index 36e0b6e59..0241eb844 100644 --- a/ops/besadii/main.go +++ b/ops/besadii/main.go @@ -96,7 +96,9 @@ func triggerBuild(log *syslog.Writer, token, branch, commit string) { Manifest: prepareManifest(commit), Note: fmt.Sprintf("Build of 'master' at '%s'", commit), Tags: []string{ - "depot", branch, + // my branch names tend to contain slashes, which are not valid + // identifiers in sourcehut. + "depot", strings.ReplaceAll(branch, "/", "_"), }, } @@ -122,8 +124,8 @@ func triggerBuild(log *syslog.Writer, token, branch, commit string) { defer resp.Body.Close() if resp.StatusCode != 200 { - respBody, err := ioutil.ReadAll(resp.Body) - log.Err(fmt.Sprintf("received non-success response from builds.sr.ht: %s (%v)[%s]", respBody, resp.Status, err)) + respBody, _ := ioutil.ReadAll(resp.Body) + log.Err(fmt.Sprintf("received non-success response from builds.sr.ht: %s (%v)", respBody, resp.Status)) } else { fmt.Fprintf(log, "triggered builds.sr.ht job for branch '%s' at commit '%s'", branch, commit) } @@ -165,10 +167,10 @@ func main() { // Before triggering builds, it is important that git // update-server-info is run so that cgit correctly serves the // repository. - err := exec.Command(gitBin, "update-server-info").Run() + err = exec.Command(gitBin, "update-server-info").Run() if err != nil { log.Alert("failed to run 'git update-server-info' for depot!") - os.Exit() + os.Exit(1) } token, err := ioutil.ReadFile("/etc/secrets/srht-token") From 8fe90430ee2bb00dd78587b9849b60e66c79680e Mon Sep 17 00:00:00 2001 From: Vincent Ambo Date: Fri, 21 Feb 2020 23:13:53 +0000 Subject: [PATCH 10/11] chore(ops/besadii): Pin git version used in besadii --- ops/besadii/default.nix | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ops/besadii/default.nix b/ops/besadii/default.nix index fc7b2286c..31f2705d7 100644 --- a/ops/besadii/default.nix +++ b/ops/besadii/default.nix @@ -5,4 +5,8 @@ depot.buildGo.program { name = "besadii"; srcs = [ ./main.go ]; + + x_defs = { + "main.gitBin" = "${depot.third_party.git}/bin/git"; + }; } From 5ed68f0f6b192cffb1bd4d1790360583d08018bb Mon Sep 17 00:00:00 2001 From: Vincent Ambo Date: Fri, 21 Feb 2020 23:16:28 +0000 Subject: [PATCH 11/11] fix(ops/besadii): Only trigger builds for branches --- ops/besadii/main.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ops/besadii/main.go b/ops/besadii/main.go index 0241eb844..460eddf26 100644 --- a/ops/besadii/main.go +++ b/ops/besadii/main.go @@ -143,10 +143,14 @@ func parseRefUpdates() ([]refUpdate, error) { return nil, fmt.Errorf("invalid ref update: '%s'", line) } + if !strings.HasPrefix(fragments[2], "refs/heads/") { + continue + } + updates = append(updates, refUpdate{ old: fragments[0], new: fragments[1], - name: fragments[2], + name: strings.TrimPrefix(fragments[2], "refs/heads/"), }) }