// Copyright (C) 2019 Marius Schellenberger package main import ( "bytes" "encoding/json" "errors" "fmt" "net/http" "net/url" "strings" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1" ) const ( contentType = "Content-Type" jsonType = "application/json" secretName = "git-auth" ) type Git struct { sec typedcorev1.SecretInterface cl *http.Client } func (g *Git) getSecret(host string) (username, password string, err error) { sec, err := g.sec.Get(secretName, metav1.GetOptions{}) if err != nil { return } s, ok := sec.Data[host] if !ok { err = fmt.Errorf("no key found for host %s in secret %s/%s", host, sec.Namespace, sec.Name) return } a := strings.SplitN(string(s), ":", 2) if len(a) < 2 { err = fmt.Errorf("missing credentials for host %s in secret %s/%s", host, sec.Namespace, sec.Name) return } username = a[0] password = a[1] return } func (g *Git) send(req *http.Request) (*http.Response, error) { user, pass, err := g.getSecret(req.URL.Host) if err != nil { return nil, err } req.SetBasicAuth(user, pass) req.Header.Set(contentType, jsonType) return g.cl.Do(req) } func (g *Git) getPullRequest(repo Repository, api, id string) (pr PullRequest, err error) { u, err := url.Parse(repo.CloneURL) if err != nil { return } u.Path = strings.Join([]string{api, "repos", repo.Owner.Login, repo.Name, "pulls", id}, "/") req, err := http.NewRequest("GET", u.String(), nil) if err != nil { return } resp, err := g.send(req) if err != nil { return } if resp.StatusCode != http.StatusOK { err = errors.New("error getting pull request") return } _, err = readBody(resp.Body, &pr) return } func (g *Git) addLabel(repo Repository, api, label, color string) (labelID int64, err error) { labelID = -1 u, err := url.Parse(repo.CloneURL) if err != nil { err = fmt.Errorf("error parsing repo URL: %s", err) return } repoLabels := strings.Join([]string{api, "repos", repo.Owner.Login, repo.Name, "labels"}, "/") u.Path = repoLabels req, err := http.NewRequest("GET", u.String(), nil) if err != nil { return } resp, err := g.send(req) if err != nil { err = fmt.Errorf("error getting labels of %s: %s", u, err) return } if resp.StatusCode != http.StatusOK { err = fmt.Errorf("error getting labels of %s", u) return } var labels []Label _, err = readBody(resp.Body, &labels) if err != nil { return } for _, l := range labels { if l.Name == label { labelID = l.ID break } } if labelID >= 0 { return } buf := new(bytes.Buffer) l := &Label{Name: label, Color: color} err = json.NewEncoder(buf).Encode(l) if err != nil { return } req, err = http.NewRequest("POST", u.String(), buf) if err != nil { return } resp, err = g.send(req) if err != nil { err = fmt.Errorf("error creating label %s for %s: %s", label, u, err) return } if resp.StatusCode != http.StatusCreated { err = fmt.Errorf("error creating label %s for %s", label, u) } var createdLabel Label _, err = readBody(resp.Body, &createdLabel) labelID = createdLabel.ID return } func (g *Git) setLabel(repo Repository, api, id, label, color string, remove []string) (err error) { labelID, err := g.addLabel(repo, api, label, color) if err != nil { return } u, err := url.Parse(repo.CloneURL) if err != nil { return } u.Path = strings.Join([]string{api, "repos", repo.Owner.Login, repo.Name, "issues", id, "labels"}, "/") req, err := http.NewRequest("GET", u.String(), nil) if err != nil { return } resp, err := g.send(req) if err != nil { return fmt.Errorf("error getting issue labels of %s: %s", u, err) } if resp.StatusCode != http.StatusOK { return fmt.Errorf("error getting issue labels of %s", u) } var labels []Label _, err = readBody(resp.Body, &labels) if err != nil { return } plint := &PostLabelsInt{[]int64{labelID}} plstring := &PostLabelsString{[]string{label}} var rm, found bool for _, l := range labels { if contains(remove, l.Name) { rm = true } else { if l.Name == label { found = true } plint.Labels = append(plint.Labels, l.ID) plstring.Labels = append(plstring.Labels, l.Name) } } if !rm && found { return } buf := new(bytes.Buffer) switch api { case githubAPI: err = json.NewEncoder(buf).Encode(plstring) case giteaAPI: err = json.NewEncoder(buf).Encode(plint) } if err != nil { return } req, err = http.NewRequest("PUT", u.String(), buf) if err != nil { return } resp, err = g.send(req) if err != nil { return fmt.Errorf("error setting issue label %s for %s: %s", label, u, err) } if resp.StatusCode != http.StatusOK { b, _ := readBody(resp.Body, nil) err = fmt.Errorf("error setting issue label %s for %s: %s", label, u, string(b)) } return }