package main
import "encoding/json"
import "fmt"
import "io"
import "net/http"
import "os"
import "os/exec"
import "regexp"
import "strings"
var repoRegex = regexp.MustCompile(
`code\.oscarkilo\.com/([a-z][-a-z0-9]*)\.git`)
// detectRepo parses the git remote URL for the klee repo name.
func detectRepo() (string, error) {
cmd := exec.Command("git", "remote", "get-url", "origin")
out, err := cmd.Output()
if err != nil {
return "", fmt.Errorf(
"not a git repo or no remote 'origin': %v", err)
}
url := strings.TrimSpace(string(out))
m := repoRegex.FindStringSubmatch(url)
if m == nil {
return "", fmt.Errorf(
"remote URL %q is not a klee repo", url)
}
return m[1], nil
}
// resolveRepo returns the repo name from --repo flag,
// OKG_REPO env var, or git remote detection.
func resolveRepo(flagRepo string) (string, error) {
if flagRepo != "" {
return flagRepo, nil
}
if v := os.Getenv("OKG_REPO"); v != "" {
return v, nil
}
return detectRepo()
}
type Client struct {
Host string
ApiKey string
http *http.Client
}
func newClient(cfg *Config) *Client {
return &Client{
Host: cfg.Host,
ApiKey: cfg.ApiKey,
http: &http.Client{},
}
}
// do performs an HTTP request and returns the response.
func (c *Client) do(
method, path string, body io.Reader,
) (*http.Response, error) {
url := c.Host + path
req, err := http.NewRequest(method, url, body)
if err != nil {
return nil, err
}
req.Header.Set("Accept", "application/json")
if c.ApiKey != "" {
req.Header.Set(
"Authorization", "Bearer "+c.ApiKey)
}
if body != nil {
req.Header.Set("Content-Type", "application/json")
}
return c.http.Do(req)
}
// getJSON performs a GET and decodes JSON into dst.
func (c *Client) getJSON(path string, dst interface{}) error {
resp, err := c.do("GET", path, nil)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
body, _ := io.ReadAll(resp.Body)
return fmt.Errorf(
"HTTP %d: %s", resp.StatusCode, string(body))
}
return json.NewDecoder(resp.Body).Decode(dst)
}
// postJSON performs a POST with a JSON body,
// decodes the response into dst.
func (c *Client) postJSON(
path string, payload interface{}, dst interface{},
) error {
body, err := jsonBody(payload)
if err != nil {
return err
}
resp, err := c.do("POST", path, body)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
b, _ := io.ReadAll(resp.Body)
return fmt.Errorf(
"HTTP %d: %s", resp.StatusCode, string(b))
}
if dst != nil {
return json.NewDecoder(resp.Body).Decode(dst)
}
return nil
}
// patchJSON performs a PATCH with a JSON body,
// decodes the response into dst.
func (c *Client) patchJSON(
path string, payload interface{}, dst interface{},
) error {
body, err := jsonBody(payload)
if err != nil {
return err
}
resp, err := c.do("PATCH", path, body)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
b, _ := io.ReadAll(resp.Body)
return fmt.Errorf(
"HTTP %d: %s", resp.StatusCode, string(b))
}
if dst != nil {
return json.NewDecoder(resp.Body).Decode(dst)
}
return nil
}
func jsonBody(v interface{}) (io.Reader, error) {
data, err := json.Marshal(v)
if err != nil {
return nil, err
}
return strings.NewReader(string(data)), nil
}