diff --git a/lib/platform/github/__snapshots__/index.spec.ts.snap b/lib/platform/github/__snapshots__/index.spec.ts.snap index 8694755cc923de746c5edb6279e0fa4e33a9d400..94255613d0d741fbbe0b0a2364a35d728bf70155 100644 --- a/lib/platform/github/__snapshots__/index.spec.ts.snap +++ b/lib/platform/github/__snapshots__/index.spec.ts.snap @@ -4544,6 +4544,14 @@ Array [ ] `; +exports[`platform/github initPlatform() should support gitAuthor and username 1`] = ` +Object { + "endpoint": "https://api.github.com/", + "gitAuthor": "renovate@whitesourcesoftware.com", + "renovateUsername": "renovate-bot", +} +`; + exports[`platform/github initPlatform() should throw if user failure 1`] = ` Array [ Object { diff --git a/lib/platform/github/index.spec.ts b/lib/platform/github/index.spec.ts index 1310d3bfeb292d6f0e7c64b1ded36d805bebd351..ea8df4b18bc746eb8878e619978c1dbc0109e0be 100644 --- a/lib/platform/github/index.spec.ts +++ b/lib/platform/github/index.spec.ts @@ -93,6 +93,15 @@ describe('platform/github', () => { ).toMatchSnapshot(); expect(httpMock.getTrace()).toMatchSnapshot(); }); + it('should support gitAuthor and username', async () => { + expect( + await github.initPlatform({ + token: 'abc123', + username: 'renovate-bot', + gitAuthor: 'renovate@whitesourcesoftware.com', + } as any) + ).toMatchSnapshot(); + }); it('should support default endpoint with email', async () => { httpMock .scope(githubApiHost) diff --git a/lib/platform/github/index.ts b/lib/platform/github/index.ts index 9fcf7bac12190ff243481ff4df1b04a670e2829d..b98c505df50c204f8c82d3ba669ead3587ce7b3a 100644 --- a/lib/platform/github/index.ts +++ b/lib/platform/github/index.ts @@ -55,6 +55,7 @@ import { LocalRepoConfig, PrList, } from './types'; +import { UserDetails, getUserDetails, getUserEmail } from './user'; const githubApi = new githubHttp.GithubHttp(); @@ -73,9 +74,13 @@ const escapeHash = (input: string): string => export async function initPlatform({ endpoint, token, + username, + gitAuthor, }: { endpoint: string; token: string; + username?: string; + gitAuthor?: string; }): Promise<PlatformResult> { if (!token) { throw new Error('Init: You must configure a GitHub personal access token'); @@ -87,48 +92,26 @@ export async function initPlatform({ } else { logger.debug('Using default github endpoint: ' + defaults.endpoint); } - let gitAuthor: string; + let userDetails: UserDetails; let renovateUsername: string; - try { - const userData = ( - await githubApi.getJson<{ login: string; name: string }>( - defaults.endpoint + 'user', - { - token, - } - ) - ).body; - renovateUsername = userData.login; - gitAuthor = userData.name; - } catch (err) { - logger.debug({ err }, 'Error authenticating with GitHub'); - throw new Error('Init: Authentication failure'); + if (username) { + renovateUsername = username; + } else { + userDetails = await getUserDetails(defaults.endpoint, token); + renovateUsername = userDetails.username; } - try { - const userEmail = ( - await githubApi.getJson<{ email: string }[]>( - defaults.endpoint + 'user/emails', - { - token, - } - ) - ).body; - if (userEmail.length && userEmail[0].email) { - gitAuthor += ` <${userEmail[0].email}>`; - } else { - logger.debug('Cannot find an email address for Renovate user'); - gitAuthor = undefined; + let discoveredGitAuthor: string; + if (!gitAuthor) { + userDetails = await getUserDetails(defaults.endpoint, token); + const userEmail = await getUserEmail(defaults.endpoint, token); + if (userEmail) { + discoveredGitAuthor = `${userDetails.name} <${userEmail}>`; } - } catch (err) { - logger.debug( - 'Cannot read user/emails endpoint on GitHub to retrieve gitAuthor' - ); - gitAuthor = undefined; } logger.debug('Authenticated as GitHub user: ' + renovateUsername); const platformConfig: PlatformResult = { endpoint: defaults.endpoint, - gitAuthor, + gitAuthor: gitAuthor || discoveredGitAuthor, renovateUsername, }; return platformConfig; diff --git a/lib/platform/github/user.ts b/lib/platform/github/user.ts new file mode 100644 index 0000000000000000000000000000000000000000..fb7f2a08d18cc0b123e20f25caf3082cc4c69ca8 --- /dev/null +++ b/lib/platform/github/user.ts @@ -0,0 +1,60 @@ +import { logger } from '../../logger'; +import * as githubHttp from '../../util/http/github'; + +const githubApi = new githubHttp.GithubHttp(); + +export interface UserDetails { + username: string; + name: string; +} + +let userDetails: UserDetails; + +export async function getUserDetails( + endpoint: string, + token: string +): Promise<UserDetails> { + if (userDetails) { + return userDetails; + } + try { + const userData = ( + await githubApi.getJson<{ login: string; name: string }>( + endpoint + 'user', + { + token, + } + ) + ).body; + userDetails = { + username: userData.login, + name: userData.name, + }; + return userDetails; + } catch (err) { + logger.debug({ err }, 'Error authenticating with GitHub'); + throw new Error('Init: Authentication failure'); + } +} + +let userEmail: string; + +export async function getUserEmail( + endpoint: string, + token: string +): Promise<string | null> { + try { + const emails = ( + await githubApi.getJson<{ email: string }[]>(endpoint + 'user/emails', { + token, + }) + ).body; + userEmail = emails?.[0].email || null; + return userEmail; + } catch (err) { + logger.debug( + 'Cannot read user/emails endpoint on GitHub to retrieve gitAuthor' + ); + return null; + } +}