diff --git a/lib/modules/platform/github/index.spec.ts b/lib/modules/platform/github/index.spec.ts index 0144c37d84fa0d41440999b8ae133ebe3f3d0e8e..ec16ee01ece7ef435918186c76a666bb733767be 100644 --- a/lib/modules/platform/github/index.spec.ts +++ b/lib/modules/platform/github/index.spec.ts @@ -1,34 +1,35 @@ import { DateTime } from 'luxon'; import * as httpMock from '../../../../test/http-mock'; -import { loadFixture, mocked } from '../../../../test/util'; +import { loadFixture, logger, mocked } from '../../../../test/util'; import { REPOSITORY_NOT_FOUND, REPOSITORY_RENAMED, } from '../../../constants/error-messages'; -import type * as _logger from '../../../logger'; import { BranchStatus, PrState, VulnerabilityAlert } from '../../../types'; -import type * as _git from '../../../util/git'; +import * as _git from '../../../util/git'; +import * as _hostRules from '../../../util/host-rules'; +import { setBaseUrl } from '../../../util/http/github'; import { toBase64 } from '../../../util/string'; -import type { CreatePRConfig, Platform } from '../types'; +import type { CreatePRConfig } from '../types'; +import * as github from '.'; const githubApiHost = 'https://api.github.com'; +jest.mock('delay'); + +jest.mock('../../../util/host-rules'); +const hostRules: jest.Mocked<typeof _hostRules> = mocked(_hostRules); + +jest.mock('../../../util/git'); +const git: jest.Mocked<typeof _git> = mocked(_git); + describe('modules/platform/github/index', () => { - let github: Platform; - let hostRules: jest.Mocked<typeof import('../../../util/host-rules')>; - let git: jest.Mocked<typeof _git>; - let logger: jest.Mocked<typeof _logger>; - beforeEach(async () => { - // reset module - jest.resetModules(); - jest.unmock('.'); - jest.mock('delay'); - jest.mock('../../../util/host-rules'); - github = await import('.'); - hostRules = mocked(await import('../../../util/host-rules')); - jest.mock('../../../util/git'); - git = mocked(await import('../../../util/git')); - logger = mocked(await import('../../../logger')); + beforeEach(() => { + jest.resetAllMocks(); + github.resetConfigs(); + + setBaseUrl(githubApiHost); + git.branchExists.mockReturnValue(true); git.isBranchStale.mockResolvedValue(true); git.getBranchCommit.mockReturnValue( diff --git a/lib/modules/platform/github/index.ts b/lib/modules/platform/github/index.ts index 4ae9268736241ba5ebb8b8aaf879a8bd3f3e3e86..d431e2df9b2b7f92200f5f0797e10147818c8a5a 100644 --- a/lib/modules/platform/github/index.ts +++ b/lib/modules/platform/github/index.ts @@ -76,19 +76,26 @@ import type { PlatformConfig, PrList, } from './types'; -import { UserDetails, getUserDetails, getUserEmail } from './user'; +import { getUserDetails, getUserEmail } from './user'; const githubApi = new githubHttp.GithubHttp(); -let config: LocalRepoConfig = {} as any; +let config: LocalRepoConfig; +let platformConfig: PlatformConfig; -const platformConfig: PlatformConfig = { - hostType: PlatformId.Github, - endpoint: 'https://api.github.com/', -}; +export function resetConfigs(): void { + config = {} as never; + platformConfig = { + hostType: PlatformId.Github, + endpoint: 'https://api.github.com/', + }; +} -const escapeHash = (input: string): string => - input ? input.replace(regEx(/#/g), '%23') : input; +resetConfigs(); + +function escapeHash(input: string): string { + return input ? input.replace(regEx(/#/g), '%23') : input; +} export async function detectGhe(token: string): Promise<void> { platformConfig.isGhe = @@ -127,20 +134,28 @@ export async function initPlatform({ await detectGhe(token); - let userDetails: UserDetails; let renovateUsername: string; if (username) { renovateUsername = username; } else { - userDetails = await getUserDetails(platformConfig.endpoint, token); - renovateUsername = userDetails.username; + platformConfig.userDetails ??= await getUserDetails( + platformConfig.endpoint, + token + ); + renovateUsername = platformConfig.userDetails.username; } let discoveredGitAuthor: string; if (!gitAuthor) { - userDetails = await getUserDetails(platformConfig.endpoint, token); - const userEmail = await getUserEmail(platformConfig.endpoint, token); - if (userEmail) { - discoveredGitAuthor = `${userDetails.name} <${userEmail}>`; + platformConfig.userDetails ??= await getUserDetails( + platformConfig.endpoint, + token + ); + platformConfig.userEmail ??= await getUserEmail( + platformConfig.endpoint, + token + ); + if (platformConfig.userEmail) { + discoveredGitAuthor = `${platformConfig.userDetails.name} <${platformConfig.userEmail}>`; } } logger.debug({ platformConfig, renovateUsername }, 'Platform config'); @@ -219,8 +234,6 @@ export async function getJsonFile( return JSON.parse(raw); } -let existingRepos; - // Initialize GitHub by getting base branch and SHA export async function initRepo({ endpoint, @@ -352,18 +365,16 @@ export async function initRepo({ config.parentRepo = config.repository; config.repository = null; // Get list of existing repos - existingRepos = - existingRepos || - ( - await githubApi.getJson<{ full_name: string }[]>( - 'user/repos?per_page=100', - { - token: forkToken || opts.token, - paginate: true, - pageLimit: 100, - } - ) - ).body.map((r) => r.full_name); + platformConfig.existingRepos ??= ( + await githubApi.getJson<{ full_name: string }[]>( + 'user/repos?per_page=100', + { + token: forkToken || opts.token, + paginate: true, + pageLimit: 100, + } + ) + ).body.map((r) => r.full_name); try { const forkedRepo = await githubApi.postJson<{ full_name: string; @@ -424,7 +435,7 @@ export async function initRepo({ logger.debug({ err }, 'Error forking repository'); throw new Error(REPOSITORY_CANNOT_FORK); } - if (existingRepos.includes(config.repository)) { + if (platformConfig.existingRepos.includes(config.repository)) { logger.debug( { repository_fork: config.repository }, 'Found existing fork' @@ -456,7 +467,7 @@ export async function initRepo({ } } else { logger.debug({ repository_fork: config.repository }, 'Created fork'); - existingRepos.push(config.repository); + platformConfig.existingRepos.push(config.repository); // Wait an arbitrary 30s to hopefully give GitHub enough time for forking to complete await delay(30000); } diff --git a/lib/modules/platform/github/types.ts b/lib/modules/platform/github/types.ts index 8665ffa7f7a3a220cf59ee6f20bf092ebb0bf00c..0c4b4d1649f75f6ca1b0f5d9d9f6ecd5de5b00c3 100644 --- a/lib/modules/platform/github/types.ts +++ b/lib/modules/platform/github/types.ts @@ -52,12 +52,20 @@ export interface GhGraphQlPr extends GhPr { labels: string[] & { nodes?: { name: string }[] }; } +export interface UserDetails { + username: string; + name: string; +} + export interface PlatformConfig { hostType: string; endpoint: string; isGhe?: boolean; gheVersion?: string | null; isGHApp?: boolean; + existingRepos?: string[]; + userDetails?: UserDetails; + userEmail?: string | null; } export interface LocalRepoConfig { diff --git a/lib/modules/platform/github/user.ts b/lib/modules/platform/github/user.ts index c0c10292bb65be03365fd6994b7347780b908834..a58e60355bf8789eade01e81e64d244a9a37549a 100644 --- a/lib/modules/platform/github/user.ts +++ b/lib/modules/platform/github/user.ts @@ -1,22 +1,13 @@ import { logger } from '../../../logger'; import * as githubHttp from '../../../util/http/github'; +import type { UserDetails } from './types'; 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 }>( @@ -26,19 +17,16 @@ export async function getUserDetails( } ) ).body; - userDetails = { + return { 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 | null; - export async function getUserEmail( endpoint: string, token: string @@ -49,8 +37,7 @@ export async function getUserEmail( token, }) ).body; - userEmail = emails?.[0].email ?? null; - return userEmail; + return emails?.[0].email ?? null; } catch (err) { logger.debug( 'Cannot read user/emails endpoint on GitHub to retrieve gitAuthor'