Compare commits
1 commit
master
...
silentmode
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7f8947b970 |
9 changed files with 188 additions and 125 deletions
|
|
@ -4,9 +4,9 @@ import (
|
|||
"bytes"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"fmt"
|
||||
"text/template"
|
||||
|
||||
"otremblay.com/jkl"
|
||||
|
|
@ -17,6 +17,7 @@ type CreateCmd struct {
|
|||
project string
|
||||
file string
|
||||
issuetype string
|
||||
silent bool
|
||||
}
|
||||
|
||||
func NewCreateCmd(args []string) (*CreateCmd, error) {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package main
|
|||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"text/template"
|
||||
|
|
@ -21,9 +22,9 @@ func NewEditCmd(args []string) (*EditCmd, error) {
|
|||
ccmd := &EditCmd{project: os.Getenv("JIRA_PROJECT")}
|
||||
f := flag.NewFlagSet("x", flag.ExitOnError)
|
||||
f.StringVar(&ccmd.project, "p", "", "Jira project key")
|
||||
f.StringVar(&ccmd.file, "f", "filename", "File to get issue description from")
|
||||
f.StringVar(&ccmd.file, "f", "", "File to get issue description from")
|
||||
f.Parse(args)
|
||||
ccmd.taskKey = flag.Arg(0)
|
||||
ccmd.taskKey = f.Arg(0)
|
||||
return ccmd, nil
|
||||
}
|
||||
|
||||
|
|
@ -31,7 +32,7 @@ func (ecmd *EditCmd) Edit() error {
|
|||
b := bytes.NewBuffer(nil)
|
||||
iss, err := jkl.GetIssue(ecmd.taskKey)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("Edit failed: %v", err)
|
||||
}
|
||||
err = editTmpl.Execute(b, iss)
|
||||
if err != nil {
|
||||
|
|
@ -42,12 +43,12 @@ func (ecmd *EditCmd) Edit() error {
|
|||
iss, err = GetIssueFromFile(ecmd.file, b, iss.EditMeta)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("Error getting issue from file: %v", err)
|
||||
}
|
||||
} else {
|
||||
iss, err = GetIssueFromTmpFile(b, iss.EditMeta)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("Error getting issue from temp file: %v", err)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import (
|
|||
"os/exec"
|
||||
"regexp"
|
||||
"strings"
|
||||
"unicode"
|
||||
|
||||
"reflect"
|
||||
|
||||
|
|
@ -17,6 +18,7 @@ import (
|
|||
|
||||
"otremblay.com/jkl"
|
||||
)
|
||||
|
||||
// def get_editor do
|
||||
// [System.get_env("EDITOR"), "nano", "vim", "vi"]
|
||||
// |> Enum.find(nil, fn (ed) -> System.find_executable(ed) != nil end)
|
||||
|
|
@ -42,12 +44,12 @@ func copyInitial(dst io.WriteSeeker, initial io.Reader) {
|
|||
func GetIssueFromTmpFile(initial io.Reader, editMeta *jkl.EditMeta) (*jkl.JiraIssue, error) {
|
||||
f, err := ioutil.TempFile(os.TempDir(), "jkl")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("Error opening tempfile: %v", err)
|
||||
}
|
||||
copyInitial(f, initial)
|
||||
f2, err := GetTextFromFile(f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("Error reading tempfile: %v", err)
|
||||
}
|
||||
return IssueFromReader(f2, editMeta), nil
|
||||
}
|
||||
|
|
@ -73,6 +75,8 @@ func GetTextFromSpecifiedFile(filename string, initial io.Reader) (io.Reader, er
|
|||
}
|
||||
|
||||
func GetTextFromFile(file *os.File) (io.Reader, error) {
|
||||
var err error
|
||||
if !*SilentMode {
|
||||
cmd := exec.Command(GetEditor(), file.Name())
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Stdout = os.Stdout
|
||||
|
|
@ -83,6 +87,7 @@ func GetTextFromFile(file *os.File) (io.Reader, error) {
|
|||
return nil, err
|
||||
}
|
||||
_, err = file.Seek(0, 0)
|
||||
}
|
||||
return file, err
|
||||
}
|
||||
|
||||
|
|
@ -108,6 +113,7 @@ func IssueFromReader(f io.Reader, editMeta *jkl.EditMeta) *jkl.JiraIssue {
|
|||
riss := reflect.ValueOf(iss).Elem()
|
||||
fieldsField := riss.FieldByName("Fields").Elem()
|
||||
currentField := reflect.Value{}
|
||||
currFieldName := ""
|
||||
brd := bufio.NewReader(f)
|
||||
for {
|
||||
b, _, err := brd.ReadLine()
|
||||
|
|
@ -131,6 +137,7 @@ func IssueFromReader(f io.Reader, editMeta *jkl.EditMeta) *jkl.JiraIssue {
|
|||
if len(parts) > 0 {
|
||||
iss.Fields.IssueType = &jkl.IssueType{}
|
||||
currentField = reflect.Value{}
|
||||
currFieldName = potentialField
|
||||
f2 := newfield.Elem()
|
||||
f3 := f2.FieldByName("Name")
|
||||
f3.SetString(strings.TrimSpace(strings.Join(parts, ":")))
|
||||
|
|
@ -139,6 +146,7 @@ func IssueFromReader(f io.Reader, editMeta *jkl.EditMeta) *jkl.JiraIssue {
|
|||
if len(parts) > 0 {
|
||||
iss.Fields.Project = &jkl.Project{}
|
||||
currentField = reflect.Value{}
|
||||
currFieldName = potentialField
|
||||
f2 := newfield.Elem()
|
||||
f3 := f2.FieldByName("Key")
|
||||
f3.SetString(strings.TrimSpace(strings.Join(parts, ":")))
|
||||
|
|
@ -147,11 +155,13 @@ func IssueFromReader(f io.Reader, editMeta *jkl.EditMeta) *jkl.JiraIssue {
|
|||
if len(parts) > 0 {
|
||||
iss.Fields.Parent = &jkl.JiraIssue{}
|
||||
currentField = reflect.Value{}
|
||||
currFieldName = potentialField
|
||||
f2 := newfield.Elem()
|
||||
f3 := f2.FieldByName("Key")
|
||||
f3.SetString(strings.TrimSpace(strings.Join(parts, ":")))
|
||||
}
|
||||
} else {
|
||||
currFieldName = potentialField
|
||||
currentField = newfield
|
||||
}
|
||||
} else if editMeta != nil {
|
||||
|
|
@ -159,7 +169,13 @@ func IssueFromReader(f io.Reader, editMeta *jkl.EditMeta) *jkl.JiraIssue {
|
|||
|
||||
}
|
||||
if currentField.IsValid() {
|
||||
currentField.SetString(strings.TrimSpace(currentField.String() + "\n" + strings.Join(parts, ":")))
|
||||
newString := currentField.String() + "\n" + strings.Join(parts, ":")
|
||||
if currFieldName != "Description" {
|
||||
newString = strings.TrimSpace(newString)
|
||||
} else if currentField.String() == "" {
|
||||
newString = strings.TrimLeftFunc(newString, unicode.IsSpace)
|
||||
}
|
||||
currentField.SetString(newString)
|
||||
}
|
||||
}
|
||||
return iss
|
||||
|
|
|
|||
|
|
@ -12,7 +12,8 @@ hell
|
|||
Issue Type: Sometype
|
||||
this is ignored
|
||||
Summary: Dookienator
|
||||
also ignored`, "\n"))
|
||||
also ignored`, "\n"), nil)
|
||||
|
||||
AssertEqual(t, `Cowboys
|
||||
from
|
||||
hell`, iss.Fields.Description)
|
||||
|
|
@ -34,3 +35,13 @@ Actual: %v`, expected, actual)
|
|||
func Assert(t *testing.T, fn func() bool) {
|
||||
|
||||
}
|
||||
|
||||
func TestIssueFromFile(t *testing.T) {
|
||||
*SilentMode = true
|
||||
issue, err := GetIssueFromFile("editor_test_file.issue", nil, nil)
|
||||
if err != nil {
|
||||
t.Errorf("Apparently we effed up some! --> %v", err)
|
||||
}
|
||||
AssertEqual(t, "Dookie", issue.Fields.Summary)
|
||||
AssertEqual(t, "McDoogal", issue.Fields.Description)
|
||||
}
|
||||
|
|
|
|||
2
cmd/jkl/editor_test_file.issue
Normal file
2
cmd/jkl/editor_test_file.issue
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
Summary: Dookie
|
||||
Description: McDoogal
|
||||
|
|
@ -14,6 +14,7 @@ import (
|
|||
|
||||
var verbose = flag.Bool("v", false, "Output debug information about jkl")
|
||||
var help = flag.Bool("h", false, "Outputs usage information message")
|
||||
var SilentMode = flag.Bool("s", false, "Silent execution.")
|
||||
|
||||
func main() {
|
||||
jkl.FindRCFile()
|
||||
|
|
|
|||
|
|
@ -39,6 +39,9 @@ func (l *listissue) Color() string {
|
|||
}
|
||||
return ""
|
||||
}
|
||||
func (l *listissue) EFByName(name string) string {
|
||||
return (*jkl.JiraIssue)(l).EFByName(name)
|
||||
}
|
||||
|
||||
type ListCmd struct {
|
||||
args []string
|
||||
|
|
@ -76,7 +79,7 @@ func (l *ListCmd) List() error {
|
|||
if issues, err := jkl.List(strings.Join(l.args, " ")); err != nil {
|
||||
return err
|
||||
} else {
|
||||
for _, issue := range issues {
|
||||
for issue := range issues {
|
||||
var li listissue
|
||||
li = listissue(*issue)
|
||||
err := l.tmpl.Execute(os.Stdout, &li)
|
||||
|
|
|
|||
51
issue.go
51
issue.go
|
|
@ -16,6 +16,8 @@ import (
|
|||
|
||||
type Search struct {
|
||||
Issues []*JiraIssue `json:"issues"`
|
||||
Total int
|
||||
MaxResults int
|
||||
}
|
||||
|
||||
type IssueType struct {
|
||||
|
|
@ -58,10 +60,8 @@ type FieldSpec struct {
|
|||
}
|
||||
Operations []string
|
||||
AllowedValues []*AllowedValue
|
||||
|
||||
}
|
||||
|
||||
|
||||
type CreateMeta struct {
|
||||
Projects []*Project
|
||||
}
|
||||
|
|
@ -168,7 +168,9 @@ func (f *Fields) UnmarshalJSON(b []byte) error{
|
|||
fmt.Fprintln(os.Stderr, objType, obj, string(mess))
|
||||
fmt.Fprintln(os.Stderr, errors.New(fmt.Sprintf("%s [%s]: %s", "Error allocating field", key, err)))
|
||||
}
|
||||
if obj != nil && !(reflect.ValueOf(obj) == reflect.Zero(reflect.TypeOf(obj))) {
|
||||
field.Set(reflect.ValueOf(obj).Elem())
|
||||
}
|
||||
} else {
|
||||
f.rawExtraFields[key] = mess
|
||||
}
|
||||
|
|
@ -223,20 +225,16 @@ type Transition struct{
|
|||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
|
||||
type Schema struct {
|
||||
System string
|
||||
Custom string
|
||||
CustomId int
|
||||
}
|
||||
|
||||
|
||||
type EditMeta struct {
|
||||
Fields map[string]*FieldSpec
|
||||
}
|
||||
|
||||
|
||||
|
||||
type JiraIssue struct {
|
||||
Key string `json:"key,omitempty"`
|
||||
Fields *Fields `json:"fields,omitempty"`
|
||||
|
|
@ -244,8 +242,8 @@ type JiraIssue struct {
|
|||
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 {
|
||||
|
|
@ -282,7 +280,8 @@ func (i *JiraIssue) UnmarshalJSON(b []byte) error {
|
|||
if len(results) == 2 {
|
||||
i.Fields.ExtraFields[k] = results[1]
|
||||
}
|
||||
} else {switch f.Schema.Type {
|
||||
} else {
|
||||
switch f.Schema.Type {
|
||||
case "user":
|
||||
a := &Author{}
|
||||
json.Unmarshal(v, &a)
|
||||
|
|
@ -290,13 +289,17 @@ func (i *JiraIssue) UnmarshalJSON(b []byte) error {
|
|||
case "option":
|
||||
val := &AllowedValue{}
|
||||
err = json.Unmarshal(v, &val)
|
||||
if err != nil {panic(err)}
|
||||
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)}
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
i.Fields.ExtraFields[k] = val
|
||||
continue
|
||||
}
|
||||
|
|
@ -331,6 +334,20 @@ func (i *JiraIssue) String() string {
|
|||
return b.String()
|
||||
}
|
||||
|
||||
func (i *JiraIssue) EFByName(name string) string {
|
||||
for k, f := range i.EditMeta.Fields {
|
||||
if f.Name == name {
|
||||
return fmt.Sprint(i.Fields.ExtraFields[k])
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func (i *JiraIssue) StoryPoints() string {
|
||||
return i.EFByName("Story Points")
|
||||
}
|
||||
|
||||
func (i *JiraIssue) PrintExtraFields() string {
|
||||
sorter := map[string]string{}
|
||||
b := bytes.NewBuffer(nil)
|
||||
|
|
@ -383,5 +400,15 @@ var issueTmplNoColorTxt = "{{.Key}}\t{{if .Fields.IssueType}}[{{.Fields.IssueTyp
|
|||
"Worklog:\n{{range .Fields.Worklog.Worklogs}}\t{{.}}\n{{end}}"
|
||||
|
||||
var CommentIdSeparator = "~"
|
||||
var issueTmpl = template.Must(template.New("issueTmpl").Parse(issueTmplTxt))
|
||||
var issueTmplNoColor = template.Must(template.New("issueTmplNoColor").Parse(issueTmplNoColorTxt))
|
||||
var issueTmpl, issueTmplNoColor *template.Template
|
||||
|
||||
func SetupTmpl() {
|
||||
isstmpl := os.Getenv("JKL_ISSUE_TMPL")
|
||||
if isstmpl != "" {
|
||||
issueTmpl = template.Must(template.New("issueTmpl").Parse(isstmpl))
|
||||
issueTmplNoColor = issueTmpl
|
||||
} else {
|
||||
issueTmpl = template.Must(template.New("issueTmpl").Parse(issueTmplTxt))
|
||||
issueTmplNoColor = template.Must(template.New("issueTmplNoColor").Parse(issueTmplNoColorTxt))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
1
jkl.go
1
jkl.go
|
|
@ -239,6 +239,7 @@ func DoTransition(taskKey string, transitionName string) error {
|
|||
}
|
||||
|
||||
func LogWork(taskKey string, workAmount string) error {
|
||||
bootHttpClient()
|
||||
payload, err := serializePayload(map[string]interface{}{"timeSpent": workAmount})
|
||||
resp, err := httpClient.Post("api/2/issue/"+taskKey+"/worklog", payload)
|
||||
if err != nil {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue