Skip to content

Commit b9283ad

Browse files
mandreandmitshur
authored andcommitted
Add missing GitHub Apps methods. (google#733)
GitHub API docs: https://developer.github.com/v3/apps/.
1 parent f706454 commit b9283ad

File tree

5 files changed

+364
-1
lines changed

5 files changed

+364
-1
lines changed

github/apps.go

Lines changed: 130 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,69 @@
55

66
package github
77

8-
import "context"
8+
import (
9+
"context"
10+
"fmt"
11+
"time"
12+
)
913

1014
// AppsService provides access to the installation related functions
1115
// in the GitHub API.
1216
//
1317
// GitHub API docs: https://developer.github.com/v3/apps/
1418
type AppsService service
1519

20+
// App represents a GitHub App.
21+
type App struct {
22+
ID *int `json:"id,omitempty"`
23+
Owner *User `json:"owner,omitempty"`
24+
Name *string `json:"name,omitempty"`
25+
Description *string `json:"description,omitempty"`
26+
ExternalURL *string `json:"external_url,omitempty"`
27+
HTMLURL *string `json:"html_url,omitempty"`
28+
CreatedAt *time.Time `json:"created_at,omitempty"`
29+
UpdatedAt *time.Time `json:"updated_at,omitempty"`
30+
}
31+
32+
// InstallationToken represents an installation token.
33+
type InstallationToken struct {
34+
Token *string `json:"token,omitempty"`
35+
ExpiresAt *time.Time `json:"expires_at,omitempty"`
36+
}
37+
38+
// Get a single GitHub App. Passing the empty string will get
39+
// the authenticated GitHub App.
40+
//
41+
// Note: appSlug is just the URL-friendly name of your GitHub App.
42+
// You can find this on the settings page for your GitHub App
43+
// (e.g., https://github.com/settings/apps/:app_slug).
44+
//
45+
// GitHub API docs: https://developer.github.com/v3/apps/#get-a-single-github-app
46+
func (s *AppsService) Get(ctx context.Context, appSlug string) (*App, *Response, error) {
47+
var u string
48+
if appSlug != "" {
49+
u = fmt.Sprintf("apps/%v", appSlug)
50+
} else {
51+
u = "app"
52+
}
53+
54+
req, err := s.client.NewRequest("GET", u, nil)
55+
if err != nil {
56+
return nil, nil, err
57+
}
58+
59+
// TODO: remove custom Accept header when this API fully launches.
60+
req.Header.Set("Accept", mediaTypeIntegrationPreview)
61+
62+
app := new(App)
63+
resp, err := s.client.Do(ctx, req, app)
64+
if err != nil {
65+
return nil, resp, err
66+
}
67+
68+
return app, resp, nil
69+
}
70+
1671
// ListInstallations lists the installations that the current GitHub App has.
1772
//
1873
// GitHub API docs: https://developer.github.com/v3/apps/#find-installations
@@ -38,3 +93,77 @@ func (s *AppsService) ListInstallations(ctx context.Context, opt *ListOptions) (
3893

3994
return i, resp, nil
4095
}
96+
97+
// GetInstallation returns the specified installation.
98+
//
99+
// GitHub API docs: https://developer.github.com/v3/apps/#get-a-single-installation
100+
func (s *AppsService) GetInstallation(ctx context.Context, id int) (*Installation, *Response, error) {
101+
u := fmt.Sprintf("app/installations/%v", id)
102+
103+
req, err := s.client.NewRequest("GET", u, nil)
104+
if err != nil {
105+
return nil, nil, err
106+
}
107+
108+
// TODO: remove custom Accept header when this API fully launches.
109+
req.Header.Set("Accept", mediaTypeIntegrationPreview)
110+
111+
i := new(Installation)
112+
resp, err := s.client.Do(ctx, req, i)
113+
if err != nil {
114+
return nil, resp, err
115+
}
116+
117+
return i, resp, nil
118+
}
119+
120+
// ListUserInstallations lists installations that are accessible to the authenticated user.
121+
//
122+
// GitHub API docs: https://developer.github.com/v3/apps/#list-installations-for-user
123+
func (s *AppsService) ListUserInstallations(ctx context.Context, opt *ListOptions) ([]*Installation, *Response, error) {
124+
u, err := addOptions("user/installations", opt)
125+
if err != nil {
126+
return nil, nil, err
127+
}
128+
129+
req, err := s.client.NewRequest("GET", u, nil)
130+
if err != nil {
131+
return nil, nil, err
132+
}
133+
134+
// TODO: remove custom Accept header when this API fully launches.
135+
req.Header.Set("Accept", mediaTypeIntegrationPreview)
136+
137+
var i struct {
138+
Installations []*Installation `json:"installations"`
139+
}
140+
resp, err := s.client.Do(ctx, req, &i)
141+
if err != nil {
142+
return nil, resp, err
143+
}
144+
145+
return i.Installations, resp, nil
146+
}
147+
148+
// CreateInstallationToken creates a new installation token.
149+
//
150+
// GitHub API docs: https://developer.github.com/v3/apps/#create-a-new-installation-token
151+
func (s *AppsService) CreateInstallationToken(ctx context.Context, id int) (*InstallationToken, *Response, error) {
152+
u := fmt.Sprintf("installations/%v/access_tokens", id)
153+
154+
req, err := s.client.NewRequest("POST", u, nil)
155+
if err != nil {
156+
return nil, nil, err
157+
}
158+
159+
// TODO: remove custom Accept header when this API fully launches.
160+
req.Header.Set("Accept", mediaTypeIntegrationPreview)
161+
162+
t := new(InstallationToken)
163+
resp, err := s.client.Do(ctx, req, t)
164+
if err != nil {
165+
return nil, resp, err
166+
}
167+
168+
return t, resp, nil
169+
}

github/apps_installation.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,33 @@ func (s *AppsService) ListRepos(ctx context.Context, opt *ListOptions) ([]*Repos
5151
return r.Repositories, resp, nil
5252
}
5353

54+
// ListUserRepos lists repositories that are accessible
55+
// to the authenticated user for an installation.
56+
//
57+
// GitHub API docs: https://developer.github.com/v3/apps/installations/#list-repositories-accessible-to-the-user-for-an-installation
58+
func (s *AppsService) ListUserRepos(ctx context.Context, id int, opt *ListOptions) ([]*Repository, *Response, error) {
59+
u := fmt.Sprintf("user/installations/%v/repositories", id)
60+
u, err := addOptions(u, opt)
61+
if err != nil {
62+
return nil, nil, err
63+
}
64+
65+
req, err := s.client.NewRequest("GET", u, nil)
66+
if err != nil {
67+
return nil, nil, err
68+
}
69+
70+
var r struct {
71+
Repositories []*Repository `json:"repositories"`
72+
}
73+
resp, err := s.client.Do(ctx, req, &r)
74+
if err != nil {
75+
return nil, resp, err
76+
}
77+
78+
return r.Repositories, resp, nil
79+
}
80+
5481
// AddRepository adds a single repository to an installation.
5582
//
5683
// GitHub API docs: https://developer.github.com/v3/apps/installations/#add-repository-to-installation

github/apps_installation_test.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,31 @@ func TestAppsService_ListRepos(t *testing.T) {
3939
}
4040
}
4141

42+
func TestAppsService_ListUserRepos(t *testing.T) {
43+
setup()
44+
defer teardown()
45+
46+
mux.HandleFunc("/user/installations/1/repositories", func(w http.ResponseWriter, r *http.Request) {
47+
testMethod(t, r, "GET")
48+
testFormValues(t, r, values{
49+
"page": "1",
50+
"per_page": "2",
51+
})
52+
fmt.Fprint(w, `{"repositories": [{"id":1}]}`)
53+
})
54+
55+
opt := &ListOptions{Page: 1, PerPage: 2}
56+
repositories, _, err := client.Apps.ListUserRepos(context.Background(), 1, opt)
57+
if err != nil {
58+
t.Errorf("Apps.ListUserRepos returned error: %v", err)
59+
}
60+
61+
want := []*Repository{{ID: Int(1)}}
62+
if !reflect.DeepEqual(repositories, want) {
63+
t.Errorf("Apps.ListUserRepos returned %+v, want %+v", repositories, want)
64+
}
65+
}
66+
4267
func TestAppsService_AddRepository(t *testing.T) {
4368
setup()
4469
defer teardown()

github/apps_test.go

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,48 @@ import (
1313
"testing"
1414
)
1515

16+
func TestAppsService_Get_authenticatedApp(t *testing.T) {
17+
setup()
18+
defer teardown()
19+
20+
mux.HandleFunc("/app", func(w http.ResponseWriter, r *http.Request) {
21+
testMethod(t, r, "GET")
22+
testHeader(t, r, "Accept", mediaTypeIntegrationPreview)
23+
fmt.Fprint(w, `{"id":1}`)
24+
})
25+
26+
app, _, err := client.Apps.Get(context.Background(), "")
27+
if err != nil {
28+
t.Errorf("Apps.Get returned error: %v", err)
29+
}
30+
31+
want := &App{ID: Int(1)}
32+
if !reflect.DeepEqual(app, want) {
33+
t.Errorf("Apps.Get returned %+v, want %+v", app, want)
34+
}
35+
}
36+
37+
func TestAppsService_Get_specifiedApp(t *testing.T) {
38+
setup()
39+
defer teardown()
40+
41+
mux.HandleFunc("/apps/a", func(w http.ResponseWriter, r *http.Request) {
42+
testMethod(t, r, "GET")
43+
testHeader(t, r, "Accept", mediaTypeIntegrationPreview)
44+
fmt.Fprint(w, `{"html_url":"https://github.com/apps/a"}`)
45+
})
46+
47+
app, _, err := client.Apps.Get(context.Background(), "a")
48+
if err != nil {
49+
t.Errorf("Apps.Get returned error: %v", err)
50+
}
51+
52+
want := &App{HTMLURL: String("https://github.com/apps/a")}
53+
if !reflect.DeepEqual(app, want) {
54+
t.Errorf("Apps.Get returned %+v, want %+v", *app.HTMLURL, *want.HTMLURL)
55+
}
56+
}
57+
1658
func TestAppsService_ListInstallations(t *testing.T) {
1759
setup()
1860
defer teardown()
@@ -38,3 +80,71 @@ func TestAppsService_ListInstallations(t *testing.T) {
3880
t.Errorf("Apps.ListInstallations returned %+v, want %+v", installations, want)
3981
}
4082
}
83+
84+
func TestAppsService_GetInstallation(t *testing.T) {
85+
setup()
86+
defer teardown()
87+
88+
mux.HandleFunc("/app/installations/1", func(w http.ResponseWriter, r *http.Request) {
89+
testMethod(t, r, "GET")
90+
testHeader(t, r, "Accept", mediaTypeIntegrationPreview)
91+
fmt.Fprint(w, `{"id":1}`)
92+
})
93+
94+
installation, _, err := client.Apps.GetInstallation(context.Background(), 1)
95+
if err != nil {
96+
t.Errorf("Apps.GetInstallation returned error: %v", err)
97+
}
98+
99+
want := &Installation{ID: Int(1)}
100+
if !reflect.DeepEqual(installation, want) {
101+
t.Errorf("Apps.GetInstallation returned %+v, want %+v", installation, want)
102+
}
103+
}
104+
105+
func TestAppsService_ListUserInstallations(t *testing.T) {
106+
setup()
107+
defer teardown()
108+
109+
mux.HandleFunc("/user/installations", func(w http.ResponseWriter, r *http.Request) {
110+
testMethod(t, r, "GET")
111+
testHeader(t, r, "Accept", mediaTypeIntegrationPreview)
112+
testFormValues(t, r, values{
113+
"page": "1",
114+
"per_page": "2",
115+
})
116+
fmt.Fprint(w, `{"installations":[{"id":1}]}`)
117+
})
118+
119+
opt := &ListOptions{Page: 1, PerPage: 2}
120+
installations, _, err := client.Apps.ListUserInstallations(context.Background(), opt)
121+
if err != nil {
122+
t.Errorf("Apps.ListUserInstallations returned error: %v", err)
123+
}
124+
125+
want := []*Installation{{ID: Int(1)}}
126+
if !reflect.DeepEqual(installations, want) {
127+
t.Errorf("Apps.ListUserInstallations returned %+v, want %+v", installations, want)
128+
}
129+
}
130+
131+
func TestAppsService_CreateInstallationToken(t *testing.T) {
132+
setup()
133+
defer teardown()
134+
135+
mux.HandleFunc("/installations/1/access_tokens", func(w http.ResponseWriter, r *http.Request) {
136+
testMethod(t, r, "POST")
137+
testHeader(t, r, "Accept", mediaTypeIntegrationPreview)
138+
fmt.Fprint(w, `{"token":"t"}`)
139+
})
140+
141+
token, _, err := client.Apps.CreateInstallationToken(context.Background(), 1)
142+
if err != nil {
143+
t.Errorf("Apps.CreateInstallationToken returned error: %v", err)
144+
}
145+
146+
want := &InstallationToken{Token: String("t")}
147+
if !reflect.DeepEqual(token, want) {
148+
t.Errorf("Apps.CreateInstallationToken returned %+v, want %+v", token, want)
149+
}
150+
}

0 commit comments

Comments
 (0)