diff --git a/README.md b/README.md index fe4a8e5f..169c35ab 100644 --- a/README.md +++ b/README.md @@ -22,8 +22,7 @@ described value. | 3 | [Github](https://developer.github.com/v3/) | `WTF_GITHUB_TOKEN` | Github API token | | 4 | [Google Calendar](https://developers.google.com/calendar/) | `WTF_GOOGLE_CAL_CLIENT_ID` | Google Calendar client ID | | 5 | | `WTF_GOOGLE_CAL_CLIENT_SECRET` | Google Calendar client secret | -| 6 | [JIRA](https://developer.atlassian.com/server/jira/platform/rest-apis/) | `WTF_JIRA_USERNAME` | You JIRA username | -| 7 | | `WTF_JIRA_PASSWORD` | Your JIRA password | +| 6 | [JIRA](https://developer.atlassian.com/server/jira/platform/rest-apis/) | `WTF_JIRA_API_KEY` | You JIRA API key | | 8 | [New Relic](https://docs.newrelic.com/docs/apis/rest-api-v2/getting-started/introduction-new-relic-rest-api-v2) | `WTF_NEW_RELIC_API_KEY` | New Relic API key | | 9 | [OpsGenie](https://docs.opsgenie.com/docs/api-overview) | `WTF_OPS_GENIE_API_KEY` | OpsGenie API key | | 10 | [OpenWeatherMap](https://openweathermap.org/api) | `WTF_OWM_API_KEY` | OpenWeatherMap API key | diff --git a/_sample_configs/complex_config.yml b/_sample_configs/complex_config.yml index 1e98b523..6d312121 100644 --- a/_sample_configs/complex_config.yml +++ b/_sample_configs/complex_config.yml @@ -52,12 +52,15 @@ wtf: username: "senorprogrammer" jira: enabled: true + domain: "https://lendesk.atlassian.net" position: top: 1 left: 1 height: 1 width: 1 + project: "WTF" refreshInterval: 900 + username: "chris.cummer" newrelic: applicationId: 10549735 enabled: true diff --git a/jira/client.go b/jira/client.go new file mode 100644 index 00000000..3bd5859b --- /dev/null +++ b/jira/client.go @@ -0,0 +1,79 @@ +package jira + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "net/http" + "os" +) + +func Fetch() string { + resp, err := jiraRequest("/rest/api/2/project/CORE") + if err != nil { + return err.Error() + } + + project := &JiraProject{} + parseJson(project, resp.Body) + //fmt.Printf("%#v\n", project) + + return "" +} + +func IssuesFor(username string) ([]JiraIssue, error) { + url := fmt.Sprintf("/rest/api/2/search?jql=assignee=%s", username) + + resp, err := jiraRequest(url) + if err != nil { + return nil, err + } + + issues := []JiraIssue{} + parseJson(issues, resp.Body) + + return issues, nil +} + +/* -------------------- Unexported Functions -------------------- */ + +func jiraRequest(path string) (*http.Response, error) { + url := fmt.Sprintf("%s%s", Config.UString("wtf.mods.jira.domain"), path) + + req, err := http.NewRequest("GET", url, nil) + if err != nil { + return nil, err + } + req.SetBasicAuth(Config.UString("wtf.mods.jira.email"), os.Getenv("WTF_JIRA_API_KEY")) + + httpClient := &http.Client{} + resp, err := httpClient.Do(req) + if err != nil { + return nil, err + } + + if resp.StatusCode < 200 || resp.StatusCode > 299 { + return nil, fmt.Errorf(resp.Status) + } + + return resp, nil +} + +func parseJson(obj interface{}, text io.Reader) { + jsonStream, err := ioutil.ReadAll(text) + if err != nil { + panic(err) + } + + decoder := json.NewDecoder(bytes.NewReader(jsonStream)) + + for { + if err := decoder.Decode(obj); err == io.EOF { + break + } else if err != nil { + panic(err) + } + } +} diff --git a/jira/structs.go b/jira/structs.go new file mode 100644 index 00000000..8f3b6bd2 --- /dev/null +++ b/jira/structs.go @@ -0,0 +1,140 @@ +package jira + +import () + +type JiraIssue struct { + Fields JiraIssueFields + Id string + Key string + Self string +} + +type JiraIssueFields struct { + Comment JiraIssueComment + Description string + Project JiraIssueProject + SubTasks []JiraIssueSubTask + TimeTracking JiraIssueTimetracking + Updated string + Watcher JiraIssueWatcher +} + +type JiraIssueWatcher struct { + IsWatching bool + Self string + WatchCount int + Watchers []JiraAttribute +} + +type JiraIssueSubTask struct { + Id string + Type struct { + Id string + Name string + Inward string + Outward string + } + OutwardIssue struct { + Id string + Key string + Self string + Fields struct { + Status struct { + IconUrl string + Name string + } + } + } +} + +type JiraIssueProject struct { + Id string + Key string + Name string + ProjectCategory JiraAttribute + Self string + Simplified bool +} + +type JiraIssueComment struct { + Author JiraAttribute + Body string + Created string + Id string + Self string + UpdateAuthor JiraAttribute + Updated string + Visibility struct { + Type string + Value string + } +} + +type JiraAttribute struct { + Active bool + DisplayName string + Name string + Self string +} + +type JiraIssueTimetracking struct { + OriginalEstimate string + OriginalEstimateSeconds int + RemainingEstimate string + RemainingEstimateSeconds int + TimeSpent string + TimeSpentSeconds int +} + +type JiraProject struct { + AssigneeType string + Components []JiraProjectComponent + Email string + IssueTypes []JiraProjectIssueType + Lead JiraProjectMember + Name string + ProjectCategory JiraProjectCategory + Simplified bool + Url string + + JiraAttribute +} + +type JiraProjectCategory struct { + Description string + Id string + Name string + Self string +} + +type JiraProjectComponent struct { + Assignee JiraProjectMember + AssigneeType string + IsAssigneeTypeValid bool + Lead JiraProjectMember + Project string + ProjectId int + RealAssigne JiraProjectMember + RealAssigneeType string + + JiraAttribute +} + +type JiraProjectIssueType struct { + AvatarId int + Description string + IconUrl string + Id string + Name string + Self string + SubTask bool +} + +type JiraProjectMember struct { + AccountId string + Active bool + DisplayName string + Key string + Name string + Self string +} diff --git a/jira/widget.go b/jira/widget.go index 9a1fdee3..5d1b97c7 100644 --- a/jira/widget.go +++ b/jira/widget.go @@ -33,11 +33,20 @@ func (widget *Widget) Refresh() { return } + issues, err := IssuesFor(Config.UString("wtf.mods.jira.username")) + widget.View.SetTitle(fmt.Sprintf(" %s ", widget.Name)) widget.RefreshedAt = time.Now() widget.View.Clear() - fmt.Fprintf(widget.View, "%s", "jira") + + if err != nil { + widget.View.SetWrap(true) + fmt.Fprintf(widget.View, "%v", err) + } else { + widget.View.SetWrap(false) + fmt.Fprintf(widget.View, "%v", issues) + } } /* -------------------- Unexported Functions -------------------- */