From 9b1e3186a83ef77bb5f8fdbb0e24de5e2a4836cd Mon Sep 17 00:00:00 2001 From: Alexy Mantha <alexymantha@live.ca> Date: Fri, 14 Jan 2022 03:55:21 -0500 Subject: [PATCH] feat(github): Add autodiscovery support for Github App (#13406) Co-authored-by: Michael Kriese <michael.kriese@visualon.de> Co-authored-by: Rhys Arkins <rhys@arkins.net> --- docs/usage/getting-started/running.md | 1 - lib/platform/github/index.spec.ts | 25 +++++++++++++++++++++++++ lib/platform/github/index.ts | 22 +++++++++++++++++----- lib/platform/github/types.ts | 1 + 4 files changed, 43 insertions(+), 6 deletions(-) diff --git a/docs/usage/getting-started/running.md b/docs/usage/getting-started/running.md index 6ae9c56fd4..d67c053e2e 100644 --- a/docs/usage/getting-started/running.md +++ b/docs/usage/getting-started/running.md @@ -174,7 +174,6 @@ Alternatively as environment variable `RENOVATE_TOKEN`, or via CLI `--token=`. **`repositories: ["orgname/repo-1","orgname/repo-2"]`** List of repositories to run on. -Auto discovery does not work with a GitHub App. Alternatively as comma-separated environment variable `RENOVATE_REPOSITORIES`. The GitHub App installation token is scoped at most to a single organization and running on multiple organizations requires multiple invocations of `renovate` with different `token` and `repositories` parameters. diff --git a/lib/platform/github/index.spec.ts b/lib/platform/github/index.spec.ts index ebb9ef0581..d1461eb4f7 100644 --- a/lib/platform/github/index.spec.ts +++ b/lib/platform/github/index.spec.ts @@ -175,6 +175,31 @@ describe('platform/github/index', () => { expect(repos).toMatchSnapshot(); expect(httpMock.getTrace()).toMatchSnapshot(); }); + it('should return an array of repos when using Github App endpoint', async () => { + //Use Github App token + await github.initPlatform({ + endpoint: githubApiHost, + username: 'renovate-bot', + gitAuthor: 'Renovate Bot', + token: 'x-access-token:123test', + }); + httpMock + .scope(githubApiHost) + .get('/installation/repositories?per_page=100') + .reply(200, { + repositories: [ + { + full_name: 'a/b', + }, + { + full_name: 'c/d', + }, + ], + }); + + const repos = await github.getRepos(); + expect(repos).toStrictEqual(['a/b', 'c/d']); + }); }); function initRepoMock( diff --git a/lib/platform/github/index.ts b/lib/platform/github/index.ts index 4c06175bbb..2bb8d39b86 100644 --- a/lib/platform/github/index.ts +++ b/lib/platform/github/index.ts @@ -109,6 +109,8 @@ export async function initPlatform({ throw new Error('Init: You must configure a GitHub personal access token'); } + platformConfig.isGHApp = token.startsWith('x-access-token:'); + if (endpoint) { platformConfig.endpoint = ensureTrailingSlash(endpoint); githubHttp.setBaseUrl(platformConfig.endpoint); @@ -148,11 +150,21 @@ export async function initPlatform({ export async function getRepos(): Promise<string[]> { logger.debug('Autodiscovering GitHub repositories'); try { - const res = await githubApi.getJson<{ full_name: string }[]>( - 'user/repos?per_page=100', - { paginate: 'all' } - ); - return res.body.map((repo) => repo.full_name); + if (platformConfig.isGHApp) { + const res = await githubApi.getJson<{ + repositories: { full_name: string }[]; + }>(`installation/repositories?per_page=100`, { + paginationField: 'repositories', + paginate: 'all', + }); + return res.body.repositories.map((repo) => repo.full_name); + } else { + const res = await githubApi.getJson<{ full_name: string }[]>( + `user/repos?per_page=100`, + { paginate: 'all' } + ); + return res.body.map((repo) => repo.full_name); + } } catch (err) /* istanbul ignore next */ { logger.error({ err }, `GitHub getRepos error`); throw err; diff --git a/lib/platform/github/types.ts b/lib/platform/github/types.ts index 296e589e54..2e819ebf9e 100644 --- a/lib/platform/github/types.ts +++ b/lib/platform/github/types.ts @@ -59,6 +59,7 @@ export interface PlatformConfig { endpoint: string; isGhe?: boolean; gheVersion?: string | null; + isGHApp?: boolean; } export interface LocalRepoConfig { -- GitLab