commit 526e3589871e57459568bb7a0000fc6d72d9f410
parent 0254f2be89712d6952cb4fdd5c8d0524b61e69ea
Author: Oliver Lowe <o@olowe.co>
Date: Sun, 22 Jun 2025 21:02:56 +1000
jira: keep http and json decoding plumbing in one spot
Diffstat:
| M | cmd/Jira/Jira.go | | | 32 | ++++++++++++-------------------- |
| M | jira/http.go | | | 70 | +++++++++++++++++++++++++--------------------------------------------- |
2 files changed, 37 insertions(+), 65 deletions(-)
diff --git a/cmd/Jira/Jira.go b/cmd/Jira/Jira.go
@@ -64,24 +64,26 @@ func (w *awin) Look(text string) bool {
w.Err(err.Error())
return true
}
+
wname := path.Join("/jira", pathname)
+ var dent fs.DirEntry
if d, ok := f.(fs.DirEntry); ok {
- if d.IsDir() {
- wname += "/"
- }
+ dent = d
} else {
stat, err := f.Stat()
if err != nil {
w.Err(err.Error())
return true
}
- if stat.IsDir() {
- wname += "/"
- }
+ dent = fs.FileInfoToDirEntry(stat)
}
+ if dent.IsDir() {
+ wname += "/"
+ }
+
win.Name(wname)
if path.Base(pathname) == "issue" {
- win.Fprintf("tag", "Comment ")
+ win.Fprintf("tag", "New ")
}
ww := &awin{win, w.fsys}
go ww.EventLoop(ww)
@@ -176,7 +178,7 @@ func (w *awin) Get(f fs.File) error {
b, err := io.ReadAll(f)
if err != nil {
- return fmt.Errorf("read %s: %w", stat.Name(), err)
+ return &fs.PathError{"read", stat.Name(), err}
}
w.Clear()
if _, err := w.Write("body", b); err != nil {
@@ -185,6 +187,8 @@ func (w *awin) Get(f fs.File) error {
return nil
}
+const defaultSearch = "status != 'done' and status != 'not done' and assignee = currentuser()"
+
func newSearch(fsys fs.FS, query string) {
win, err := acme.New()
if err != nil {
@@ -219,18 +223,6 @@ func printIssues(issues []jira.Issue) string {
const usage string = "usage: Jira [-d]"
-func readCreds(name string) (username, password string, err error) {
- b, err := os.ReadFile(name)
- if err != nil {
- return "", "", err
- }
- u, p, found := strings.Cut(strings.TrimSpace(string(b)), ":")
- if !found {
- return "", "", fmt.Errorf("missing userpass field separator %q", ":")
- }
- return u, p, nil
-}
-
var debug bool
func init() {
diff --git a/jira/http.go b/jira/http.go
@@ -36,36 +36,16 @@ func (resp errorResponse) Error() string {
func (c *Client) Projects() ([]Project, error) {
u := *c.APIRoot
u.Path = path.Join(u.Path, "project")
- resp, err := c.get(u.String())
- if err != nil {
- return nil, err
- }
- if resp.StatusCode != http.StatusOK {
- return nil, fmt.Errorf("non-ok status: %s", resp.Status)
- }
- defer resp.Body.Close()
var p []Project
- if err := json.NewDecoder(resp.Body).Decode(&p); err != nil {
- return nil, fmt.Errorf("decode project: %w", err)
- }
- return p, nil
+ err := c.getJSON(u.String(), &p)
+ return p, err
}
func (c *Client) Project(name string) (*Project, error) {
u := fmt.Sprintf("%s/project/%s", c.APIRoot, name)
- resp, err := c.get(u)
- if err != nil {
- return nil, err
- }
- if resp.StatusCode != http.StatusOK {
- return nil, fmt.Errorf("non-ok status: %s", resp.Status)
- }
- defer resp.Body.Close()
var p Project
- if err := json.NewDecoder(resp.Body).Decode(&p); err != nil {
- return nil, fmt.Errorf("decode project: %w", err)
- }
- return &p, nil
+ err := c.getJSON(u, &p)
+ return &p, err
}
func (c *Client) Issues(project string) ([]Issue, error) {
@@ -118,19 +98,9 @@ func (c *Client) CheckIssue(name string) (bool, error) {
func (c *Client) Issue(name string) (*Issue, error) {
u := *c.APIRoot
u.Path = path.Join(u.Path, "issue", name)
- resp, err := c.get(u.String())
- if err != nil {
- return nil, err
- }
- if resp.StatusCode != http.StatusOK {
- return nil, fmt.Errorf("non-ok status: %s", resp.Status)
- }
- defer resp.Body.Close()
var is Issue
- if err := json.NewDecoder(resp.Body).Decode(&is); err != nil {
- return nil, fmt.Errorf("decode issue: %w", err)
- }
- return &is, nil
+ err := c.getJSON(u.String(), &is)
+ return &is, err
}
func (c *Client) checkComment(ikey, id string) (bool, error) {
@@ -153,16 +123,9 @@ func (c *Client) checkComment(ikey, id string) (bool, error) {
func (c *Client) Comment(ikey, id string) (*Comment, error) {
u := *c.APIRoot
u.Path = path.Join(u.Path, "issue", ikey, "comment", id)
- resp, err := c.get(u.String())
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
var com Comment
- if err := json.NewDecoder(resp.Body).Decode(&com); err != nil {
- return nil, fmt.Errorf("decode comment: %w", err)
- }
- return &com, nil
+ err := c.getJSON(u.String(), &com)
+ return &com, err
}
func (c *Client) CreateIssue(issue Issue) (*Issue, error) {
@@ -204,6 +167,23 @@ func (c *Client) PostComment(issueKey string, body io.Reader) error {
return nil
}
+func (c *Client) getJSON(url string, v any) error {
+ resp, err := c.get(url)
+ if err != nil {
+ return err
+ }
+ defer resp.Body.Close()
+ dec := json.NewDecoder(resp.Body)
+ if resp.StatusCode != http.StatusOK {
+ var eresp errorResponse
+ if err := dec.Decode(&eresp); err != nil {
+ return fmt.Errorf("status %s: decode error response: %w", resp.Status, err)
+ }
+ return eresp
+ }
+ return dec.Decode(v)
+}
+
func (c *Client) get(url string) (*http.Response, error) {
req, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil {