package main import ( "encoding/json" "flag" "fmt" "github.com/go-ini/ini" "io/ioutil" "net/http" "net/url" "os" "strconv" "strings" ) type jwt struct { Scope string Access_token string } type projects struct { Projects []project } type project struct { Project string } type builds struct { Builds []build } type build struct { Project string Build_id string Status string Exit_code int } type config struct { idp string id string secret string } func main() { var config string flag.StringVar(&config, "config", "", "what config file to read?") flag.Parse() if config == "" { fmt.Fprintf(os.Stderr, "MUST give config file\n") os.Exit(1) } cfg, err := get_creds(config) if err != nil { os.Exit(1) } token, err := get_access_token(cfg) if err != nil { os.Exit(1) } // fmt.Fprintf(os.Stdout, "%s\n", token) projects, err := get_projects(cfg, token) if err != nil { os.Exit(1) } builds, err := get_builds(cfg, token) if err != nil { os.Exit(1) } for _, p := range projects.Projects { status := get_status(p.Project, builds) if status != "done" { fmt.Printf("%-40s %s\n", p.Project, status) } } } func NewConfig(idp string, id string, secret string) *config { new := config{idp: idp, id: id, secret: secret} return &new } func get_creds(filename string) (*config, error) { cfg, err := ini.Load(filename) if err != nil { fmt.Fprintf(os.Stderr, "reading config %s: %v\n", filename, err) return nil, err } idp := cfg.Section("").Key("idp").String() id := cfg.Section("").Key("id").String() secret := cfg.Section("").Key("secret").String() return NewConfig(idp, id, secret), nil } func get_access_token(cfg *config) (string, error) { data := url.Values{} data.Add("grant_type", "client_credentials") data.Add("scope", "uapi_projects_get uapi_builds_get") url := fmt.Sprintf("%s/token", cfg.idp) client := &http.Client{} req, err := http.NewRequest("POST", url, strings.NewReader(data.Encode())) req.SetBasicAuth(cfg.id, cfg.secret) req.Header.Add("Content-Type", "application/x-www-form-urlencoded") req.Header.Add("Content-Length", strconv.Itoa(len(data.Encode()))) resp, err := client.Do(req) if err != nil { fmt.Fprintf(os.Stderr, "POST %s: %v\n", cfg.idp, err) return "", err } bodyText, err := ioutil.ReadAll(resp.Body) if err != nil { fmt.Fprintf(os.Stderr, "reading HTTP response: %v\n", err) return "", err } s := string(bodyText) res := jwt{} json.Unmarshal([]byte(s), &res) return res.Access_token, nil } func get_projects(cfg *config, token string) (*projects, error) { url := fmt.Sprintf("%s/projects", cfg.idp) body, err := get_raw(url, token) if err != nil { return nil, err } res := projects{} json.Unmarshal(body, &res) return &res, nil } func get_builds(cfg *config, token string) (*builds, error) { url := fmt.Sprintf("%s/builds", cfg.idp) body, err := get_raw(url, token) if err != nil { return nil, err } res := builds{} json.Unmarshal(body, &res) return &res, nil } func get_raw(url string, token string) ([]byte, error) { client := &http.Client{} req, err := http.NewRequest("GET", url, nil) req.Header.Add("Authorization", fmt.Sprintf("bearer %s", token)) resp, err := client.Do(req) if err != nil { fmt.Fprintf(os.Stderr, "GET %s: %v\n", url, err) return nil, err } body, err := ioutil.ReadAll(resp.Body) if err != nil { fmt.Fprintf(os.Stderr, "reading HTTP response: %v\n", err) return nil, err } return body, nil } func get_status(project string, builds *builds) string { var status string status = "unknown" for _, b := range builds.Builds { if b.Project == project { status = b.Status } } return status }