From b91a2a689ae829ce5156ad533a2b5197c413b93c Mon Sep 17 00:00:00 2001 From: Emory Ruscus <47612504+emoryruscus@users.noreply.github.com> Date: Tue, 23 Jul 2019 11:20:11 -0400 Subject: [PATCH 01/16] Update apps.go Add installation token parameters, allowing creation of permission-scoped github tokens. --- github/apps.go | 54 ++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 50 insertions(+), 4 deletions(-) diff --git a/github/apps.go b/github/apps.go index f675a9abd18..9a3af9978c1 100644 --- a/github/apps.go +++ b/github/apps.go @@ -6,8 +6,12 @@ package github import ( + "bytes" "context" + "encoding/json" "fmt" + "io" + "io/ioutil" "time" ) @@ -32,8 +36,21 @@ type App struct { // InstallationToken represents an installation token. type InstallationToken struct { - Token *string `json:"token,omitempty"` - ExpiresAt *time.Time `json:"expires_at,omitempty"` + Token *string `json:"token,omitempty"` + ExpiresAt *time.Time `json:"expires_at,omitempty"` + Permissions *InstallationPermissions `json:"permissions,omitempty"` + Repositories *[]Repository `json:"repositories,emitempty"` +} + +// InstallationTokenParameters allow restricting a token's access to specific repositories. +type InstallationTokenParameters struct { + // The ids of the repositories that the installation token can access. + // Providing repository ids restricts the access of an installation token to specific repositories. + RepositoryIDs []int64 `json:"repository_ids,omitempty"` + + // The permissions granted to the access token. + // The permissions object includes the permission names and their access type. + Permissions *InstallationPermissions `json:"permissions,omitempty"` } // InstallationPermissions lists the repository and organization permissions for an installation. @@ -194,10 +211,10 @@ func (s *AppsService) ListUserInstallations(ctx context.Context, opt *ListOption // CreateInstallationToken creates a new installation token. // // GitHub API docs: https://developer.github.com/v3/apps/#create-a-new-installation-token -func (s *AppsService) CreateInstallationToken(ctx context.Context, id int64) (*InstallationToken, *Response, error) { +func (s *AppsService) CreateInstallationToken(ctx context.Context, id int64, body ...interface{}) (*InstallationToken, *Response, error) { u := fmt.Sprintf("app/installations/%v/access_tokens", id) - req, err := s.client.NewRequest("POST", u, nil) + req, err := s.client.NewRequest("POST", u, body) if err != nil { return nil, nil, err } @@ -282,3 +299,32 @@ func (s *AppsService) getInstallation(ctx context.Context, url string) (*Install return i, resp, nil } + +// GetReadWriter converts a body interface into an io.ReadWriter object. +func GetReadWriter(body interface{}) (io.ReadWriter, error) { + var buf io.ReadWriter + if body != nil { + buf = new(bytes.Buffer) + enc := json.NewEncoder(buf) + err := enc.Encode(body) + if err != nil { + return nil, err + } + } + return buf, nil +} + +// GetReadCloser converts a body interface into an io.ReadCloser object. +func GetReadCloser(body interface{}) (io.ReadCloser, error) { + buf, err := GetReadWriter(body) + if err != nil { + return nil, err + } + + all, err := ioutil.ReadAll(buf) + if err != nil { + return nil, err + } + + return ioutil.NopCloser(bytes.NewBuffer(all)), nil +} From d0834e010998da69dc9c4193e416584af38b7c44 Mon Sep 17 00:00:00 2001 From: Emory Ruscus <47612504+emoryruscus@users.noreply.github.com> Date: Tue, 23 Jul 2019 11:57:40 -0400 Subject: [PATCH 02/16] Update apps_test.go Add test for creating installation tokens with additional parameters. https://developer.github.com/v3/apps/#create-a-new-installation-token --- github/apps_test.go | 51 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/github/apps_test.go b/github/apps_test.go index 8d5b27d38ce..6932e4adad2 100644 --- a/github/apps_test.go +++ b/github/apps_test.go @@ -6,8 +6,10 @@ package github import ( + "bytes" "context" "fmt" + "io/ioutil" "net/http" "reflect" "testing" @@ -225,6 +227,55 @@ func TestAppsService_CreateInstallationToken(t *testing.T) { } } +func TestAppsService_CreateInstallationTokenWithParameters(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + installationTokenParameters := &InstallationTokenParameters{ + RepositoryIDs: []int64{1234}, + Permissions: &InstallationPermissions{ + Contents: String("write"), + Issues: String("read"), + }, + } + + // Convert InstallationTokenParameters into an io.ReadCloser object for comparison. + itpSlice := []InstallationTokenParameters{*installationTokenParameters} + wantBody, err := GetReadCloser(itpSlice) + if err != nil { + t.Errorf("GetReadCloser returned error: %v", err) + } + + mux.HandleFunc("/app/installations/1/access_tokens", func(w http.ResponseWriter, r *http.Request) { + // Read request body contents. + var gotBodyBytes []byte + gotBodyBytes, err = ioutil.ReadAll(r.Body) + if err != nil { + t.Errorf("ReadAll returned error: %v", err) + } + r.Body = ioutil.NopCloser(bytes.NewBuffer(gotBodyBytes)) + + if !reflect.DeepEqual(r.Body, wantBody) { + t.Errorf("request sent %+v, want %+v", r.Body, wantBody) + } + + testMethod(t, r, "POST") + testHeader(t, r, "Accept", mediaTypeIntegrationPreview) + fmt.Fprint(w, `{"token":"t"}`) + }) + + token, _, err := client.Apps.CreateInstallationToken(context.Background(), 1, installationTokenParameters) + if err != nil { + t.Errorf("Apps.CreateInstallationToken returned error: %v", err) + } + + want := &InstallationToken{Token: String("t")} + if !reflect.DeepEqual(token, want) { + t.Errorf("Apps.CreateInstallationToken returned %+v, want %+v", token, want) + } +} + + func TestAppsService_CreateAttachement(t *testing.T) { client, mux, _, teardown := setup() defer teardown() From 0d94311fb2c053103f6cde763a4246aa3df2b504 Mon Sep 17 00:00:00 2001 From: Emory Ruscus <47612504+emoryruscus@users.noreply.github.com> Date: Wed, 24 Jul 2019 11:14:02 -0400 Subject: [PATCH 03/16] Update apps.go - Change 'parameters' to 'options' --- github/apps.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/github/apps.go b/github/apps.go index 9a3af9978c1..d714120f32b 100644 --- a/github/apps.go +++ b/github/apps.go @@ -39,13 +39,13 @@ type InstallationToken struct { Token *string `json:"token,omitempty"` ExpiresAt *time.Time `json:"expires_at,omitempty"` Permissions *InstallationPermissions `json:"permissions,omitempty"` - Repositories *[]Repository `json:"repositories,emitempty"` + Repositories []*Repository `json:"repositories,emitempty"` } -// InstallationTokenParameters allow restricting a token's access to specific repositories. -type InstallationTokenParameters struct { - // The ids of the repositories that the installation token can access. - // Providing repository ids restricts the access of an installation token to specific repositories. +// InstallationTokenOptions allow restricting a token's access to specific repositories. +type InstallationTokenOptions struct { + // The IDs of the repositories that the installation token can access. + // Providing repository IDs restricts the access of an installation token to specific repositories. RepositoryIDs []int64 `json:"repository_ids,omitempty"` // The permissions granted to the access token. @@ -211,10 +211,10 @@ func (s *AppsService) ListUserInstallations(ctx context.Context, opt *ListOption // CreateInstallationToken creates a new installation token. // // GitHub API docs: https://developer.github.com/v3/apps/#create-a-new-installation-token -func (s *AppsService) CreateInstallationToken(ctx context.Context, id int64, body ...interface{}) (*InstallationToken, *Response, error) { +func (s *AppsService) CreateInstallationToken(ctx context.Context, id int64, opt *InstallationTokenOptions) (*InstallationToken, *Response, error) { u := fmt.Sprintf("app/installations/%v/access_tokens", id) - req, err := s.client.NewRequest("POST", u, body) + req, err := s.client.NewRequest("POST", u, opt) if err != nil { return nil, nil, err } From ad7cafc664dc563639f4a29f0839ba9d46f0bf30 Mon Sep 17 00:00:00 2001 From: Emory Ruscus <47612504+emoryruscus@users.noreply.github.com> Date: Wed, 24 Jul 2019 11:20:38 -0400 Subject: [PATCH 04/16] Update apps_test.go Change 'parameters' to 'options'. --- github/apps_test.go | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/github/apps_test.go b/github/apps_test.go index 6932e4adad2..a47db5e3db7 100644 --- a/github/apps_test.go +++ b/github/apps_test.go @@ -227,11 +227,11 @@ func TestAppsService_CreateInstallationToken(t *testing.T) { } } -func TestAppsService_CreateInstallationTokenWithParameters(t *testing.T) { +func TestAppsService_CreateInstallationTokenWithOptions(t *testing.T) { client, mux, _, teardown := setup() defer teardown() - installationTokenParameters := &InstallationTokenParameters{ + installationTokenOptions := &InstallationTokenOptions{ RepositoryIDs: []int64{1234}, Permissions: &InstallationPermissions{ Contents: String("write"), @@ -239,9 +239,8 @@ func TestAppsService_CreateInstallationTokenWithParameters(t *testing.T) { }, } - // Convert InstallationTokenParameters into an io.ReadCloser object for comparison. - itpSlice := []InstallationTokenParameters{*installationTokenParameters} - wantBody, err := GetReadCloser(itpSlice) + // Convert InstallationTokenOptions into an io.ReadCloser object for comparison. + wantBody, err := GetReadCloser(installationTokenOptions) if err != nil { t.Errorf("GetReadCloser returned error: %v", err) } @@ -264,7 +263,7 @@ func TestAppsService_CreateInstallationTokenWithParameters(t *testing.T) { fmt.Fprint(w, `{"token":"t"}`) }) - token, _, err := client.Apps.CreateInstallationToken(context.Background(), 1, installationTokenParameters) + token, _, err := client.Apps.CreateInstallationToken(context.Background(), 1, installationTokenOptions) if err != nil { t.Errorf("Apps.CreateInstallationToken returned error: %v", err) } @@ -275,7 +274,6 @@ func TestAppsService_CreateInstallationTokenWithParameters(t *testing.T) { } } - func TestAppsService_CreateAttachement(t *testing.T) { client, mux, _, teardown := setup() defer teardown() @@ -298,6 +296,7 @@ func TestAppsService_CreateAttachement(t *testing.T) { t.Errorf("CreateAttachment = %+v, want %+v", got, want) } } + func TestAppsService_FindOrganizationInstallation(t *testing.T) { client, mux, _, teardown := setup() defer teardown() From 243b6b0bb8ae40b72772a01e24ec2a26d7e10cbb Mon Sep 17 00:00:00 2001 From: Emory Ruscus <47612504+emoryruscus@users.noreply.github.com> Date: Thu, 1 Aug 2019 15:26:15 -0400 Subject: [PATCH 05/16] Update apps_test.go --- github/apps_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/github/apps_test.go b/github/apps_test.go index a47db5e3db7..78931caa252 100644 --- a/github/apps_test.go +++ b/github/apps_test.go @@ -216,7 +216,7 @@ func TestAppsService_CreateInstallationToken(t *testing.T) { fmt.Fprint(w, `{"token":"t"}`) }) - token, _, err := client.Apps.CreateInstallationToken(context.Background(), 1) + token, _, err := client.Apps.CreateInstallationToken(context.Background(), 1, nil) if err != nil { t.Errorf("Apps.CreateInstallationToken returned error: %v", err) } From 89c7ea22a43006e6264802c93ef04e442e1ec638 Mon Sep 17 00:00:00 2001 From: Emory Ruscus <47612504+emoryruscus@users.noreply.github.com> Date: Thu, 1 Aug 2019 16:12:39 -0400 Subject: [PATCH 06/16] Update github-accessors.go Add GetPermissions() and GetRepositories() accessor functions. --- github/github-accessors.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/github/github-accessors.go b/github/github-accessors.go index b4ca033d300..abcc017e9a5 100644 --- a/github/github-accessors.go +++ b/github/github-accessors.go @@ -3892,6 +3892,22 @@ func (i *InstallationToken) GetToken() string { return *i.Token } +// GetPermissions returns the Permissions field if it's non-nil, zero value otherwise. +func (i *InstallationToken) GetPermissions() *InstallationPermissions { + if i == nil { + return nil + } + return i.Permissions +} + +// GetRepositories returns the Repositories field if it's non-nil, zero value otherwise. +func (i *InstallationToken) GetRepositories() []*Repository { + if i == nil { + return nil + } + return i.Repositories +} + // GetExpiresAt returns the ExpiresAt field if it's non-nil, zero value otherwise. func (i *InteractionRestriction) GetExpiresAt() Timestamp { if i == nil || i.ExpiresAt == nil { From 431e8e6dd0c1426ad20f0a590e0376004171a3d7 Mon Sep 17 00:00:00 2001 From: Emory Ruscus <47612504+emoryruscus@users.noreply.github.com> Date: Thu, 1 Aug 2019 16:20:58 -0400 Subject: [PATCH 07/16] Update github-accessors.go Try to comply with Travis build failure. --- github/github-accessors.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/github/github-accessors.go b/github/github-accessors.go index abcc017e9a5..2331ef5024b 100644 --- a/github/github-accessors.go +++ b/github/github-accessors.go @@ -3892,7 +3892,7 @@ func (i *InstallationToken) GetToken() string { return *i.Token } -// GetPermissions returns the Permissions field if it's non-nil, zero value otherwise. +// GetPermissions returns the Permissions field. func (i *InstallationToken) GetPermissions() *InstallationPermissions { if i == nil { return nil @@ -3900,12 +3900,12 @@ func (i *InstallationToken) GetPermissions() *InstallationPermissions { return i.Permissions } -// GetRepositories returns the Repositories field if it's non-nil, zero value otherwise. -func (i *InstallationToken) GetRepositories() []*Repository { +// GetPermissions returns the Permissions field. +func (i *InstallationTokenOptions) GetPermissions() *InstallationPermissions { if i == nil { return nil } - return i.Repositories + return i.Permissions } // GetExpiresAt returns the ExpiresAt field if it's non-nil, zero value otherwise. From bc6f11701e3a2898f34d5817fa1af82790ba6fb4 Mon Sep 17 00:00:00 2001 From: Emory Ruscus <47612504+emoryruscus@users.noreply.github.com> Date: Thu, 1 Aug 2019 16:27:37 -0400 Subject: [PATCH 08/16] Update github-accessors.go Reformat file for Travis. --- github/github-accessors.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/github/github-accessors.go b/github/github-accessors.go index 2331ef5024b..f4d1984d334 100644 --- a/github/github-accessors.go +++ b/github/github-accessors.go @@ -3884,14 +3884,6 @@ func (i *InstallationToken) GetExpiresAt() time.Time { return *i.ExpiresAt } -// GetToken returns the Token field if it's non-nil, zero value otherwise. -func (i *InstallationToken) GetToken() string { - if i == nil || i.Token == nil { - return "" - } - return *i.Token -} - // GetPermissions returns the Permissions field. func (i *InstallationToken) GetPermissions() *InstallationPermissions { if i == nil { @@ -3900,6 +3892,14 @@ func (i *InstallationToken) GetPermissions() *InstallationPermissions { return i.Permissions } +// GetToken returns the Token field if it's non-nil, zero value otherwise. +func (i *InstallationToken) GetToken() string { + if i == nil || i.Token == nil { + return "" + } + return *i.Token +} + // GetPermissions returns the Permissions field. func (i *InstallationTokenOptions) GetPermissions() *InstallationPermissions { if i == nil { From 96f8146dfacbd347b47aa66432e5c4a70436e0bf Mon Sep 17 00:00:00 2001 From: Emory Ruscus Date: Mon, 5 Aug 2019 10:32:30 -0400 Subject: [PATCH 09/16] gofmt spacing fix --- github/apps.go | 1 - 1 file changed, 1 deletion(-) diff --git a/github/apps.go b/github/apps.go index d714120f32b..829647b8ef1 100644 --- a/github/apps.go +++ b/github/apps.go @@ -325,6 +325,5 @@ func GetReadCloser(body interface{}) (io.ReadCloser, error) { if err != nil { return nil, err } - return ioutil.NopCloser(bytes.NewBuffer(all)), nil } From d00e1b10f7aa6ad2e845afb909ba343e6b3af8b2 Mon Sep 17 00:00:00 2001 From: Emory Ruscus <47612504+emoryruscus@users.noreply.github.com> Date: Mon, 5 Aug 2019 10:39:34 -0400 Subject: [PATCH 10/16] Update apps.go gofmt fix spacing issue --- github/apps.go | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/github/apps.go b/github/apps.go index d714120f32b..4350d290f67 100644 --- a/github/apps.go +++ b/github/apps.go @@ -316,15 +316,15 @@ func GetReadWriter(body interface{}) (io.ReadWriter, error) { // GetReadCloser converts a body interface into an io.ReadCloser object. func GetReadCloser(body interface{}) (io.ReadCloser, error) { - buf, err := GetReadWriter(body) - if err != nil { - return nil, err - } - - all, err := ioutil.ReadAll(buf) - if err != nil { - return nil, err - } - - return ioutil.NopCloser(bytes.NewBuffer(all)), nil + buf, err := GetReadWriter(body) + if err != nil { + return nil, err + } + + all, err := ioutil.ReadAll(buf) + if err != nil { + return nil, err + } + return ioutil.NopCloser(bytes.NewBuffer(all)), nil } + From 24ee2e660e90cfc6dbadde53ebec20490052a5f4 Mon Sep 17 00:00:00 2001 From: Emory Ruscus <47612504+emoryruscus@users.noreply.github.com> Date: Thu, 8 Aug 2019 11:05:31 -0400 Subject: [PATCH 11/16] Move reader functions for coverage test. Move GetReadWriter and GetReadCloser from apps.go to apps_test.go to improve coverage. --- github/apps.go | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/github/apps.go b/github/apps.go index 829647b8ef1..2a32596a44f 100644 --- a/github/apps.go +++ b/github/apps.go @@ -299,31 +299,3 @@ func (s *AppsService) getInstallation(ctx context.Context, url string) (*Install return i, resp, nil } - -// GetReadWriter converts a body interface into an io.ReadWriter object. -func GetReadWriter(body interface{}) (io.ReadWriter, error) { - var buf io.ReadWriter - if body != nil { - buf = new(bytes.Buffer) - enc := json.NewEncoder(buf) - err := enc.Encode(body) - if err != nil { - return nil, err - } - } - return buf, nil -} - -// GetReadCloser converts a body interface into an io.ReadCloser object. -func GetReadCloser(body interface{}) (io.ReadCloser, error) { - buf, err := GetReadWriter(body) - if err != nil { - return nil, err - } - - all, err := ioutil.ReadAll(buf) - if err != nil { - return nil, err - } - return ioutil.NopCloser(bytes.NewBuffer(all)), nil -} From d0693320a7664a89fd1291a5a12f2b9eb054bd51 Mon Sep 17 00:00:00 2001 From: Emory Ruscus <47612504+emoryruscus@users.noreply.github.com> Date: Thu, 8 Aug 2019 11:05:51 -0400 Subject: [PATCH 12/16] Move reader functions for coverage test. Move GetReadWriter and GetReadCloser from apps.go to apps_test.go to improve coverage. --- github/apps_test.go | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/github/apps_test.go b/github/apps_test.go index 78931caa252..f53f641e17f 100644 --- a/github/apps_test.go +++ b/github/apps_test.go @@ -380,3 +380,31 @@ func TestAppsService_FindUserInstallation(t *testing.T) { t.Errorf("Apps.FindUserInstallation returned %+v, want %+v", installation, want) } } + +// GetReadWriter converts a body interface into an io.ReadWriter object. +func GetReadWriter(body interface{}) (io.ReadWriter, error) { + var buf io.ReadWriter + if body != nil { + buf = new(bytes.Buffer) + enc := json.NewEncoder(buf) + err := enc.Encode(body) + if err != nil { + return nil, err + } + } + return buf, nil +} + +// GetReadCloser converts a body interface into an io.ReadCloser object. +func GetReadCloser(body interface{}) (io.ReadCloser, error) { + buf, err := GetReadWriter(body) + if err != nil { + return nil, err + } + + all, err := ioutil.ReadAll(buf) + if err != nil { + return nil, err + } + return ioutil.NopCloser(bytes.NewBuffer(all)), nil +} From 9a57f54ce074b58a4e3d2c1a18dc1feb01e7cac5 Mon Sep 17 00:00:00 2001 From: Emory Ruscus <47612504+emoryruscus@users.noreply.github.com> Date: Thu, 8 Aug 2019 11:40:27 -0400 Subject: [PATCH 13/16] Update apps.go Fix imports. --- github/apps.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/github/apps.go b/github/apps.go index 2a32596a44f..e129e0a09b3 100644 --- a/github/apps.go +++ b/github/apps.go @@ -6,12 +6,8 @@ package github import ( - "bytes" "context" - "encoding/json" "fmt" - "io" - "io/ioutil" "time" ) From 14c5f86cf8943a3f315318d97615484afa35890a Mon Sep 17 00:00:00 2001 From: Emory Ruscus <47612504+emoryruscus@users.noreply.github.com> Date: Thu, 8 Aug 2019 11:40:33 -0400 Subject: [PATCH 14/16] Update apps_test.go Fix imports. --- github/apps_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/github/apps_test.go b/github/apps_test.go index f53f641e17f..55ef2a095ae 100644 --- a/github/apps_test.go +++ b/github/apps_test.go @@ -8,7 +8,9 @@ package github import ( "bytes" "context" + "encoding/json" "fmt" + "io" "io/ioutil" "net/http" "reflect" From 6289bf9592b335b49570806e8bd7559e5e0b96c0 Mon Sep 17 00:00:00 2001 From: Emory Ruscus <47612504+emoryruscus@users.noreply.github.com> Date: Tue, 23 Jul 2019 11:20:11 -0400 Subject: [PATCH 15/16] parent c756c329c19dbbadba0675b42af693093c3f2c45 author Emory Ruscus <47612504+emoryruscus@users.noreply.github.com> 1563895211 -0400 committer Emory Ruscus 1565621142 -0400 Update apps.go Add installation token parameters, allowing creation of permission-scoped github tokens. Update apps_test.go Add test for creating installation tokens with additional parameters. https://developer.github.com/v3/apps/#create-a-new-installation-token Update apps.go - Change 'parameters' to 'options' Update apps_test.go Change 'parameters' to 'options'. Update apps_test.go Update github-accessors.go Add GetPermissions() and GetRepositories() accessor functions. Update github-accessors.go Try to comply with Travis build failure. Update github-accessors.go Reformat file for Travis. gofmt spacing fix Move reader functions for coverage test. Move GetReadWriter and GetReadCloser from apps.go to apps_test.go to improve coverage. Move reader functions for coverage test. Move GetReadWriter and GetReadCloser from apps.go to apps_test.go to improve coverage. Update apps.go Fix imports. Update apps_test.go Fix imports. --- github/apps.go | 21 ++++++++-- github/apps_test.go | 82 +++++++++++++++++++++++++++++++++++++- github/github-accessors.go | 16 ++++++++ 3 files changed, 114 insertions(+), 5 deletions(-) diff --git a/github/apps.go b/github/apps.go index f675a9abd18..e129e0a09b3 100644 --- a/github/apps.go +++ b/github/apps.go @@ -32,8 +32,21 @@ type App struct { // InstallationToken represents an installation token. type InstallationToken struct { - Token *string `json:"token,omitempty"` - ExpiresAt *time.Time `json:"expires_at,omitempty"` + Token *string `json:"token,omitempty"` + ExpiresAt *time.Time `json:"expires_at,omitempty"` + Permissions *InstallationPermissions `json:"permissions,omitempty"` + Repositories []*Repository `json:"repositories,emitempty"` +} + +// InstallationTokenOptions allow restricting a token's access to specific repositories. +type InstallationTokenOptions struct { + // The IDs of the repositories that the installation token can access. + // Providing repository IDs restricts the access of an installation token to specific repositories. + RepositoryIDs []int64 `json:"repository_ids,omitempty"` + + // The permissions granted to the access token. + // The permissions object includes the permission names and their access type. + Permissions *InstallationPermissions `json:"permissions,omitempty"` } // InstallationPermissions lists the repository and organization permissions for an installation. @@ -194,10 +207,10 @@ func (s *AppsService) ListUserInstallations(ctx context.Context, opt *ListOption // CreateInstallationToken creates a new installation token. // // GitHub API docs: https://developer.github.com/v3/apps/#create-a-new-installation-token -func (s *AppsService) CreateInstallationToken(ctx context.Context, id int64) (*InstallationToken, *Response, error) { +func (s *AppsService) CreateInstallationToken(ctx context.Context, id int64, opt *InstallationTokenOptions) (*InstallationToken, *Response, error) { u := fmt.Sprintf("app/installations/%v/access_tokens", id) - req, err := s.client.NewRequest("POST", u, nil) + req, err := s.client.NewRequest("POST", u, opt) if err != nil { return nil, nil, err } diff --git a/github/apps_test.go b/github/apps_test.go index 8d5b27d38ce..55ef2a095ae 100644 --- a/github/apps_test.go +++ b/github/apps_test.go @@ -6,8 +6,12 @@ package github import ( + "bytes" "context" + "encoding/json" "fmt" + "io" + "io/ioutil" "net/http" "reflect" "testing" @@ -214,7 +218,54 @@ func TestAppsService_CreateInstallationToken(t *testing.T) { fmt.Fprint(w, `{"token":"t"}`) }) - token, _, err := client.Apps.CreateInstallationToken(context.Background(), 1) + token, _, err := client.Apps.CreateInstallationToken(context.Background(), 1, nil) + if err != nil { + t.Errorf("Apps.CreateInstallationToken returned error: %v", err) + } + + want := &InstallationToken{Token: String("t")} + if !reflect.DeepEqual(token, want) { + t.Errorf("Apps.CreateInstallationToken returned %+v, want %+v", token, want) + } +} + +func TestAppsService_CreateInstallationTokenWithOptions(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + installationTokenOptions := &InstallationTokenOptions{ + RepositoryIDs: []int64{1234}, + Permissions: &InstallationPermissions{ + Contents: String("write"), + Issues: String("read"), + }, + } + + // Convert InstallationTokenOptions into an io.ReadCloser object for comparison. + wantBody, err := GetReadCloser(installationTokenOptions) + if err != nil { + t.Errorf("GetReadCloser returned error: %v", err) + } + + mux.HandleFunc("/app/installations/1/access_tokens", func(w http.ResponseWriter, r *http.Request) { + // Read request body contents. + var gotBodyBytes []byte + gotBodyBytes, err = ioutil.ReadAll(r.Body) + if err != nil { + t.Errorf("ReadAll returned error: %v", err) + } + r.Body = ioutil.NopCloser(bytes.NewBuffer(gotBodyBytes)) + + if !reflect.DeepEqual(r.Body, wantBody) { + t.Errorf("request sent %+v, want %+v", r.Body, wantBody) + } + + testMethod(t, r, "POST") + testHeader(t, r, "Accept", mediaTypeIntegrationPreview) + fmt.Fprint(w, `{"token":"t"}`) + }) + + token, _, err := client.Apps.CreateInstallationToken(context.Background(), 1, installationTokenOptions) if err != nil { t.Errorf("Apps.CreateInstallationToken returned error: %v", err) } @@ -247,6 +298,7 @@ func TestAppsService_CreateAttachement(t *testing.T) { t.Errorf("CreateAttachment = %+v, want %+v", got, want) } } + func TestAppsService_FindOrganizationInstallation(t *testing.T) { client, mux, _, teardown := setup() defer teardown() @@ -330,3 +382,31 @@ func TestAppsService_FindUserInstallation(t *testing.T) { t.Errorf("Apps.FindUserInstallation returned %+v, want %+v", installation, want) } } + +// GetReadWriter converts a body interface into an io.ReadWriter object. +func GetReadWriter(body interface{}) (io.ReadWriter, error) { + var buf io.ReadWriter + if body != nil { + buf = new(bytes.Buffer) + enc := json.NewEncoder(buf) + err := enc.Encode(body) + if err != nil { + return nil, err + } + } + return buf, nil +} + +// GetReadCloser converts a body interface into an io.ReadCloser object. +func GetReadCloser(body interface{}) (io.ReadCloser, error) { + buf, err := GetReadWriter(body) + if err != nil { + return nil, err + } + + all, err := ioutil.ReadAll(buf) + if err != nil { + return nil, err + } + return ioutil.NopCloser(bytes.NewBuffer(all)), nil +} diff --git a/github/github-accessors.go b/github/github-accessors.go index b4ca033d300..f4d1984d334 100644 --- a/github/github-accessors.go +++ b/github/github-accessors.go @@ -3884,6 +3884,14 @@ func (i *InstallationToken) GetExpiresAt() time.Time { return *i.ExpiresAt } +// GetPermissions returns the Permissions field. +func (i *InstallationToken) GetPermissions() *InstallationPermissions { + if i == nil { + return nil + } + return i.Permissions +} + // GetToken returns the Token field if it's non-nil, zero value otherwise. func (i *InstallationToken) GetToken() string { if i == nil || i.Token == nil { @@ -3892,6 +3900,14 @@ func (i *InstallationToken) GetToken() string { return *i.Token } +// GetPermissions returns the Permissions field. +func (i *InstallationTokenOptions) GetPermissions() *InstallationPermissions { + if i == nil { + return nil + } + return i.Permissions +} + // GetExpiresAt returns the ExpiresAt field if it's non-nil, zero value otherwise. func (i *InteractionRestriction) GetExpiresAt() Timestamp { if i == nil || i.ExpiresAt == nil { From 9d6fd70563e526dbabcf4a8bc5f10e02fcc5c0af Mon Sep 17 00:00:00 2001 From: Emory Ruscus <47612504+emoryruscus@users.noreply.github.com> Date: Tue, 13 Aug 2019 10:00:58 -0400 Subject: [PATCH 16/16] Update apps.go Change 'emitempty' to 'omitempty'. --- github/apps.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/github/apps.go b/github/apps.go index e129e0a09b3..5041e801280 100644 --- a/github/apps.go +++ b/github/apps.go @@ -35,7 +35,7 @@ type InstallationToken struct { Token *string `json:"token,omitempty"` ExpiresAt *time.Time `json:"expires_at,omitempty"` Permissions *InstallationPermissions `json:"permissions,omitempty"` - Repositories []*Repository `json:"repositories,emitempty"` + Repositories []*Repository `json:"repositories,omitempty"` } // InstallationTokenOptions allow restricting a token's access to specific repositories.