Commit Diff


commit - 82b8536397b0c1fe84af1b0ca1aabf33faaabceb
commit + 6de81a7b43fe19e0a9e9791192ffa8c723c0c4ad
blob - fb5a932b3fc71fc0b29256b428ffa3c53f47ffad
blob + 0fca4f89803514e2c44e429cccfbf22ca671a43a
--- jira/http.go
+++ 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, err
 	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
 	}
-	return nil, fmt.Errorf("TODO")
+	var created Issue
+	if err := json.NewDecoder(resp.Body).Decode(&created); err != nil {
+		return nil, fmt.Errorf("decode created issue: %w", err)
+	}
+	return &created, nil
 }
 
 func (c *Client) PostComment(issueKey string, body io.Reader) error {
blob - a4339567b02f6a29f302567eda5fbba16a3fd198
blob + 3eecbeb0c6c3453c9913ab8c323ee8a3e6d4e38e
--- jira/jira.go
+++ 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)
+}
blob - 2af937f6316d5c2ea8d6b78d866af66a24992d70
blob + 65b1c6661d55328871224e5b858fc401e0e3f060
--- jira/print.go
+++ 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 {