issues

Github, Jira, Gitlab issues from Plan 9's acme
Log | Files | Refs | README | LICENSE

commit 6de81a7b43fe19e0a9e9791192ffa8c723c0c4ad
parent 82b8536397b0c1fe84af1b0ca1aabf33faaabceb
Author: Oliver Lowe <o@olowe.co>
Date:   Thu, 19 Jun 2025 11:07:44 +1000

jira: set correct fields when creating issues

Need to omit lots of fields

Diffstat:
Mjira/http.go | 28++++++++++++++++++++++++++--
Mjira/jira.go | 51+++++++++++++++++++++++++++++++--------------------
Mjira/print.go | 6++++--
3 files changed, 61 insertions(+), 24 deletions(-)

diff --git a/jira/http.go b/jira/http.go @@ -9,6 +9,7 @@ import ( "net/url" "os" "path" + "strings" ) type Client struct { @@ -18,6 +19,20 @@ type Client struct { APIRoot *url.URL } +type errorResponse struct { + Errors map[string]string +} + +func (resp errorResponse) Error() string { + errs := make([]string, len(resp.Errors)) + var i int + for k, v := range resp.Errors { + errs[i] = fmt.Sprintf("%s: %s", k, v) + i++ + } + return strings.Join(errs, "; ") +} + func (c *Client) Projects() ([]Project, error) { u := *c.APIRoot u.Path = path.Join(u.Path, "project") @@ -157,10 +172,19 @@ func (c *Client) CreateIssue(issue Issue) (*Issue, error) { if err != nil { return nil, fmt.Errorf("post json: %w", err) } + defer resp.Body.Close() if resp.StatusCode >= http.StatusBadRequest { - return nil, fmt.Errorf("non-ok status: %s", resp.Status) + var eresp errorResponse + if err := json.NewDecoder(resp.Body).Decode(&eresp); err != nil { + return nil, fmt.Errorf("status %s: decode error response: %w", resp.Status, err) + } + return nil, eresp + } + var created Issue + if err := json.NewDecoder(resp.Body).Decode(&created); err != nil { + return nil, fmt.Errorf("decode created issue: %w", err) } - return nil, fmt.Errorf("TODO") + return &created, nil } func (c *Client) PostComment(issueKey string, body io.Reader) error { diff --git a/jira/jira.go b/jira/jira.go @@ -9,29 +9,32 @@ import ( const timestamp = "2006-01-02T15:04:05.999-0700" type Issue struct { - ID string // TODO(otl): int? - URL string - Key string - Reporter User - Assignee User - Summary string - Status struct { + ID string `json:"id,omitempty"` // TODO(otl): int? + URL string `json:"url,omitempty"` + Key string `json:"key,omitempty"` + Reporter *User `json:"reporter,omitempty"` + Assignee *User `json:"assignee,omitempty"` + Summary string `json:"summary"` + Status *struct { Name string `json:"name"` - } `json:"status"` - Description string - Project Project - Created time.Time - Updated time.Time - Comments []Comment - Links []Issue - Subtasks []Issue + } `json:"status,omitempty"` + Description string `json:"description"` + Project Project `json:"project"` + Created time.Time `json:"created,omitzero"` + Updated time.Time `json:"updated,omitzero"` + Type struct { + Name string `json:"name"` + } `json:"issuetype"` + Comments []Comment `json:"comments,omitempty"` + Links []Issue `json:"links,omitempty"` + Subtasks []Issue `json:"subtasks,omitempty"` } type Project struct { - ID string `json:"id"` // TODO(otl): int? + ID string `json:"id,omitempty"` // TODO(otl): int? // Name string `json:"name"` - Key string `json:"key"` - URL string `json:"self"` + Key string `json:"key,omitempty"` + URL string `json:"self,omitempty"` } type Comment struct { @@ -97,8 +100,8 @@ func (issue *Issue) UnmarshalJSON(b []byte) error { type alias Issue iaux := &struct { - Created string - Updated string + Created string `json:"created"` + Updated string `json:"updated"` Comment map[string]json.RawMessage IssueLinks []struct { InwardIssue *Issue @@ -140,3 +143,11 @@ func (issue *Issue) UnmarshalJSON(b []byte) error { } return nil } + +func (issue *Issue) MarshalJSON() ([]byte, error) { + type alias Issue + aux := struct { + Fields *alias `json:"fields"` + }{(*alias)(issue)} + return json.Marshal(aux) +} diff --git a/jira/print.go b/jira/print.go @@ -19,9 +19,11 @@ func printIssues(issues []Issue) string { func printIssue(i *Issue) string { buf := &strings.Builder{} - fmt.Fprintln(buf, "From:", i.Reporter) + if i.Reporter != nil { + fmt.Fprintln(buf, "From:", i.Reporter) + } fmt.Fprintln(buf, "Date:", i.Created.Format(time.RFC1123Z)) - if i.Assignee.String() != "" { + if i.Assignee != nil { fmt.Fprintln(buf, "Assignee:", i.Assignee) } if u, err := url.Parse(i.URL); err == nil {