From 24ba1ee07c2b61a6ebc6416364f045c761f8c3e5 Mon Sep 17 00:00:00 2001 From: Chris Cummer Date: Thu, 23 Jul 2020 05:50:21 -0700 Subject: [PATCH 1/3] Provides the option to display the date the current onCall schedule will end. Config setting: ``` pagerduty: showOnCallEnd: [true|false] ``` If `true`, the date will be displayed below the onCall person's name: ``` eng-droplet 1 - Chris Cummer Jul 27, 2020 ``` Signed-off-by: Chris Cummer --- modules/pagerduty/settings.go | 2 ++ modules/pagerduty/widget.go | 60 +++++++++++++++++++++++++++-------- 2 files changed, 49 insertions(+), 13 deletions(-) diff --git a/modules/pagerduty/settings.go b/modules/pagerduty/settings.go index 962299cd..25bd7799 100644 --- a/modules/pagerduty/settings.go +++ b/modules/pagerduty/settings.go @@ -21,6 +21,7 @@ type Settings struct { myName string `help:"The name to highlight when on-call in PagerDuty."` scheduleIDs []interface{} `help:"An array of schedule IDs you want to restrict the OnCalls query to."` showIncidents bool `help:"Whether or not to list incidents." optional:"true"` + showOnCallEnd bool `help:"Whether or not to display the date the oncall schedule ends." optional:"true"` showSchedules bool `help:"Whether or not to show schedules." optional:"true"` teamIDs []interface{} `help:"An array of team IDs to restrict the incidents query to" optional:"true"` userIDs []interface{} `help:"An array of user IDs to restrict the incidents query to" optional:"true"` @@ -36,6 +37,7 @@ func NewSettingsFromYAML(name string, ymlConfig *config.Config, globalConfig *co myName: ymlConfig.UString("myName"), scheduleIDs: ymlConfig.UList("scheduleIDs", []interface{}{}), showIncidents: ymlConfig.UBool("showIncidents", true), + showOnCallEnd: ymlConfig.UBool("showOnCallEnd", false), showSchedules: ymlConfig.UBool("showSchedules", true), teamIDs: ymlConfig.UList("teamIDs", []interface{}{}), userIDs: ymlConfig.UList("userIDs", []interface{}{}), diff --git a/modules/pagerduty/widget.go b/modules/pagerduty/widget.go index 1ef5159a..07680ce2 100644 --- a/modules/pagerduty/widget.go +++ b/modules/pagerduty/widget.go @@ -3,6 +3,7 @@ package pagerduty import ( "fmt" "sort" + "time" "github.com/PagerDuty/go-pagerduty" "github.com/rivo/tview" @@ -10,12 +11,18 @@ import ( "github.com/wtfutil/wtf/view" ) +const ( + onCallTimeAPILayout = "2006-01-02T15:04:05Z" + onCallTimeDisplayLayout = "Jan 2, 2006" +) + type Widget struct { view.TextWidget settings *Settings } +// NewWidget creates and returns an instance of PagerDuty widget func NewWidget(app *tview.Application, settings *Settings) *Widget { widget := Widget{ TextWidget: view.NewTextWidget(app, settings.common), @@ -69,11 +76,13 @@ func (widget *Widget) Refresh() { func (widget *Widget) contentFrom(onCalls []pagerduty.OnCall, incidents []pagerduty.Incident) string { var str string + // Incidents + if widget.settings.showIncidents { str += "[yellow] Incidents[white]" if len(incidents) > 0 { for _, incident := range incidents { - str += fmt.Sprintf("\n [%s]%s[white]\n", widget.settings.common.Colors.Subheading, incident.Summary) + str += fmt.Sprintf("\n[%s]%s[white]\n", widget.settings.common.Colors.Subheading, incident.Summary) str += fmt.Sprintf(" Status: %s\n", incident.Status) str += fmt.Sprintf(" Service: %s\n", incident.Service.Summary) str += fmt.Sprintf(" Escalation: %s\n", incident.EscalationPolicy.Summary) @@ -83,23 +92,25 @@ func (widget *Widget) contentFrom(onCalls []pagerduty.OnCall, incidents []pagerd } } - tree := make(map[string][]pagerduty.OnCall) + onCallTree := make(map[string][]pagerduty.OnCall) filter := make(map[string]bool) for _, item := range widget.settings.escalationFilter { filter[item.(string)] = true } + // OnCalls + for _, onCall := range onCalls { - key := onCall.EscalationPolicy.Summary - if len(widget.settings.escalationFilter) == 0 || filter[key] { - tree[key] = append(tree[key], onCall) + summary := onCall.EscalationPolicy.Summary + if len(widget.settings.escalationFilter) == 0 || filter[summary] { + onCallTree[summary] = append(onCallTree[summary], onCall) } } // We want to sort our escalation policies for predictability/ease of finding - keys := make([]string, 0, len(tree)) - for k := range tree { + keys := make([]string, 0, len(onCallTree)) + for k := range onCallTree { keys = append(keys, k) } @@ -116,16 +127,24 @@ func (widget *Widget) contentFrom(onCalls []pagerduty.OnCall, incidents []pagerd key, ) - values := tree[key] + values := onCallTree[key] sort.Sort(ByEscalationLevel(values)) - for _, item := range values { + for _, onCall := range values { str += fmt.Sprintf( " [%s]%d - %s\n", widget.settings.common.Colors.Text, - item.EscalationLevel, - widget.userSummary(item), + onCall.EscalationLevel, + widget.userSummary(onCall), ) + + onCallEnd := widget.onCallEndSummary(onCall) + if onCallEnd != "" { + str += fmt.Sprintf( + " %s\n", + onCallEnd, + ) + } } } } @@ -133,8 +152,23 @@ func (widget *Widget) contentFrom(onCalls []pagerduty.OnCall, incidents []pagerd return str } -func (widget *Widget) userSummary(item pagerduty.OnCall) string { - summary := item.User.Summary +// onCallEndSummary may or may not return the date that the specified onCall schedule ends +func (widget *Widget) onCallEndSummary(onCall pagerduty.OnCall) string { + if !widget.settings.showOnCallEnd || onCall.End == "" { + return "" + } + + end, err := time.Parse(onCallTimeAPILayout, onCall.End) + if err != nil { + return "" + } + + return end.Format(onCallTimeDisplayLayout) +} + +// userSummary returns the name of the person assigned to the specified onCall scehdule +func (widget *Widget) userSummary(onCall pagerduty.OnCall) string { + summary := onCall.User.Summary if summary == widget.settings.myName { summary = fmt.Sprintf("[::b]%s", summary) From 391ce432a7a671915a7259f1a1460d000fc125ca Mon Sep 17 00:00:00 2001 From: Chris Cummer Date: Thu, 23 Jul 2020 06:26:51 -0700 Subject: [PATCH 2/3] go mod tidy Signed-off-by: Chris Cummer --- Makefile | 1 + go.sum | 10 ---------- modules/pagerduty/widget.go | 8 ++++++-- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/Makefile b/Makefile index b1464163..691f8964 100644 --- a/Makefile +++ b/Makefile @@ -102,6 +102,7 @@ install: ## lint: runs a number of code quality checks against the source code lint: + golangci-lint cache clean golangci-lint run # lint: diff --git a/go.sum b/go.sum index c4eed3e6..743907f9 100644 --- a/go.sum +++ b/go.sum @@ -161,8 +161,6 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/digitalocean/godo v1.37.0 h1:NEj5ne2cvLBHo1GJY1DNN/iEt9ipa72CMwwAjKEA530= -github.com/digitalocean/godo v1.37.0/go.mod h1:p7dOjjtSBqCTUksqtA5Fd3uaKs9kyTq2xcz76ulEJRU= github.com/digitalocean/godo v1.38.0 h1:to+pLe5RJqflJiyxhaLJfJgT3YzwHRSg19mOWkKt6A0= github.com/digitalocean/godo v1.38.0/go.mod h1:p7dOjjtSBqCTUksqtA5Fd3uaKs9kyTq2xcz76ulEJRU= github.com/dlclark/regexp2 v1.2.0 h1:8sAhBGEM0dRWogWqWyQeIJnxjWO6oIjl8FKqREDsGfk= @@ -647,8 +645,6 @@ github.com/sethgrid/pester v0.0.0-20171127025028-760f8913c048/go.mod h1:Ad7IjTpv github.com/sguiheux/go-coverage v0.0.0-20190710153556-287b082a7197 h1:qu90yDtRE5WEfRT5mn9v0Xz9RaopLguhbPwZKx4dHq8= github.com/sguiheux/go-coverage v0.0.0-20190710153556-287b082a7197/go.mod h1:0hhKrsUsoT7yvxwNGKa+TSYNA26DNWMqReeZEQq/9FI= github.com/shirou/gopsutil v0.0.0-20170406131756-e49a95f3d5f8/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= -github.com/shirou/gopsutil v2.20.4+incompatible h1:cMT4rxS55zx9NVUnCkrmXCsEB/RNfG9SwHY9evtX8Ng= -github.com/shirou/gopsutil v2.20.4+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shirou/gopsutil v2.20.6+incompatible h1:P37G9YH8M4vqkKcwBosp+URN5O8Tay67D2MbR361ioY= github.com/shirou/gopsutil v2.20.6+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= @@ -722,8 +718,6 @@ github.com/wtfutil/spotigopher v0.0.0-20191127141047-7d8168fe103a/go.mod h1:AlO4 github.com/wtfutil/todoist v0.0.2-0.20191216004217-0ec29ceda61a h1:nD8ALd4TSo+zPHK5MqQWFj01G8fMMHFfC3rWvoq/9JA= github.com/wtfutil/todoist v0.0.2-0.20191216004217-0ec29ceda61a/go.mod h1:YuuGLJSsTK6DGBD5Zaf3J8LSMfpEC2WtzYPey3XVOdI= github.com/xanzy/go-gitlab v0.15.0/go.mod h1:8zdQa/ri1dfn8eS3Ir1SyfvOKlw7WBJ8DVThkpGiXrs= -github.com/xanzy/go-gitlab v0.32.1 h1:eKGfAP2FWbqStD7DtGoRBb18IYwjuCxdtEVea2rNge4= -github.com/xanzy/go-gitlab v0.32.1/go.mod h1:sPLojNBn68fMUWSxIJtdVVIP8uSBYqesTfDUseX11Ug= github.com/xanzy/go-gitlab v0.33.0 h1:MUJZknbLhVXSFzBA5eqGGhQ2yHSu8tPbGBPeB3sN4B0= github.com/xanzy/go-gitlab v0.33.0/go.mod h1:sPLojNBn68fMUWSxIJtdVVIP8uSBYqesTfDUseX11Ug= github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= @@ -943,10 +937,6 @@ google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsb google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.25.0 h1:LodzhlzZEUfhXzNUMIfVlf9Gr6Ua5MMtoFWh7+f47qA= -google.golang.org/api v0.25.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0 h1:jMF5hhVfMkTZwHW1SDpKq5CkgWLXOb31Foaca9Zr3oM= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.29.0 h1:BaiDisFir8O4IJxvAabCGGkQ6yCJegNQqSVoYUNAnbk= google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= diff --git a/modules/pagerduty/widget.go b/modules/pagerduty/widget.go index 07680ce2..e8d01ffb 100644 --- a/modules/pagerduty/widget.go +++ b/modules/pagerduty/widget.go @@ -154,7 +154,11 @@ func (widget *Widget) contentFrom(onCalls []pagerduty.OnCall, incidents []pagerd // onCallEndSummary may or may not return the date that the specified onCall schedule ends func (widget *Widget) onCallEndSummary(onCall pagerduty.OnCall) string { - if !widget.settings.showOnCallEnd || onCall.End == "" { + if !widget.settings.showOnCallEnd { + return "" + } + + if onCall.End == "" { return "" } @@ -166,7 +170,7 @@ func (widget *Widget) onCallEndSummary(onCall pagerduty.OnCall) string { return end.Format(onCallTimeDisplayLayout) } -// userSummary returns the name of the person assigned to the specified onCall scehdule +// userSummary returns the name of the person assigned to the specified onCall schedule func (widget *Widget) userSummary(onCall pagerduty.OnCall) string { summary := onCall.User.Summary From e581646d315bfd083892dd061121a049e1aea0cd Mon Sep 17 00:00:00 2001 From: Chris Cummer Date: Thu, 23 Jul 2020 09:50:01 -0700 Subject: [PATCH 3/3] Include the link in incidents, and set the colours according to user config Signed-off-by: Chris Cummer --- modules/pagerduty/client.go | 10 ++++++---- modules/pagerduty/widget.go | 16 ++++++++++------ 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/modules/pagerduty/client.go b/modules/pagerduty/client.go index d509de21..ad47b81c 100644 --- a/modules/pagerduty/client.go +++ b/modules/pagerduty/client.go @@ -6,6 +6,10 @@ import ( "github.com/PagerDuty/go-pagerduty" ) +const ( + queryTimeFmt = "2006-01-02T15:04:05Z07:00" +) + // GetOnCalls returns a list of people currently on call func GetOnCalls(apiKey string, scheduleIDs []string) ([]pagerduty.OnCall, error) { client := pagerduty.NewClient(apiKey) @@ -14,10 +18,8 @@ func GetOnCalls(apiKey string, scheduleIDs []string) ([]pagerduty.OnCall, error) var queryOpts pagerduty.ListOnCallOptions queryOpts.ScheduleIDs = scheduleIDs - - timeFmt := "2006-01-02T15:04:05Z07:00" - queryOpts.Since = time.Now().Format(timeFmt) - queryOpts.Until = time.Now().Format(timeFmt) + queryOpts.Since = time.Now().Format(queryTimeFmt) + queryOpts.Until = time.Now().Format(queryTimeFmt) oncalls, err := client.ListOnCalls(queryOpts) if err != nil { diff --git a/modules/pagerduty/widget.go b/modules/pagerduty/widget.go index e8d01ffb..1361c780 100644 --- a/modules/pagerduty/widget.go +++ b/modules/pagerduty/widget.go @@ -79,17 +79,21 @@ func (widget *Widget) contentFrom(onCalls []pagerduty.OnCall, incidents []pagerd // Incidents if widget.settings.showIncidents { - str += "[yellow] Incidents[white]" + str += fmt.Sprintf("[%s] Incidents[white]\n", widget.settings.common.Colors.Subheading) + if len(incidents) > 0 { for _, incident := range incidents { - str += fmt.Sprintf("\n[%s]%s[white]\n", widget.settings.common.Colors.Subheading, incident.Summary) - str += fmt.Sprintf(" Status: %s\n", incident.Status) - str += fmt.Sprintf(" Service: %s\n", incident.Service.Summary) + str += fmt.Sprintf("\n [%s]%s[white]\n", widget.settings.common.Colors.Label, tview.Escape(incident.Summary)) + str += fmt.Sprintf(" Status: %s\n", incident.Status) + str += fmt.Sprintf(" Service: %s\n", incident.Service.Summary) str += fmt.Sprintf(" Escalation: %s\n", incident.EscalationPolicy.Summary) + str += fmt.Sprintf(" Link: %s\n", incident.HTMLURL) } } else { str += "\n No open incidents\n" } + + str += "\n" } onCallTree := make(map[string][]pagerduty.OnCall) @@ -117,13 +121,13 @@ func (widget *Widget) contentFrom(onCalls []pagerduty.OnCall, incidents []pagerd sort.Strings(keys) if len(keys) > 0 { - str += fmt.Sprintf("\n[%s] Schedules[white]\n", widget.settings.common.Colors.Subheading) + str += fmt.Sprintf("[%s] Schedules[white]\n", widget.settings.common.Colors.Subheading) // Print out policies, and escalation order of users for _, key := range keys { str += fmt.Sprintf( "\n [%s]%s\n", - widget.settings.common.Colors.Subheading, + widget.settings.common.Colors.Label, key, )