aboutsummaryrefslogtreecommitdiff
path: root/cmd
diff options
context:
space:
mode:
authorFranck Cuny <franck@fcuny.net>2024-03-20 19:00:15 -0700
committerFranck Cuny <franck@fcuny.net>2024-03-20 19:03:03 -0700
commit496ee376a75798f2a1af247e6934138cad0a84e2 (patch)
tree94528bf55ae2552ee47bd61cf35239c07b092d56 /cmd
parentchore: update flake (diff)
downloadinfra-496ee376a75798f2a1af247e6934138cad0a84e2.tar.gz
`ghalogs` get the logs of a GHA workflow run
Add a few internal packages to get the root of the git repository and to create clickable links in the terminal.
Diffstat (limited to 'cmd')
-rw-r--r--cmd/ghalogs/main.go139
1 files changed, 139 insertions, 0 deletions
diff --git a/cmd/ghalogs/main.go b/cmd/ghalogs/main.go
new file mode 100644
index 0000000..f4935f0
--- /dev/null
+++ b/cmd/ghalogs/main.go
@@ -0,0 +1,139 @@
+package main
+
+import (
+ "context"
+ "encoding/json"
+ "flag"
+ "fmt"
+ "net/http"
+ "os"
+ "strconv"
+ "text/tabwriter"
+ "time"
+
+ "github.com/fcuny/world/internal/git"
+ "github.com/fcuny/world/internal/terminal"
+ "github.com/fcuny/world/internal/version"
+)
+
+const API_URL = "https://api.github.com"
+
+const usage = `Usage:
+ gha-log
+`
+
+type githubActionRun struct {
+ Workflows []Workflow `json:"workflow_runs"`
+}
+
+type Workflow struct {
+ ID int `json:"id"`
+ Name string `json:"name"`
+ Title string `json:"display_title"`
+ Conclusion string `json:"conclusion"`
+ RunStartedAt time.Time `json:"run_started_at"`
+}
+
+type Unmarshaler interface {
+ UnmarshalJSON([]byte) error
+}
+
+func (w *Workflow) UnmarshalJSON(data []byte) error {
+ type Alias Workflow
+ aux := &struct {
+ RunStartedAt string `json:"run_started_at"`
+ *Alias
+ }{
+ Alias: (*Alias)(w),
+ }
+ if err := json.Unmarshal(data, &aux); err != nil {
+ return err
+ }
+ runStartedAt, err := time.Parse(time.RFC3339, aux.RunStartedAt)
+ if err != nil {
+ return err
+ }
+ w.RunStartedAt = runStartedAt
+ return nil
+}
+
+func main() {
+ flag.Usage = func() { fmt.Fprintf(os.Stderr, "%s\n", usage) }
+
+ var (
+ tokenFlag string
+ userFlag string
+ versionFlag bool
+ )
+ flag.StringVar(&tokenFlag, "token", "", "GitHub API token")
+ flag.StringVar(&tokenFlag, "t", "", "GitHub API token")
+ flag.StringVar(&userFlag, "user", "fcuny", "GitHub API token")
+ flag.StringVar(&userFlag, "u", "fcuny", "GitHub API token")
+ flag.BoolVar(&versionFlag, "version", false, "Print version information")
+ flag.BoolVar(&versionFlag, "v", false, "Print version information")
+
+ if versionFlag {
+ information := version.VersionAndBuildInfo()
+ fmt.Println(information)
+ return
+ }
+
+ flag.Parse()
+
+ if tokenFlag == "" {
+ fmt.Fprintf(os.Stderr, "The API token is not set\n")
+ os.Exit(1)
+ }
+
+ ctx := context.TODO()
+
+ repositoryName, err := git.Root()
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "could not get the repository name: %v\n", err)
+ os.Exit(1)
+ }
+
+ url := fmt.Sprintf("%s/repos/%s/%s/actions/runs", API_URL, userFlag, repositoryName)
+ req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "could not create a request: %v\n", err)
+ os.Exit(1)
+ }
+
+ req.Header.Set("Authorization", fmt.Sprintf("token %s", tokenFlag))
+ req.Header.Set("Accept", "application/vnd.github.v3+json")
+ req.Header.Set("X-GitHub-Api-Version", "2022-11-28")
+
+ client := http.Client{
+ Timeout: 30 * time.Second,
+ }
+
+ res, err := client.Do(req)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "error making http request: %s\n", err)
+ os.Exit(1)
+ }
+
+ if res.StatusCode != http.StatusOK {
+ fmt.Fprintf(os.Stderr, "unexpected status code: %d\n", res.StatusCode)
+ os.Exit(1)
+ }
+
+ var b githubActionRun
+ if err := json.NewDecoder(res.Body).Decode(&b); err != nil {
+ fmt.Fprintf(os.Stderr, "error parsing the JSON response: %v\n", err)
+ os.Exit(1)
+ }
+
+ w := tabwriter.NewWriter(os.Stdout, 0, 0, 1, ' ', tabwriter.Debug)
+ for _, run := range b.Workflows {
+ status := "✅"
+ if run.Conclusion != "success" {
+ status = "❌"
+ }
+
+ linkToAction := terminal.Link(strconv.Itoa(run.ID), fmt.Sprintf("http://github.com/%s/%s/actions/runs/%d/", userFlag, repositoryName, run.ID))
+ fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n", linkToAction, run.Name, run.RunStartedAt.Format("2006-01-02 15:04:05"), run.Title, status)
+ }
+ w.Flush()
+}