Skip to content

Commit

Permalink
Merge pull request #109 from imjaroiswebdev/incidents-support
Browse files Browse the repository at this point in the history
add support for `/incidents` List/Get/Create/Manage
  • Loading branch information
imjaroiswebdev authored Dec 22, 2022
2 parents cf44a2f + 01d5d4d commit 3d20d69
Show file tree
Hide file tree
Showing 4 changed files with 356 additions and 0 deletions.
178 changes: 178 additions & 0 deletions pagerduty/incident.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
package pagerduty

import (
"fmt"
"log"
)

// IncidentService handles the communication with incident
// related methods of the PagerDuty API.
type IncidentService service

// Incident represents a incident.
type Incident struct {
ID string `json:"id,omitempty"`
Type string `json:"type,omitempty"`
Summary string `json:"summary,omitempty"`
Self string `json:"self,omitempty"`
HTMLURL string `json:"html_url,omitempty"`
IncidentNumber int `json:"incident_number,omitempty"`
CreatedAt string `json:"created_at,omitempty"`
Status string `json:"status,omitempty"`
Title string `json:"title,omitempty"`
Resolution string `json:"resolution,omitempty"`
AlertCounts *AlertCounts `json:"alert_counts,omitempty"`
PendingActions []*PendingAction `json:"pending_actions,omitempty"`
IncidentKey string `json:"incident_key,omitempty"`
Service *ServiceReference `json:"service,omitempty"`
AssignedVia string `json:"assigned_via,omitempty"`
Assignments []*IncidentAssignment `json:"assignments,omitempty"`
Acknowledgements []*IncidentAcknowledgement `json:"acknowledgements,omitempty"`
LastStatusChangeAt string `json:"last_status_change_at,omitempty"`
LastStatusChangeBy *IncidentAttributeReference `json:"last_status_change_by,omitempty"`
FirstTriggerLogEntry *IncidentAttributeReference `json:"first_trigger_log_entry,omitempty"`
EscalationPolicy *EscalationPolicyReference `json:"escalation_policy,omitempty"`
Teams []*TeamReference `json:"teams,omitempty"`
Urgency string `json:"urgency,omitempty"`
}

type AlertCounts struct {
All int `json:"all"`
Resolved int `json:"resolved"`
Triggered int `json:"triggered"`
}

type PendingAction struct {
At string `json:"at"`
Type string `json:"type"`
}

type IncidentAssignment struct {
At string `json:"at"`
Assignee UserReference `json:"assignee"`
}

type IncidentAcknowledgement struct {
At string `json:"at"`
Acknowledger IncidentAttributeReference `json:"acknowledger"`
}

// IncidentPayload represents an incident.
type IncidentPayload struct {
Incident *Incident `json:"incident,omitempty"`
}

// ManageIncidentsPayload represents a payload with a list of incidents data.
type ManageIncidentsPayload struct {
Incidents []*Incident `json:"incidents,omitempty"`
}

// ListIncidentsOptions represents options when listing incidents.
type ListIncidentsOptions struct {
Limit int `url:"limit,omitempty"`
Offset int `url:"offset,omitempty"`
Total int `url:"total,omitempty"`
DateRange string `url:"date_range,omitempty"`
IncidentKey string `url:"incident_key,omitempty"`
Include []string `url:"include,omitempty,brackets"`
ServiceIDs []string `url:"service_ids,omitempty,brackets"`
Since string `url:"since,omitempty"`
SortBy []string `url:"sort_by,omitempty,brackets"`
Statuses []string `url:"statuses,omitempty,brackets"`
TeamIDs []string `url:"team_ids,omitempty,brackets"`
TimeZone string `url:"time_zone,omitempty"`
Until string `url:"until,omitempty"`
Urgencies []string `url:"urgencies,omitempty,brackets"`
UserIDs []string `url:"user_ids,omitempty,brackets"`
}

// ManageIncidentsOptions represents options when listing incidents.
type ManageIncidentsOptions struct {
Limit int `url:"limit,omitempty"`
Offset int `url:"offset,omitempty"`
Total int `url:"total,omitempty"`
}

// ListIncidentsResponse represents a list response of incidents.
type ListIncidentsResponse struct {
Limit int `json:"limit,omitempty"`
More bool `json:"more,omitempty"`
Offset int `json:"offset,omitempty"`
Total int `json:"total,omitempty"`
Incidents []*Incident `json:"incidents,omitempty"`
}

type ManageIncidentsResponse ListIncidentsResponse

// List lists existing incidents.
func (s *IncidentService) List(o *ListIncidentsOptions) (*ListIncidentsResponse, *Response, error) {
u := "/incidents"
v := new(ListIncidentsResponse)

resp, err := s.client.newRequestDo("GET", u, o, nil, &v)
if err != nil {
return nil, nil, err
}

return v, resp, nil
}

// ListAll lists all result pages for incidents list.
func (s *IncidentService) ListAll(o *ListIncidentsOptions) ([]*Incident, error) {
var incidents = make([]*Incident, 0, 25)
more := true
offset := 0

for more {
log.Printf("==== Getting incidents at offset %d", offset)
v := new(ListIncidentsResponse)
_, err := s.client.newRequestDo("GET", "/incidents", o, nil, &v)
if err != nil {
return incidents, err
}
incidents = append(incidents, v.Incidents...)
more = v.More
offset += v.Limit
o.Offset = offset
}
return incidents, nil
}

// ManageIncidents updates existing incidents.
func (s *IncidentService) ManageIncidents(incidents []*Incident, o *ManageIncidentsOptions) (*ManageIncidentsResponse, *Response, error) {
u := "/incidents"
v := new(ManageIncidentsResponse)

resp, err := s.client.newRequestDo("PUT", u, o, &ManageIncidentsPayload{Incidents: incidents}, &v)
if err != nil {
return nil, nil, err
}

return v, resp, nil
}

// Create an incident
func (s *IncidentService) Create(incident *Incident) (*Incident, *Response, error) {
u := "/incidents"
v := new(IncidentPayload)

resp, err := s.client.newRequestDo("POST", u, nil, &IncidentPayload{Incident: incident}, &v)
if err != nil {
return nil, nil, err
}

return v.Incident, resp, nil
}

// Get retrieves information about an incident.
func (s *IncidentService) Get(id string) (*Incident, *Response, error) {
u := fmt.Sprintf("/incidents/%s", id)
v := new(IncidentPayload)

resp, err := s.client.newRequestDo("GET", u, nil, nil, &v)
if err != nil {
return nil, nil, err
}

return v.Incident, resp, nil
}
172 changes: 172 additions & 0 deletions pagerduty/incident_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
package pagerduty

import (
"encoding/json"
"net/http"
"reflect"
"testing"
)

func TestIncidentsList(t *testing.T) {
setup()
defer teardown()

mux.HandleFunc("/incidents", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
w.Write([]byte(`{"incidents": [{"id": "P1D3Z4B"}]}`))
})

resp, _, err := client.Incidents.List(&ListIncidentsOptions{})
if err != nil {
t.Fatal(err)
}

want := &ListIncidentsResponse{
Incidents: []*Incident{
{
ID: "P1D3Z4B",
},
},
}

if !reflect.DeepEqual(resp, want) {
t.Errorf("returned %#v; want %#v", resp, want)
}
}

func TestIncidentsListAll(t *testing.T) {
setup()
defer teardown()
var reqCount int

mux.HandleFunc("/incidents", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
switch reqCount {
case 0:
w.Write([]byte(`{"incidents":[{"id":"P1D3Z4B"}],"limit":1,"offset":0,"more":true}`))
reqCount++
case 1:
w.Write([]byte(`{"incidents":[{"id":"Z1D3K79"}],"limit":1,"offset":1,"more":true}`))
reqCount++
default:
w.Write([]byte(`{"incidents":[{"id":"U1D3NS1"}],"limit":1,"offset":2,"more":false}`))
}
})

resp, err := client.Incidents.ListAll(&ListIncidentsOptions{})
if err != nil {
t.Fatal(err)
}

want := []*Incident{
{
ID: "P1D3Z4B",
},
{
ID: "Z1D3K79",
},
{
ID: "U1D3NS1",
},
}

if !reflect.DeepEqual(resp, want) {
t.Errorf("returned %#v; want %#v", resp, want)
}
}

func TestIncidentsManage(t *testing.T) {
setup()
defer teardown()

input := []*Incident{{ID: "P1D3Z4B"}}

mux.HandleFunc("/incidents", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "PUT")
payload := &ManageIncidentsPayload{Incidents: input}
v := new(ManageIncidentsPayload)
json.NewDecoder(r.Body).Decode(v)
if !reflect.DeepEqual(v, payload) {
t.Errorf("Request body = %+v, want %+v", v, payload)
}
w.Write([]byte(`{"incidents": [{"id": "P1D3Z4B"}]}`))
})

resp, _, err := client.Incidents.ManageIncidents(input, &ManageIncidentsOptions{})
if err != nil {
t.Fatal(err)
}

want := &ManageIncidentsResponse{
Incidents: []*Incident{
{
ID: "P1D3Z4B",
},
},
}

if !reflect.DeepEqual(resp, want) {
t.Errorf("returned %#v; want %#v", resp, want)
}
}

func TestIncidentsCreate(t *testing.T) {
setup()
defer teardown()

input := &Incident{
Type: "incident",
Title: "test incident",
}

mux.HandleFunc("/incidents", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "POST")
payload := &IncidentPayload{Incident: input}
v := new(IncidentPayload)
json.NewDecoder(r.Body).Decode(v)
if !reflect.DeepEqual(v, payload) {
t.Errorf("Request body = %+v, want %+v", v, payload)
}
w.Write([]byte(`{"incident": {"id": "1", "type": "incident", "title": "test incident"}}`))
})

resp, _, err := client.Incidents.Create(input)
if err != nil {
t.Fatal(err)
}

want := &Incident{
ID: "1",
Type: "incident",
Title: "test incident",
}

if !reflect.DeepEqual(resp, want) {
t.Errorf("returned %#v; want %#v", resp, want)
}
}

func TestIncidentsGet(t *testing.T) {
setup()
defer teardown()

mux.HandleFunc("/incidents/1", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
w.Write([]byte(`{"incident": {"id": "1", "type": "incident", "title": "test incident"}}`))
})

resp, _, err := client.Incidents.Get("1")
if err != nil {
t.Fatal(err)
}

want := &Incident{
ID: "1",
Type: "incident",
Title: "test incident",
}

if !reflect.DeepEqual(resp, want) {
t.Errorf("returned %#v; want %#v", resp, want)
}
}
2 changes: 2 additions & 0 deletions pagerduty/pagerduty.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ type Client struct {
OnCall *OnCallService
AutomationActionsRunner *AutomationActionsRunnerService
AutomationActionsAction *AutomationActionsActionService
Incidents *IncidentService
}

// Response is a wrapper around http.Response
Expand Down Expand Up @@ -125,6 +126,7 @@ func NewClient(config *Config) (*Client, error) {
c.OnCall = &OnCallService{c}
c.AutomationActionsRunner = &AutomationActionsRunnerService{c}
c.AutomationActionsAction = &AutomationActionsActionService{c}
c.Incidents = &IncidentService{c}

InitCache(c)
PopulateCache()
Expand Down
4 changes: 4 additions & 0 deletions pagerduty/references.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,7 @@ type RulesetReference resourceReference

// SubscriberReference represents a reference to a subscriber schema
type SubscriberReference resourceReference

// IncidentAttributeReference represents a reference to a Incident
// Attribute schema
type IncidentAttributeReference resourceReference

0 comments on commit 3d20d69

Please sign in to comment.