From b62a9bfc3789c255bd47c6fef5040c413c4af14b Mon Sep 17 00:00:00 2001 From: Eric Voshall <6836155+ericvoshall@users.noreply.github.com> Date: Fri, 22 Jul 2022 11:01:15 -0400 Subject: [PATCH] Handle incorrect return type Signed-off-by: Eric Voshall <6836155+ericvoshall@users.noreply.github.com> --- ...eInstanceGithubCredentialsProvider.test.ts | 75 +++++++++++++++++++ ...SingleInstanceGithubCredentialsProvider.ts | 5 +- 2 files changed, 79 insertions(+), 1 deletion(-) diff --git a/packages/integration/src/github/SingleInstanceGithubCredentialsProvider.test.ts b/packages/integration/src/github/SingleInstanceGithubCredentialsProvider.test.ts index 246a859b7a..d738edf417 100644 --- a/packages/integration/src/github/SingleInstanceGithubCredentialsProvider.test.ts +++ b/packages/integration/src/github/SingleInstanceGithubCredentialsProvider.test.ts @@ -20,6 +20,7 @@ const octokit = { paginate: async (fn: any) => (await fn()).data, apps: { listInstallations: jest.fn(), + listReposAccessibleToInstallation: jest.fn(), createInstallationAccessToken: jest.fn(), }, }; @@ -325,4 +326,78 @@ describe('SingleInstanceGithubCredentialsProvider tests', () => { expect(headers).toEqual({ Authorization: 'Bearer secret_token' }); expect(token).toEqual('secret_token'); }); + + it('should not throw when paginate response is an array of repositories', async () => { + const repoName = 'foobar'; + octokit.apps.listInstallations.mockResolvedValue({ + headers: { + etag: '123', + }, + data: [ + { + id: 1, + repository_selection: 'all', + account: { + login: 'backstage', + }, + }, + ], + } as RestEndpointMethodTypes['apps']['listInstallations']['response']); + + octokit.apps.createInstallationAccessToken.mockResolvedValueOnce({ + data: { + expires_at: DateTime.local().plus({ hours: 1 }).toString(), + token: 'secret_token', + repository_selection: 'selected', + }, + } as RestEndpointMethodTypes['apps']['createInstallationAccessToken']['response']); + + octokit.apps.listReposAccessibleToInstallation.mockReturnValue({ + data: [{ name: repoName }], + } as unknown as RestEndpointMethodTypes['apps']['listReposAccessibleToInstallation']['response']); + + await expect( + github.getCredentials({ + url: `https://github.com/backstage/${repoName}`, + }), + ).resolves.not.toThrow(); + }); + + it('should not throw when paginate response is an object with a property containing an array of repositories', async () => { + const repoName = 'foobar'; + octokit.apps.listInstallations.mockResolvedValue({ + headers: { + etag: '123', + }, + data: [ + { + id: 1, + repository_selection: 'all', + account: { + login: 'backstage', + }, + }, + ], + } as RestEndpointMethodTypes['apps']['listInstallations']['response']); + + octokit.apps.createInstallationAccessToken.mockResolvedValueOnce({ + data: { + expires_at: DateTime.local().plus({ hours: 1 }).toString(), + token: 'secret_token', + repository_selection: 'selected', + }, + } as RestEndpointMethodTypes['apps']['createInstallationAccessToken']['response']); + + octokit.apps.listReposAccessibleToInstallation.mockReturnValue({ + data: { + repositories: [{ name: repoName }], + }, + } as RestEndpointMethodTypes['apps']['listReposAccessibleToInstallation']['response']); + + await expect( + github.getCredentials({ + url: `https://github.com/backstage/${repoName}`, + }), + ).resolves.not.toThrow(); + }); }); diff --git a/packages/integration/src/github/SingleInstanceGithubCredentialsProvider.ts b/packages/integration/src/github/SingleInstanceGithubCredentialsProvider.ts index e56c1521dd..2fd2e7f7dc 100644 --- a/packages/integration/src/github/SingleInstanceGithubCredentialsProvider.ts +++ b/packages/integration/src/github/SingleInstanceGithubCredentialsProvider.ts @@ -119,7 +119,10 @@ class GithubAppManager { const repos = await installationClient.paginate( installationClient.apps.listReposAccessibleToInstallation, ); - const hasRepo = repos.repositories.some(repository => { + // The return type of the paginate method is incorrect. + const repositories: RestEndpointMethodTypes['apps']['listReposAccessibleToInstallation']['response']['data']['repositories'] = + repos.repositories ?? repos; + const hasRepo = repositories.some(repository => { return repository.name === repo; }); if (!hasRepo) {