-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
4fd2ebf
commit 3f3859e
Showing
10 changed files
with
299 additions
and
753 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,57 @@ | ||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= | ||
github.com/AlecAivazis/survey/v2 v2.3.7 h1:6I/u8FvytdGsgonrYsVn2t8t4QiRnh6QSTqkkhIiSjQ= | ||
github.com/AlecAivazis/survey/v2 v2.3.7/go.mod h1:xUTIdE4KCOIjsBAE1JYsUPoCqYdZ1reCfTwbto0Fduo= | ||
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s= | ||
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w= | ||
github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI= | ||
github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= | ||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u7lxST/RaJw+cv273q79D81Xbog= | ||
github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68= | ||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= | ||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= | ||
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU= | ||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= | ||
github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE= | ||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= | ||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4= | ||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= | ||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||
github.com/savioxavier/termlink v1.3.0 h1:3Gl4FzQjUyiHzmoEDfmWEhgIwDiJY4poOQHP+k8ReA4= | ||
github.com/savioxavier/termlink v1.3.0/go.mod h1:5T5ePUlWbxCHIwyF8/Ez1qufOoGM89RCg9NvG+3G3gc= | ||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | ||
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= | ||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= | ||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | ||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= | ||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= | ||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | ||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= | ||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= | ||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s= | ||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= | ||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= | ||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= | ||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | ||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | ||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= | ||
golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= | ||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= | ||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | ||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= | ||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= | ||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= | ||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,209 @@ | ||
package main | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"github.com/AlecAivazis/survey/v2" | ||
"log" | ||
"math" | ||
"net/http" | ||
"net/url" | ||
"os/exec" | ||
"runtime" | ||
) | ||
|
||
type Credential struct { | ||
ApiUser string | ||
ApiKey string | ||
} | ||
|
||
type JiraClient struct { | ||
Domain string | ||
Credential Credential | ||
} | ||
|
||
// Issue By Issue Picker - struct | ||
type Issue struct { | ||
SummaryText, Key string | ||
} | ||
|
||
type Section struct { | ||
Label, Sub, Id string | ||
Issues []Issue | ||
} | ||
|
||
type IssuePickerResp struct { | ||
Sections []Section | ||
} | ||
|
||
// Issue By JQL - struct | ||
|
||
type Fields struct { | ||
Summary string | ||
} | ||
|
||
type IssueJql struct { | ||
Key string | ||
Fields Fields | ||
} | ||
|
||
type IssueJqlResp struct { | ||
Issues []IssueJql | ||
} | ||
|
||
func (j *JiraClient) call(req *http.Request) (*http.Response, error) { | ||
client := http.Client{} | ||
req.SetBasicAuth(j.Credential.ApiUser, j.Credential.ApiKey) | ||
req.Header.Set("Accept", "application/json") | ||
req.Header.Set("Content-Type", "application/json") | ||
return client.Do(req) | ||
} | ||
|
||
func (j *JiraClient) search() { | ||
args := getUserInput() | ||
issues := j.getIssuesUsingIssuePicker(args) | ||
selectedIssueKey := loadIssueListPrompt(issues) | ||
if len(selectedIssueKey) > 0 { | ||
j.openIssueInBrowser(selectedIssueKey) | ||
} | ||
} | ||
|
||
func (j *JiraClient) currentUserSearch(jql string) { | ||
issues := j.getIssuesUsingJql(jql) | ||
selectedIssueKey := loadIssueListPrompt(issues[:]) | ||
if len(selectedIssueKey) > 0 { | ||
j.openIssueInBrowser(selectedIssueKey) | ||
} | ||
} | ||
|
||
func (j *JiraClient) advancedJqlSearch(jql string) { | ||
if len(jql) == 0 { | ||
jql = getUserInput() | ||
} | ||
issues := j.getIssuesUsingJql(jql) | ||
selectedIssueKey := loadIssueListPrompt(issues[:]) | ||
if len(selectedIssueKey) > 0 { | ||
j.openIssueInBrowser(selectedIssueKey) | ||
} | ||
} | ||
|
||
func (j *JiraClient) openIssueInBrowser(issueKey string) { | ||
jiraLink := fmt.Sprintf("%s/browse/%s", j.Domain, issueKey) | ||
fmt.Printf("Opening %s in browser\n", issueKey) | ||
openbrowser(jiraLink) | ||
} | ||
|
||
// https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issue-search/#api-rest-api-3-issue-picker-get | ||
func (j *JiraClient) getIssuesUsingIssuePicker(args string) []Issue { | ||
// Call Rest API | ||
requestUrl := fmt.Sprintf("%s/rest/api/3/issue/picker?query=%s", j.Domain, url.QueryEscape(args)) | ||
req, err := http.NewRequest("GET", requestUrl, nil) | ||
resp, err := j.call(req) | ||
if err != nil || resp.StatusCode != 200 { | ||
log.Fatal("Error Occurred: ", resp.StatusCode) | ||
} | ||
defer resp.Body.Close() | ||
|
||
var issuePickerResp IssuePickerResp | ||
err = json.NewDecoder(resp.Body).Decode(&issuePickerResp) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
return issuePickerResp.Sections[0].Issues | ||
} | ||
|
||
func (j *JiraClient) getIssuesUsingJql(jql string) []Issue { | ||
// Call Rest API | ||
requestUrl := fmt.Sprintf("%s/rest/api/3/search?jql=%s", j.Domain, url.QueryEscape(jql)) | ||
req, err := http.NewRequest("GET", requestUrl, nil) | ||
resp, err := j.call(req) | ||
if err != nil || resp.StatusCode != 200 { | ||
log.Println("Error Occurred: No Issues Found") | ||
return []Issue{} | ||
} | ||
defer resp.Body.Close() | ||
|
||
var issueJqlResp IssueJqlResp | ||
err = json.NewDecoder(resp.Body).Decode(&issueJqlResp) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
|
||
issuesJql := issueJqlResp.Issues | ||
issuesLen := math.Min(5, float64(len(issuesJql))) | ||
issues := make([]Issue, int(issuesLen)) | ||
for i, issueJql := range issuesJql { | ||
if i == 5 { | ||
break | ||
} | ||
issues[i] = Issue{ | ||
SummaryText: issueJql.Fields.Summary, | ||
Key: issueJql.Key, | ||
} | ||
} | ||
|
||
return issues[:] | ||
} | ||
|
||
func loadIssueListPrompt(issues []Issue) string { | ||
if len(issues) == 0 { | ||
return "" | ||
} | ||
|
||
// Create a prompt for JIRA Link | ||
descriptions := make(map[string]string) | ||
issuesLen := math.Min(5, float64(len(issues))) | ||
options := make([]string, int(issuesLen)) | ||
|
||
for i, issue := range issues { | ||
if i == 5 { | ||
break | ||
} | ||
issueKey := issue.Key | ||
options[i] = issueKey | ||
descriptions[issueKey] = issue.SummaryText | ||
} | ||
|
||
issueKey := "" | ||
prompt := &survey.Select{ | ||
Message: "Select Issue:", | ||
Options: options[:], | ||
Description: func(value string, index int) string { | ||
return descriptions[value] | ||
}, | ||
} | ||
err := survey.AskOne(prompt, &issueKey) | ||
|
||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
|
||
return issueKey | ||
} | ||
|
||
func openbrowser(url string) { | ||
var err error | ||
switch runtime.GOOS { | ||
case "linux": | ||
err = exec.Command("xdg-open", url).Start() | ||
case "windows": | ||
err = exec.Command("rundll32", "url.dll,FileProtocolHandler", url).Start() | ||
case "darwin": | ||
err = exec.Command("open", url).Start() | ||
default: | ||
err = fmt.Errorf("unsupported platform") | ||
} | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
} | ||
|
||
func getUserInput() string { | ||
var userInput = "" | ||
prompt := &survey.Input{ | ||
Renderer: survey.Renderer{}, | ||
Message: "Enter Query Here: ", | ||
} | ||
survey.AskOne(prompt, &userInput) | ||
return userInput | ||
} |
Oops, something went wrong.