mirror of
https://github.com/taigrr/wtf
synced 2025-01-18 04:03:14 -08:00
Adds module to display VictorOps on call information
This commit is contained in:
parent
1d888118c5
commit
f7cf070f32
3
main.go
3
main.go
@ -51,6 +51,7 @@ import (
|
||||
"github.com/wtfutil/wtf/travisci"
|
||||
"github.com/wtfutil/wtf/trello"
|
||||
"github.com/wtfutil/wtf/twitter"
|
||||
"github.com/wtfutil/wtf/victorops"
|
||||
"github.com/wtfutil/wtf/weatherservices/prettyweather"
|
||||
"github.com/wtfutil/wtf/weatherservices/weather"
|
||||
"github.com/wtfutil/wtf/wtf"
|
||||
@ -243,6 +244,8 @@ func addWidget(app *tview.Application, pages *tview.Pages, widgetName string) {
|
||||
widgets = append(widgets, trello.NewWidget(app))
|
||||
case "twitter":
|
||||
widgets = append(widgets, twitter.NewWidget(app, pages))
|
||||
case "victorops":
|
||||
widgets = append(widgets, victorops.NewWidget(app))
|
||||
case "weather":
|
||||
widgets = append(widgets, weather.NewWidget(app, pages))
|
||||
case "zendesk":
|
||||
|
86
victorops/client.go
Normal file
86
victorops/client.go
Normal file
@ -0,0 +1,86 @@
|
||||
package victorops
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/wtfutil/wtf/logger"
|
||||
"github.com/wtfutil/wtf/wtf"
|
||||
)
|
||||
|
||||
// Fetch gets the current oncall users
|
||||
func Fetch() ([]OnCallTeam, error) {
|
||||
scheduleURL := "https://api.victorops.com/api-public/v1/oncall/current"
|
||||
response, err := victorOpsRequest(scheduleURL, apiID(), apiKey())
|
||||
return response, err
|
||||
}
|
||||
|
||||
/* ---------------- Unexported Functions ---------------- */
|
||||
func apiID() string {
|
||||
return wtf.Config.UString(
|
||||
"wtf.mods.victorops.apiID",
|
||||
os.Getenv("WTF_VICTOROPS_API_ID"),
|
||||
)
|
||||
}
|
||||
|
||||
func apiKey() string {
|
||||
return wtf.Config.UString(
|
||||
"wtf.mods.victorops.apiKey",
|
||||
os.Getenv("WTF_VICTOROPS_API_KEY"),
|
||||
)
|
||||
}
|
||||
|
||||
func victorOpsRequest(url string, apiID string, apiKey string) ([]OnCallTeam, error) {
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
logger.Log(fmt.Sprintf("Failed to initialize sessions to VictorOps. ERROR: %s", err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req.Header.Set("X-VO-Api-Id", apiID)
|
||||
req.Header.Set("X-VO-Api-Key", apiKey)
|
||||
client := &http.Client{}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
logger.Log(fmt.Sprintf("Failed to make request to VictorOps. ERROR: %s", err))
|
||||
return nil, err
|
||||
}
|
||||
if resp.StatusCode != 200 {
|
||||
return nil, fmt.Errorf("%s", resp.Status)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
response := &OnCallResponse{}
|
||||
if err := json.NewDecoder(resp.Body).Decode(response); err != nil {
|
||||
logger.Log(fmt.Sprintf("Failed to decode JSON response. ERROR: %s", err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
teams := parseTeams(response)
|
||||
return teams, nil
|
||||
}
|
||||
|
||||
func parseTeams(input *OnCallResponse) []OnCallTeam {
|
||||
var teamResults []OnCallTeam
|
||||
|
||||
for _, data := range input.TeamsOnCall {
|
||||
var team OnCallTeam
|
||||
team.Name = data.Team.Name
|
||||
team.Slug = data.Team.Slug
|
||||
var userList []string
|
||||
for _, userData := range data.OnCallNow {
|
||||
escalationPolicy := userData.EscalationPolicy.Name
|
||||
for _, user := range userData.Users {
|
||||
userList = append(userList, user.OnCallUser.Username)
|
||||
}
|
||||
team.OnCall = append(team.OnCall, OnCall{escalationPolicy, strings.Join(userList, ", ")})
|
||||
}
|
||||
teamResults = append(teamResults, team)
|
||||
}
|
||||
|
||||
return teamResults
|
||||
}
|
22
victorops/oncallresponse.go
Normal file
22
victorops/oncallresponse.go
Normal file
@ -0,0 +1,22 @@
|
||||
package victorops
|
||||
|
||||
// OnCallResponse object
|
||||
type OnCallResponse struct {
|
||||
TeamsOnCall []struct {
|
||||
Team struct {
|
||||
Name string `json:"name"`
|
||||
Slug string `json:"slug"`
|
||||
} `json:"team"`
|
||||
OnCallNow []struct {
|
||||
EscalationPolicy struct {
|
||||
Name string `json:"name"`
|
||||
Slug string `json:"slug"`
|
||||
} `json:"escalationPolicy"`
|
||||
Users []struct {
|
||||
OnCallUser struct {
|
||||
Username string `json:"username"`
|
||||
} `json:"onCalluser"`
|
||||
} `json:"users"`
|
||||
} `json:"oncallNow"`
|
||||
} `json:"teamsOnCall"`
|
||||
}
|
16
victorops/oncallteam.go
Normal file
16
victorops/oncallteam.go
Normal file
@ -0,0 +1,16 @@
|
||||
package victorops
|
||||
|
||||
// OnCallTeam object to make
|
||||
// managing objects easier
|
||||
type OnCallTeam struct {
|
||||
Name string
|
||||
Slug string
|
||||
OnCall []OnCall
|
||||
}
|
||||
|
||||
// OnCall object to handle
|
||||
// different on call policies
|
||||
type OnCall struct {
|
||||
Policy string
|
||||
Userlist string
|
||||
}
|
89
victorops/widget.go
Normal file
89
victorops/widget.go
Normal file
@ -0,0 +1,89 @@
|
||||
package victorops
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/rivo/tview"
|
||||
"github.com/wtfutil/wtf/wtf"
|
||||
)
|
||||
|
||||
// HelpText to display to users
|
||||
const HelpText = `
|
||||
Keyboard commands for VictorOps
|
||||
|
||||
/: Show/hide this help window
|
||||
arrow down: Scroll down the list
|
||||
arrow up: Scroll up the list
|
||||
`
|
||||
|
||||
// Widget contains text info
|
||||
type Widget struct {
|
||||
wtf.TextWidget
|
||||
teams []OnCallTeam
|
||||
}
|
||||
|
||||
// NewWidget creates a new widget
|
||||
func NewWidget(app *tview.Application) *Widget {
|
||||
widget := Widget{
|
||||
TextWidget: wtf.NewTextWidget(app, "VictorOps - OnCall", "victorops", true),
|
||||
}
|
||||
|
||||
widget.View.SetScrollable(true)
|
||||
widget.View.SetRegions(true)
|
||||
|
||||
return &widget
|
||||
}
|
||||
|
||||
// Refresh gets latest content for the widget
|
||||
func (widget *Widget) Refresh() {
|
||||
if widget.Disabled() {
|
||||
return
|
||||
}
|
||||
|
||||
teams, err := Fetch()
|
||||
widget.View.SetTitle(widget.ContextualTitle(widget.Name))
|
||||
|
||||
if err != nil {
|
||||
widget.View.SetWrap(true)
|
||||
widget.View.SetText(err.Error())
|
||||
} else {
|
||||
widget.teams = teams
|
||||
}
|
||||
|
||||
widget.display()
|
||||
}
|
||||
|
||||
func (widget *Widget) display() {
|
||||
if widget.teams == nil {
|
||||
return
|
||||
}
|
||||
|
||||
widget.View.SetWrap(false)
|
||||
widget.View.Clear()
|
||||
widget.View.SetText(widget.contentFrom(widget.teams))
|
||||
}
|
||||
|
||||
func (widget *Widget) contentFrom(teams []OnCallTeam) string {
|
||||
teamToDisplay := wtf.Config.UString("wtf.mods.victorops.team")
|
||||
var str string
|
||||
for _, team := range teams {
|
||||
if len(teamToDisplay) > 0 && teamToDisplay != team.Slug {
|
||||
continue
|
||||
}
|
||||
|
||||
str = fmt.Sprintf("%s[green]%s\n", str, team.Name)
|
||||
if len(team.OnCall) == 0 {
|
||||
str = fmt.Sprintf("%s[grey]no one\n", str)
|
||||
}
|
||||
for _, onCall := range team.OnCall {
|
||||
str = fmt.Sprintf("%s[white]%s - %s\n", str, onCall.Policy, onCall.Userlist)
|
||||
}
|
||||
|
||||
str = fmt.Sprintf("%s\n", str)
|
||||
}
|
||||
|
||||
if len(str) == 0 {
|
||||
str = "Could not find any teams to display"
|
||||
}
|
||||
return str
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user