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
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,7 @@

# Output of the go coverage tool, specifically when used with LiteIDE
*.out

# Build output
/github_status
/dist/
34 changes: 0 additions & 34 deletions Jenkinsfile

This file was deleted.

4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build:
check:
golangci-lint run

release:
snapshot:
goreleaser release --snapshot --clean

.PHONY: build check release
.PHONY: build check snapshot
55 changes: 54 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,57 @@
# github_status
GitHub Status

![example workflow](https://github.com/mikemadden42/github_status/actions/workflows/go.yml/badge.svg)

Print the current status of each GitHub component, from
[githubstatus.com](https://www.githubstatus.com).

## Install

```sh
go install github.com/mikemadden42/github_status@latest
```

## Usage

```sh
github_status
```

```
All Systems Operational

Git Operations operational
Webhooks operational
API Requests operational
Issues operational
Pull Requests operational
Actions operational
Packages operational
Pages operational
Copilot operational
Codespaces operational
Copilot AI Model Providers operational
```

Statuses are colored: green for operational, yellow for degraded performance or
partial outage, red for major outage and blue for maintenance.

### Scripting

With `-check`, `github_status` exits with status 1 if any component is not
operational:

```sh
github_status -check || echo "GitHub is having problems"
```

It also exits with status 1 if the status page can't be reached.

## Development

```sh
go test ./...
make check # golangci-lint
make build # goreleaser snapshot build into dist/
make snapshot # full goreleaser snapshot release (local only, nothing is published)
```
10 changes: 5 additions & 5 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
- [x] Use `json.NewDecoder(resp.Body).Decode` instead of `io.ReadAll` + `Unmarshal`
- [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
- [x] Exit non-zero when any component isn't operational (with `-check`)

## Tests / CI

Expand All @@ -45,7 +45,7 @@

## Housekeeping

- [ ] Delete the Jenkinsfile unless Jenkins is in use (build-only, no tests, echo-only post blocks)
- [ ] `make release` uses `--snapshot`, so it never publishes. Rename the target or drop the flag
- [ ] Add `dist/` and `github_status` to `.gitignore`
- [ ] Expand the README with usage, install and example output
- [x] Delete the Jenkinsfile unless Jenkins is in use (build-only, no tests, echo-only post blocks)
- [x] `make release` uses `--snapshot`, so it never publishes. Renamed to `make snapshot`
- [x] Add `dist/` and `github_status` to `.gitignore`
- [x] Expand the README with usage, install and example output
19 changes: 19 additions & 0 deletions github_status.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package main

import (
"encoding/json"
"flag"
"fmt"
"io"
"net/http"
Expand All @@ -29,9 +30,16 @@ type summary struct {
const summaryURL = "https://www.githubstatus.com/api/v2/summary.json"

func main() {
check := flag.Bool("check", false, "exit with status 1 if any component is not operational")
flag.Parse()

s, err := fetch(summaryURL)
checkErr(err)
checkErr(render(os.Stdout, s))

if *check && !operational(s) {
os.Exit(1)
}
}

// fetch retrieves and decodes the status page summary at url.
Expand Down Expand Up @@ -76,6 +84,17 @@ func render(w io.Writer, s summary) error {
return nil
}

// operational reports whether every component shown on the status page is
// operational.
func operational(s summary) bool {
for _, component := range s.Components {
if component.Showcase && component.Status != "operational" {
return false
}
}
return true
}

// statusColor returns the color used to display a component status.
func statusColor(status string) *color.Color {
switch status {
Expand Down
22 changes: 22 additions & 0 deletions github_status_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,3 +117,25 @@ func TestStatusColor(t *testing.T) {
}
}
}

func TestOperational(t *testing.T) {
s, err := fetch(serveFixture(t).URL)
if err != nil {
t.Fatal(err)
}
if operational(s) {
t.Error("fixture has an outage, want operational false")
}

for i := range s.Components {
s.Components[i].Status = "operational"
}
if !operational(s) {
t.Error("all components operational, want operational true")
}

s.Components[2].Status = "major_outage" // the non-showcase filler row
if !operational(s) {
t.Error("only a non-showcase component is down, want operational true")
}
}
Loading