import { DateTime } from 'luxon'; import type { RenovateConfig } from '../../../config/types.ts'; import { instrument } from '../../../instrumentation/index.ts'; import { logger } from '../../../logger/index.ts'; import { platform } from '../../../modules/platform/index.ts'; import { scm } from '../../../modules/platform/scm.ts'; import { ExternalHostError } from '../../../types/errors/external-host-error.ts'; import { coerceArray } from '../../../util/array.ts'; import { getCache } from '../../../util/cache/repository/index.ts'; import { getInheritedOrGlobal } from '../../../util/common.ts'; import type { BranchConfig } from '../../types.ts'; export async function getPrHourlyCount( config: RenovateConfig, ): Promise { return await instrument('getPrHourlyCount', async () => { try { const prList = await platform.getPrList(); const currentHourStart = DateTime.utc().startOf('hour'); logger.debug( `Calculating PRs created so far in this hour currentHourStart=${String(currentHourStart)}`, ); const soFarThisHour = prList.filter( (pr) => pr.sourceBranch !== getInheritedOrGlobal('onboardingBranch') && pr.sourceBranch.startsWith(config.branchPrefix!) && DateTime.fromISO(pr.createdAt!).toUTC() > currentHourStart, ); logger.debug( `${soFarThisHour.length} PRs have been created so far in this hour.`, ); return soFarThisHour.length; } catch (err) { // istanbul ignore if if (err instanceof ExternalHostError) { throw err; } logger.error({ err }, 'Error checking PRs created per hour'); return 0; } }); } export async function getConcurrentPrsCount( config: RenovateConfig, branches: BranchConfig[], ): Promise { return await instrument('getConcurrentPrsCount', async () => { let openPrCount = 0; for (const { branchName } of branches) { try { const pr = await platform.getBranchPr(branchName, config.baseBranch); if ( pr && pr.sourceBranch !== getInheritedOrGlobal('onboardingBranch') && pr.state === 'open' ) { openPrCount++; } } catch (err) { // istanbul ignore if if (err instanceof ExternalHostError) { throw err; } else { // no-op } } } logger.debug(`${openPrCount} PRs are currently open`); return openPrCount; }); } export async function getCommitsHourlyCount( branches: BranchConfig[], ): Promise { return await instrument('getCommitsHourlyCount', async () => { try { const currentHourStart = DateTime.utc().startOf('hour'); logger.debug( `Calculating commits so far in this hour currentHourStart=${String(currentHourStart)}, for ${branches.length} branches`, ); const cache = getCache(); const cachedBranches = coerceArray(cache.branches); // if we don't have all of our branches in our cache (for instance, if we're not using the Repository Cache, or this is the first run against a repo), we need to fall back to the SCM const needsScmFallback = branches.some( (branch) => !cachedBranches.find((b) => b.branchName === branch.branchName) ?.commitTimestamp, ); const fallbackUpdateDates = needsScmFallback ? await scm.getAllBranchUpdateDates() : {}; let soFarThisHour = 0; for (const branch of branches) { // First try to get from cache const branchCache = cachedBranches.find( (b) => b.branchName === branch.branchName, ); if (branchCache?.commitTimestamp) { const commitTime = DateTime.fromISO( branchCache.commitTimestamp, ).toUTC(); if (commitTime > currentHourStart) { soFarThisHour++; } } else { // Fallback to SCM if not in cache const updateDate = fallbackUpdateDates[branch.branchName]; if (updateDate && updateDate > currentHourStart) { soFarThisHour++; } } } logger.debug(`${soFarThisHour} commits so far in this hour.`); return soFarThisHour; } catch (err) { logger.error({ err }, 'Error checking commits per hour'); return 0; } }); } export async function getConcurrentBranchesCount( branches: BranchConfig[], ): Promise { return await instrument('getConcurrentBranchesCount', async () => { let existingBranchCount = 0; for (const branch of branches) { if (await scm.branchExists(branch.branchName)) { existingBranchCount++; } } logger.debug(`${existingBranchCount} already existing branches found.`); return existingBranchCount; }); }