1
0
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:
Devin Collins 2019-01-20 00:34:18 -08:00
parent 1d888118c5
commit f7cf070f32
5 changed files with 216 additions and 0 deletions

View File

@ -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
View 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
}

View 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
View 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
View 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
}