commit - 8d9dbdfc8a07bca44bcef1a030dc1e248a6ddeaf
commit + ba9e266535f5c1704c277e5402192008034adc16
blob - b83bcf3e4b98697cc1693190dc78ba336010b40a
blob + 0e557dbc3006d3655385cd682f92608262fdf8e2
--- jira/jira.go
+++ jira/jira.go
-//
+// https://developer.atlassian.com/cloud/jira/platform/rest/v2/
+// https://jira.atlassian.com/rest/api/latest/issue/JRA-9
package main
import (
"time"
)
+const timestamp = "2006-01-02T15:04:05.999-0700"
+
type Issue struct {
- ID string `json:"id"` // TODO(otl): int?
- URL string `json:"self"`
- Key string `json:"key"`
+ ID string // TODO(otl): int?
+ URL string
+ Key string
+ Reporter User
+ Summary string
Description string
Project Project
+ Created time.Time
+ Updated time.Time
Comments []Comment
}
}
type Comment struct {
- URL string `json:"self"`
ID string `json:"id"` // TODO(otl): int?
+ URL string `json:"self"`
Body string `json:"body"`
Created time.Time `json:"created"`
Updated time.Time `json:"updated"`
return err
}
var err error
- tstamp := "2006-01-02T15:04:05.999-0700"
- c.Created, err = time.Parse(tstamp, aux.Created)
+ c.Created, err = time.Parse(timestamp, aux.Created)
if err != nil {
return fmt.Errorf("parse created time: %w", err)
}
- c.Updated, err = time.Parse(tstamp, aux.Updated)
+ c.Updated, err = time.Parse(timestamp, aux.Updated)
if err != nil {
return fmt.Errorf("parse updated time: %w", err)
}
}
func (issue *Issue) UnmarshalJSON(b []byte) error {
- type alias Issue
aux := &struct {
- Fields struct {
- Description string
- Comment []Comment
- Project Project
- }
+ ID string
+ Self string
+ Key string
+ Fields json.RawMessage
+ }{}
+ if err := json.Unmarshal(b, aux); err != nil {
+ return err
+ }
+ issue.ID = aux.ID
+ issue.URL = aux.Self
+ issue.Key = aux.Key
+
+ type alias Issue
+ iaux := &struct {
+ Created string
+ Updated string
+ Comment map[string]json.RawMessage
*alias
}{
alias: (*alias)(issue),
}
- if err := json.Unmarshal(b, aux); err != nil {
+ if err := json.Unmarshal(aux.Fields, iaux); err != nil {
return err
}
- issue.Comments = aux.Fields.Comment
- issue.Description = aux.Fields.Description
- issue.Project = aux.Fields.Project
+
+ var err error
+ issue.Created, err = time.Parse(timestamp, iaux.Created)
+ if err != nil {
+ return fmt.Errorf("created time: %w", err)
+ }
+ issue.Updated, err = time.Parse(timestamp, iaux.Updated)
+ if err != nil {
+ return fmt.Errorf("updated time: %w", err)
+ }
+
+ if bb, ok := iaux.Comment["comments"]; ok {
+ if err := json.Unmarshal(bb, &issue.Comments); err != nil {
+ return fmt.Errorf("unmarshal comments: %w", err)
+ }
+ }
return nil
}
blob - 7b7992b9e2273f94ef78eb36746b8d7bc5e7d6e2
blob + 228ee2633969341e9376cc0ca2f9173fa531c45a
--- jira/jira_test.go
+++ jira/jira_test.go
import (
"encoding/json"
"os"
+ "path/filepath"
"testing"
)
func TestIssue(t *testing.T) {
- f, err := os.Open("issue.json")
+ names, err := filepath.Glob("issue*.json")
if err != nil {
t.Fatal(err)
}
- defer f.Close()
- var issue Issue
- if err := json.NewDecoder(f).Decode(&issue); err != nil {
- t.Fatal(err)
+ for _, name := range names {
+ f, err := os.Open(name)
+ if err != nil {
+ t.Fatalf("%s: %v", name, err)
+ }
+ defer f.Close()
+ var issue Issue
+ if err := json.NewDecoder(f).Decode(&issue); err != nil {
+ t.Fatalf("%s: %v", name, err)
+ }
}
}
-
-func TestPrint(t *testing.T) {
- f, err := os.Open("issue.json")
- if err != nil {
- t.Fatal(err)
- }
- defer f.Close()
- var issue Issue
- if err := json.NewDecoder(f).Decode(&issue); err != nil {
- t.Fatal(err)
- }
- printIssue(os.Stdout, &issue)
-}
blob - b8598ddab249a4c773596c165ff8186cd28c2ab6
blob + 6a0a9f61dbdc6dfb8597452dab7845f69dbab1e4
--- jira/print.go
+++ jira/print.go
"fmt"
"io"
"strings"
+ "time"
)
func printIssue(w io.Writer, i *Issue) (n int, err error) {
buf := &strings.Builder{}
+ fmt.Fprintln(buf, "From:", i.Reporter.Name)
fmt.Fprintln(buf, "URL:", i.URL)
+ fmt.Fprintln(buf, "Subject:", i.Summary)
fmt.Fprintln(buf)
fmt.Fprintln(buf, i.Description)
fmt.Fprintln(buf)
-
for _, c := range i.Comments {
- buf.WriteString("\t")
- printComment(buf, &c)
+ date := c.Created
+ if !c.Updated.IsZero() {
+ date = c.Updated
+ }
+ fmt.Fprintf(buf, "%s/\t%s\t%s (%s)\n", c.ID, summarise(c.Body), c.Author.Name, date.Format(time.DateTime))
}
return w.Write([]byte(buf.String()))
}
fmt.Fprintln(buf, c.Body)
return w.Write([]byte(buf.String()))
}
+
+func summarise(body string) string {
+ max := 36
+ if len(body) < max {
+ body = strings.ReplaceAll(body, "\n", " ")
+ return strings.TrimSpace(body)
+ }
+ body = body[:max]
+ body = strings.ReplaceAll(body, "\r", "")
+ body = strings.ReplaceAll(body, "\n", " ")
+ body = strings.TrimSpace(body)
+ body = strings.ReplaceAll(body, " ", " ")
+ return body + "..."
+}