Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@

## Code quality

- [ ] Trim the `summary` struct to the fields actually used; `interface{}` should be `any`
- [ ] Print the overall status (`Status.Description`)
- [ ] Replace the if/else chain with a `switch` (staticcheck QF1003) covering
- [x] Trim the `summary` struct to the fields actually used; `interface{}` should be `any`
- [x] Print the overall status (`Status.Description`)
- [x] Replace the if/else chain with a `switch` (staticcheck QF1003) covering
`operational`, `degraded_performance`, `partial_outage`, `major_outage`,
`under_maintenance`
- [ ] Filter the "Visit www.githubstatus.com for more information" filler row
- [x] Filter the "Visit www.githubstatus.com for more information" filler row
- [x] Use `json.NewDecoder(resp.Body).Decode` instead of `io.ReadAll` + `Unmarshal`
- [ ] Use the readable URL `https://www.githubstatus.com/api/v2/summary.json`
- [x] Use the readable URL `https://www.githubstatus.com/api/v2/summary.json`
- [x] Add a package comment (revive)
- [ ] Exit non-zero when any component isn't operational

Expand Down
61 changes: 30 additions & 31 deletions github_status.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,35 +17,16 @@ import (

type summary struct {
Components []struct {
CreatedAt string `json:"created_at"`
Description string `json:"description"`
Group bool `json:"group"`
GroupID interface{} `json:"group_id"`
ID string `json:"id"`
Name string `json:"name"`
OnlyShowIfDegraded bool `json:"only_show_if_degraded"`
PageID string `json:"page_id"`
Position int64 `json:"position"`
Showcase bool `json:"showcase"`
Status string `json:"status"`
UpdatedAt string `json:"updated_at"`
Name string `json:"name"`
Status string `json:"status"`
Showcase bool `json:"showcase"`
} `json:"components"`
Incidents []interface{} `json:"incidents"`
Page struct {
ID string `json:"id"`
Name string `json:"name"`
TimeZone string `json:"time_zone"`
UpdatedAt string `json:"updated_at"`
URL string `json:"url"`
} `json:"page"`
ScheduledMaintenances []interface{} `json:"scheduled_maintenances"`
Status struct {
Status struct {
Description string `json:"description"`
Indicator string `json:"indicator"`
} `json:"status"`
}

const summaryURL = "https://kctbh9vrtdwd.statuspage.io/api/v2/summary.json"
const summaryURL = "https://www.githubstatus.com/api/v2/summary.json"

func main() {
s, err := fetch(summaryURL)
Expand Down Expand Up @@ -74,25 +55,43 @@ func fetch(url string) (summary, error) {
return s, nil
}

// render writes one line per component to w, with the status colorized.
// render writes the overall status followed by one line per component to w,
// with each component status colorized. Components not shown on the status
// page (showcase false) are skipped.
func render(w io.Writer, s summary) error {
if _, err := fmt.Fprintf(w, "%s\n\n", s.Status.Description); err != nil {
return err
}
for _, component := range s.Components {
c := color.New(color.FgYellow)
if component.Status == "operational" {
c = color.New(color.FgGreen)
} else if component.Status == "major_outage" {
c = color.New(color.FgRed)
if !component.Showcase {
continue
}
if _, err := fmt.Fprintf(w, "%-60s", component.Name); err != nil {
return err
}
if _, err := c.Fprintln(w, component.Status); err != nil {
if _, err := statusColor(component.Status).Fprintln(w, component.Status); err != nil {
return err
}
}
return nil
}

// statusColor returns the color used to display a component status.
func statusColor(status string) *color.Color {
switch status {
case "operational":
return color.New(color.FgGreen)
case "degraded_performance", "partial_outage":
return color.New(color.FgYellow)
case "major_outage":
return color.New(color.FgRed)
case "under_maintenance":
return color.New(color.FgBlue)
default:
return color.New(color.FgYellow)
}
}

func checkErr(err error) {
if err != nil {
fmt.Fprintln(os.Stderr, "error:", err)
Expand Down
25 changes: 22 additions & 3 deletions github_status_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ func TestFetch(t *testing.T) {
if err != nil {
t.Fatalf("fetch: %v", err)
}
if got := len(s.Components); got != 3 {
t.Fatalf("got %d components, want 3", got)
if got := len(s.Components); got != 4 {
t.Fatalf("got %d components, want 4", got)
}
if got := s.Status.Description; got != "Partial System Outage" {
t.Errorf("status description = %q", got)
Expand Down Expand Up @@ -90,11 +90,30 @@ func TestRender(t *testing.T) {
t.Fatal(err)
}

want := fmt.Sprintf("%-60s%s\n%-60s%s\n%-60s%s\n",
want := fmt.Sprintf("Partial System Outage\n\n%-60s%s\n%-60s%s\n%-60s%s\n",
"Git Operations", "operational",
"Actions", "major_outage",
"Pages", "degraded_performance")
if got := buf.String(); got != want {
t.Errorf("render output mismatch\ngot:\n%s\nwant:\n%s", got, want)
}
}

func TestStatusColor(t *testing.T) {
tests := []struct {
status string
want color.Attribute
}{
{"operational", color.FgGreen},
{"degraded_performance", color.FgYellow},
{"partial_outage", color.FgYellow},
{"major_outage", color.FgRed},
{"under_maintenance", color.FgBlue},
{"something_new", color.FgYellow},
}
for _, tt := range tests {
if !statusColor(tt.status).Equals(color.New(tt.want)) {
t.Errorf("statusColor(%q) is not %v", tt.status, tt.want)
}
}
}
7 changes: 4 additions & 3 deletions testdata/summary.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@
"updated_at": "2026-11-14T12:00:00.000Z"
},
"components": [
{"id": "1", "name": "Git Operations", "status": "operational", "group": false, "position": 1},
{"id": "2", "name": "Actions", "status": "major_outage", "group": false, "position": 2},
{"id": "3", "name": "Pages", "status": "degraded_performance", "group": false, "position": 3}
{"id": "1", "name": "Git Operations", "status": "operational", "showcase": true, "group": false, "position": 1},
{"id": "2", "name": "Actions", "status": "major_outage", "showcase": true, "group": false, "position": 2},
{"id": "3", "name": "Visit www.githubstatus.com for more information", "status": "operational", "showcase": false, "group": false, "position": 3},
{"id": "4", "name": "Pages", "status": "degraded_performance", "showcase": true, "group": false, "position": 4}
],
"incidents": [],
"scheduled_maintenances": [],
Expand Down
Loading