diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 480b9d01db26750c8f327406a01a94ba89d8fc24..e9e23fa395aaaa154366e5646233f133397865ae 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -404,7 +404,7 @@ jobs: - name: Check coverage threshold run: | pnpm nyc check-coverage -t ./coverage/nyc \ - --branches 99.4 \ + --branches 99.57 \ --functions 100 \ --lines 100 \ --statements 100 diff --git a/lib/config/presets/index.ts b/lib/config/presets/index.ts index b1bf1f417162a26e08fd7a09f9a916a026804c47..ea8c6ba89ab739ee6f0f832223bba9a0cc17f63e 100644 --- a/lib/config/presets/index.ts +++ b/lib/config/presets/index.ts @@ -183,9 +183,9 @@ export function parsePreset(input: string): ParsedPreset { throw new Error(PRESET_INVALID); } ({ repo, presetPath, presetName, tag } = - nonScopedPresetWithSubdirRegex.exec(str)?.groups ?? {}); + nonScopedPresetWithSubdirRegex.exec(str)!.groups!); } else { - ({ repo, presetName, tag } = gitPresetRegex.exec(str)?.groups ?? {}); + ({ repo, presetName, tag } = gitPresetRegex.exec(str)!.groups!); if (presetSource === 'npm' && !repo.startsWith('renovate-config-')) { repo = `renovate-config-${repo}`; diff --git a/lib/logger/once.ts b/lib/logger/once.ts index 7bb3447b82ecbe797e84278f7220da5edb957b8e..4c7ea2fb25012d55cfa5fd23d80b825c2a55c45b 100644 --- a/lib/logger/once.ts +++ b/lib/logger/once.ts @@ -8,7 +8,7 @@ type OmitFn = (...args: any[]) => any; * * @example getCallSite() // => 'Object.<anonymous> (/path/to/file.js:10:15)' */ -function getCallSite(omitFn: OmitFn = getCallSite): string | null { +function getCallSite(omitFn: OmitFn): string | null { const stackTraceLimitOrig = Error.stackTraceLimit; const prepareStackTraceOrig = Error.prepareStackTrace; diff --git a/lib/modules/datasource/npm/get.ts b/lib/modules/datasource/npm/get.ts index 30f18299df45533880013fa522b86205e2d7df55..611ee6d491981365a4e54f3ffb11c6b299671fdd 100644 --- a/lib/modules/datasource/npm/get.ts +++ b/lib/modules/datasource/npm/get.ts @@ -105,7 +105,12 @@ export async function getDependency( .plus({ minutes: cacheMinutes }) .toISO()!; let cacheHardTtlMinutes = GlobalConfig.get('cacheHardTtlMinutes'); - if (!(is.number(cacheHardTtlMinutes) && cacheHardTtlMinutes > cacheMinutes)) { + if ( + !( + is.number(cacheHardTtlMinutes) && + /* istanbul ignore next: needs test */ cacheHardTtlMinutes > cacheMinutes + ) + ) { cacheHardTtlMinutes = cacheMinutes; } @@ -204,7 +209,9 @@ export async function getDependency( cacheNamespace, packageUrl, { ...dep, cacheData }, - etag ? cacheHardTtlMinutes : cacheMinutes + etag + ? /* istanbul ignore next: needs test */ cacheHardTtlMinutes + : cacheMinutes ); } else { dep.isPrivate = true; diff --git a/lib/modules/datasource/nuget/v3.ts b/lib/modules/datasource/nuget/v3.ts index d515d3c916e40dc95f64007278ea0fb3ec06a55a..b2b77cf7bdcf46aef60ccd30268daf12cd3273e8 100644 --- a/lib/modules/datasource/nuget/v3.ts +++ b/lib/modules/datasource/nuget/v3.ts @@ -63,7 +63,9 @@ export async function getResourceUrl( ({ type, version }) => type === resourceType && semver.valid(version) ) .sort((x, y) => - x.version && y.version ? semver.compare(x.version, y.version) : 0 + x.version && y.version + ? semver.compare(x.version, y.version) + : /* istanbul ignore next: hard to test */ 0 ); const { serviceId, version } = services.pop()!; diff --git a/lib/modules/manager/composer/artifacts.ts b/lib/modules/manager/composer/artifacts.ts index 74113bff12fc45150bd4c376a5950b18911569f0..56c1179b92c0d64d8f87d8a66d4939550e025312 100644 --- a/lib/modules/manager/composer/artifacts.ts +++ b/lib/modules/manager/composer/artifacts.ts @@ -24,6 +24,7 @@ import { getRepoStatus } from '../../../util/git'; import * as hostRules from '../../../util/host-rules'; import { regEx } from '../../../util/regex'; import { Json } from '../../../util/schema-utils'; +import { coerceString } from '../../../util/string'; import { GitTagsDatasource } from '../../datasource/git-tags'; import { PackagistDatasource } from '../../datasource/packagist'; import type { UpdateArtifact, UpdateArtifactsResult } from '../types'; @@ -71,7 +72,7 @@ function getAuthJson(): string | null { } if (gitlabHostRule?.token) { - const host = gitlabHostRule.resolvedHost ?? 'gitlab.com'; + const host = coerceString(gitlabHostRule.resolvedHost, 'gitlab.com'); authJson['gitlab-token'] = authJson['gitlab-token'] ?? {}; authJson['gitlab-token'][host] = gitlabHostRule.token; // https://getcomposer.org/doc/articles/authentication-for-private-packages.md#gitlab-token diff --git a/lib/modules/manager/composer/utils.ts b/lib/modules/manager/composer/utils.ts index 241bb8f757796498b15e28d5a79de2051e54d3a3..974ab2678252a7c3a4549ed557bcae5afe1c0ad1 100644 --- a/lib/modules/manager/composer/utils.ts +++ b/lib/modules/manager/composer/utils.ts @@ -4,6 +4,7 @@ import { GlobalConfig } from '../../../config/global'; import { logger } from '../../../logger'; import type { HostRuleSearchResult } from '../../../types'; import type { ToolConstraint } from '../../../util/exec/types'; +import { coerceNumber } from '../../../util/number'; import { api, id as composerVersioningId } from '../../versioning/composer'; import type { UpdateArtifactsConfig } from '../types'; import type { Lockfile, PackageFile } from './schema'; @@ -78,8 +79,8 @@ export function extractConstraints( const phpVersion = config?.platform.php; if (phpVersion) { const major = api.getMajor(phpVersion); - const minor = api.getMinor(phpVersion) ?? 0; - const patch = api.getPatch(phpVersion) ?? 0; + const minor = coerceNumber(api.getMinor(phpVersion)); + const patch = coerceNumber(api.getPatch(phpVersion)); res.php = `<=${major}.${minor}.${patch}`; } else if (require.php) { res.php = require.php; diff --git a/lib/modules/manager/gomod/artifacts.ts b/lib/modules/manager/gomod/artifacts.ts index 329eeb726c1c4bd291ba7aec579b8311fcc14bb6..df9c4bacb0d252bb5c1afea0cfd1fb6c0ebc4b22 100644 --- a/lib/modules/manager/gomod/artifacts.ts +++ b/lib/modules/manager/gomod/artifacts.ts @@ -5,6 +5,7 @@ import upath from 'upath'; import { GlobalConfig } from '../../../config/global'; import { TEMPORARY_ERROR } from '../../../constants/error-messages'; import { logger } from '../../../logger'; +import { coerceArray } from '../../../util/array'; import { exec } from '../../../util/exec'; import type { ExecOptions } from '../../../util/exec/types'; import { @@ -97,7 +98,9 @@ function useModcacherw(goVersion: string | undefined): boolean { return true; } - const [, majorPart, minorPart] = regEx(/(\d+)\.(\d+)/).exec(goVersion) ?? []; + const [, majorPart, minorPart] = coerceArray( + regEx(/(\d+)\.(\d+)/).exec(goVersion) + ); const [major, minor] = [majorPart, minorPart].map((x) => parseInt(x, 10)); return ( @@ -196,7 +199,9 @@ export async function updateArtifacts({ GONOSUMDB: process.env.GONOSUMDB, GOSUMDB: process.env.GOSUMDB, GOINSECURE: process.env.GOINSECURE, - GOFLAGS: useModcacherw(goConstraints) ? '-modcacherw' : null, + GOFLAGS: useModcacherw(goConstraints) + ? '-modcacherw' + : /* istanbul ignore next: hard to test */ null, CGO_ENABLED: GlobalConfig.get('binarySource') === 'docker' ? '0' : null, ...getGitEnvironmentVariables(['go']), }, @@ -342,7 +347,7 @@ export async function updateArtifacts({ }); } } - for (const f of status.deleted || []) { + for (const f of coerceArray(status.deleted)) { res.push({ file: { type: 'deletion', diff --git a/lib/modules/manager/leiningen/extract.ts b/lib/modules/manager/leiningen/extract.ts index f3eaab6e23d548b1babc45c24cf95867bdfff88e..7e936a9b52d9b771b41e776927e76db0fe2557a3 100644 --- a/lib/modules/manager/leiningen/extract.ts +++ b/lib/modules/manager/leiningen/extract.ts @@ -1,3 +1,4 @@ +import { coerceArray } from '../../../util/array'; import { newlineRegex, regEx } from '../../../util/regex'; import { ClojureDatasource } from '../../datasource/clojure'; import type { PackageDependency, PackageFileContent } from '../types'; @@ -139,8 +140,9 @@ function extractLeinRepos(content: string): string[] { } } const repoSectionContent = repoContent.slice(0, endIdx); - const matches = - repoSectionContent.match(regEx(/"https?:\/\/[^"]*"/g)) ?? []; + const matches = coerceArray( + repoSectionContent.match(regEx(/"https?:\/\/[^"]*"/g)) + ); const urls = matches.map((x) => x.replace(regEx(/^"/), '').replace(regEx(/"$/), '') ); diff --git a/lib/modules/manager/puppet/puppetfile-parser.ts b/lib/modules/manager/puppet/puppetfile-parser.ts index a039d4049a67ae896fbb62b68936cb074dd4b4b2..51fbdbe43c37f971d87e0d435747888a1b27fbda 100644 --- a/lib/modules/manager/puppet/puppetfile-parser.ts +++ b/lib/modules/manager/puppet/puppetfile-parser.ts @@ -1,3 +1,4 @@ +import { coerceArray } from '../../../util/array'; import { newlineRegex, regEx } from '../../../util/regex'; import type { PuppetfileModule } from './types'; @@ -34,7 +35,7 @@ export class Puppetfile { ): PuppetfileModule[] { const modules = this.forgeModules.get(forgeUrl ?? null); - return modules ?? []; + return coerceArray(modules); } } diff --git a/lib/modules/versioning/hermit/index.ts b/lib/modules/versioning/hermit/index.ts index d029b05daf74a194b9e25c1b7c99ed5288fb91a8..6679e1f859a896978e6da8ba81ec954f8f731d04 100644 --- a/lib/modules/versioning/hermit/index.ts +++ b/lib/modules/versioning/hermit/index.ts @@ -39,7 +39,7 @@ export class HermitVersioning extends RegExpVersioningApi { compatibility, } = groups; const release = [ - typeof major === 'undefined' ? 0 : Number.parseInt(major, 10), + Number.parseInt(major, 10), typeof minor === 'undefined' ? 0 : Number.parseInt(minor, 10), typeof patch === 'undefined' ? 0 : Number.parseInt(patch, 10), typeof supplement === 'undefined' ? 0 : Number.parseInt(supplement, 10), diff --git a/lib/workers/repository/config-migration/branch/rebase.ts b/lib/workers/repository/config-migration/branch/rebase.ts index a638401972ea06f563d672090b7ba3f8809a075d..eb082c893a6a4f9528c881650098d1251ed1b8e9 100644 --- a/lib/workers/repository/config-migration/branch/rebase.ts +++ b/lib/workers/repository/config-migration/branch/rebase.ts @@ -76,5 +76,8 @@ export function jsonStripWhitespaces(json: string | null): string | null { * * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#parameters */ - return quickStringify(JSON5.parse(json)) ?? null; + return ( + quickStringify(JSON5.parse(json)) ?? + /* istanbul ignore next: should never happen */ null + ); } diff --git a/lib/workers/repository/dependency-dashboard.ts b/lib/workers/repository/dependency-dashboard.ts index e8aed9e49e359ad2687586d64c967367c7304077..aac1ada612d0453a810729564360d436e3de173d 100644 --- a/lib/workers/repository/dependency-dashboard.ts +++ b/lib/workers/repository/dependency-dashboard.ts @@ -6,6 +6,7 @@ import type { PackageFile } from '../../modules/manager/types'; import { platform } from '../../modules/platform'; import { GitHubMaxPrBodyLen } from '../../modules/platform/github'; import { regEx } from '../../util/regex'; +import { coerceString } from '../../util/string'; import * as template from '../../util/template'; import type { BranchConfig, SelectAllConfig } from '../types'; import { extractRepoProblems } from './common'; @@ -76,8 +77,7 @@ function getAllSelectedBranches( function getCheckedBranches(issueBody: string): Record<string, string> { let dependencyDashboardChecks: Record<string, string> = {}; - for (const [, type, branchName] of issueBody?.matchAll(markedBranchesRe) ?? - []) { + for (const [, type, branchName] of issueBody.matchAll(markedBranchesRe)) { dependencyDashboardChecks[branchName] = type; } dependencyDashboardChecks = getAllSelectedBranches( @@ -427,7 +427,7 @@ export async function ensureDependencyDashboard( ); if (updatedIssue) { const { dependencyDashboardChecks } = parseDashboardIssue( - updatedIssue.body ?? '' + coerceString(updatedIssue.body) ); for (const branchName of Object.keys(config.dependencyDashboardChecks!)) { delete dependencyDashboardChecks[branchName]; diff --git a/lib/workers/repository/errors-warnings.spec.ts b/lib/workers/repository/errors-warnings.spec.ts index c935be6022bc3e84c6a43f7382039b5fb849fce0..f7f1b91c7ae4801c6a31703403c109dad4efaccc 100644 --- a/lib/workers/repository/errors-warnings.spec.ts +++ b/lib/workers/repository/errors-warnings.spec.ts @@ -331,5 +331,10 @@ describe('workers/repository/errors-warnings', () => { const res = getDepWarningsOnboardingPR(packageFiles, config); expect(res).toBe(''); }); + + it('handles undefined', () => { + const res = getDepWarningsOnboardingPR(undefined as never, {}); + expect(res).toBe(''); + }); }); }); diff --git a/lib/workers/repository/errors-warnings.ts b/lib/workers/repository/errors-warnings.ts index b60ebb687723cf33cb6cbde1309aeaa0dc6d9c1f..b4932e189009dbc8e558f2d8231e3719ff9c74a8 100644 --- a/lib/workers/repository/errors-warnings.ts +++ b/lib/workers/repository/errors-warnings.ts @@ -2,6 +2,7 @@ import type { RenovateConfig } from '../../config/types'; import { logger } from '../../logger'; import type { PackageFile } from '../../modules/manager/types'; +import { coerceArray } from '../../util/array'; import { emojify } from '../../util/emoji'; import { regEx } from '../../util/regex'; import type { DepWarnings } from '../types'; @@ -41,8 +42,8 @@ function getDepWarnings( for (const file of files ?? []) { // TODO: remove condition when type is fixed (#22198) if (file.packageFile) { - for (const dep of file.deps ?? []) { - for (const w of dep.warnings ?? []) { + for (const dep of coerceArray(file.deps)) { + for (const w of coerceArray(dep.warnings)) { const message = w.message; if (!warnings.includes(message)) { warnings.push(message);