Skip to content

Commit

Permalink
Merge pull request #3 from Canva/merge-with-upstream
Browse files Browse the repository at this point in the history
Merge with upstream [ODC-764]
  • Loading branch information
taj-p authored Jul 5, 2022
2 parents 4a58cab + 0631526 commit c06c4d8
Show file tree
Hide file tree
Showing 38 changed files with 4,318 additions and 1,822 deletions.
13 changes: 10 additions & 3 deletions .github/workflows/go.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,20 @@ jobs:

build:
runs-on: ubuntu-latest
strategy:
matrix:
go:
- "1.15"
- "1.16"
- "1.17"
- "1.18"
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3

- name: Set up Go
uses: actions/setup-go@v2
uses: actions/setup-go@v3
with:
go-version: "1.15"
go-version: ${{ matrix.go }}

- name: Build
run: go build -v ./...
Expand Down
56 changes: 50 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,60 @@
# go-sentry [![CircleCI](https://circleci.com/gh/jianyuan/go-sentry/tree/master.svg?style=svg)](https://circleci.com/gh/jianyuan/go-sentry/tree/master) [![GoDoc](https://godoc.org/github.com/jianyuan/go-sentry/sentry?status.svg)](https://godoc.org/github.com/jianyuan/go-sentry/sentry)
# go-sentry [![Go Reference](https://pkg.go.dev/badge/github.com/jianyuan/go-sentry/v2/sentry.svg)](https://pkg.go.dev/github.com/jianyuan/go-sentry/v2/sentry)

Go library for accessing the [Sentry Web API](https://docs.sentry.io/api/).

## Install
## Installation
go-sentry is compatible with modern Go releases in module mode, with Go installed:

```sh
go get -u github.com/jianyuan/go-sentry/sentry
go get github.com/jianyuan/go-sentry/v2/sentry
```

## Usage

```go
import "github.com/jianyuan/go-sentry/v2/sentry"
```

Create a new Sentry client. Then, use the various services on the client to access different parts of the
Sentry Web API. For example:

```go
client := sentry.NewClient(nil)

// List all organizations
orgs, _, err := client.Organizations.List(ctx, nil)
```

## Documentation
Read the [GoDoc](https://godoc.org/github.com/jianyuan/go-sentry/sentry).
### Authentication

The library does not directly handle authentication. When creating a new client, pass an
`http.Client` that can handle authentication for you. We recommend the [oauth2](https://pkg.go.dev/golang.org/x/oauth2)
library. For example:

```go
package main

import (
"github.com/jianyuan/go-sentry/v2/sentry"
"golang.org/x/oauth2"
)

func main() {
ctx := context.Background()
tokenSrc := oauth2.StaticTokenSource(
&oauth2.Token{AccessToken: "YOUR-API-KEY"},
)
httpClient := oauth2.NewClient(ctx, tokenSrc)

client := sentry.NewClient(httpClient)

// List all organizations
orgs, _, err := client.Organizations.List(ctx, nil)
}
```

## Code structure
The code structure was inspired by [dghubble/go-twitter](https://github.com/dghubble/go-twitter).
The code structure was inspired by [google/go-github](https://github.com/google/go-github).

## License
This library is distributed under the [MIT License](LICENSE).
9 changes: 4 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,13 @@ module github.com/canva/go-sentry
go 1.18

require (
github.com/dghubble/sling v1.4.0
github.com/stretchr/testify v1.7.1
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80
github.com/google/go-querystring v1.1.0
github.com/peterhellberg/link v1.1.0
github.com/stretchr/testify v1.8.0
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
20 changes: 13 additions & 7 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,22 +1,28 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dghubble/sling v1.4.0 h1:/n8MRosVTthvMbwlNZgLx579OGVjUOy3GNEv5BIqAWY=
github.com/dghubble/sling v1.4.0/go.mod h1:0r40aNsU9EdDUVBNhfCstAtFgutjgJGYbO1oNzkMoM8=
github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/peterhellberg/link v1.1.0 h1:s2+RH8EGuI/mI4QwrWGSYQCRz7uNgip9BaM04HKu5kc=
github.com/peterhellberg/link v1.1.0/go.mod h1:gtSlOT4jmkY8P47hbTc8PTgiDDWpdPbFYl75keYyBB8=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 h1:nrZ3ySNYwJbSpD6ce9duiP+QkD3JuLCcWkdaehUS/3Y=
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80/go.mod h1:iFyPdL66DjUD96XmzVL3ZntbzcflLnznH0fr99w5VqE=
github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s=
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
github.com/stretchr/testify v1.7.4 h1:wZRexSlwd7ZXfKINDLsO4r7WBt3gTKONc6K/VesHvHM=
github.com/stretchr/testify v1.7.4/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.7.5 h1:s5PTfem8p8EbKQOctVV53k6jCJt3UX4IEJzwh+C324Q=
github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
5 changes: 5 additions & 0 deletions renovate.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"extends": [
"config:base"
]
}
63 changes: 63 additions & 0 deletions sentry/dashboard_widgets.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package sentry

import (
"context"
"fmt"
)

// DashboardWidget represents a Dashboard Widget.
// https://github.com/getsentry/sentry/blob/22.5.0/src/sentry/api/serializers/rest_framework/dashboard.py#L230-L243
type DashboardWidget struct {
ID *string `json:"id,omitempty"`
Title *string `json:"title,omitempty"`
DisplayType *string `json:"displayType,omitempty"`
Interval *string `json:"interval,omitempty"`
Queries []*DashboardWidgetQuery `json:"queries,omitempty"`
WidgetType *string `json:"widgetType,omitempty"`
Limit *int `json:"limit,omitempty"`
Layout *DashboardWidgetLayout `json:"layout,omitempty"`
}

type DashboardWidgetLayout struct {
X *int `json:"x,omitempty"`
Y *int `json:"y,omitempty"`
W *int `json:"w,omitempty"`
H *int `json:"h,omitempty"`
MinH *int `json:"minH,omitempty"`
}

type DashboardWidgetQuery struct {
ID *string `json:"id,omitempty"`
Fields []string `json:"fields,omitempty"`
Aggregates []string `json:"aggregates,omitempty"`
Columns []string `json:"columns,omitempty"`
FieldAliases []string `json:"fieldAliases,omitempty"`
Name *string `json:"name,omitempty"`
Conditions *string `json:"conditions,omitempty"`
OrderBy *string `json:"orderby,omitempty"`
}

// DashboardWidgetsService provides methods for accessing Sentry dashboard widget API endpoints.
type DashboardWidgetsService service

type DashboardWidgetErrors map[string][]string

// Validate a dashboard widget configuration.
func (s *DashboardWidgetsService) Validate(ctx context.Context, organizationSlug string, widget *DashboardWidget) (DashboardWidgetErrors, *Response, error) {
u := fmt.Sprintf("0/organizations/%v/dashboards/widgets/", organizationSlug)

req, err := s.client.NewRequest("POST", u, widget)
if err != nil {
return nil, nil, err
}

widgetErrors := make(DashboardWidgetErrors)
resp, err := s.client.Do(ctx, req, &widgetErrors)
if err != nil {
return nil, resp, err
}
if len(widgetErrors) == 0 {
return nil, resp, err
}
return widgetErrors, resp, err
}
95 changes: 95 additions & 0 deletions sentry/dashboard_widgets_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package sentry

import (
"context"
"fmt"
"net/http"
"testing"

"github.com/stretchr/testify/assert"
)

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

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

widget := &DashboardWidget{
Title: String("Number of Errors"),
DisplayType: String("big_number"),
Interval: String("5m"),
Queries: []*DashboardWidgetQuery{
{
ID: String("115037"),
Fields: []string{"count()"},
Aggregates: []string{"count()"},
Columns: []string{},
FieldAliases: []string{},
Name: String(""),
Conditions: String("!event.type:transaction"),
OrderBy: String(""),
},
},
WidgetType: String("discover"),
Layout: &DashboardWidgetLayout{
X: Int(0),
Y: Int(0),
W: Int(2),
H: Int(1),
MinH: Int(1),
},
}
ctx := context.Background()
widgetErrors, _, err := client.DashboardWidgets.Validate(ctx, "the-interstellar-jurisdiction", widget)
assert.Nil(t, widgetErrors)
assert.NoError(t, err)
}

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

mux.HandleFunc("/api/0/organizations/the-interstellar-jurisdiction/dashboards/widgets/", func(w http.ResponseWriter, r *http.Request) {
assertMethod(t, "POST", r)
w.Header().Set("Content-Type", "application/json")
fmt.Fprint(w, `{"widgetType":["\"discover-invalid\" is not a valid choice."]}`)
})

widget := &DashboardWidget{
Title: String("Number of Errors"),
DisplayType: String("big_number"),
Interval: String("5m"),
Queries: []*DashboardWidgetQuery{
{
ID: String("115037"),
Fields: []string{"count()"},
Aggregates: []string{"count()"},
Columns: []string{},
FieldAliases: []string{},
Name: String(""),
Conditions: String("!event.type:transaction"),
OrderBy: String(""),
},
},
WidgetType: String("discover-invalid"),
Layout: &DashboardWidgetLayout{
X: Int(0),
Y: Int(0),
W: Int(2),
H: Int(1),
MinH: Int(1),
},
}
ctx := context.Background()
widgetErrors, _, err := client.DashboardWidgets.Validate(ctx, "the-interstellar-jurisdiction", widget)
expected := DashboardWidgetErrors{
"widgetType": []string{`"discover-invalid" is not a valid choice.`},
}
assert.Equal(t, expected, widgetErrors)
assert.NoError(t, err)
}
Loading

0 comments on commit c06c4d8

Please sign in to comment.