diff --git a/lib/util/exec/buildpack.ts b/lib/util/exec/buildpack.ts index 14c9bec7f15acbc5d87ec4b567f290f666aa1f78..ba8c92c01cc9ee7ac9cc08b5952b77b5d9dd6f01 100644 --- a/lib/util/exec/buildpack.ts +++ b/lib/util/exec/buildpack.ts @@ -7,7 +7,7 @@ import { id as composerVersioningId } from '../../modules/versioning/composer'; import { id as npmVersioningId } from '../../modules/versioning/npm'; import { id as pep440VersioningId } from '../../modules/versioning/pep440'; import { id as semverVersioningId } from '../../modules/versioning/semver'; -import type { ToolConfig, ToolConstraint } from './types'; +import type { Opt, ToolConfig, ToolConstraint } from './types'; const allToolConfig: Record<string, ToolConfig> = { bundler: { @@ -61,7 +61,9 @@ export function isBuildpack(): boolean { return !!process.env.BUILDPACK; } -export function isDynamicInstall(toolConstraints?: ToolConstraint[]): boolean { +export function isDynamicInstall( + toolConstraints?: Opt<ToolConstraint[]> +): boolean { const { binarySource } = GlobalConfig.get(); if (binarySource !== 'install') { return false; @@ -125,9 +127,9 @@ export async function resolveConstraint( } export async function generateInstallCommands( - toolConstraints: ToolConstraint[] + toolConstraints: Opt<ToolConstraint[]> ): Promise<string[]> { - const installCommands = []; + const installCommands: string[] = []; if (toolConstraints?.length) { for (const toolConstraint of toolConstraints) { const toolVersion = await resolveConstraint(toolConstraint); diff --git a/lib/util/exec/index.ts b/lib/util/exec/index.ts index 85424870b29ff069e33375ece8d09f95a002cf86..0bbd94e620290df8b411e971343621fe334efa93 100644 --- a/lib/util/exec/index.ts +++ b/lib/util/exec/index.ts @@ -52,7 +52,7 @@ function dockerEnvVars(extraEnv: ExtraEnv, childEnv: ExtraEnv): string[] { return extraEnvKeys.filter((key) => is.nonEmptyString(childEnv[key])); } -function getCwd({ cwd, cwdFile }: ExecOptions): string { +function getCwd({ cwd, cwdFile }: ExecOptions): string | undefined { const defaultCwd = GlobalConfig.get('localDir'); const paramCwd = cwdFile ? upath.join(defaultCwd, upath.dirname(cwdFile)) @@ -139,7 +139,8 @@ export async function exec( opts: ExecOptions = {} ): Promise<ExecResult> { const { docker } = opts; - const dockerChildPrefix = GlobalConfig.get('dockerChildPrefix'); + const dockerChildPrefix = + GlobalConfig.get('dockerChildPrefix') ?? 'renovate_'; const { rawCommands, rawOptions } = await prepareRawExec(cmd, opts); const useDocker = isDocker(docker); diff --git a/lib/util/exec/types.ts b/lib/util/exec/types.ts index 1abfb3af20c039ea17c9d8334469f8e683efe0c9..b97279b2af8675e21c6f91ccf75b0d25cc180ebe 100644 --- a/lib/util/exec/types.ts +++ b/lib/util/exec/types.ts @@ -17,9 +17,6 @@ export type Opt<T> = T | null | undefined; export type VolumesPair = [string, string]; export type VolumeOption = Opt<string | VolumesPair>; -export type DockerExtraCommand = Opt<string>; -export type DockerExtraCommands = Opt<DockerExtraCommand[]>; - export interface DockerOptions { image: string; tag?: Opt<string>; @@ -48,7 +45,7 @@ export interface ExecOptions { extraEnv?: Opt<ExtraEnv>; docker?: Opt<DockerOptions>; toolConstraints?: Opt<ToolConstraint[]>; - preCommands?: DockerExtraCommands; + preCommands?: Opt<string[]>; // Following are pass-through to child process maxBuffer?: number | undefined; timeout?: number | undefined; diff --git a/lib/util/git/index.spec.ts b/lib/util/git/index.spec.ts index d22551eb39f4ada4fbc406a4ad6a041e2ca58e6d..4f0d99779b4801c1bdc16a50bbb0279c95d91ef8 100644 --- a/lib/util/git/index.spec.ts +++ b/lib/util/git/index.spec.ts @@ -293,7 +293,7 @@ describe('util/git/index', () => { }; await git.commitFiles({ branchName: 'renovate/branch_with_changes', - files: [file], + files: [file, { type: 'addition', path: 'dummy', contents: null }], message: 'Create something', }); const branchFiles = await git.getBranchFiles( diff --git a/lib/util/git/index.ts b/lib/util/git/index.ts index 32b53c13e05ac570c4bb49329776490e0f8c3949..014c0efb17b7127ba9b6ea04a241a19f059ef5a1 100644 --- a/lib/util/git/index.ts +++ b/lib/util/git/index.ts @@ -117,7 +117,7 @@ async function getDefaultBranch(git: SimpleGit): Promise<string> { res = (await git.raw(['remote', 'show', 'origin'])) .split('\n') .map((line) => line.trim()) - .find((line) => line.startsWith(headPrefix)) + .find((line) => line.startsWith(headPrefix))! .replace(headPrefix, ''); } return res.replace('origin/', '').trim(); @@ -144,7 +144,8 @@ async function getDefaultBranch(git: SimpleGit): Promise<string> { let config: LocalConfig = {} as any; -let git: SimpleGit | undefined; +// TODO: can be undefined +let git: SimpleGit; let gitInitialized: boolean; let privateKeySet = false; @@ -152,7 +153,7 @@ let privateKeySet = false; export const GIT_MINIMUM_VERSION = '2.33.0'; // git show-current export async function validateGitVersion(): Promise<boolean> { - let version: string; + let version: string | undefined; const globalGit = simpleGit(); try { const raw = await globalGit.raw(['--version']); @@ -248,7 +249,7 @@ async function cleanLocalBranches(): Promise<void> { } } -export function setGitAuthor(gitAuthor: string): void { +export function setGitAuthor(gitAuthor: string | undefined): void { const gitAuthorParsed = parseGitAuthor( gitAuthor || 'Renovate Bot <renovate@whitesourcesoftware.com>' ); @@ -325,8 +326,8 @@ export async function syncGit(): Promise<void> { return; } gitInitialized = true; - const { localDir } = GlobalConfig.get(); - logger.debug('Initializing git repository into ' + localDir); + const localDir = GlobalConfig.get('localDir')!; + logger.debug(`Initializing git repository into ${localDir}`); const gitHead = upath.join(localDir, '.git/HEAD'); let clone = true; @@ -355,7 +356,7 @@ export async function syncGit(): Promise<void> { if (clone) { const cloneStart = Date.now(); try { - const opts = []; + const opts: string[] = []; if (config.fullClone) { logger.debug('Performing full clone'); } else { @@ -506,10 +507,10 @@ export async function getFileList(): Promise<string[]> { } return files .split(newlineRegex) - .filter(Boolean) + .filter(is.string) .filter((line) => line.startsWith('100')) - .map((line) => line.split(regEx(/\t/)).pop()) - .filter((file: string) => + .map((line) => line.split(regEx(/\t/)).pop()!) + .filter((file) => submodules.every((submodule: string) => !file.startsWith(submodule)) ); } @@ -557,7 +558,7 @@ export async function isBranchModified(branchName: string): Promise<boolean> { return false; } // Retrieve the author of the most recent commit - let lastAuthor: string; + let lastAuthor: string | undefined; try { lastAuthor = ( await git.raw([ @@ -691,7 +692,7 @@ export async function deleteBranch(branchName: string): Promise<void> { } export async function mergeBranch(branchName: string): Promise<void> { - let status: StatusResult; + let status: StatusResult | undefined; try { await syncGit(); await git.reset(ResetMode.HARD); @@ -742,7 +743,9 @@ export async function getBranchLastCommitTime( } } -export async function getBranchFiles(branchName: string): Promise<string[]> { +export async function getBranchFiles( + branchName: string +): Promise<string[] | null> { await syncGit(); try { const diff = await gitRetry(() => @@ -815,7 +818,7 @@ export async function prepareCommit({ message, force = false, }: CommitFilesConfig): Promise<CommitResult | null> { - const { localDir } = GlobalConfig.get(); + const localDir = GlobalConfig.get('localDir')!; await syncGit(); logger.debug(`Preparing files for committing to branch ${branchName}`); await handleCommitAuth(localDir); @@ -848,7 +851,6 @@ export async function prepareCommit({ // This is usually a git submodule update logger.trace({ fileName }, 'Adding directory commit'); } else if (file.contents === null) { - // istanbul ignore next continue; } else { let contents: Buffer; @@ -1135,7 +1137,9 @@ const treeShaRegex = regEx(/tree\s+(?<treeSha>[0-9a-f]{40})\s*/); */ export async function listCommitTree(commitSha: string): Promise<TreeItem[]> { const commitOutput = await git.catFile(['-p', commitSha]); - const { treeSha } = treeShaRegex.exec(commitOutput)?.groups ?? {}; + const { treeSha } = + treeShaRegex.exec(commitOutput)?.groups ?? + /* istanbul ignore next: will never happen */ {}; const contents = await git.catFile(['-p', treeSha]); const lines = contents.split(newlineRegex); const result: TreeItem[] = []; diff --git a/lib/util/git/private-key.spec.ts b/lib/util/git/private-key.spec.ts index 21faa327a4460d09f78cb947f903521716c9bec3..d3921992b2df424c3edfd27bbd3852252e8e1321 100644 --- a/lib/util/git/private-key.spec.ts +++ b/lib/util/git/private-key.spec.ts @@ -1,10 +1,7 @@ import { mocked } from '../../../test/util'; import * as exec_ from '../exec'; -import { - configSigningKey, - setPrivateKey, - writePrivateKey, -} from './private-key'; +import { configSigningKey, writePrivateKey } from './private-key'; +import { setPrivateKey } from '.'; jest.mock('fs-extra'); jest.mock('../exec'); @@ -20,7 +17,7 @@ describe('util/git/private-key', () => { it('throws error if failing', async () => { setPrivateKey('some-key'); - exec.exec.mockResolvedValueOnce({ + exec.exec.mockRejectedValueOnce({ stderr: `something wrong`, stdout: '', }); diff --git a/lib/util/git/private-key.ts b/lib/util/git/private-key.ts index 834c0930a1c874f6e96520445246f27082e13016..254c280258a447c8b599a66ca9ff0fc0bf4786fd 100644 --- a/lib/util/git/private-key.ts +++ b/lib/util/git/private-key.ts @@ -6,8 +6,8 @@ import { logger } from '../../logger'; import { exec } from '../exec'; import { newlineRegex } from '../regex'; -let gitPrivateKey: string; -let keyId: string; +let gitPrivateKey: string | undefined; +let keyId: string | undefined; export function setPrivateKey(key: string): void { gitPrivateKey = key?.trim(); @@ -21,10 +21,10 @@ async function importKey(): Promise<void> { await fs.outputFile(keyFileName, gitPrivateKey); const { stdout, stderr } = await exec(`gpg --import ${keyFileName}`); logger.debug({ stdout, stderr }, 'Private key import result'); - keyId = (stdout + stderr) + keyId = `${stdout}${stderr}` .split(newlineRegex) .find((line) => line.includes('secret key imported')) - .replace('gpg: key ', '') + ?.replace('gpg: key ', '') .split(':') .shift(); await fs.remove(keyFileName); diff --git a/lib/util/git/types.ts b/lib/util/git/types.ts index 9879eee87a7c41ee4f99e4fe99e84da1eda0cebc..587cd5205d55bd81285b5285eb7d51963dd477c3 100644 --- a/lib/util/git/types.ts +++ b/lib/util/git/types.ts @@ -26,7 +26,7 @@ export interface LocalConfig extends StorageConfig { branchCommits: Record<string, CommitSha>; branchIsModified: Record<string, boolean>; ignoredAuthors: string[]; - gitAuthorName?: string; + gitAuthorName?: string | null; gitAuthorEmail?: string; writeGitDone?: boolean; diff --git a/lib/util/package-rules.spec.ts b/lib/util/package-rules.spec.ts index 427c9754c0125bb34d9ef1d285da3770916a987f..98c018f383c0c8ab9cc76b0203d1f0580f5fdff3 100644 --- a/lib/util/package-rules.spec.ts +++ b/lib/util/package-rules.spec.ts @@ -52,7 +52,6 @@ describe('util/package-rules', () => { }, { excludePackagePatterns: ['*'], - matchPackageNames: ['b'], }, { matchUpdateTypes: ['bump'], @@ -340,6 +339,10 @@ describe('util/package-rules', () => { matchDatasources: [OrbDatasource.id, DockerDatasource.id], x: 1, }, + { + matchDatasources: [DockerDatasource.id], + y: 1, + }, ], }; const dep = { @@ -349,6 +352,7 @@ describe('util/package-rules', () => { }; const res = applyPackageRules({ ...config, ...dep }); expect(res.x).toBe(1); + expect(res.y).toBeUndefined(); }); it('filters branches with matching branch', () => { @@ -446,6 +450,10 @@ describe('util/package-rules', () => { matchUpdateTypes: ['minor', 'patch'], x: 1, }, + { + matchUpdateTypes: ['minor'], + y: 1, + }, ], }; const dep = { @@ -455,6 +463,7 @@ describe('util/package-rules', () => { }; const res = applyPackageRules({ ...config, ...dep }); expect(res.x).toBe(1); + expect(res.y).toBeUndefined(); }); it('matches matchSourceUrlPrefixes', () => { @@ -649,6 +658,14 @@ describe('util/package-rules', () => { }, }); expect(res2.x).toBeUndefined(); + const res3 = applyPackageRules({ + ...config, + ...{ + depName: 'test', + lockedVersion: '^1.0.0', + }, + }); + expect(res3.x).toBe(1); }); it('checks if matchCurrentVersion selector is valid and satisfies the condition on pinned to range overlap', () => { diff --git a/lib/util/package-rules.ts b/lib/util/package-rules.ts index ec18e0f909ddcd078f670097f42470d1e48a6a1d..abe8428496a9ae8fbf0001d61f892122779efb03 100644 --- a/lib/util/package-rules.ts +++ b/lib/util/package-rules.ts @@ -73,7 +73,7 @@ function matchesRule( } positiveMatch = true; } - if (matchPaths.length) { + if (matchPaths.length && packageFile) { const isMatch = matchPaths.some( (rulePath) => packageFile.includes(rulePath) || @@ -86,21 +86,21 @@ function matchesRule( } if (matchDepTypes.length) { const isMatch = - matchDepTypes.includes(depType) || + (depType && matchDepTypes.includes(depType)) || depTypes?.some((dt) => matchDepTypes.includes(dt)); if (!isMatch) { return false; } positiveMatch = true; } - if (matchLanguages.length) { + if (matchLanguages.length && language) { const isMatch = matchLanguages.includes(language); if (!isMatch) { return false; } positiveMatch = true; } - if (matchBaseBranches.length) { + if (matchBaseBranches.length && baseBranch) { const isMatch = matchBaseBranches.some((matchBaseBranch): boolean => { const isAllowedPred = configRegexPredicate(matchBaseBranch); if (isAllowedPred) { @@ -114,14 +114,14 @@ function matchesRule( } positiveMatch = true; } - if (matchManagers.length) { + if (matchManagers.length && manager) { const isMatch = matchManagers.includes(manager); if (!isMatch) { return false; } positiveMatch = true; } - if (matchDatasources.length) { + if (matchDatasources.length && datasource) { const isMatch = matchDatasources.includes(datasource); if (!isMatch) { return false; @@ -130,7 +130,7 @@ function matchesRule( } if (matchUpdateTypes.length) { const isMatch = - matchUpdateTypes.includes(updateType) || + (updateType && matchUpdateTypes.includes(updateType)) || (isBump && matchUpdateTypes.includes('bump')); if (!isMatch) { return false; @@ -169,7 +169,7 @@ function matchesRule( } positiveMatch = true; } - if (excludePackageNames.length) { + if (excludePackageNames.length && depName) { const isMatch = excludePackageNames.includes(depName); if (isMatch) { return false; @@ -221,7 +221,7 @@ function matchesRule( } positiveMatch = true; } - if (matchCurrentVersion) { + if (matchCurrentVersion && currentValue) { const version = allVersioning.get(versioning); const matchCurrentVersionStr = matchCurrentVersion.toString(); const matchCurrentVersionPred = configRegexPredicate( diff --git a/tsconfig.strict.json b/tsconfig.strict.json index 3ae8abea46c1fea93fb7a19c89828386d4833de0..b21b703173a3d42dab11ff82cdd5bd31bcc66f7d 100644 --- a/tsconfig.strict.json +++ b/tsconfig.strict.json @@ -266,13 +266,7 @@ "lib/modules/platform/gitlab/index.ts", "lib/modules/platform/index.ts", "lib/renovate.ts", - "lib/util/exec/buildpack.ts", - "lib/util/exec/docker/index.ts", - "lib/util/exec/index.ts", - "lib/util/git/index.ts", - "lib/util/git/private-key.ts", - "lib/util/git/url.ts", - "lib/util/package-rules.ts", + "lib/util/package-rules.ts", // depends on config -> manager "lib/workers/repository/update/branch/artifacts.ts", "lib/workers/repository/update/branch/auto-replace.ts", "lib/workers/repository/update/branch/automerge.ts", @@ -359,14 +353,11 @@ "lib/workers/repository/updates/generate.ts", "test/util.ts", "tools/docs/config.ts", - "tools/docs/datasources.ts", "tools/docs/manager.ts", "tools/docs/modules.ts", "tools/docs/platforms.ts", "tools/docs/presets.ts", "tools/docs/schema.ts", - "tools/docs/templates.ts", - "tools/docs/utils.ts", "tools/docs/versioning.ts", "tools/generate-docs.ts", "tools/generate-schema.ts"