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