commit bb01c102da3cc788c78e7a26d67299f300a8f814 from: Oliver Lowe date: Sun Jan 12 11:01:14 2025 UTC cmd/jiraexport: only print comments if asked commit - 438e3045216521b085564bac4c1a287a9079c26f commit + bb01c102da3cc788c78e7a26d67299f300a8f814 blob - aa6995ef1121bf8982368fc0b0917c12feab532c blob + ad472c6e511a1c41841942545d18fadc1f9d1413 --- cmd/jiraexport/jiraexport.go +++ cmd/jiraexport/jiraexport.go @@ -1,15 +1,18 @@ // Command jiraexport prints the named Jira issues, and their comments, -// RFC 5322 mail message format (email). +// in RFC 5322 mail message format (email). // // Usage: -// jiraexport [ -d duration ] issue [ ... ] // +// jiraexport [ -d duration ] issue... +// // The options are: // // -d duration // Exclude any issues and comments unmodified since duration. // Duration may be given in the format accepted by time.ParseDuration. // For example, 24h (24 hours). The default is 7 days. +// -c +// Only print comments, excluding the issue. // // # Example // @@ -17,6 +20,12 @@ // // jiraexport -d 24h SRE-1234 SRE-5678 // +// Archive the first 500 tickets of a project in a mbox file: +// +// for i in `seq 1 500` +// do +// jiraexport TEST-$i >>issues.mbox +// done package main import ( @@ -53,10 +62,30 @@ func readJiraAuth() (user, pass string, err error) { return u, p, nil } +func copyMessage(w io.Writer, msg *mail.Message) (n int, err error) { + for k, v := range msg.Header { + for i := range v { + nn, err := fmt.Fprintf(w, "%s: %s\n", k, v[i]) + n += nn + if err != nil { + return n, fmt.Errorf("write header field %s: %w", k, err) + } + } + } + nnn, err := fmt.Fprintln(w) + n += nnn + if err != nil { + return n, err + } + nn, err := io.Copy(w, msg.Body) + return n + int(nn), err +} + const usage string = "jiraexport [-d duration] [-u url] issue [...]" var since = flag.Duration("d", 7*24*time.Hour, "exclude activity older than this duration") var apiRoot = flag.String("u", "http://[::1]:8080", "base URL for the JIRA API") +var onlyComments = flag.Bool("c", false, "only print comments") func init() { log.SetFlags(0) @@ -93,38 +122,24 @@ func main() { continue } dir := path.Join(proj, num) - f, err := fsys.Open(path.Join(dir, "issue")) + issue, err := fsys.Open(path.Join(dir, "issue")) if err != nil { log.Println(err) continue } - info, err := f.Stat() + msg, err := mail.ReadMessage(issue) if err != nil { - f.Close() - log.Println(err) + log.Println("read issue:", err) + issue.Close() continue } - if time.Since(info.ModTime()) >= *since { - f.Close() - continue - } - msg, err := mail.ReadMessage(f) - if err != nil { - f.Close() - log.Println(err) - continue - } - // fmt.Println("From nobody", info.ModTime().Format(time.ANSIC)) - fmt.Println("Subject:", msg.Header.Get("Subject")) - /* - if _, err := io.Copy(os.Stdout, f); err != nil { - f.Close() - log.Println(err) - continue + subject := msg.Header.Get("Subject") + if !*onlyComments { + if _, err := copyMessage(os.Stdout, msg); err != nil { + log.Println("print issue:", err) } - */ - fmt.Println() - f.Close() + } + issue.Close() dents, err := fs.ReadDir(fsys, dir) if err != nil { @@ -148,12 +163,13 @@ func main() { log.Println(err) continue } + fmt.Println() fmt.Println("From nobody", info.ModTime().Format(time.ANSIC)) + fmt.Println("Subject:", subject) if _, err := io.Copy(os.Stdout, f); err != nil { log.Println(err) } f.Close() - fmt.Println() } } }