Files
renovate/lib/workers/repository/update/pr/participants.ts
Sebastian Poxhofer 97327c3d28 refactor(linters): add prefer-coerce-array rule (#45492)
* refactor(linters): add prefer-coerce-array rule

Refs #45217

`x ?? []` and `coerceArray(x)` say the same thing, but only the second
one is searchable and consistent. The rule flags a `??` whose default is
a bare `[]` literal; a non-empty default or an asserted `([] as Foo[])`
still passes.

Applying it across `lib/` surfaced three spots the helper cannot cover,
which keep `?? []` with a disable comment or a narrower fix:

- `package-files.ts` destructures a tuple, which `coerceArray()` widens
- `generate.spec.ts` defaults `matchAll()`, an iterator rather than an array
- `mise/upgradeable-tooling.ts` declares a `Record` return, so its
  `?? []` fallback was wrong to begin with and becomes `coerceObject()`

* refactor(platform/github): hoist the GHE version header lookup

`Object.entries(...).find()` returns a tuple, and defaulting it with
`?? []` only to destructure the second element reads as an array
default when it is not one. Name the found entry instead, which drops
the `?? []` rather than routing a tuple through `coerceArray()`.
2026-08-28 09:27:58 +00:00

118 lines
3.8 KiB
TypeScript

import { isArray, isNonEmptyString, isNumber } from '@sindresorhus/is';
import { GlobalConfig } from '../../../../config/global.ts';
import type { RenovateConfig } from '../../../../config/types.ts';
import { logger } from '../../../../logger/index.ts';
import type { Pr } from '../../../../modules/platform/index.ts';
import { platform } from '../../../../modules/platform/index.ts';
import { coerceArray } from '../../../../util/array.ts';
import { noLeadingAtSymbol } from '../../../../util/common.ts';
import { sampleSize } from '../../../../util/sample.ts';
import { codeOwnersForPr } from './code-owners.ts';
async function addCodeOwners(
config: RenovateConfig,
assigneesOrReviewers: string[],
pr: Pr,
): Promise<string[]> {
const codeOwners = await codeOwnersForPr(pr);
const assignees =
config.expandCodeOwnersGroups && platform.expandGroupMembers
? await platform.expandGroupMembers(codeOwners)
: codeOwners;
return [...new Set(assigneesOrReviewers.concat(assignees))];
}
function filterUnavailableUsers(
config: RenovateConfig,
users: string[],
): Promise<string[]> {
return config.filterUnavailableUsers && platform.filterUnavailableUsers
? platform.filterUnavailableUsers(users)
: Promise.resolve(users);
}
function prepareParticipants(
config: RenovateConfig,
usernames: string[],
): Promise<string[]> {
const normalizedUsernames = [
...new Set(usernames.map(noLeadingAtSymbol).filter(isNonEmptyString)),
];
return filterUnavailableUsers(config, normalizedUsernames);
}
export async function addParticipants(
config: RenovateConfig,
pr: Pr,
): Promise<void> {
let assignees = coerceArray(config.assignees);
logger.debug(`addParticipants(pr=${pr?.number})`);
if (config.assigneesFromCodeOwners) {
assignees = await addCodeOwners(config, assignees, pr);
}
if (assignees.length > 0) {
try {
assignees = await prepareParticipants(config, assignees);
if (isNumber(config.assigneesSampleSize)) {
assignees = sampleSize(assignees, config.assigneesSampleSize);
}
if (assignees.length > 0) {
if (GlobalConfig.get('dryRun')) {
logger.info(`DRY-RUN: Would add assignees to PR #${pr.number}`);
} else {
await platform.addAssignees(pr.number, assignees);
logger.debug({ assignees }, 'Added assignees');
}
}
} catch (err) {
logger.debug(
{ assignees: config.assignees, err },
'Failed to add assignees',
);
}
}
let reviewers = coerceArray(config.reviewers);
if (config.reviewersFromCodeOwners) {
reviewers = await addCodeOwners(config, reviewers, pr);
logger.debug(
`Reviewers from code owners: ${reviewers.map((reviewer) => `"${reviewer}"`).join(', ')}`,
);
}
if (
isArray(config.additionalReviewers) &&
config.additionalReviewers.length > 0
) {
logger.debug(
`Additional reviewers: ${config.additionalReviewers.map((reviewer) => `"${reviewer}"`).join(', ')}`,
);
reviewers = reviewers.concat(config.additionalReviewers);
}
if (reviewers.length > 0) {
try {
reviewers = await prepareParticipants(config, reviewers);
if (isNumber(config.reviewersSampleSize)) {
logger.debug(
`Sampling reviewersSampleSize=${config.reviewersSampleSize} reviewers`,
);
reviewers = sampleSize(reviewers, config.reviewersSampleSize);
}
if (reviewers.length > 0) {
if (GlobalConfig.get('dryRun')) {
logger.info(`DRY-RUN: Would add reviewers to PR #${pr.number}`);
} else {
await platform.addReviewers(pr.number, reviewers);
logger.debug({ reviewers }, 'Added reviewers');
}
}
} catch (err) {
logger.debug(
{ reviewers: config.reviewers, err },
'Failed to add reviewers',
);
}
}
}