Merge branch 'master' of https://git.otremblay.com/jkl
This commit is contained in:
commit
eccf4460a1
8 changed files with 518 additions and 45 deletions
|
|
@ -6,6 +6,8 @@ import (
|
||||||
"flag"
|
"flag"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
"fmt"
|
||||||
|
"text/template"
|
||||||
|
|
||||||
"otremblay.com/jkl"
|
"otremblay.com/jkl"
|
||||||
)
|
)
|
||||||
|
|
@ -14,6 +16,7 @@ type CreateCmd struct {
|
||||||
args []string
|
args []string
|
||||||
project string
|
project string
|
||||||
file string
|
file string
|
||||||
|
issuetype string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCreateCmd(args []string) (*CreateCmd, error) {
|
func NewCreateCmd(args []string) (*CreateCmd, error) {
|
||||||
|
|
@ -22,6 +25,7 @@ func NewCreateCmd(args []string) (*CreateCmd, error) {
|
||||||
f.StringVar(&ccmd.project, "p", "", "Jira project key")
|
f.StringVar(&ccmd.project, "p", "", "Jira project key")
|
||||||
f.StringVar(&ccmd.file, "f", "", "File to get issue description from")
|
f.StringVar(&ccmd.file, "f", "", "File to get issue description from")
|
||||||
f.Parse(args)
|
f.Parse(args)
|
||||||
|
ccmd.args = f.Args()
|
||||||
return ccmd, nil
|
return ccmd, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -39,18 +43,32 @@ func (ccmd *CreateCmd) Create() error {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ccmd.project == "" {
|
||||||
|
return ErrCcmdJiraProjectRequired
|
||||||
|
}
|
||||||
|
isstype := ""
|
||||||
|
if len(ccmd.args) > 0 {
|
||||||
|
isstype = ccmd.args[0]
|
||||||
|
}
|
||||||
|
cm, err := jkl.GetCreateMeta(ccmd.project, isstype)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, fmt.Sprintf("Error getting the CreateMeta for project [%s] and issue types [%s]", ccmd.project, isstype), err)
|
||||||
|
}
|
||||||
|
|
||||||
if !readfile {
|
if !readfile {
|
||||||
b.WriteString(CREATE_TEMPLATE)
|
createTemplate.Execute(b, cm)
|
||||||
}
|
}
|
||||||
var iss *jkl.JiraIssue
|
var iss *jkl.JiraIssue
|
||||||
var err error
|
// TODO: Evil badbad don't do this.
|
||||||
|
em := &jkl.EditMeta{Fields: cm.Projects[0].IssueTypes[0].Fields}
|
||||||
if ccmd.file != "" {
|
if ccmd.file != "" {
|
||||||
iss, err = GetIssueFromFile(ccmd.file, b)
|
iss, err = GetIssueFromFile(ccmd.file, b, em)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
iss, err = GetIssueFromTmpFile(b)
|
iss, err = GetIssueFromTmpFile(b, em)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -60,13 +78,24 @@ func (ccmd *CreateCmd) Create() error {
|
||||||
(iss.Fields.Project == nil || iss.Fields.Project.Key == "") {
|
(iss.Fields.Project == nil || iss.Fields.Project.Key == "") {
|
||||||
iss.Fields.Project = &jkl.Project{Key: ccmd.project}
|
iss.Fields.Project = &jkl.Project{Key: ccmd.project}
|
||||||
}
|
}
|
||||||
return jkl.Create(iss)
|
iss, err = jkl.Create(iss)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Println(iss.Key)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ccmd *CreateCmd) Run() error {
|
func (ccmd *CreateCmd) Run() error {
|
||||||
return ccmd.Create()
|
return ccmd.Create()
|
||||||
}
|
}
|
||||||
|
|
||||||
const CREATE_TEMPLATE = `Issue Type:
|
var createTemplate = template.Must(template.New("createissue").Parse(`{{range .Projects -}}
|
||||||
|
Project: {{.Key}}
|
||||||
|
{{range .IssueTypes -}}
|
||||||
|
Issue Type: {{.Name}}
|
||||||
Summary:
|
Summary:
|
||||||
Description:`
|
Description:
|
||||||
|
{{.RangeFieldSpecs}}
|
||||||
|
{{end}}
|
||||||
|
{{end}}`))
|
||||||
|
|
|
||||||
|
|
@ -39,13 +39,13 @@ func (ecmd *EditCmd) Edit() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ecmd.file != "" {
|
if ecmd.file != "" {
|
||||||
iss, err = GetIssueFromFile(ecmd.file, b)
|
iss, err = GetIssueFromFile(ecmd.file, b, iss.EditMeta)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
iss, err = GetIssueFromTmpFile(b)
|
iss, err = GetIssueFromTmpFile(b, iss.EditMeta)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,72 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"bytes"
|
||||||
"flag"
|
"flag"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"otremblay.com/jkl"
|
||||||
)
|
)
|
||||||
|
|
||||||
type EditCommentCmd struct {
|
type EditCommentCmd struct {
|
||||||
args []string
|
args []string
|
||||||
file string
|
file string
|
||||||
issueKey string
|
issueKey string
|
||||||
|
commentId string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewEditCommentCmd(args []string) (*EditCommentCmd, error) {
|
func NewEditCommentCmd(args []string) (*EditCommentCmd, error) {
|
||||||
ccmd := &EditCommentCmd{}
|
ccmd := &EditCommentCmd{}
|
||||||
f := flag.NewFlagSet("comments", flag.ExitOnError)
|
f := flag.NewFlagSet("editcomments", flag.ExitOnError)
|
||||||
f.StringVar(&ccmd.file, "f", "", "File to get issue comment from")
|
f.StringVar(&ccmd.file, "f", "", "File to get issue comment from")
|
||||||
f.Parse(args)
|
f.Parse(args)
|
||||||
if len(f.Args()) < 1 {
|
if len(f.Args()) < 1 {
|
||||||
return nil, ErrNotEnoughArgs
|
return nil, ErrNotEnoughArgs
|
||||||
}
|
}
|
||||||
ccmd.issueKey = f.Arg(0)
|
ids := strings.Split(f.Arg(0), jkl.CommentIdSeparator)
|
||||||
|
ccmd.issueKey = ids[0]
|
||||||
|
if len(ids) < 2 {
|
||||||
|
if len(f.Args()) == 2 {
|
||||||
|
ccmd.commentId = f.Args()[1]
|
||||||
|
} else {
|
||||||
|
return nil, ErrNotEnoughArgs
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ccmd.commentId = ids[1]
|
||||||
|
}
|
||||||
return ccmd, nil
|
return ccmd, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *EditCommentCmd) Run() error {
|
func (e *EditCommentCmd) Run() error {
|
||||||
return errors.New("Not implemented")
|
|
||||||
}
|
|
||||||
|
// Get Comment
|
||||||
|
comm, err := jkl.GetComment(e.issueKey, e.commentId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
b := bytes.NewBufferString(comm.Body)
|
||||||
|
var rdr io.Reader
|
||||||
|
if e.file != "" {
|
||||||
|
rdr, err = GetTextFromSpecifiedFile(e.file, b)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rdr, err = GetTextFromTmpFile(b)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
btxt, err := ioutil.ReadAll(rdr)
|
||||||
|
txt := strings.TrimSpace(string(btxt))
|
||||||
|
if txt == "" || txt == strings.TrimSpace(comm.Body) {
|
||||||
|
// Nothing to do
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
comm.Body = txt
|
||||||
|
return jkl.EditComment(e.issueKey, e.commentId, comm)
|
||||||
|
}
|
||||||
|
|
@ -17,7 +17,6 @@ import (
|
||||||
|
|
||||||
"otremblay.com/jkl"
|
"otremblay.com/jkl"
|
||||||
)
|
)
|
||||||
|
|
||||||
// def get_editor do
|
// def get_editor do
|
||||||
// [System.get_env("EDITOR"), "nano", "vim", "vi"]
|
// [System.get_env("EDITOR"), "nano", "vim", "vi"]
|
||||||
// |> Enum.find(nil, fn (ed) -> System.find_executable(ed) != nil end)
|
// |> Enum.find(nil, fn (ed) -> System.find_executable(ed) != nil end)
|
||||||
|
|
@ -40,7 +39,7 @@ func copyInitial(dst io.WriteSeeker, initial io.Reader) {
|
||||||
dst.Seek(0, 0)
|
dst.Seek(0, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetIssueFromTmpFile(initial io.Reader) (*jkl.JiraIssue, error) {
|
func GetIssueFromTmpFile(initial io.Reader, editMeta *jkl.EditMeta) (*jkl.JiraIssue, error) {
|
||||||
f, err := ioutil.TempFile(os.TempDir(), "jkl")
|
f, err := ioutil.TempFile(os.TempDir(), "jkl")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -50,7 +49,7 @@ func GetIssueFromTmpFile(initial io.Reader) (*jkl.JiraIssue, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return IssueFromReader(f2), nil
|
return IssueFromReader(f2, editMeta), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetTextFromTmpFile(initial io.Reader) (io.Reader, error) {
|
func GetTextFromTmpFile(initial io.Reader) (io.Reader, error) {
|
||||||
|
|
@ -87,7 +86,7 @@ func GetTextFromFile(file *os.File) (io.Reader, error) {
|
||||||
return file, err
|
return file, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetIssueFromFile(filename string, initial io.Reader) (*jkl.JiraIssue, error) {
|
func GetIssueFromFile(filename string, initial io.Reader, editMeta *jkl.EditMeta) (*jkl.JiraIssue, error) {
|
||||||
f, err := os.Open(filename)
|
f, err := os.Open(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -99,12 +98,12 @@ func GetIssueFromFile(filename string, initial io.Reader) (*jkl.JiraIssue, error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return IssueFromReader(f2), nil
|
return IssueFromReader(f2, editMeta), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var spacex = regexp.MustCompile(`\s`)
|
var spacex = regexp.MustCompile(`\s`)
|
||||||
|
|
||||||
func IssueFromReader(f io.Reader) *jkl.JiraIssue {
|
func IssueFromReader(f io.Reader, editMeta *jkl.EditMeta) *jkl.JiraIssue {
|
||||||
iss := &jkl.JiraIssue{Fields: &jkl.Fields{}}
|
iss := &jkl.JiraIssue{Fields: &jkl.Fields{}}
|
||||||
riss := reflect.ValueOf(iss).Elem()
|
riss := reflect.ValueOf(iss).Elem()
|
||||||
fieldsField := riss.FieldByName("Fields").Elem()
|
fieldsField := riss.FieldByName("Fields").Elem()
|
||||||
|
|
@ -155,6 +154,9 @@ func IssueFromReader(f io.Reader) *jkl.JiraIssue {
|
||||||
} else {
|
} else {
|
||||||
currentField = newfield
|
currentField = newfield
|
||||||
}
|
}
|
||||||
|
} else if editMeta != nil {
|
||||||
|
// If it's not valid, throw it at the createmeta. It will probably end up in ExtraFields.
|
||||||
|
|
||||||
}
|
}
|
||||||
if currentField.IsValid() {
|
if currentField.IsValid() {
|
||||||
currentField.SetString(strings.TrimSpace(currentField.String() + "\n" + strings.Join(parts, ":")))
|
currentField.SetString(strings.TrimSpace(currentField.String() + "\n" + strings.Join(parts, ":")))
|
||||||
|
|
@ -163,6 +165,6 @@ func IssueFromReader(f io.Reader) *jkl.JiraIssue {
|
||||||
return iss
|
return iss
|
||||||
}
|
}
|
||||||
|
|
||||||
func IssueFromList(list []string) *jkl.JiraIssue {
|
func IssueFromList(list []string, editMeta *jkl.EditMeta) *jkl.JiraIssue {
|
||||||
return IssueFromReader(bytes.NewBufferString(strings.Join(list, "\n")))
|
return IssueFromReader(bytes.NewBufferString(strings.Join(list, "\n")), editMeta)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"sort"
|
||||||
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
|
@ -54,6 +55,9 @@ func getCmd(args []string, depth int) (Runner, error) {
|
||||||
case "edit":
|
case "edit":
|
||||||
return NewEditCmd(args[1:])
|
return NewEditCmd(args[1:])
|
||||||
case "comment":
|
case "comment":
|
||||||
|
if strings.Contains(strings.Join(args,""),jkl.CommentIdSeparator){
|
||||||
|
return NewEditCommentCmd(args[1:])
|
||||||
|
}
|
||||||
return NewCommentCmd(args[1:])
|
return NewCommentCmd(args[1:])
|
||||||
case "edit-comment":
|
case "edit-comment":
|
||||||
return NewEditCommentCmd(args[1:])
|
return NewEditCommentCmd(args[1:])
|
||||||
|
|
@ -67,6 +71,13 @@ func getCmd(args []string, depth int) (Runner, error) {
|
||||||
|
|
||||||
if depth == 0 {
|
if depth == 0 {
|
||||||
// Assume args[0] is a task key
|
// Assume args[0] is a task key
|
||||||
|
if len(args) == 1 {
|
||||||
|
// Default to task info
|
||||||
|
args = append(args, "task")
|
||||||
|
}
|
||||||
|
if verbs[sort.SearchStrings(verbs, args[1])] != args[1] {
|
||||||
|
return &TaskCmd{args}, nil
|
||||||
|
}
|
||||||
args[0], args[1] = args[1], args[0]
|
args[0], args[1] = args[1], args[0]
|
||||||
return getCmd(args, depth+1)
|
return getCmd(args, depth+1)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -81,6 +92,11 @@ func getCmd(args []string, depth int) (Runner, error) {
|
||||||
return nil, ErrTaskSubCommandNotFound
|
return nil, ErrTaskSubCommandNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var verbs = []string{"list", "create", "task", "edit", "comment","edit-comment"}
|
||||||
|
func init(){
|
||||||
|
sort.Strings(verbs)
|
||||||
|
}
|
||||||
|
|
||||||
const usage = `Usage:
|
const usage = `Usage:
|
||||||
jkl [options] <command> [args]
|
jkl [options] <command> [args]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package main
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"otremblay.com/jkl"
|
"otremblay.com/jkl"
|
||||||
)
|
)
|
||||||
|
|
@ -18,7 +19,12 @@ func (t *TaskCmd) Handle() error {
|
||||||
return t.Get(t.args[0])
|
return t.Get(t.args[0])
|
||||||
}
|
}
|
||||||
if c == 2 {
|
if c == 2 {
|
||||||
return t.Transition(t.args[0], t.args[1])
|
fmt.Println(t.args)
|
||||||
|
err := t.Transition(t.args[0], t.args[1])
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return t.Log(t.args[0], strings.Join(t.args[1:]," "))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return ErrTaskSubCommandNotFound
|
return ErrTaskSubCommandNotFound
|
||||||
}
|
}
|
||||||
|
|
@ -35,7 +41,11 @@ func (t *TaskCmd) Get(taskKey string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TaskCmd) Transition(taskKey, transition string) error {
|
func (t *TaskCmd) Transition(taskKey, transition string) error {
|
||||||
return nil
|
return jkl.DoTransition(taskKey, transition)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TaskCmd) Log(taskKey, time string) error {
|
||||||
|
return jkl.LogWork(taskKey, time)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TaskCmd) Run() error {
|
func (t *TaskCmd) Run() error {
|
||||||
|
|
|
||||||
273
issue.go
273
issue.go
|
|
@ -2,10 +2,16 @@ package jkl
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
"encoding/json"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
"sort"
|
||||||
|
"regexp"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Search struct {
|
type Search struct {
|
||||||
|
|
@ -14,7 +20,30 @@ type Search struct {
|
||||||
|
|
||||||
type IssueType struct {
|
type IssueType struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Fields map[string]FieldSpec
|
Fields map[string]*FieldSpec
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *IssueType) RangeFieldSpecs() string {
|
||||||
|
output := bytes.NewBuffer(nil)
|
||||||
|
keys := make([]string, 0, len(it.Fields))
|
||||||
|
for k, _ := range it.Fields {
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
sort.Strings(keys)
|
||||||
|
for _, k := range keys {
|
||||||
|
fmt.Fprintln(output, fmt.Sprintf("%s: %v", it.Fields[k].Name, it.Fields[k].AllowedValues))
|
||||||
|
}
|
||||||
|
return output.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
type AllowedValue struct {
|
||||||
|
Id string
|
||||||
|
Self string
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AllowedValue) String() string{
|
||||||
|
return a.Value
|
||||||
}
|
}
|
||||||
|
|
||||||
type FieldSpec struct {
|
type FieldSpec struct {
|
||||||
|
|
@ -22,23 +51,39 @@ type FieldSpec struct {
|
||||||
Required bool
|
Required bool
|
||||||
Schema struct {
|
Schema struct {
|
||||||
Type string
|
Type string
|
||||||
|
Custom string
|
||||||
|
CustomId int
|
||||||
|
Items string
|
||||||
}
|
}
|
||||||
|
Operations []string
|
||||||
|
AllowedValues []*AllowedValue
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type CreateMeta struct {
|
||||||
|
Projects []*Project
|
||||||
}
|
}
|
||||||
|
|
||||||
type Project struct {
|
type Project struct {
|
||||||
Key string `json:"key,omitempty"`
|
Key string `json:"key,omitempty"`
|
||||||
IssueTypes []IssueType
|
Name string
|
||||||
|
IssueTypes []*IssueType
|
||||||
}
|
}
|
||||||
|
|
||||||
type Author struct {
|
type Author struct {
|
||||||
Name string
|
Name string `json:"name"`
|
||||||
DisplayName string
|
DisplayName string `json:"displayName"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Author) String() string {
|
||||||
|
return a.DisplayName
|
||||||
}
|
}
|
||||||
|
|
||||||
type Comment struct {
|
type Comment struct {
|
||||||
Id string
|
Id string `json:"id"`
|
||||||
Author *Author
|
Author *Author `json:"author"`
|
||||||
Body string
|
Body string `json:"body"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CommentColl struct {
|
type CommentColl struct {
|
||||||
|
|
@ -54,6 +99,86 @@ type TimeTracking struct {
|
||||||
RemainingEstimateSeconds int
|
RemainingEstimateSeconds int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *Attachment) String() string {
|
||||||
|
return fmt.Sprintf("Filename: [%s]\tAuthor:[%s]\tURL:[%s]", a.Filename, a.Author.Name, a.Content)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Attachment struct {
|
||||||
|
Filename string
|
||||||
|
Author *Author
|
||||||
|
Content string
|
||||||
|
}
|
||||||
|
|
||||||
|
type LinkType struct {
|
||||||
|
Id string
|
||||||
|
Name string
|
||||||
|
Inward string
|
||||||
|
Outward string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *IssueLink) String() string {
|
||||||
|
if i.InwardIssue != nil {
|
||||||
|
return fmt.Sprintf("%s --> %s: %s", i.LinkType.Inward, i.InwardIssue.Key, i.InwardIssue.Fields.Summary)
|
||||||
|
}
|
||||||
|
if i.OutwardIssue != nil {
|
||||||
|
return fmt.Sprintf("%s --> %s: %s", i.LinkType.Outward, i.OutwardIssue.Key, i.OutwardIssue.Fields.Summary)
|
||||||
|
}
|
||||||
|
return "Issue Link Got Weird"
|
||||||
|
}
|
||||||
|
|
||||||
|
type IssueLink struct {
|
||||||
|
LinkType *LinkType `json:"type"`
|
||||||
|
InwardIssue *JiraIssue
|
||||||
|
OutwardIssue *JiraIssue
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Worklog) String() string {
|
||||||
|
return fmt.Sprintf("%s worked %s on %s", w.Author.Name, w.TimeSpent, w.Started)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Worklog struct {
|
||||||
|
Author *Author
|
||||||
|
Comment string
|
||||||
|
TimeSpent string
|
||||||
|
TimeSpentSeconds int
|
||||||
|
Started string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Worklogs struct {
|
||||||
|
Worklogs []*Worklog `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Fields) UnmarshalJSON(b []byte) error{
|
||||||
|
err := json.Unmarshal(b, &f.rawFields)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("splosion")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
f.rawExtraFields = map[string]json.RawMessage{}
|
||||||
|
vf := reflect.ValueOf(f).Elem()
|
||||||
|
for key, mess := range f.rawFields {
|
||||||
|
field := vf.FieldByNameFunc(func(s string)bool{return strings.ToLower(key) == strings.ToLower(s)})
|
||||||
|
if field.IsValid() {
|
||||||
|
objType := field.Type()
|
||||||
|
obj := reflect.New(objType).Interface()
|
||||||
|
err := json.Unmarshal(mess, &obj)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, objType, obj, string(mess))
|
||||||
|
fmt.Fprintln(os.Stderr, errors.New(fmt.Sprintf("%s [%s]: %s","Error allocating field",key, err)))
|
||||||
|
}
|
||||||
|
field.Set(reflect.ValueOf(obj).Elem())
|
||||||
|
} else {
|
||||||
|
f.rawExtraFields[key] = mess
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type Priority struct {
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
|
||||||
type Fields struct {
|
type Fields struct {
|
||||||
*IssueType `json:"issuetype,omitempty"`
|
*IssueType `json:"issuetype,omitempty"`
|
||||||
Assignee *Author `json:",omitempty"`
|
Assignee *Author `json:",omitempty"`
|
||||||
|
|
@ -64,6 +189,13 @@ type Fields struct {
|
||||||
Parent *JiraIssue `json:",omitempty"`
|
Parent *JiraIssue `json:",omitempty"`
|
||||||
Status *Status `json:",omitempty"`
|
Status *Status `json:",omitempty"`
|
||||||
TimeTracking *TimeTracking `json:"timetracking,omitempty"`
|
TimeTracking *TimeTracking `json:"timetracking,omitempty"`
|
||||||
|
Attachment []*Attachment `json:"attachment,omitempty"`
|
||||||
|
IssueLinks []*IssueLink `json:"issueLinks,omitempty"`
|
||||||
|
Priority *Priority `json:",omitempty"`
|
||||||
|
Worklog *Worklogs `json:"worklog,omitempty"`
|
||||||
|
rawFields map[string]json.RawMessage
|
||||||
|
rawExtraFields map[string]json.RawMessage
|
||||||
|
ExtraFields map[string]interface{} `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Fields) PrettyRemaining() string {
|
func (f *Fields) PrettyRemaining() string {
|
||||||
|
|
@ -84,9 +216,99 @@ func PrettySeconds(seconds int) string {
|
||||||
return fmt.Sprintf("%dd %2dh %2dm %2ds", days, hours, minutes, seconds)
|
return fmt.Sprintf("%dd %2dh %2dm %2ds", days, hours, minutes, seconds)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Transition struct{
|
||||||
|
Id string `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type Schema struct {
|
||||||
|
System string
|
||||||
|
Custom string
|
||||||
|
CustomId int
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type EditMeta struct {
|
||||||
|
Fields map[string]*FieldSpec
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
type JiraIssue struct {
|
type JiraIssue struct {
|
||||||
Key string `json:"key,omitempty"`
|
Key string `json:"key,omitempty"`
|
||||||
Fields *Fields `json:"fields"`
|
Fields *Fields `json:"fields,omitempty"`
|
||||||
|
Transitions []*Transition `json:"transitions,omitempty"`
|
||||||
|
EditMeta *EditMeta `json:"editmeta,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var sprintRegexp = regexp.MustCompile(`name=([^,]+),`)
|
||||||
|
func (i *JiraIssue) UnmarshalJSON(b []byte) error {
|
||||||
|
tmp := map[string]json.RawMessage{}
|
||||||
|
if len(b) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
i.Fields = &Fields{}
|
||||||
|
i.EditMeta = &EditMeta{Fields:map[string]*FieldSpec{}}
|
||||||
|
err := json.Unmarshal(b, &tmp)
|
||||||
|
if err != nil && *Verbose {
|
||||||
|
fmt.Fprintln(os.Stderr, errors.New(fmt.Sprintf("%s: %s", "Error unpacking raw json", err)))
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(tmp["fields"], &i.Fields)
|
||||||
|
if err != nil && *Verbose {
|
||||||
|
fmt.Fprintln(os.Stderr, errors.New(fmt.Sprintf("%s: %s", "Error unpacking fields", err)))
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(tmp["transitions"], &i.Transitions)
|
||||||
|
if err != nil && *Verbose {
|
||||||
|
fmt.Fprintln(os.Stderr, errors.New(fmt.Sprintf("%s: %s", "Error unpacking transitions", err)))
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(tmp["editmeta"], &i.EditMeta)
|
||||||
|
if err != nil && *Verbose{
|
||||||
|
fmt.Fprintln(os.Stderr, errors.New(fmt.Sprintf("%s: %s", "Error unpacking EditMeta", err)))
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(tmp["key"], &i.Key)
|
||||||
|
if err != nil && *Verbose {
|
||||||
|
fmt.Fprintln(os.Stderr, errors.New(fmt.Sprintf("%s: %s", "Error unpacking key", err)))
|
||||||
|
}
|
||||||
|
|
||||||
|
i.Fields.ExtraFields = map[string]interface{}{}
|
||||||
|
for k, v := range i.Fields.rawExtraFields {
|
||||||
|
if f, ok := i.EditMeta.Fields[k]; ok {
|
||||||
|
if f.Schema.Custom == "com.pyxis.greenhopper.jira:gh-sprint" {
|
||||||
|
results := sprintRegexp.FindStringSubmatch(string(v))
|
||||||
|
if len(results) == 2 {
|
||||||
|
i.Fields.ExtraFields[k] = results[1]
|
||||||
|
}
|
||||||
|
} else {switch f.Schema.Type {
|
||||||
|
case "user":
|
||||||
|
a := &Author{}
|
||||||
|
json.Unmarshal(v, &a)
|
||||||
|
i.Fields.ExtraFields[k] = a
|
||||||
|
case "option":
|
||||||
|
val := &AllowedValue{}
|
||||||
|
err = json.Unmarshal(v, &val)
|
||||||
|
if err != nil {panic(err)}
|
||||||
|
i.Fields.ExtraFields[k] = val
|
||||||
|
case "array":
|
||||||
|
if f.Schema.Items == "option" {
|
||||||
|
val := []*AllowedValue{}
|
||||||
|
err = json.Unmarshal(v, &val)
|
||||||
|
if err != nil {panic(err)}
|
||||||
|
i.Fields.ExtraFields[k] = val
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
|
default:
|
||||||
|
if string(v) != "null" {
|
||||||
|
i.Fields.ExtraFields[k] = string(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *JiraIssue) URL() string {
|
func (i *JiraIssue) URL() string {
|
||||||
|
|
@ -107,7 +329,26 @@ func (i *JiraIssue) String() string {
|
||||||
return b.String()
|
return b.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
var commentTemplate = `{{if .Fields.Comment }}{{$k := .Key}}{{range .Fields.Comment.Comments}}{{.Author.DisplayName}} ({{$k}}#{{.Id}}):
|
func (i *JiraIssue) PrintExtraFields() string{
|
||||||
|
sorter := map[string]string{}
|
||||||
|
b := bytes.NewBuffer(nil)
|
||||||
|
for k, v := range i.Fields.ExtraFields {
|
||||||
|
if f, ok := i.EditMeta.Fields[k]; ok && v != nil {
|
||||||
|
sorter[f.Name] = fmt.Sprintf("%s: %s", f.Name, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
keys := make([]string, 0, len(sorter))
|
||||||
|
for k, _ := range sorter {
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
sort.Strings(keys)
|
||||||
|
for _, v := range keys {
|
||||||
|
fmt.Fprintln(b, sorter[v])
|
||||||
|
}
|
||||||
|
return b.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
var commentTemplate = `{{if .Fields.Comment }}{{$k := .Key}}{{range .Fields.Comment.Comments}}{{.Author.DisplayName}} [~{{.Author.Name}}] ({{$k}}`+CommentIdSeparator+`{{.Id}}):
|
||||||
-----------------
|
-----------------
|
||||||
{{.Body}}
|
{{.Body}}
|
||||||
-----------------
|
-----------------
|
||||||
|
|
@ -117,18 +358,28 @@ var commentTemplate = `{{if .Fields.Comment }}{{$k := .Key}}{{range .Fields.Comm
|
||||||
var issueTmplTxt = "\x1b[1m{{.Key}}\x1b[0m\t{{if .Fields.IssueType}}[{{.Fields.IssueType.Name}}]{{end}}\t{{.Fields.Summary}}\n\n" +
|
var issueTmplTxt = "\x1b[1m{{.Key}}\x1b[0m\t{{if .Fields.IssueType}}[{{.Fields.IssueType.Name}}]{{end}}\t{{.Fields.Summary}}\n\n" +
|
||||||
"\x1b[1mURL\x1b[0m: {{.URL}}\n\n" +
|
"\x1b[1mURL\x1b[0m: {{.URL}}\n\n" +
|
||||||
"{{if .Fields.Status}}\x1b[1mStatus\x1b[0m:\t {{.Fields.Status.Name}}\n{{end}}" +
|
"{{if .Fields.Status}}\x1b[1mStatus\x1b[0m:\t {{.Fields.Status.Name}}\n{{end}}" +
|
||||||
|
"{{if .Fields.Priority}}\x1b[1mStatus\x1b[0m:\t {{.Fields.Priority.Name}}\n{{end}}" +
|
||||||
|
"\x1b[1mTransitions\x1b[0m: {{range .Transitions}}[{{.Name}}] {{end}}\n"+
|
||||||
"{{if .Fields.Assignee}}\x1b[1mAssignee:\x1b[0m\t{{.Fields.Assignee.Name}}\n{{end}}\n" +
|
"{{if .Fields.Assignee}}\x1b[1mAssignee:\x1b[0m\t{{.Fields.Assignee.Name}}\n{{end}}\n" +
|
||||||
"\x1b[1mTime Remaining/Original Estimate:\x1b[0m\t{{.Fields.PrettyRemaining}} / {{.Fields.PrettyOriginalEstimate}}\n\n" +
|
"\x1b[1mTime Remaining/Original Estimate:\x1b[0m\t{{.Fields.PrettyRemaining}} / {{.Fields.PrettyOriginalEstimate}}\n\n" +
|
||||||
|
"{{$i := .}}{{range $k, $v := .Fields.ExtraFields}}{{with index $i.EditMeta.Fields $k}}\x1b[1m{{.Name}}\x1b[0m{{end}}: {{$v}}\n{{end}}\n\n"+
|
||||||
"\x1b[1mDescription:\x1b[0m {{.Fields.Description}} \n\n" +
|
"\x1b[1mDescription:\x1b[0m {{.Fields.Description}} \n\n" +
|
||||||
"\x1b[1mComments:\x1b[0m\n\n" + commentTemplate
|
"\x1b[1mIssue Links\x1b[0m: \n{{range .Fields.IssueLinks}}\t{{.}}\n{{end}}\n\n" +
|
||||||
|
"\x1b[1mComments:\x1b[0m\n\n" + commentTemplate +
|
||||||
|
"Worklog:\n{{range .Fields.Worklog.Worklogs}}\t{{.}}\n{{end}}"
|
||||||
|
|
||||||
var issueTmplNoColorTxt = "{{.Key}}\t{{if .Fields.IssueType}}[{{.Fields.IssueType.Name}}]{{end}}\t{{.Fields.Summary}}\n\n" +
|
var issueTmplNoColorTxt = "{{.Key}}\t{{if .Fields.IssueType}}[{{.Fields.IssueType.Name}}]{{end}}\t{{.Fields.Summary}}\n\n" +
|
||||||
"URL: {{.URL}}\n\n" +
|
"URL: {{.URL}}\n\n" +
|
||||||
"{{if .Fields.Status}}Status:\t {{.Fields.Status.Name}}\n{{end}}" +
|
"{{if .Fields.Status}}Status:\t {{.Fields.Status.Name}}\n{{end}}" +
|
||||||
|
"Transitions: {{range .Transitions}}[{{.Name}}] {{end}}\n"+
|
||||||
"{{if .Fields.Assignee}}Assignee:\t{{.Fields.Assignee.Name}}\n{{end}}\n" +
|
"{{if .Fields.Assignee}}Assignee:\t{{.Fields.Assignee.Name}}\n{{end}}\n" +
|
||||||
"Time Remaining/Original Estimate:\t{{.Fields.PrettyRemaining}} / {{.Fields.PrettyOriginalEstimate}}\n\n" +
|
"Time Remaining/Original Estimate:\t{{.Fields.PrettyRemaining}} / {{.Fields.PrettyOriginalEstimate}}\n\n" +
|
||||||
|
"{{.PrintExtraFields}}\n\n"+
|
||||||
"Description: {{.Fields.Description}} \n\n" +
|
"Description: {{.Fields.Description}} \n\n" +
|
||||||
"Comments:\n\n" + commentTemplate
|
"Issue Links: \n{{range .Fields.IssueLinks}}\t{{.}}\n{{end}}\n\n" +
|
||||||
|
"Comments:\n\n" + commentTemplate+
|
||||||
|
"Worklog:\n{{range .Fields.Worklog.Worklogs}}\t{{.}}\n{{end}}"
|
||||||
|
|
||||||
|
var CommentIdSeparator = "~"
|
||||||
var issueTmpl = template.Must(template.New("issueTmpl").Parse(issueTmplTxt))
|
var issueTmpl = template.Must(template.New("issueTmpl").Parse(issueTmplTxt))
|
||||||
var issueTmplNoColor = template.Must(template.New("issueTmplNoColor").Parse(issueTmplNoColorTxt))
|
var issueTmplNoColor = template.Must(template.New("issueTmplNoColor").Parse(issueTmplNoColorTxt))
|
||||||
135
jkl.go
135
jkl.go
|
|
@ -24,22 +24,63 @@ func bootHttpClient() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Create(issue *JiraIssue) error {
|
func Create(issue *JiraIssue) (*JiraIssue, error) {
|
||||||
bootHttpClient()
|
bootHttpClient()
|
||||||
payload, err := formatPayload(issue)
|
payload, err := formatPayload(issue)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
// fmt.Println(issue)
|
// fmt.Println(issue)
|
||||||
resp, err := httpClient.Post("api/2/issue", payload)
|
resp, err := httpClient.Post("api/2/issue", payload)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(resp.StatusCode)
|
fmt.Println(resp.StatusCode)
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
if resp.StatusCode >= 400 {
|
if resp.StatusCode >= 400 {
|
||||||
io.Copy(os.Stderr, resp.Body)
|
io.Copy(os.Stderr, resp.Body)
|
||||||
|
return nil, errors.New(fmt.Sprintf("HTTP error, %v", resp.StatusCode))
|
||||||
}
|
}
|
||||||
return nil
|
dec := json.NewDecoder(resp.Body)
|
||||||
|
issue = &JiraIssue{}
|
||||||
|
err = dec.Decode(issue)
|
||||||
|
if err != nil {
|
||||||
|
b, _ := ioutil.ReadAll(resp.Body)
|
||||||
|
fmt.Println(string(b))
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return issue, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetCreateMeta(projectKey, issueType string) (*CreateMeta, error) {
|
||||||
|
bootHttpClient()
|
||||||
|
path := fmt.Sprintf("api/2/issue/createmeta?expand=projects.issuetypes.fields&issuetypeNames=%s&projectKeys=%s", strings.Title(strings.ToLower(issueType)), projectKey)
|
||||||
|
fmt.Println(path)
|
||||||
|
resp, err := httpClient.Get(path)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
b, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if resp.StatusCode >= 400 {
|
||||||
|
fmt.Println("Status code:", resp.StatusCode)
|
||||||
|
fmt.Println("Response:")
|
||||||
|
fmt.Println(string(b))
|
||||||
|
return nil, errors.New("Some http error happened.")
|
||||||
|
}
|
||||||
|
fmt.Println(string(b))
|
||||||
|
dec := json.NewDecoder(bytes.NewBuffer(b))
|
||||||
|
var createmeta = &CreateMeta{}
|
||||||
|
err = dec.Decode(createmeta)
|
||||||
|
if err != nil {
|
||||||
|
b, _ := ioutil.ReadAll(resp.Body)
|
||||||
|
fmt.Println(string(b))
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return createmeta, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func Edit(issue *JiraIssue) error {
|
func Edit(issue *JiraIssue) error {
|
||||||
|
|
@ -93,10 +134,9 @@ func List(jql string) ([]*JiraIssue, error) {
|
||||||
|
|
||||||
func GetIssue(taskKey string) (*JiraIssue, error) {
|
func GetIssue(taskKey string) (*JiraIssue, error) {
|
||||||
bootHttpClient()
|
bootHttpClient()
|
||||||
path := "api/2/issue/" + taskKey
|
path := "api/2/issue/" + taskKey+"?expand=transitions,operations,editmeta"
|
||||||
resp, err := httpClient.Get(path)
|
resp, err := httpClient.Get(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(resp.StatusCode)
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
dec := json.NewDecoder(resp.Body)
|
dec := json.NewDecoder(resp.Body)
|
||||||
|
|
@ -127,16 +167,97 @@ func AddComment(taskKey string, comment string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetComment(taskKey string, commentId string) (*Comment, error) {
|
||||||
|
bootHttpClient()
|
||||||
|
path := "api/2/issue/" + taskKey + "/comment/" + commentId
|
||||||
|
resp, err := httpClient.Get(path)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(resp.StatusCode)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
dec := json.NewDecoder(resp.Body)
|
||||||
|
var comment = &Comment{}
|
||||||
|
err = dec.Decode(comment)
|
||||||
|
if err != nil {
|
||||||
|
b, _ := ioutil.ReadAll(resp.Body)
|
||||||
|
fmt.Println(string(b))
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return comment, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func EditComment(taskKey string, commentId string, comment *Comment) error {
|
||||||
|
bootHttpClient()
|
||||||
|
payload, err := serializePayload(comment)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
resp, err := httpClient.Put("api/2/issue/"+taskKey+"/comment/"+commentId, payload)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(resp.StatusCode)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resp.StatusCode >= 400 {
|
||||||
|
io.Copy(os.Stderr, resp.Body)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func DoTransition(taskKey string, transitionName string) error {
|
||||||
|
iss, err := GetIssue(taskKey)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var t *Transition
|
||||||
|
fmt.Println(iss.Transitions)
|
||||||
|
for _, transition := range iss.Transitions {
|
||||||
|
if strings.ToLower(transition.Name) == strings.ToLower(transitionName) {
|
||||||
|
t = transition
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if t == nil {
|
||||||
|
return errors.New("Transition not found")
|
||||||
|
}
|
||||||
|
payload, err := serializePayload(map[string]interface{}{"transition": t})
|
||||||
|
resp, err := httpClient.Post("api/2/issue/"+taskKey+"/transitions/", payload)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(resp.StatusCode)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resp.StatusCode >= 400 {
|
||||||
|
io.Copy(os.Stderr, resp.Body)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func LogWork(taskKey string, workAmount string) error {
|
||||||
|
payload, err := serializePayload(map[string]interface{}{"timeSpent": workAmount})
|
||||||
|
resp, err := httpClient.Post("api/2/issue/"+taskKey+"/worklog", payload)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(resp.StatusCode)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resp.StatusCode >= 400 {
|
||||||
|
io.Copy(os.Stderr, resp.Body)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func formatPayload(issue *JiraIssue) (io.Reader, error) {
|
func formatPayload(issue *JiraIssue) (io.Reader, error) {
|
||||||
if issue.Fields != nil &&
|
if issue.Fields != nil &&
|
||||||
issue.Fields.Project != nil &&
|
issue.Fields.Project != nil &&
|
||||||
issue.Fields.Project.Key == "" {
|
issue.Fields.Project.Key == "" {
|
||||||
issue.Fields.Project.Key = os.Getenv("JIRA_PROJECT")
|
issue.Fields.Project.Key = os.Getenv("JIRA_PROJECT")
|
||||||
}
|
}
|
||||||
|
return serializePayload(issue)
|
||||||
|
}
|
||||||
|
|
||||||
|
func serializePayload(i interface{}) (io.Reader, error) {
|
||||||
var b []byte
|
var b []byte
|
||||||
payload := bytes.NewBuffer(b)
|
payload := bytes.NewBuffer(b)
|
||||||
enc := json.NewEncoder(payload)
|
enc := json.NewEncoder(payload)
|
||||||
err := enc.Encode(issue)
|
err := enc.Encode(i)
|
||||||
fmt.Println(payload.String())
|
fmt.Println(payload.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue