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