Some betterment of things
This commit is contained in:
parent
a54632176b
commit
c5811d75b7
10 changed files with 115 additions and 50 deletions
|
|
@ -28,7 +28,7 @@ var ErrCcmdJiraProjectRequired = errors.New("Jira project needs to be set")
|
||||||
|
|
||||||
func (ccmd *CreateCmd) Create() error {
|
func (ccmd *CreateCmd) Create() error {
|
||||||
var b = bytes.NewBufferString(CREATE_TEMPLATE)
|
var b = bytes.NewBufferString(CREATE_TEMPLATE)
|
||||||
var iss *jkl.Issue
|
var iss *jkl.JiraIssue
|
||||||
var err error
|
var err error
|
||||||
if ccmd.file != "" {
|
if ccmd.file != "" {
|
||||||
iss, err = GetIssueFromFile(ccmd.file, b)
|
iss, err = GetIssueFromFile(ccmd.file, b)
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ func copyInitial(dst io.WriteSeeker, initial io.Reader) {
|
||||||
dst.Seek(0, 0)
|
dst.Seek(0, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetIssueFromTmpFile(initial io.Reader) (*jkl.Issue, error) {
|
func GetIssueFromTmpFile(initial io.Reader) (*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
|
||||||
|
|
@ -87,7 +87,7 @@ func GetTextFromFile(file *os.File) (io.Reader, error) {
|
||||||
return file, err
|
return file, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetIssueFromFile(filename string, initial io.Reader) (*jkl.Issue, error) {
|
func GetIssueFromFile(filename string, initial io.Reader) (*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
|
||||||
|
|
@ -104,8 +104,8 @@ func GetIssueFromFile(filename string, initial io.Reader) (*jkl.Issue, error) {
|
||||||
|
|
||||||
var spacex = regexp.MustCompile(`\s`)
|
var spacex = regexp.MustCompile(`\s`)
|
||||||
|
|
||||||
func IssueFromFile(f io.Reader) *jkl.Issue {
|
func IssueFromFile(f io.Reader) *jkl.JiraIssue {
|
||||||
iss := &jkl.Issue{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()
|
||||||
currentField := reflect.Value{}
|
currentField := reflect.Value{}
|
||||||
|
|
@ -143,6 +143,6 @@ func IssueFromFile(f io.Reader) *jkl.Issue {
|
||||||
return iss
|
return iss
|
||||||
}
|
}
|
||||||
|
|
||||||
func IssueFromList(list []string) *jkl.Issue {
|
func IssueFromList(list []string) *jkl.JiraIssue {
|
||||||
return IssueFromFile(bytes.NewBufferString(strings.Join(list, "\n")))
|
return IssueFromFile(bytes.NewBufferString(strings.Join(list, "\n")))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,11 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"os"
|
"otremblay.com/jkl"
|
||||||
|
|
||||||
"github.com/joho/godotenv"
|
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
findRCFile()
|
jkl.FindRCFile()
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
if len(flag.Args()) == 0 {
|
if len(flag.Args()) == 0 {
|
||||||
fmt.Print(usage)
|
fmt.Print(usage)
|
||||||
|
|
@ -23,22 +20,6 @@ func main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func findRCFile() {
|
|
||||||
dir, err := os.Getwd()
|
|
||||||
if err != nil {
|
|
||||||
|
|
||||||
log.Fatalln(err)
|
|
||||||
}
|
|
||||||
path := strings.Split(dir, "/")
|
|
||||||
for i := len(path) - 1; i > 0; i-- {
|
|
||||||
err := godotenv.Load(strings.Join(path[0:i], "/") + "/.jklrc")
|
|
||||||
if err == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log.Fatalln("No .jklrc found")
|
|
||||||
}
|
|
||||||
|
|
||||||
func runcmd(args []string) error {
|
func runcmd(args []string) error {
|
||||||
switch args[0] {
|
switch args[0] {
|
||||||
case "list":
|
case "list":
|
||||||
|
|
|
||||||
5
cmd/jkl/jkl_test.go
Normal file
5
cmd/jkl/jkl_test.go
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -8,14 +8,16 @@ import (
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"golang.org/x/crypto/ssh/terminal"
|
"golang.org/x/crypto/ssh/terminal"
|
||||||
"otremblay.com/jkl"
|
"otremblay.com/jkl"
|
||||||
)
|
)
|
||||||
|
|
||||||
type listissue jkl.Issue
|
type listissue jkl.JiraIssue
|
||||||
|
|
||||||
func (l *listissue) URL() string {
|
func (l *listissue) URL() string {
|
||||||
i := jkl.Issue(*l)
|
i := jkl.JiraIssue(*l)
|
||||||
return (&i).URL()
|
return (&i).URL()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *listissue) Color() string {
|
func (l *listissue) Color() string {
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ func (f *jklfile) String() string {
|
||||||
func (f *jklfile) Write(data []byte, off int64) (uint32, fuse.Status) {
|
func (f *jklfile) Write(data []byte, off int64) (uint32, fuse.Status) {
|
||||||
n, err := f.File.WriteAt(data, off)
|
n, err := f.File.WriteAt(data, off)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fuse.EACCES
|
return uint32(0),fuse.EACCES
|
||||||
}
|
}
|
||||||
return uint32(n), fuse.OK
|
return uint32(n), fuse.OK
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ import (
|
||||||
|
|
||||||
type jklfs struct {
|
type jklfs struct {
|
||||||
pathfs.FileSystem
|
pathfs.FileSystem
|
||||||
issuePerDirs map[string]*jkl.Issue
|
issuePerDirs map[string]*jkl.JiraIssue
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j *jklfs) GetAttr(name string, context *fuse.Context) (*fuse.Attr, fuse.Status) {
|
func (j *jklfs) GetAttr(name string, context *fuse.Context) (*fuse.Attr, fuse.Status) {
|
||||||
|
|
@ -90,7 +90,7 @@ func main() {
|
||||||
if len(flag.Args()) < 1 {
|
if len(flag.Args()) < 1 {
|
||||||
log.Fatal("Usage:\n jklfs MOUNTPOINT")
|
log.Fatal("Usage:\n jklfs MOUNTPOINT")
|
||||||
}
|
}
|
||||||
nfs := pathfs.NewPathNodeFs(&jklfs{pathfs.NewDefaultFileSystem(), map[string]*jkl.Issue{}}, nil)
|
nfs := pathfs.NewPathNodeFs(&jklfs{pathfs.NewDefaultFileSystem(), map[string]*jkl.JiraIssue{}}, nil)
|
||||||
server, _, err := nodefs.MountRoot(flag.Arg(0), nfs.Root(), nil)
|
server, _, err := nodefs.MountRoot(flag.Arg(0), nfs.Root(), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Mount fail: %v\n", err)
|
log.Fatalf("Mount fail: %v\n", err)
|
||||||
|
|
|
||||||
32
issue.go
32
issue.go
|
|
@ -4,19 +4,30 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"os"
|
||||||
"text/template"
|
"text/template"
|
||||||
"os"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Search struct {
|
type Search struct {
|
||||||
Issues []*Issue `json:"issues"`
|
Issues []*JiraIssue `json:"issues"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type IssueType struct {
|
type IssueType struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
|
Fields map[string]FieldSpec
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type FieldSpec struct {
|
||||||
|
Name string
|
||||||
|
Required bool
|
||||||
|
Schema struct {
|
||||||
|
Type string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type Project struct {
|
type Project struct {
|
||||||
Key string `json:"key,omitempty"`
|
Key string `json:"key,omitempty"`
|
||||||
|
IssueTypes []IssueType
|
||||||
}
|
}
|
||||||
|
|
||||||
type Author struct {
|
type Author struct {
|
||||||
|
|
@ -25,6 +36,7 @@ type Author struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Comment struct {
|
type Comment struct {
|
||||||
|
Id string
|
||||||
Author *Author
|
Author *Author
|
||||||
Body string
|
Body string
|
||||||
}
|
}
|
||||||
|
|
@ -49,7 +61,7 @@ type Fields struct {
|
||||||
Summary string `json:"summary,omitempty"`
|
Summary string `json:"summary,omitempty"`
|
||||||
Description string `json:"description,omitempty"`
|
Description string `json:"description,omitempty"`
|
||||||
Comment *CommentColl `json:"comment,omitempty"`
|
Comment *CommentColl `json:"comment,omitempty"`
|
||||||
Parent *Issue `json:",omitempty"`
|
Parent *JiraIssue `json:",omitempty"`
|
||||||
Status *Status `json:",omitempty"`
|
Status *Status `json:",omitempty"`
|
||||||
TimeTracking *TimeTracking `json:"timetracking,omitempty"`
|
TimeTracking *TimeTracking `json:"timetracking,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
@ -72,16 +84,16 @@ 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 Issue struct {
|
type JiraIssue struct {
|
||||||
Key string `json:"key,omitempty"`
|
Key string `json:"key,omitempty"`
|
||||||
Fields *Fields `json:"fields"`
|
Fields *Fields `json:"fields"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Issue) URL() string {
|
func (i *JiraIssue) URL() string {
|
||||||
return os.Getenv("JIRA_ROOT") + "browse/"+ i.Key
|
return os.Getenv("JIRA_ROOT") + "browse/" + i.Key
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Issue) String() string {
|
func (i *JiraIssue) String() string {
|
||||||
var b = bytes.NewBuffer(nil)
|
var b = bytes.NewBuffer(nil)
|
||||||
err := issueTmpl.Execute(b, i)
|
err := issueTmpl.Execute(b, i)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -91,7 +103,7 @@ func (i *Issue) String() string {
|
||||||
return b.String()
|
return b.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
var commentTemplate = `{{if .Fields.Comment }}{{range .Fields.Comment.Comments}}{{.Author.DisplayName}}:
|
var commentTemplate = `{{if .Fields.Comment }}{{$k := .Key}}{{range .Fields.Comment.Comments}}{{.Author.DisplayName}} ({{$k}}#{{.Id}}):
|
||||||
-----------------
|
-----------------
|
||||||
{{.Body}}
|
{{.Body}}
|
||||||
-----------------
|
-----------------
|
||||||
|
|
|
||||||
36
jkl.go
36
jkl.go
|
|
@ -6,11 +6,15 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/joho/godotenv"
|
||||||
)
|
)
|
||||||
|
|
||||||
var defaultIssue = &Issue{}
|
var defaultIssue = &JiraIssue{}
|
||||||
|
|
||||||
func bootHttpClient() {
|
func bootHttpClient() {
|
||||||
if httpClient == nil {
|
if httpClient == nil {
|
||||||
|
|
@ -18,7 +22,7 @@ func bootHttpClient() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Create(issue *Issue) error {
|
func Create(issue *JiraIssue) error {
|
||||||
bootHttpClient()
|
bootHttpClient()
|
||||||
payload, err := formatPayload(issue)
|
payload, err := formatPayload(issue)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -36,7 +40,7 @@ func Create(issue *Issue) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func Edit(issue *Issue) error {
|
func Edit(issue *JiraIssue) error {
|
||||||
bootHttpClient()
|
bootHttpClient()
|
||||||
payload, err := formatPayload(issue)
|
payload, err := formatPayload(issue)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -53,7 +57,7 @@ func Edit(issue *Issue) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func List(jql string) ([]*Issue, error) {
|
func List(jql string) ([]*JiraIssue, error) {
|
||||||
bootHttpClient()
|
bootHttpClient()
|
||||||
path := "api/2/search?fields=*all&maxResults=1000"
|
path := "api/2/search?fields=*all&maxResults=1000"
|
||||||
if jql != "" {
|
if jql != "" {
|
||||||
|
|
@ -75,7 +79,7 @@ func List(jql string) ([]*Issue, error) {
|
||||||
return issues.Issues, nil
|
return issues.Issues, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetIssue(taskKey string) (*Issue, error) {
|
func GetIssue(taskKey string) (*JiraIssue, error) {
|
||||||
bootHttpClient()
|
bootHttpClient()
|
||||||
path := "api/2/issue/" + taskKey
|
path := "api/2/issue/" + taskKey
|
||||||
resp, err := httpClient.Get(path)
|
resp, err := httpClient.Get(path)
|
||||||
|
|
@ -84,7 +88,7 @@ func GetIssue(taskKey string) (*Issue, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
dec := json.NewDecoder(resp.Body)
|
dec := json.NewDecoder(resp.Body)
|
||||||
var issue = &Issue{}
|
var issue = &JiraIssue{}
|
||||||
err = dec.Decode(issue)
|
err = dec.Decode(issue)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b, _ := ioutil.ReadAll(resp.Body)
|
b, _ := ioutil.ReadAll(resp.Body)
|
||||||
|
|
@ -111,7 +115,7 @@ func AddComment(taskKey string, comment string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatPayload(issue *Issue) (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 == "" {
|
||||||
|
|
@ -128,3 +132,21 @@ func formatPayload(issue *Issue) (io.Reader, error) {
|
||||||
}
|
}
|
||||||
return payload, nil
|
return payload, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func FindRCFile() string {
|
||||||
|
dir, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
path := strings.Split(dir, "/")
|
||||||
|
for i := len(path); i > 0; i-- {
|
||||||
|
dotenvpath := strings.Join(path[0:i], "/") + "/.jklrc"
|
||||||
|
err := godotenv.Load(dotenvpath)
|
||||||
|
if err == nil {
|
||||||
|
return dotenvpath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Fatalln("No .jklrc found")
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
|
||||||
43
jkl_test.go
Normal file
43
jkl_test.go
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
package jkl
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
"text/template"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestUnmarshalProjects(t *testing.T) {
|
||||||
|
f, err := os.Open("projects.json")
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
dec := json.NewDecoder(f)
|
||||||
|
x := struct{ Projects []Project }{}
|
||||||
|
|
||||||
|
err = dec.Decode(&x)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
for _, p := range x.Projects {
|
||||||
|
for _, it := range p.IssueTypes {
|
||||||
|
for sn, f := range it.Fields {
|
||||||
|
fmt.Println(it.Name, sn, f.Name, f.Required, f.Schema.Type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type TestType struct {
|
||||||
|
Field string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TestType) String() string {
|
||||||
|
return t.Field
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStringerInTemplate(t *testing.T) {
|
||||||
|
x := template.Must(template.New("stuff").Parse("{{.}}"))
|
||||||
|
x.Execute(os.Stdout, &TestType{"This works"})
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue