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() }