Skip to content

Commit

Permalink
Add methods to get and update organization integration configData (#80)
Browse files Browse the repository at this point in the history
* Extend OrganizationIntegrationsService to support GET org integration details endpoint

* Support variable shape configData for org integrations

* Implement OrganizationIntegrationsService UpdateConfig
  • Loading branch information
sbrudz authored Apr 14, 2023
1 parent 97df7c9 commit 7a0b01c
Show file tree
Hide file tree
Showing 2 changed files with 182 additions and 9 deletions.
49 changes: 42 additions & 7 deletions sentry/organization_integrations.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,29 +16,34 @@ type OrganizationIntegrationProvider struct {
Features []string `json:"features"`
}

// IntegrationConfigData for defining integration-specific configuration data.
type IntegrationConfigData map[string]interface{}

// OrganizationIntegration represents an integration added for the organization.
// https://github.com/getsentry/sentry/blob/22.7.0/src/sentry/api/serializers/models/integration.py#L93
type OrganizationIntegration struct {
// https://github.com/getsentry/sentry/blob/22.7.0/src/sentry/api/serializers/models/integration.py#L35
ID string `json:"id"`
Name string `json:"name"`
Icon string `json:"icon"`
Icon *string `json:"icon"`
DomainName string `json:"domainName"`
AccountType string `json:"accountType"`
AccountType *string `json:"accountType"`
Scopes []string `json:"scopes"`
Status string `json:"status"`
Provider OrganizationIntegrationProvider `json:"provider"`

// https://github.com/getsentry/sentry/blob/22.7.0/src/sentry/api/serializers/models/integration.py#L138
ExternalId string `json:"externalId"`
OrganizationId int `json:"organizationId"`
OrganizationIntegrationStatus string `json:"organizationIntegrationStatus"`
GracePeriodEnd *time.Time `json:"gracePeriodEnd"`
ConfigData *IntegrationConfigData `json:"configData"`
ExternalId string `json:"externalId"`
OrganizationId int `json:"organizationId"`
OrganizationIntegrationStatus string `json:"organizationIntegrationStatus"`
GracePeriodEnd *time.Time `json:"gracePeriodEnd"`
}

// OrganizationIntegrationsService provides methods for accessing Sentry organization integrations API endpoints.
// Paths: https://github.com/getsentry/sentry/blob/22.7.0/src/sentry/api/urls.py#L1236-L1240
// Paths: https://github.com/getsentry/sentry/blob/22.7.0/src/sentry/api/urls.py#L1236-L1245
// Endpoints: https://github.com/getsentry/sentry/blob/22.7.0/src/sentry/api/endpoints/integrations/organization_integrations/index.py
// Endpoints: https://github.com/getsentry/sentry/blob/22.7.0/src/sentry/api/endpoints/integrations/organization_integrations/details.py
type OrganizationIntegrationsService service

type ListOrganizationIntegrationsParams struct {
Expand Down Expand Up @@ -66,3 +71,33 @@ func (s *OrganizationIntegrationsService) List(ctx context.Context, organization
}
return integrations, resp, nil
}

// Get organization integration details.
func (s *OrganizationIntegrationsService) Get(ctx context.Context, organizationSlug string, integrationID string) (*OrganizationIntegration, *Response, error) {
u := fmt.Sprintf("0/organizations/%v/integrations/%v/", organizationSlug, integrationID)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}

integration := new(OrganizationIntegration)
resp, err := s.client.Do(ctx, req, integration)
if err != nil {
return nil, resp, err
}
return integration, resp, nil
}

type UpdateConfigOrganizationIntegrationsParams = IntegrationConfigData

// UpdateConfig - update configData for organization integration.
// https://github.com/getsentry/sentry/blob/22.7.0/src/sentry/api/endpoints/integrations/organization_integrations/details.py#L94-L102
func (s *OrganizationIntegrationsService) UpdateConfig(ctx context.Context, organizationSlug string, integrationID string, params *UpdateConfigOrganizationIntegrationsParams) (*Response, error) {
u := fmt.Sprintf("0/organizations/%v/integrations/%v/", organizationSlug, integrationID)
req, err := s.client.NewRequest("POST", u, params)
if err != nil {
return nil, err
}

return s.client.Do(ctx, req, nil)
}
142 changes: 140 additions & 2 deletions sentry/organization_integrations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package sentry

import (
"context"
"encoding/json"
"fmt"
"net/http"
"testing"
Expand Down Expand Up @@ -62,9 +63,9 @@ func TestOrganizationIntegrationsService_List(t *testing.T) {
{
ID: "123456",
Name: "octocat",
Icon: "https://avatars.githubusercontent.com/u/583231?v=4",
Icon: String("https://avatars.githubusercontent.com/u/583231?v=4"),
DomainName: "github.com/octocat",
AccountType: "Organization",
AccountType: String("Organization"),
Scopes: []string{"read", "write"},
Status: "active",
Provider: OrganizationIntegrationProvider{
Expand All @@ -80,6 +81,7 @@ func TestOrganizationIntegrationsService_List(t *testing.T) {
"stacktrace-link",
},
},
ConfigData: &IntegrationConfigData{},
ExternalId: "87654321",
OrganizationId: 2,
OrganizationIntegrationStatus: "active",
Expand All @@ -88,3 +90,139 @@ func TestOrganizationIntegrationsService_List(t *testing.T) {
}
assert.Equal(t, expected, integrations)
}

func TestOrganizationIntegrationsService_Get(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()

mux.HandleFunc("/api/0/organizations/the-interstellar-jurisdiction/integrations/456789/", func(w http.ResponseWriter, r *http.Request) {
assertMethod(t, "GET", r)
w.Header().Set("Content-Type", "application/json")
fmt.Fprint(w, `{
"id": "456789",
"name": "Interstellar PagerDuty",
"icon": null,
"domainName": "the-interstellar-jurisdiction",
"accountType": null,
"scopes": null,
"status": "active",
"provider": {
"key": "pagerduty",
"slug": "pagerduty",
"name": "PagerDuty",
"canAdd": true,
"canDisable": false,
"features": [
"alert-rule",
"incident-management"
],
"aspects": {
"alerts": [
{
"type": "info",
"text": "The PagerDuty integration adds a new Alert Rule action to all projects. To enable automatic notifications sent to PagerDuty you must create a rule using the PagerDuty action in your project settings."
}
]
}
},
"configOrganization": [
{
"name": "service_table",
"type": "table",
"label": "PagerDuty services with the Sentry integration enabled",
"help": "If services need to be updated, deleted, or added manually please do so here. Alert rules will need to be individually updated for any additions or deletions of services.",
"addButtonText": "",
"columnLabels": {
"service": "Service",
"integration_key": "Integration Key"
},
"columnKeys": [
"service",
"integration_key"
],
"confirmDeleteMessage": "Any alert rules associated with this service will stop working. The rules will still exist but will show a removed service."
}
],
"configData": {
"service_table": [
{
"service": "testing123",
"integration_key": "abc123xyz",
"id": 22222
}
]
},
"externalId": "999999",
"organizationId": 2,
"organizationIntegrationStatus": "active",
"gracePeriodEnd": null
}`)
})

ctx := context.Background()
integration, _, err := client.OrganizationIntegrations.Get(ctx, "the-interstellar-jurisdiction", "456789")
assert.NoError(t, err)
expected := OrganizationIntegration{
ID: "456789",
Name: "Interstellar PagerDuty",
Icon: nil,
DomainName: "the-interstellar-jurisdiction",
AccountType: nil,
Scopes: nil,
Status: "active",
Provider: OrganizationIntegrationProvider{
Key: "pagerduty",
Slug: "pagerduty",
Name: "PagerDuty",
CanAdd: true,
CanDisable: false,
Features: []string{
"alert-rule",
"incident-management",
},
},
ConfigData: &IntegrationConfigData{
"service_table": []interface{}{
map[string]interface{}{
"service": "testing123",
"integration_key": "abc123xyz",
"id": json.Number("22222"),
},
},
},
ExternalId: "999999",
OrganizationId: 2,
OrganizationIntegrationStatus: "active",
GracePeriodEnd: nil,
}
assert.Equal(t, &expected, integration)
}

func TestOrganizationIntegrationsService_UpdateConfig(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()

mux.HandleFunc("/api/0/organizations/the-interstellar-jurisdiction/integrations/456789/", func(w http.ResponseWriter, r *http.Request) {
assertMethod(t, "POST", r)
w.Header().Set("Content-Type", "application/json")
})

updateConfigOrganizationIntegrationsParams := UpdateConfigOrganizationIntegrationsParams{
"service_table": []interface{}{
map[string]interface{}{
"service": "testing123",
"integration_key": "abc123xyz",
"id": json.Number("22222"),
},
map[string]interface{}{
"service": "testing456",
"integration_key": "efg456lmn",
"id": "",
},
},
}
ctx := context.Background()
resp, err := client.OrganizationIntegrations.UpdateConfig(ctx, "the-interstellar-jurisdiction", "456789", &updateConfigOrganizationIntegrationsParams)
assert.NoError(t, err)
assert.Equal(t, int64(0), resp.ContentLength)
}

0 comments on commit 7a0b01c

Please sign in to comment.