bugzilla/client/client.go (112 lines of code) (raw):

/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package client import ( "bytes" "encoding/json" "errors" "fmt" "io/ioutil" "net/http" "regexp" "strconv" "strings" "github.com/mozilla/OneCRL-Tools/bugzilla/api/general" "github.com/mozilla/OneCRL-Tools/bugzilla/api/attachments" "github.com/mozilla/OneCRL-Tools/bugzilla/api" "github.com/mozilla/OneCRL-Tools/bugzilla/api/auth" "github.com/mozilla/OneCRL-Tools/bugzilla/api/bugs" ) type Client struct { host string base string authenticator auth.Authenticator inner *http.Client tool string } // NewClient constructs an unauthenticated client. To add // and authenticator please see the WithAuth method. // // The provided "host" string must be <protocol>://<hostname>[:<port>] // WITHOUT any path. The "rest" resource is automatically appended to // every constructed client. func NewClient(host string) *Client { host = strings.TrimRight(host, "/") return &Client{ host: host, base: host + "/rest", authenticator: new(auth.Unauthenticated), inner: new(http.Client), tool: "https://github.com/mozilla/OneCRL-Tools/bugzilla", } } func (c *Client) WithAuth(authenticator auth.Authenticator) *Client { c.authenticator = authenticator return c } // WithToolHeader sets the header value for X-AUTOMATED-TOOL, which // is sent with every request. // // By default, this is set to "https://github.com/mozilla/OneCRL-Tools/bugzilla", // however it would be appreciated if consumers of this library set this to // pointer to the code that is actually making API calls. func (c *Client) WithToolHeader(tool string) *Client { c.tool = tool return c } func (c *Client) Version() (*general.VersionResponse, error) { resp := new(general.VersionResponse) return resp, c.do(new(general.Version), resp) } func (c *Client) CreateBug(bug *bugs.Create) (*bugs.CreateResponse, error) { resp := new(bugs.CreateResponse) return resp, c.do(bug, resp) } func (c *Client) GetBug(bug int) (*bugs.GetResponse, error) { resp := new(bugs.GetResponse) return resp, c.do(&bugs.Get{Id: bug}, resp) } func (c *Client) CreateAttachment(attachment *attachments.Create) (*attachments.CreateResponse, error) { resp := new(attachments.CreateResponse) return resp, c.do(attachment, resp) } func (c *Client) UpdateBug(bug *bugs.Update) (*bugs.UpdateResponse, error) { resp := new(bugs.UpdateResponse) return resp, c.do(bug, resp) } // ShowBug returns a URL formatted for the configured Bugzilla instance // that is of the format <SCHEME>://<HOST>/show_bug.cgi?id=<BUG_ID> // // This is the GUI web view for the given bug id. func (c *Client) ShowBug(id int) string { return fmt.Sprintf("%s/show_bug.cgi?id=%d", c.host, id) } var r = regexp.MustCompile(`.*id=(?P<ID>\d+).*`) // IDFromShowBug takes in a string that was constructed from Client.ShowBug // and returns back the original ID number. func (c *Client) IDFromShowBug(url string) (int, error) { matches := r.FindStringSubmatch(url) if len(matches) < 2 { return 0, fmt.Errorf("no matches for a bug ID found in %s", url) } return strconv.Atoi(matches[1]) } func (c *Client) do(in api.Endpoint, out interface{}) error { req, err := c.newRequest(in) if err != nil { return err } resp, err := c.inner.Do(req) if err != nil { return err } defer resp.Body.Close() b, err := ioutil.ReadAll(resp.Body) if err != nil { return err } if resp.StatusCode != in.Expect() { return errors.New(string(b)) } return json.Unmarshal(b, out) } func (c *Client) newRequest(endpoint api.Endpoint) (*http.Request, error) { req, err := http.NewRequest(endpoint.Method(), c.base+endpoint.Resource(), nil) if err != nil { return nil, err } if endpoint.Method() != http.MethodGet { b, err := json.Marshal(endpoint) if err != nil { return nil, err } req.Body = ioutil.NopCloser(bytes.NewReader(b)) } req.Header.Set("X-AUTOMATED-TOOL", c.tool) req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") // The default Go user agent is blocked for bad bots req.Header.Set("User-Agent", "Mozilla/5.0 (X11; Slackware; Linux x86_64; "+ "rv:80.0) Gecko/20100101 Firefox/80.0 OneCRL-Tools") c.authenticator.Authenticate(req.Header) return req, nil }