From f5f06c73be8c5b29f3458c40bc0d18259685296e Mon Sep 17 00:00:00 2001 From: Michael Kriese <michael.kriese@visualon.de> Date: Wed, 20 Apr 2022 06:19:59 +0200 Subject: [PATCH] refactor(manager): more strict null checks (#15168) --- lib/modules/manager/composer/artifacts.ts | 7 ++- lib/modules/manager/composer/extract.ts | 14 ++--- lib/modules/manager/composer/range.ts | 5 +- lib/modules/manager/composer/types.ts | 4 +- lib/modules/manager/composer/update-locked.ts | 6 ++- lib/modules/manager/composer/utils.ts | 11 ++-- .../manager/git-submodules/artifacts.ts | 3 +- lib/modules/manager/git-submodules/update.ts | 6 ++- lib/modules/manager/gomod/artifacts.ts | 20 ++++--- lib/modules/manager/gomod/extract.ts | 3 +- lib/modules/manager/gomod/update.ts | 29 ++++++++--- .../manager/gradle-wrapper/artifacts.ts | 16 +++--- lib/modules/manager/gradle-wrapper/utils.ts | 8 +-- .../manager/gradle/__testutil__/gradle.ts | 28 ++++++---- lib/modules/manager/gradle/extract.ts | 2 +- lib/modules/manager/gradle/extract/catalog.ts | 10 ++-- lib/modules/manager/gradle/parser.ts | 40 ++++++++------ lib/modules/manager/gradle/types.ts | 4 +- lib/modules/manager/gradle/update.ts | 3 +- lib/modules/manager/gradle/utils.ts | 2 +- lib/modules/manager/nuget/artifacts.ts | 4 +- lib/modules/manager/nuget/extract.ts | 5 +- lib/modules/manager/terraform/extract.ts | 11 ++-- .../manager/terraform/lockfile/hash.ts | 2 +- .../manager/terraform/lockfile/index.ts | 52 +++++++++++++------ .../manager/terraform/lockfile/util.ts | 44 ++++++++++------ lib/modules/manager/terraform/modules.ts | 25 +++++---- lib/modules/manager/terraform/providers.ts | 25 +++++---- .../manager/terraform/required-providers.ts | 19 ++++--- .../manager/terraform/required-version.ts | 10 ++-- lib/modules/manager/terraform/resources.ts | 24 +++++---- lib/modules/manager/terraform/types.ts | 5 +- lib/modules/manager/terraform/util.ts | 8 +-- lib/modules/manager/terragrunt/extract.ts | 9 ++-- lib/modules/manager/terragrunt/modules.ts | 27 ++++++---- lib/modules/manager/terragrunt/providers.ts | 10 ++-- lib/modules/manager/terragrunt/types.ts | 5 +- lib/modules/versioning/index.ts | 2 +- tsconfig.strict.json | 49 ----------------- 39 files changed, 314 insertions(+), 243 deletions(-) diff --git a/lib/modules/manager/composer/artifacts.ts b/lib/modules/manager/composer/artifacts.ts index 2d35c4008a..0ac7c6ef0a 100644 --- a/lib/modules/manager/composer/artifacts.ts +++ b/lib/modules/manager/composer/artifacts.ts @@ -138,7 +138,12 @@ export async function updateArtifacts({ } else { args = ( - 'update ' + updatedDeps.map((dep) => quote(dep.depName)).join(' ') + 'update ' + + updatedDeps + .map((dep) => dep.depName) + .filter(is.string) + .map((dep) => quote(dep)) + .join(' ') ).trim() + ' --with-dependencies'; } args += getComposerArguments(config, composerToolConstraint); diff --git a/lib/modules/manager/composer/extract.ts b/lib/modules/manager/composer/extract.ts index e39a83b169..021c89fa51 100644 --- a/lib/modules/manager/composer/extract.ts +++ b/lib/modules/manager/composer/extract.ts @@ -10,6 +10,7 @@ import type { ComposerConfig, ComposerLock, ComposerManagerData, + ComposerRepositories, Repo, } from './types'; @@ -31,7 +32,7 @@ function transformRegUrl(url: string): string { * other entries will be added to registryUrls */ function parseRepositories( - repoJson: ComposerConfig['repositories'], + repoJson: ComposerRepositories, repositories: Record<string, Repo>, registryUrls: string[] ): void { @@ -44,7 +45,8 @@ function parseRepositories( switch (repo.type) { case 'vcs': case 'git': - repositories[name] = repo; + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + repositories[name!] = repo; break; case 'composer': registryUrls.push(transformRegUrl(repo.url)); @@ -95,7 +97,7 @@ export async function extractPackageFile( // handle lockfile const lockfilePath = fileName.replace(regEx(/\.json$/), '.lock'); const lockContents = await readLocalFile(lockfilePath, 'utf8'); - let lockParsed: ComposerLock; + let lockParsed: ComposerLock | undefined; if (lockContents) { logger.debug({ packageFile: fileName }, 'Found composer lock file'); res.lockFiles = [lockfilePath]; @@ -114,13 +116,13 @@ export async function extractPackageFile( res.registryUrls = registryUrls; } - const deps = []; - const depTypes = ['require', 'require-dev']; + const deps: PackageDependency[] = []; + const depTypes: ('require' | 'require-dev')[] = ['require', 'require-dev']; for (const depType of depTypes) { if (composerJson[depType]) { try { for (const [depName, version] of Object.entries( - composerJson[depType] as Record<string, string> + composerJson[depType]! )) { const currentValue = version.trim(); // Default datasource and packageName diff --git a/lib/modules/manager/composer/range.ts b/lib/modules/manager/composer/range.ts index ab6fe7044d..02b7daff82 100644 --- a/lib/modules/manager/composer/range.ts +++ b/lib/modules/manager/composer/range.ts @@ -42,7 +42,10 @@ export function getRangeStrategy(config: RangeConfig): RangeStrategy { logger.trace({ dependency: depName }, 'Pinning app require'); return 'pin'; } - if (isComplexRange || ['typo3-cms-extension'].includes(composerJsonType)) { + if ( + isComplexRange || + (composerJsonType && ['typo3-cms-extension'].includes(composerJsonType)) + ) { return 'widen'; } return 'replace'; diff --git a/lib/modules/manager/composer/types.ts b/lib/modules/manager/composer/types.ts index 65e9c3fe7a..896ff7bd8b 100644 --- a/lib/modules/manager/composer/types.ts +++ b/lib/modules/manager/composer/types.ts @@ -6,6 +6,8 @@ export interface Repo { 'packagist.org'?: boolean; url: string; } +export type ComposerRepositories = Record<string, Repo | boolean> | Repo[]; + export interface ComposerConfig { type?: string; /** @@ -25,7 +27,7 @@ export interface ComposerConfig { * (Yes this can be confusing, as it is also not properly documented in the composer docs) * See https://getcomposer.org/doc/05-repositories.md#disabling-packagist-org */ - repositories?: Record<string, Repo | boolean> | Repo[]; + repositories?: ComposerRepositories; require?: Record<string, string>; 'require-dev'?: Record<string, string>; diff --git a/lib/modules/manager/composer/update-locked.ts b/lib/modules/manager/composer/update-locked.ts index dddd358e85..186f54d80f 100644 --- a/lib/modules/manager/composer/update-locked.ts +++ b/lib/modules/manager/composer/update-locked.ts @@ -12,12 +12,14 @@ export function updateLockedDependency( `composer.updateLockedDependency: ${depName}@${currentVersion} -> ${newVersion} [${lockFile}]` ); try { - const locked = JSON.parse(lockFileContent) as ComposerLock; + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + const locked = JSON.parse(lockFileContent!) as ComposerLock; if ( locked.packages?.find( (entry) => entry.name === depName && - composer.equals(entry.version || '', newVersion) + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + composer.equals(entry.version || '', newVersion!) ) ) { return { status: 'already-updated' }; diff --git a/lib/modules/manager/composer/utils.ts b/lib/modules/manager/composer/utils.ts index 885e3743a4..6787845ebf 100644 --- a/lib/modules/manager/composer/utils.ts +++ b/lib/modules/manager/composer/utils.ts @@ -18,8 +18,11 @@ export function getComposerArguments( if (config.composerIgnorePlatformReqs) { if (config.composerIgnorePlatformReqs.length === 0) { - const major = api.getMajor(toolConstraint.constraint); - const minor = api.getMinor(toolConstraint.constraint); + // TODO: toolConstraint.constraint can be null or undefined? + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + const major = api.getMajor(toolConstraint.constraint!); + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + const minor = api.getMinor(toolConstraint.constraint!); args += api.matches(`${major}.${minor}`, '^2.2') ? " --ignore-platform-req='ext-*' --ignore-platform-req='lib-*'" : ' --ignore-platform-reqs'; @@ -42,7 +45,9 @@ export function getComposerArguments( return args; } -export function getPhpConstraint(constraints: Record<string, string>): string { +export function getPhpConstraint( + constraints: Record<string, string> +): string | null { const { php } = constraints; if (php) { diff --git a/lib/modules/manager/git-submodules/artifacts.ts b/lib/modules/manager/git-submodules/artifacts.ts index 0351f203d0..1a85a0b97e 100644 --- a/lib/modules/manager/git-submodules/artifacts.ts +++ b/lib/modules/manager/git-submodules/artifacts.ts @@ -8,7 +8,8 @@ export default function updateArtifacts({ updatedDeps.forEach((dep) => { logger.info('Updating submodule ' + dep.depName); res.push({ - file: { type: 'addition', path: dep.depName, contents: '' }, + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + file: { type: 'addition', path: dep.depName!, contents: '' }, }); }); return res; diff --git a/lib/modules/manager/git-submodules/update.ts b/lib/modules/manager/git-submodules/update.ts index 72c1da2cd5..6639a01f7a 100644 --- a/lib/modules/manager/git-submodules/update.ts +++ b/lib/modules/manager/git-submodules/update.ts @@ -13,8 +13,10 @@ export default async function updateDependency({ const submoduleGit = Git(upath.join(localDir, upgrade.depName)); try { - await git.submoduleUpdate(['--init', upgrade.depName]); - await submoduleGit.checkout([upgrade.newDigest]); + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + await git.submoduleUpdate(['--init', upgrade.depName!]); + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + await submoduleGit.checkout([upgrade.newDigest!]); return fileContent; } catch (err) { logger.debug({ err }, 'submodule checkout error'); diff --git a/lib/modules/manager/gomod/artifacts.ts b/lib/modules/manager/gomod/artifacts.ts index 715679ade4..0063080871 100644 --- a/lib/modules/manager/gomod/artifacts.ts +++ b/lib/modules/manager/gomod/artifacts.ts @@ -43,7 +43,7 @@ function getGitEnvironmentVariables(): NodeJS.ProcessEnv { // get extra host rules for other git-based Go Module hosts const hostRules = getAll() || []; - const goGitAllowedHostType: string[] = [ + const goGitAllowedHostType: (string | undefined)[] = [ // All known git platforms PlatformId.Azure, PlatformId.Bitbucket, @@ -62,13 +62,15 @@ function getGitEnvironmentVariables(): NodeJS.ProcessEnv { hostRule.matchHost && goGitAllowedHostType.includes(hostRule.hostType) ) { - const httpUrl = createURLFromHostOrURL(hostRule.matchHost).toString(); + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + const httpUrl = createURLFromHostOrURL(hostRule.matchHost!)?.toString(); if (validateUrl(httpUrl)) { logger.debug( `Adding Git authentication for Go Module retrieval for ${httpUrl} using token auth.` ); environmentVariables = getGitAuthenticatedEnvironmentVariables( - httpUrl, + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + httpUrl!, hostRule, environmentVariables ); @@ -87,7 +89,8 @@ function getUpdateImportPathCmds( { constraints, newMajor }: UpdateArtifactsConfig ): string[] { const updateImportCommands = updatedDeps - .map((dep) => dep.depName) + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + .map((dep) => dep.depName!) .filter((x) => !x.startsWith('gopkg.in')) .map((depName) => `mod upgrade --mod-name=${depName} -t=${newMajor}`); @@ -121,7 +124,7 @@ function getUpdateImportPathCmds( return updateImportCommands; } -function useModcacherw(goVersion: string): boolean { +function useModcacherw(goVersion: string | undefined): boolean { if (!is.string(goVersion)) { return true; } @@ -179,7 +182,7 @@ export async function updateArtifacts({ * @param match A string representing a golang replace directive block * @returns A commented out block with // renovate-replace */ - const blockCommentOut = (match): string => + const blockCommentOut = (match: string): string => match.replace(/(\r?\n)/g, '$1// renovate-replace '); // Comment out golang replace directives @@ -213,7 +216,7 @@ export async function updateArtifacts({ }, }; - const execCommands = []; + const execCommands: string[] = []; let args = 'get -d -t ./...'; logger.debug({ cmd, args }, 'go get command included'); @@ -223,7 +226,8 @@ export async function updateArtifacts({ const isImportPathUpdateRequired = config.postUpdateOptions?.includes('gomodUpdateImportPaths') && config.updateType === 'major' && - config.newMajor > 1; + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + config.newMajor! > 1; if (isImportPathUpdateRequired) { const updateImportCmds = getUpdateImportPathCmds(updatedDeps, config); if (updateImportCmds.length > 0) { diff --git a/lib/modules/manager/gomod/extract.ts b/lib/modules/manager/gomod/extract.ts index fc03775b33..97f78f62c4 100644 --- a/lib/modules/manager/gomod/extract.ts +++ b/lib/modules/manager/gomod/extract.ts @@ -71,7 +71,8 @@ export function extractPackageFile(content: string): PackageFile | null { if (multiMatch && !line.endsWith('// indirect')) { logger.trace({ lineNumber }, `require line: "${line}"`); const dep = getDep(lineNumber, multiMatch, 'require'); - dep.managerData.multiLine = true; + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + dep.managerData!.multiLine = true; deps.push(dep); } else if (line.trim() !== ')') { logger.debug(`No multi-line match: ${line}`); diff --git a/lib/modules/manager/gomod/update.ts b/lib/modules/manager/gomod/update.ts index 505e8ad331..e6eb87ed57 100644 --- a/lib/modules/manager/gomod/update.ts +++ b/lib/modules/manager/gomod/update.ts @@ -21,6 +21,10 @@ export function updateDependency({ logger.warn('gomod manager does not support replacement updates yet'); return null; } + // istanbul ignore if: should never happen + if (!depName || !upgrade.managerData) { + return null; + } const depNameNoVersion = getDepNameWithNoVersion(depName); const lines = fileContent.split(newlineRegex); const lineToChange = lines[upgrade.managerData.lineNumber]; @@ -34,7 +38,7 @@ export function updateDependency({ ); return null; } - let updateLineExp: RegExp; + let updateLineExp: RegExp | undefined; if (depType === 'replace') { updateLineExp = regEx( /^(?<depPart>replace\s+[^\s]+[\s]+[=][>]+\s+)(?<divider>[^\s]+\s+)[^\s]+/ @@ -54,9 +58,11 @@ export function updateDependency({ } let newLine: string; if (upgrade.updateType === 'digest') { - const newDigestRightSized = upgrade.newDigest.substring( + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + const newDigestRightSized = upgrade.newDigest!.substring( 0, - upgrade.currentDigest.length + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + upgrade.currentDigest!.length ); if (lineToChange.includes(newDigestRightSized)) { return fileContent; @@ -66,12 +72,16 @@ export function updateDependency({ 'gomod: need to update digest' ); newLine = lineToChange.replace( - updateLineExp, + // TODO: can be undefined? + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + updateLineExp!, `$<depPart>$<divider>${newDigestRightSized}` ); } else { newLine = lineToChange.replace( - updateLineExp, + // TODO: can be undefined? + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + updateLineExp!, `$<depPart>$<divider>${upgrade.newValue}` ); } @@ -86,7 +96,8 @@ export function updateDependency({ 'rethinkdb/rethinkdb-go.v5' ); } else if ( - upgrade.newMajor > 1 && + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + upgrade.newMajor! > 1 && !newLine.includes(`/v${upgrade.newMajor}`) ) { if (depName === depNameNoVersion) { @@ -94,7 +105,8 @@ export function updateDependency({ newLine = newLine.replace(depName, `${depName}/v${upgrade.newMajor}`); } else { // Replace version - const [oldV] = upgrade.currentValue.split('.'); + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + const [oldV] = upgrade.currentValue!.split('.'); newLine = newLine.replace( regEx(`/${oldV}(\\s+)`, undefined, false), `/v${upgrade.newMajor}$1` @@ -105,7 +117,8 @@ export function updateDependency({ if (lineToChange.endsWith('+incompatible')) { let toAdd = '+incompatible'; - if (upgrade.updateType === 'major' && upgrade.newMajor >= 2) { + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + if (upgrade.updateType === 'major' && upgrade.newMajor! >= 2) { toAdd = ''; } newLine += toAdd; diff --git a/lib/modules/manager/gradle-wrapper/artifacts.ts b/lib/modules/manager/gradle-wrapper/artifacts.ts index e6dc86f725..3fba527ee3 100644 --- a/lib/modules/manager/gradle-wrapper/artifacts.ts +++ b/lib/modules/manager/gradle-wrapper/artifacts.ts @@ -1,3 +1,4 @@ +import is from '@sindresorhus/is'; import { quote } from 'shlex'; import upath from 'upath'; import { GlobalConfig } from '../../../config/global'; @@ -37,7 +38,7 @@ async function addIfUpdated( return null; } -function getDistributionUrl(newPackageFileContent: string): string { +function getDistributionUrl(newPackageFileContent: string): string | null { const distributionUrlLine = newPackageFileContent .split(newlineRegex) .find((line) => line.startsWith('distributionUrl=')); @@ -67,7 +68,8 @@ export async function updateArtifacts({ const gradlewPath = upath.resolve(projectDir, `./${gradlew}`); let cmd = await prepareGradleCommand( gradlew, - projectDir, + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + projectDir!, await stat(gradlewPath).catch(() => null), `wrapper` ); @@ -91,14 +93,16 @@ export async function updateArtifacts({ cmd += ` --gradle-distribution-sha256-sum ${quote(checksum)}`; } } else { - cmd += ` --gradle-version ${quote(config.newValue)}`; + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + cmd += ` --gradle-version ${quote(config.newValue!)}`; } logger.debug(`Updating gradle wrapper: "${cmd}"`); const execOptions: ExecOptions = { docker: { image: 'java', tagConstraint: - config.constraints?.java ?? getJavaContraint(config.currentValue), + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + config.constraints?.java ?? getJavaContraint(config.currentValue!), tagScheme: getJavaVersioning(), }, extraEnv, @@ -133,9 +137,9 @@ export async function updateArtifacts({ addIfUpdated(status, fileProjectPath) ) ) - ).filter(Boolean); + ).filter(is.truthy); logger.debug( - { files: updateArtifactsResult.map((r) => r.file.path) }, + { files: updateArtifactsResult.map((r) => r.file?.path) }, `Returning updated gradle-wrapper files` ); return updateArtifactsResult; diff --git a/lib/modules/manager/gradle-wrapper/utils.ts b/lib/modules/manager/gradle-wrapper/utils.ts index 3c8e42ae97..c990f20819 100644 --- a/lib/modules/manager/gradle-wrapper/utils.ts +++ b/lib/modules/manager/gradle-wrapper/utils.ts @@ -30,7 +30,7 @@ export async function prepareGradleCommand( cwd: string, gradlew: Stats | null, args: string | null -): Promise<string> { +): Promise<string | null> { // istanbul ignore if if (gradlew?.isFile() === true) { // if the file is not executable by others @@ -60,11 +60,11 @@ export function getJavaContraint(gradleVersion: string): string | null { } const major = gradleVersioning.getMajor(gradleVersion); - if (major >= 7) { + if (major && major >= 7) { return '^16.0.0'; } // first public gradle version was 2.0 - if (major > 0 && major < 5) { + if (major && major > 0 && major < 5) { return '^8.0.0'; } return '^11.0.0'; @@ -87,7 +87,7 @@ export function extractGradleVersion( for (const line of lines) { const distributionUrlMatch = DISTRIBUTION_URL_REGEX.exec(line); - if (distributionUrlMatch) { + if (distributionUrlMatch?.groups) { return { url: distributionUrlMatch.groups.url, version: distributionUrlMatch.groups.version, diff --git a/lib/modules/manager/gradle/__testutil__/gradle.ts b/lib/modules/manager/gradle/__testutil__/gradle.ts index 66b9b3e175..ff5fb9c2a0 100644 --- a/lib/modules/manager/gradle/__testutil__/gradle.ts +++ b/lib/modules/manager/gradle/__testutil__/gradle.ts @@ -10,7 +10,12 @@ const gradleJavaVersionSupport = { const skipJava = process.env.SKIP_JAVA_TESTS === 'true'; const enforceJava = process.env[failIfNoJavaEnv] === 'true' && !skipJava; -function parseJavaVersion(javaVersionOutput: string): number { +function parseJavaVersion( + javaVersionOutput: string | undefined +): number | null { + if (!javaVersionOutput) { + return null; + } const versionMatch = /version "(?:1\.)?(\d+)[\d._-]*"/.exec( javaVersionOutput ); @@ -25,12 +30,12 @@ ${javaVersionOutput}`); return 0; } -let cachedJavaVersion: number | null = null; +let cachedJavaVersion: number | null | undefined = undefined; -function determineJavaVersion(): number { - if (!cachedJavaVersion) { - let javaVersionCommand: SpawnSyncReturns<string>; - let error: Error; +function determineJavaVersion(): number | null { + if (cachedJavaVersion === undefined) { + let javaVersionCommand: SpawnSyncReturns<string> | undefined; + let error: Error | undefined; try { javaVersionCommand = spawnSync('java', ['-version'], { encoding: 'utf8', @@ -52,7 +57,7 @@ Result of java -version: ${error.toString()}` ); } - cachedJavaVersion = parseJavaVersion(javaVersionCommand.stderr); + cachedJavaVersion = parseJavaVersion(javaVersionCommand?.stderr); } return cachedJavaVersion; } @@ -60,8 +65,11 @@ ${error.toString()}` class WithGradle { private gradleSupportsThisJavaVersion: boolean; - constructor(gradleVersion: number) { + constructor(gradleVersion: keyof typeof gradleJavaVersionSupport) { const javaVersion = determineJavaVersion(); + if (!javaVersion) { + throw Error(`Unknown java version!`); + } if (gradleJavaVersionSupport[gradleVersion] === undefined) { throw Error(`Unknown gradle version '${gradleVersion}'!`); } @@ -91,6 +99,8 @@ class WithGradle { } } -export function ifSystemSupportsGradle(gradleVersion: number): WithGradle { +export function ifSystemSupportsGradle( + gradleVersion: keyof typeof gradleJavaVersionSupport +): WithGradle { return new WithGradle(gradleVersion); } diff --git a/lib/modules/manager/gradle/extract.ts b/lib/modules/manager/gradle/extract.ts index d7587357fb..68822666dc 100644 --- a/lib/modules/manager/gradle/extract.ts +++ b/lib/modules/manager/gradle/extract.ts @@ -42,7 +42,7 @@ export async function extractAllPackageFiles( const extractedDeps: PackageDependency<GradleManagerData>[] = []; const registry: VariableRegistry = {}; const packageFilesByName: Record<string, PackageFile> = {}; - const registryUrls = []; + const registryUrls: string[] = []; const reorderedFiles = reorderFiles(packageFiles); for (const packageFile of reorderedFiles) { packageFilesByName[packageFile] = { diff --git a/lib/modules/manager/gradle/extract/catalog.ts b/lib/modules/manager/gradle/extract/catalog.ts index 2179fd1327..37db667140 100644 --- a/lib/modules/manager/gradle/extract/catalog.ts +++ b/lib/modules/manager/gradle/extract/catalog.ts @@ -30,7 +30,7 @@ function isArtifactDescriptor( } function isVersionPointer( - obj: GradleVersionCatalogVersion + obj: GradleVersionCatalogVersion | undefined ): obj is VersionPointer { return hasKey('ref', obj); } @@ -50,7 +50,7 @@ function extractVersion({ versionStartIndex, versionSubContent, }: { - version: GradleVersionCatalogVersion; + version: GradleVersionCatalogVersion | undefined; versions: Record<string, GradleVersionPointerTarget>; depStartIndex: number; depSubContent: string; @@ -82,7 +82,7 @@ function extractLiteralVersion({ depSubContent, sectionKey, }: { - version: GradleVersionPointerTarget; + version: GradleVersionPointerTarget | undefined; depStartIndex: number; depSubContent: string; sectionKey: string; @@ -99,8 +99,8 @@ function extractLiteralVersion({ // https://docs.gradle.org/current/userguide/platforms.html#sub::toml-dependencies-format const versionKeys = ['require', 'prefer', 'strictly']; let found = false; - let currentValue: string; - let fileReplacePosition: number; + let currentValue: string | undefined; + let fileReplacePosition: number | undefined; if (version.reject || version.rejectAll) { return { skipReason: 'unsupported-version' }; diff --git a/lib/modules/manager/gradle/parser.ts b/lib/modules/manager/gradle/parser.ts index 7f1cbc78b6..51f81e4581 100644 --- a/lib/modules/manager/gradle/parser.ts +++ b/lib/modules/manager/gradle/parser.ts @@ -120,7 +120,8 @@ function handleAssignment({ if (dep) { dep.groupName = key; dep.managerData = { - fileReplacePosition: valToken.offset + dep.depName.length + 1, + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + fileReplacePosition: valToken.offset + dep.depName!.length + 1, packageFile, }; } @@ -148,7 +149,8 @@ function processDepString({ const dep = parseDependencyString(token.value); if (dep) { dep.managerData = { - fileReplacePosition: token.offset + dep.depName.length + 1, + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + fileReplacePosition: token.offset + dep.depName!.length + 1, packageFile, }; return { deps: [dep] }; @@ -166,8 +168,8 @@ function processDepInterpolation({ if (interpolationResult && isDependencyString(interpolationResult)) { const dep = parseDependencyString(interpolationResult); if (dep) { - let packageFile: string; - let fileReplacePosition: number; + let packageFile: string | undefined; + let fileReplacePosition: number | undefined; token.children.forEach((child) => { const variable = variables[child.value]; if (child?.type === TokenType.Variable && variable) { @@ -298,7 +300,8 @@ function processPredefinedRegistryUrl({ google: GOOGLE_REPO, gradlePluginPortal: GRADLE_PLUGIN_PORTAL_REPO, }[registryName]; - return { urls: [registryUrl] }; + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + return { urls: [registryUrl!] }; } const annoyingMethods = new Set([ @@ -696,7 +699,7 @@ export function parseGradle( ): ParseGradleResult { let vars: PackageVariables = { ...initVars }; const deps: PackageDependency<GradleManagerData>[] = []; - const urls = []; + const urls: string[] = []; const tokens = tokenize(input); let prevTokensLength = tokens.length; @@ -737,22 +740,25 @@ export function parseProps( packageFile?: string ): { vars: PackageVariables; deps: PackageDependency<GradleManagerData>[] } { let offset = 0; - const vars = {}; - const deps = []; + const vars: PackageVariables = {}; + const deps: PackageDependency[] = []; for (const line of input.split(newlineRegex)) { const lineMatch = propRegex.exec(line); - if (lineMatch) { + if (lineMatch?.groups) { const { key, value, leftPart } = lineMatch.groups; if (isDependencyString(value)) { const dep = parseDependencyString(value); - deps.push({ - ...dep, - managerData: { - fileReplacePosition: - offset + leftPart.length + dep.depName.length + 1, - packageFile, - }, - }); + if (dep) { + deps.push({ + ...dep, + managerData: { + fileReplacePosition: + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + offset + leftPart.length + dep.depName!.length + 1, + packageFile, + }, + }); + } } else { vars[key] = { key, diff --git a/lib/modules/manager/gradle/types.ts b/lib/modules/manager/gradle/types.ts index 3606100735..b6efc5cd70 100644 --- a/lib/modules/manager/gradle/types.ts +++ b/lib/modules/manager/gradle/types.ts @@ -38,7 +38,7 @@ export interface SyntaxMatcher { export type TokenMap = Record<string, Token>; export interface SyntaxHandlerInput { - packageFile: string; + packageFile?: string; variables: PackageVariables; tokenMap: TokenMap; } @@ -57,7 +57,7 @@ export interface SyntaxMatchConfig { export interface MatchConfig { tokens: Token[]; variables: PackageVariables; - packageFile: string; + packageFile?: string; } export interface ParseGradleResult { diff --git a/lib/modules/manager/gradle/update.ts b/lib/modules/manager/gradle/update.ts index dd254f4e58..02629ca4e5 100644 --- a/lib/modules/manager/gradle/update.ts +++ b/lib/modules/manager/gradle/update.ts @@ -12,7 +12,8 @@ export function updateDependency({ logger.warn('gradle manager does not support replacement updates yet'); return null; } - const offset = managerData.fileReplacePosition; + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + const offset = managerData!.fileReplacePosition; const leftPart = fileContent.slice(0, offset); const rightPart = fileContent.slice(offset); const version = versionLikeSubstring(rightPart); diff --git a/lib/modules/manager/gradle/utils.ts b/lib/modules/manager/gradle/utils.ts index b5f491429c..a3c1febfae 100644 --- a/lib/modules/manager/gradle/utils.ts +++ b/lib/modules/manager/gradle/utils.ts @@ -79,7 +79,7 @@ export function interpolateString( childTokens: Token[], variables: PackageVariables ): string | null { - const resolvedSubstrings = []; + const resolvedSubstrings: string[] = []; for (const childToken of childTokens) { const type = childToken.type; if (type === TokenType.String) { diff --git a/lib/modules/manager/nuget/artifacts.ts b/lib/modules/manager/nuget/artifacts.ts index fc73500dec..8977900ab3 100644 --- a/lib/modules/manager/nuget/artifacts.ts +++ b/lib/modules/manager/nuget/artifacts.ts @@ -35,7 +35,7 @@ async function addSourceCmds( ): Promise<string[]> { const registries = (await getConfiguredRegistries(packageFileName)) || getDefaultRegistries(); - const result = []; + const result: string[] = []; for (const registry of registries) { const { username, password } = hostRules.find({ hostType: NugetDatasource.id, @@ -162,7 +162,7 @@ export async function updateArtifacts({ const newLockFileContentMap = await getLockFileContentMap(lockFileNames); - const retArray = []; + const retArray: UpdateArtifactsResult[] = []; for (const lockFileName of lockFileNames) { if ( existingLockFileContentMap[lockFileName] === diff --git a/lib/modules/manager/nuget/extract.ts b/lib/modules/manager/nuget/extract.ts index 9862c9a900..ea4507e79b 100644 --- a/lib/modules/manager/nuget/extract.ts +++ b/lib/modules/manager/nuget/extract.ts @@ -38,7 +38,7 @@ function extractDepsFromXml(xmlNode: XmlDocument): PackageDependency[] { const results: PackageDependency[] = []; const todo: XmlElement[] = [xmlNode]; while (todo.length) { - const child = todo.pop(); + const child = todo.pop()!; const { name, attr } = child; if (elemNames.has(name)) { @@ -49,7 +49,8 @@ function extractDepsFromXml(xmlNode: XmlDocument): PackageDependency[] { attr?.VersionOverride || child.valueWithPath('VersionOverride'); const currentValue = checkVersion - ?.exec(version) + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + ?.exec(version!) ?.groups?.currentValue?.trim(); if (depName && currentValue) { results.push({ diff --git a/lib/modules/manager/terraform/extract.ts b/lib/modules/manager/terraform/extract.ts index ce2580c55f..1f2aae7a14 100644 --- a/lib/modules/manager/terraform/extract.ts +++ b/lib/modules/manager/terraform/extract.ts @@ -3,6 +3,7 @@ import { logger } from '../../../logger'; import { newlineRegex, regEx } from '../../../util/regex'; import type { ExtractConfig, PackageDependency, PackageFile } from '../types'; import { TerraformDependencyTypes } from './common'; +import type { ProviderLock } from './lockfile/types'; import { extractLocks, findLockFile, readLockFile } from './lockfile/util'; import { analyseTerraformModule, extractTerraformModule } from './modules'; import { @@ -21,7 +22,7 @@ import { analyseTerraformResource, extractTerraformResource, } from './resources'; -import type { TerraformManagerData } from './types'; +import type { ExtractionResult, TerraformManagerData } from './types'; import { checkFileContainsDependency, getTerraformDependencyType, @@ -59,14 +60,14 @@ export async function extractPackageFile( for (let lineNumber = 0; lineNumber < lines.length; lineNumber += 1) { const line = lines[lineNumber]; const terraformDependency = dependencyBlockExtractionRegex.exec(line); - if (terraformDependency) { + if (terraformDependency?.groups) { logger.trace( `Matched ${terraformDependency.groups.type} on line ${lineNumber}` ); const tfDepType = getTerraformDependencyType( terraformDependency.groups.type ); - let result = null; + let result: ExtractionResult | null = null; switch (tfDepType) { case TerraformDependencyTypes.required_providers: { result = extractTerraformRequiredProviders(lineNumber, lines); @@ -114,7 +115,7 @@ export async function extractPackageFile( logger.warn({ err }, 'Error extracting terraform plugins'); } - const locks = []; + const locks: ProviderLock[] = []; const lockFilePath = findLockFile(fileName); if (lockFilePath) { const lockFileContent = await readLockFile(lockFilePath); @@ -127,7 +128,7 @@ export async function extractPackageFile( } deps.forEach((dep) => { - switch (dep.managerData.terraformDependencyType) { + switch (dep.managerData?.terraformDependencyType) { case TerraformDependencyTypes.required_providers: analyzeTerraformRequiredProvider(dep, locks); break; diff --git a/lib/modules/manager/terraform/lockfile/hash.ts b/lib/modules/manager/terraform/lockfile/hash.ts index 735ab95b31..d86e12b914 100644 --- a/lib/modules/manager/terraform/lockfile/hash.ts +++ b/lib/modules/manager/terraform/lockfile/hash.ts @@ -105,7 +105,7 @@ export class TerraformProviderHash { registryURL: string, repository: string, version: string - ): Promise<string[]> { + ): Promise<string[] | null> { const builds = await TerraformProviderHash.terraformDatasource.getBuilds( registryURL, repository, diff --git a/lib/modules/manager/terraform/lockfile/index.ts b/lib/modules/manager/terraform/lockfile/index.ts index 7cae28fd08..a5af21f1a4 100644 --- a/lib/modules/manager/terraform/lockfile/index.ts +++ b/lib/modules/manager/terraform/lockfile/index.ts @@ -1,3 +1,4 @@ +import is from '@sindresorhus/is'; import pMap from 'p-map'; import { logger } from '../../../../logger'; import { GetPkgReleasesConfig, getPkgReleases } from '../../../datasource'; @@ -26,7 +27,11 @@ async function updateAllLocks( datasource: 'terraform-provider', depName: lock.packageName, }; - const { releases } = await getPkgReleases(updateConfig); + const { releases } = (await getPkgReleases(updateConfig)) ?? {}; + // istanbul ignore if: needs test + if (!releases) { + return null; + } const versioning = getVersioning(updateConfig.versioning); const versionsList = releases.map((release) => release.version); const newVersion = versioning.getSatisfyingVersion( @@ -35,17 +40,18 @@ async function updateAllLocks( ); // if the new version is the same as the last, signal that no update is needed - if (newVersion === lock.version) { + if (!newVersion || newVersion === lock.version) { return null; } const update: ProviderLockUpdate = { newVersion, newConstraint: lock.constraints, - newHashes: await TerraformProviderHash.createHashes( - lock.registryUrl, - lock.packageName, - newVersion - ), + newHashes: + (await TerraformProviderHash.createHashes( + lock.registryUrl, + lock.packageName, + newVersion + )) ?? [], ...lock, }; return update; @@ -53,7 +59,7 @@ async function updateAllLocks( { concurrency: 4 } // allow to look up 4 lock in parallel ); - return updates.filter(Boolean); + return updates.filter(is.truthy); } export async function updateArtifacts({ @@ -83,7 +89,8 @@ export async function updateArtifacts({ updates.push(...maintenanceUpdates); } else { const providerDeps = updatedDeps.filter((dep) => - ['provider', 'required_provider'].includes(dep.depType) + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + ['provider', 'required_provider'].includes(dep.depType!) ); for (const dep of providerDeps) { massageProviderLookupName(dep); @@ -96,21 +103,32 @@ export async function updateArtifacts({ const updateLock = locks.find( (value) => value.packageName === packageName ); + // istanbul ignore if: needs test + if (!updateLock) { + continue; + } const update: ProviderLockUpdate = { - newVersion, - newConstraint, - newHashes: await TerraformProviderHash.createHashes( - registryUrl, - packageName, - newVersion - ), + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + newVersion: newVersion!, + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + newConstraint: newConstraint!, + newHashes: + (await TerraformProviderHash.createHashes( + registryUrl, + updateLock.packageName, + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + newVersion! + )) ?? /* istanbul ignore next: needs test */ [], ...updateLock, }; updates.push(update); } } // if no updates have been found or there are failed hashes abort - if (updates.length === 0 || updates.some((value) => !value.newHashes)) { + if ( + updates.length === 0 || + updates.some((value) => !value.newHashes?.length) + ) { return null; } diff --git a/lib/modules/manager/terraform/lockfile/util.ts b/lib/modules/manager/terraform/lockfile/util.ts index 75bfb5874f..d1f4730353 100644 --- a/lib/modules/manager/terraform/lockfile/util.ts +++ b/lib/modules/manager/terraform/lockfile/util.ts @@ -30,7 +30,7 @@ export function readLockFile(lockFilePath: string): Promise<string> { return readLocalFile(lockFilePath, 'utf8'); } -export function extractLocks(lockFileContent: string): ProviderLock[] { +export function extractLocks(lockFileContent: string): ProviderLock[] | null { const lines = lockFileContent.split(newlineRegex); const blockStarts: number[] = []; // get first lines of blocks @@ -72,11 +72,11 @@ export function extractLocks(lockFileContent: string): ProviderLock[] { end: -1, }, }; - const hashes = []; + const hashes: string[] = []; slice.lines.forEach((line, index) => { const hashLineResult = hashLineRegex.exec(line); - if (hashLineResult) { + if (hashLineResult?.groups) { hashes.push(hashLineResult.groups.hash); relativeLineNumbers.hashes.start = relativeLineNumbers.hashes.start === -1 @@ -87,21 +87,21 @@ export function extractLocks(lockFileContent: string): ProviderLock[] { } const providerStartLineResult = providerStartLineRegex.exec(line); - if (providerStartLineResult) { + if (providerStartLineResult?.groups) { packageName = `${providerStartLineResult.groups.namespace}/${providerStartLineResult.groups.depName}`; registryUrl = providerStartLineResult.groups.registryUrl; return; } const versionLineResult = versionLineRegex.exec(line); - if (versionLineResult) { + if (versionLineResult?.groups) { version = versionLineResult.groups.version; relativeLineNumbers.version = index; return; } const constraintLineResult = constraintLineRegex.exec(line); - if (constraintLineResult) { + if (constraintLineResult?.groups) { constraints = constraintLineResult.groups.constraint; relativeLineNumbers.constraint = index; } @@ -124,9 +124,9 @@ export function extractLocks(lockFileContent: string): ProviderLock[] { return locks; } -export function isPinnedVersion(value: string): boolean { +export function isPinnedVersion(value: string | undefined): boolean { const versioning = getVersioning('hashicorp'); - return !!versioning.isSingleVersion(value); + return !!value && !!versioning.isSingleVersion(value); } export function writeLockUpdates( @@ -139,23 +139,31 @@ export function writeLockUpdates( const sections: string[][] = []; // sort updates in order of appearance in the lockfile - updates.sort((a, b) => a.lineNumbers.block.start - b.lineNumbers.block.start); + /* eslint-disable @typescript-eslint/no-unnecessary-type-assertion */ + updates.sort( + (a, b) => a.lineNumbers.block!.start - b.lineNumbers.block!.start + ); + /* eslint-enable @typescript-eslint/no-unnecessary-type-assertion */ updates.forEach((update, index, array) => { // re add leading whitespace - let startWhitespace; + let startWhitespace: number | undefined; if (index > 0) { // get end of the - startWhitespace = array[index - 1].lineNumbers.block.end; + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + startWhitespace = array[index - 1].lineNumbers.block!.end; } const leadingNonRelevantLines = lines.slice( startWhitespace, - update.lineNumbers.block.start + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + update.lineNumbers.block!.start ); sections.push(leadingNonRelevantLines); const providerBlockLines = lines.slice( - update.lineNumbers.block.start, - update.lineNumbers.block.end + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + update.lineNumbers.block!.start, + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + update.lineNumbers.block!.end ); const newProviderBlockLines: string[] = []; let hashLinePrefix = ''; @@ -180,7 +188,7 @@ export function writeLockUpdates( } const hashLineRegexResult = hashLineRegex.exec(providerBlockLine); - if (hashLineRegexResult) { + if (hashLineRegexResult?.groups) { // skip hash line but safe the whitespace hashLinePrefix = hashLineRegexResult.groups.prefix; hashLineSuffix = hashLineRegexResult.groups.suffix; @@ -188,11 +196,13 @@ export function writeLockUpdates( } newProviderBlockLines.push(providerBlockLine); }); + const hashesWithWhitespace = update.newHashes.map( (value) => `${hashLinePrefix}${value}${hashLineSuffix}` ); newProviderBlockLines.splice( - update.lineNumbers.hashes.start, + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + update.lineNumbers.hashes.start!, 0, ...hashesWithWhitespace ); @@ -200,7 +210,7 @@ export function writeLockUpdates( }); const trailingNotUpdatedLines = lines.slice( - updates[updates.length - 1].lineNumbers.block.end + updates[updates.length - 1].lineNumbers.block?.end ); sections.push(trailingNotUpdatedLines); diff --git a/lib/modules/manager/terraform/modules.ts b/lib/modules/manager/terraform/modules.ts index c780de02c2..cbb41c017f 100644 --- a/lib/modules/manager/terraform/modules.ts +++ b/lib/modules/manager/terraform/modules.ts @@ -27,17 +27,20 @@ export function extractTerraformModule( ): ExtractionResult { const result = extractTerraformProvider(startingLine, lines, moduleName); result.dependencies.forEach((dep) => { - dep.managerData.terraformDependencyType = TerraformDependencyTypes.module; + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + dep.managerData!.terraformDependencyType = TerraformDependencyTypes.module; }); return result; } export function analyseTerraformModule(dep: PackageDependency): void { - const githubRefMatch = githubRefMatchRegex.exec(dep.managerData.source); - const bitbucketRefMatch = bitbucketRefMatchRegex.exec(dep.managerData.source); - const gitTagsRefMatch = gitTagsRefMatchRegex.exec(dep.managerData.source); + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + const source = dep.managerData!.source as string; + const githubRefMatch = githubRefMatchRegex.exec(source); + const bitbucketRefMatch = bitbucketRefMatchRegex.exec(source); + const gitTagsRefMatch = gitTagsRefMatchRegex.exec(source); - if (githubRefMatch) { + if (githubRefMatch?.groups) { dep.packageName = githubRefMatch.groups.project.replace( regEx(/\.git$/), '' @@ -46,7 +49,7 @@ export function analyseTerraformModule(dep: PackageDependency): void { dep.depName = 'github.com/' + dep.packageName; dep.currentValue = githubRefMatch.groups.tag; dep.datasource = GithubTagsDatasource.id; - } else if (bitbucketRefMatch) { + } else if (bitbucketRefMatch?.groups) { dep.depType = 'module'; dep.depName = bitbucketRefMatch.groups.workspace + @@ -55,7 +58,7 @@ export function analyseTerraformModule(dep: PackageDependency): void { dep.packageName = dep.depName; dep.currentValue = bitbucketRefMatch.groups.tag; dep.datasource = BitBucketTagsDatasource.id; - } else if (gitTagsRefMatch) { + } else if (gitTagsRefMatch?.groups) { dep.depType = 'module'; if (gitTagsRefMatch.groups.path.includes('//')) { logger.debug('Terraform module contains subdirectory'); @@ -68,13 +71,13 @@ export function analyseTerraformModule(dep: PackageDependency): void { } dep.currentValue = gitTagsRefMatch.groups.tag; dep.datasource = GitTagsDatasource.id; - } else if (dep.managerData.source) { - const moduleParts = dep.managerData.source.split('//')[0].split('/'); + } else if (source) { + const moduleParts = source.split('//')[0].split('/'); if (moduleParts[0] === '..') { dep.skipReason = 'local'; } else if (moduleParts.length >= 3) { - const hostnameMatch = hostnameMatchRegex.exec(dep.managerData.source); - if (hostnameMatch) { + const hostnameMatch = hostnameMatchRegex.exec(source); + if (hostnameMatch?.groups) { dep.registryUrls = [`https://${hostnameMatch.groups.hostname}`]; } dep.depType = 'module'; diff --git a/lib/modules/manager/terraform/providers.ts b/lib/modules/manager/terraform/providers.ts index 429734703f..e8b026a1c1 100644 --- a/lib/modules/manager/terraform/providers.ts +++ b/lib/modules/manager/terraform/providers.ts @@ -5,7 +5,7 @@ import { TerraformProviderDatasource } from '../../datasource/terraform-provider import type { PackageDependency } from '../types'; import { TerraformDependencyTypes } from './common'; import type { ProviderLock } from './lockfile/types'; -import type { ExtractionResult } from './types'; +import type { ExtractionResult, TerraformManagerData } from './types'; import { getLockedVersion, keyValueExtractionRegex, @@ -22,8 +22,8 @@ export function extractTerraformProvider( moduleName: string ): ExtractionResult { let lineNumber = startingLine; - const deps: PackageDependency[] = []; - const dep: PackageDependency = { + const deps: PackageDependency<TerraformManagerData>[] = []; + const dep: PackageDependency<TerraformManagerData> = { managerData: { moduleName, terraformDependencyType: TerraformDependencyTypes.provider, @@ -48,12 +48,14 @@ export function extractTerraformProvider( // only update fields inside the root block if (braceCounter === 1) { const kvMatch = keyValueExtractionRegex.exec(line); - if (kvMatch) { + if (kvMatch?.groups) { if (kvMatch.groups.key === 'version') { dep.currentValue = kvMatch.groups.value; } else if (kvMatch.groups.key === 'source') { - dep.managerData.source = kvMatch.groups.value; - dep.managerData.sourceLine = lineNumber; + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + dep.managerData!.source = kvMatch.groups.value; + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + dep.managerData!.sourceLine = lineNumber; } } } @@ -75,12 +77,13 @@ export function analyzeTerraformProvider( locks: ProviderLock[] ): void { dep.depType = 'provider'; - dep.depName = dep.managerData.moduleName; + dep.depName = dep.managerData?.moduleName; dep.datasource = TerraformProviderDatasource.id; - if (is.nonEmptyString(dep.managerData.source)) { - const source = sourceExtractionRegex.exec(dep.managerData.source); - if (!source) { + if (is.nonEmptyString(dep.managerData?.source)) { + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + const source = sourceExtractionRegex.exec(dep.managerData!.source); + if (!source?.groups) { dep.skipReason = 'unsupported-url'; return; } @@ -92,7 +95,7 @@ export function analyzeTerraformProvider( dep.registryUrls = [`https://${source.groups.hostname}`]; dep.packageName = `${source.groups.namespace}/${source.groups.type}`; } else { - dep.packageName = dep.managerData.source; + dep.packageName = dep.managerData?.source; } } massageProviderLookupName(dep); diff --git a/lib/modules/manager/terraform/required-providers.ts b/lib/modules/manager/terraform/required-providers.ts index b22ce0a940..1c730c3f6d 100644 --- a/lib/modules/manager/terraform/required-providers.ts +++ b/lib/modules/manager/terraform/required-providers.ts @@ -3,7 +3,7 @@ import type { PackageDependency } from '../types'; import { TerraformDependencyTypes } from './common'; import type { ProviderLock } from './lockfile/types'; import { analyzeTerraformProvider } from './providers'; -import type { ExtractionResult } from './types'; +import type { ExtractionResult, TerraformManagerData } from './types'; import { keyValueExtractionRegex } from './util'; export const providerBlockExtractionRegex = regEx(/^\s*(?<key>[^\s]+)\s+=\s+{/); @@ -19,10 +19,11 @@ function extractBlock( lineNumber += 1; line = lines[lineNumber]; const kvMatch = keyValueExtractionRegex.exec(line); - if (kvMatch) { + if (kvMatch?.groups) { switch (kvMatch.groups.key) { case 'source': - dep.managerData.source = kvMatch.groups.value; + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + dep.managerData!.source = kvMatch.groups.value; break; case 'version': @@ -44,9 +45,9 @@ export function extractTerraformRequiredProviders( ): ExtractionResult { let lineNumber = startingLine; let line: string; - const deps: PackageDependency[] = []; + const deps: PackageDependency<TerraformManagerData>[] = []; do { - const dep: PackageDependency = { + const dep: PackageDependency<TerraformManagerData> = { managerData: { terraformDependencyType: TerraformDependencyTypes.required_providers, }, @@ -55,15 +56,17 @@ export function extractTerraformRequiredProviders( lineNumber += 1; line = lines[lineNumber]; const kvMatch = keyValueExtractionRegex.exec(line); - if (kvMatch) { + if (kvMatch?.groups) { dep.currentValue = kvMatch.groups.value; - dep.managerData.moduleName = kvMatch.groups.key; + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + dep.managerData!.moduleName = kvMatch.groups.key; deps.push(dep); } else { const nameMatch = providerBlockExtractionRegex.exec(line); if (nameMatch?.groups) { - dep.managerData.moduleName = nameMatch.groups.key; + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + dep.managerData!.moduleName = nameMatch.groups.key; lineNumber = extractBlock(lineNumber, lines, dep); deps.push(dep); } diff --git a/lib/modules/manager/terraform/required-version.ts b/lib/modules/manager/terraform/required-version.ts index ba20b85c6e..195188e607 100644 --- a/lib/modules/manager/terraform/required-version.ts +++ b/lib/modules/manager/terraform/required-version.ts @@ -3,14 +3,14 @@ import { regEx } from '../../../util/regex'; import { GithubTagsDatasource } from '../../datasource/github-tags'; import type { PackageDependency } from '../types'; import { TerraformDependencyTypes } from './common'; -import type { ExtractionResult } from './types'; +import type { ExtractionResult, TerraformManagerData } from './types'; import { keyValueExtractionRegex } from './util'; export function extractTerraformRequiredVersion( startingLine: number, lines: string[] -): ExtractionResult { - const deps: PackageDependency[] = []; +): ExtractionResult | null { + const deps: PackageDependency<TerraformManagerData>[] = []; let lineNumber = startingLine; let braceCounter = 0; do { @@ -26,8 +26,8 @@ export function extractTerraformRequiredVersion( braceCounter = braceCounter + openBrackets - closedBrackets; const kvMatch = keyValueExtractionRegex.exec(line); - if (kvMatch && kvMatch.groups.key === 'required_version') { - const dep: PackageDependency = { + if (kvMatch?.groups && kvMatch.groups.key === 'required_version') { + const dep: PackageDependency<TerraformManagerData> = { currentValue: kvMatch.groups.value, lineNumber, managerData: { diff --git a/lib/modules/manager/terraform/resources.ts b/lib/modules/manager/terraform/resources.ts index 26762dcb7d..3d717aa098 100644 --- a/lib/modules/manager/terraform/resources.ts +++ b/lib/modules/manager/terraform/resources.ts @@ -24,18 +24,19 @@ export function extractTerraformResource( ): ExtractionResult { let lineNumber = startingLine; let line = lines[lineNumber]; - const deps: PackageDependency[] = []; + const deps: PackageDependency<ResourceManagerData>[] = []; + const managerData: ResourceManagerData = { + terraformDependencyType: TerraformDependencyTypes.resource, + }; const dep: PackageDependency<ResourceManagerData> = { - managerData: { - terraformDependencyType: TerraformDependencyTypes.resource, - }, + managerData, }; const typeMatch = resourceTypeExtractionRegex.exec(line); // Sets the resourceType, e.g. "helm_release" 'resource "helm_release" "test_release"' - dep.managerData.resourceType = - TerraformResourceTypes[typeMatch?.groups?.type] ?? + managerData.resourceType = + TerraformResourceTypes[typeMatch?.groups?.type as TerraformResourceTypes] ?? TerraformResourceTypes.unknown; /** @@ -46,13 +47,13 @@ export function extractTerraformResource( lineNumber += 1; line = lines[lineNumber]; const kvMatch = keyValueExtractionRegex.exec(line); - if (kvMatch) { + if (kvMatch?.groups) { switch (kvMatch.groups.key) { case 'chart': case 'image': case 'name': case 'repository': - dep.managerData[kvMatch.groups.key] = kvMatch.groups.value; + managerData[kvMatch.groups.key] = kvMatch.groups.value; break; case 'version': case 'terraform_version': @@ -71,6 +72,10 @@ export function extractTerraformResource( export function analyseTerraformResource( dep: PackageDependency<ResourceManagerData> ): void { + // istanbul ignore if: should tested? + if (!dep.managerData) { + return; + } switch (dep.managerData.resourceType) { case TerraformResourceTypes.docker_container: if (dep.managerData.image) { @@ -106,7 +111,8 @@ export function analyseTerraformResource( dep.skipReason = 'local-chart'; } dep.depType = 'helm_release'; - dep.registryUrls = [dep.managerData.repository]; + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + dep.registryUrls = [dep.managerData.repository!]; dep.depName = dep.managerData.chart; dep.datasource = HelmDatasource.id; break; diff --git a/lib/modules/manager/terraform/types.ts b/lib/modules/manager/terraform/types.ts index 865289501d..584ac9f08d 100644 --- a/lib/modules/manager/terraform/types.ts +++ b/lib/modules/manager/terraform/types.ts @@ -6,10 +6,13 @@ import type { export interface ExtractionResult { lineNumber: number; - dependencies: PackageDependency[]; + dependencies: PackageDependency<TerraformManagerData>[]; } export interface TerraformManagerData { + moduleName?: string; + source?: string; + sourceLine?: number; terraformDependencyType: TerraformDependencyTypes; } diff --git a/lib/modules/manager/terraform/util.ts b/lib/modules/manager/terraform/util.ts index 9b531cb636..dea1126352 100644 --- a/lib/modules/manager/terraform/util.ts +++ b/lib/modules/manager/terraform/util.ts @@ -53,18 +53,20 @@ export function massageProviderLookupName(dep: PackageDependency): void { if (!dep.packageName) { dep.packageName = dep.depName; } - if (!dep.packageName.includes('/')) { + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + if (!dep.packageName!.includes('/')) { dep.packageName = `hashicorp/${dep.packageName}`; } // handle cases like `Telmate/proxmox` - dep.packageName = dep.packageName.toLowerCase(); + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + dep.packageName = dep.packageName!.toLowerCase(); } export function getLockedVersion( dep: PackageDependency, locks: ProviderLock[] -): string { +): string | undefined { const depRegistryUrl = dep.registryUrls ? dep.registryUrls[0] : TerraformProviderDatasource.defaultRegistryUrls[0]; diff --git a/lib/modules/manager/terragrunt/extract.ts b/lib/modules/manager/terragrunt/extract.ts index c1fde992d1..929bec4d31 100644 --- a/lib/modules/manager/terragrunt/extract.ts +++ b/lib/modules/manager/terragrunt/extract.ts @@ -3,7 +3,7 @@ import { newlineRegex, regEx } from '../../../util/regex'; import type { PackageDependency, PackageFile } from '../types'; import { TerragruntDependencyTypes } from './common'; import { analyseTerragruntModule, extractTerragruntModule } from './modules'; -import type { TerraformManagerData } from './types'; +import type { ExtractionResult, TerraformManagerData } from './types'; import { checkFileContainsDependency, getTerragruntDependencyType, @@ -23,14 +23,14 @@ export function extractPackageFile(content: string): PackageFile | null { for (let lineNumber = 0; lineNumber < lines.length; lineNumber += 1) { const line = lines[lineNumber]; const terragruntDependency = dependencyBlockExtractionRegex.exec(line); - if (terragruntDependency) { + if (terragruntDependency?.groups) { logger.trace( `Matched ${terragruntDependency.groups.type} on line ${lineNumber}` ); const tfDepType = getTerragruntDependencyType( terragruntDependency.groups.type ); - let result = null; + let result: ExtractionResult | null = null; switch (tfDepType) { case TerragruntDependencyTypes.terragrunt: { result = extractTerragruntModule(lineNumber, lines); @@ -54,7 +54,8 @@ export function extractPackageFile(content: string): PackageFile | null { logger.warn({ err }, 'Error extracting terragrunt plugins'); } deps.forEach((dep) => { - switch (dep.managerData.terragruntDependencyType) { + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + switch (dep.managerData!.terragruntDependencyType) { case TerragruntDependencyTypes.terragrunt: analyseTerragruntModule(dep); break; diff --git a/lib/modules/manager/terragrunt/modules.ts b/lib/modules/manager/terragrunt/modules.ts index dfa1cbaea2..16ea8f6a26 100644 --- a/lib/modules/manager/terragrunt/modules.ts +++ b/lib/modules/manager/terragrunt/modules.ts @@ -6,7 +6,7 @@ import { TerraformModuleDatasource } from '../../datasource/terraform-module'; import type { PackageDependency } from '../types'; import { TerragruntDependencyTypes } from './common'; import { extractTerragruntProvider } from './providers'; -import type { ExtractionResult } from './types'; +import type { ExtractionResult, TerraformManagerData } from './types'; export const githubRefMatchRegex = regEx( /github\.com([/:])(?<project>[^/]+\/[a-z0-9-_.]+).*\?ref=(?<tag>.*)$/i @@ -23,17 +23,22 @@ export function extractTerragruntModule( const moduleName = 'terragrunt'; const result = extractTerragruntProvider(startingLine, lines, moduleName); result.dependencies.forEach((dep) => { - dep.managerData.terragruntDependencyType = + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + dep.managerData!.terragruntDependencyType = TerragruntDependencyTypes.terragrunt; }); return result; } -export function analyseTerragruntModule(dep: PackageDependency): void { - const githubRefMatch = githubRefMatchRegex.exec(dep.managerData.source); - const gitTagsRefMatch = gitTagsRefMatchRegex.exec(dep.managerData.source); +export function analyseTerragruntModule( + dep: PackageDependency<TerraformManagerData> +): void { + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + const source = dep.managerData!.source; + const githubRefMatch = githubRefMatchRegex.exec(source ?? ''); + const gitTagsRefMatch = gitTagsRefMatchRegex.exec(source ?? ''); - if (githubRefMatch) { + if (githubRefMatch?.groups) { dep.depType = 'github'; dep.packageName = githubRefMatch.groups.project.replace( regEx(/\.git$/), @@ -42,7 +47,7 @@ export function analyseTerragruntModule(dep: PackageDependency): void { dep.depName = 'github.com/' + dep.packageName; dep.currentValue = githubRefMatch.groups.tag; dep.datasource = GithubTagsDatasource.id; - } else if (gitTagsRefMatch) { + } else if (gitTagsRefMatch?.groups) { dep.depType = 'gitTags'; if (gitTagsRefMatch.groups.path.includes('//')) { logger.debug('Terragrunt module contains subdirectory'); @@ -55,13 +60,13 @@ export function analyseTerragruntModule(dep: PackageDependency): void { } dep.currentValue = gitTagsRefMatch.groups.tag; dep.datasource = GitTagsDatasource.id; - } else if (dep.managerData.source) { - const moduleParts = dep.managerData.source.split('//')[0].split('/'); + } else if (source) { + const moduleParts = source.split('//')[0].split('/'); if (moduleParts[0] === '..') { dep.skipReason = 'local'; } else if (moduleParts.length >= 3) { - const hostnameMatch = hostnameMatchRegex.exec(dep.managerData.source); - if (hostnameMatch) { + const hostnameMatch = hostnameMatchRegex.exec(source); + if (hostnameMatch?.groups) { dep.registryUrls = [`https://${hostnameMatch.groups.hostname}`]; } dep.depType = 'terragrunt'; diff --git a/lib/modules/manager/terragrunt/providers.ts b/lib/modules/manager/terragrunt/providers.ts index 898a99a554..b009439eb2 100644 --- a/lib/modules/manager/terragrunt/providers.ts +++ b/lib/modules/manager/terragrunt/providers.ts @@ -1,7 +1,7 @@ import { newlineRegex, regEx } from '../../../util/regex'; import type { PackageDependency } from '../types'; import { TerragruntDependencyTypes } from './common'; -import type { ExtractionResult } from './types'; +import type { ExtractionResult, TerraformManagerData } from './types'; import { keyValueExtractionRegex } from './util'; export const sourceExtractionRegex = regEx( @@ -9,7 +9,7 @@ export const sourceExtractionRegex = regEx( ); function extractBracesContent(content: string): number { - const stack = []; + const stack: string[] = []; let i = 0; for (i; i < content.length; i += 1) { if (content[i] === '{') { @@ -31,12 +31,12 @@ export function extractTerragruntProvider( ): ExtractionResult { const lineNumber = startingLine; let line: string; - const deps: PackageDependency[] = []; - const managerData: Record<string, unknown> = { + const deps: PackageDependency<TerraformManagerData>[] = []; + const managerData: TerraformManagerData = { moduleName, terragruntDependencyType: TerragruntDependencyTypes.terragrunt, }; - const dep: PackageDependency = { managerData }; + const dep: PackageDependency<TerraformManagerData> = { managerData }; const teraformContent = lines .slice(lineNumber) .join('\n') diff --git a/lib/modules/manager/terragrunt/types.ts b/lib/modules/manager/terragrunt/types.ts index 0f474282e3..d3d1044a9b 100644 --- a/lib/modules/manager/terragrunt/types.ts +++ b/lib/modules/manager/terragrunt/types.ts @@ -6,10 +6,13 @@ import type { export interface ExtractionResult { lineNumber: number; - dependencies: PackageDependency[]; + dependencies: PackageDependency<TerraformManagerData>[]; } export interface TerraformManagerData { + moduleName: string; + source?: string; + sourceLine?: number; terragruntDependencyType: TerragruntDependencyTypes; } diff --git a/lib/modules/versioning/index.ts b/lib/modules/versioning/index.ts index 769bb8da13..616d9e03bb 100644 --- a/lib/modules/versioning/index.ts +++ b/lib/modules/versioning/index.ts @@ -14,7 +14,7 @@ export const getVersionings = (): Map< VersioningApi | VersioningApiConstructor > => versionings; -export function get(versioning: string): VersioningApi { +export function get(versioning: string | undefined): VersioningApi { if (!versioning) { logger.trace('Missing versioning, using semver as fallback.'); return versionings.get('semver') as VersioningApi; diff --git a/tsconfig.strict.json b/tsconfig.strict.json index 5de7ec6fc1..e3c3d894ed 100644 --- a/tsconfig.strict.json +++ b/tsconfig.strict.json @@ -40,31 +40,6 @@ "lib/config/validation.ts", "lib/modules/datasource/github-releases/test/index.ts", "lib/modules/manager/api.ts", - "lib/modules/manager/composer/artifacts.ts", - "lib/modules/manager/composer/extract.ts", - "lib/modules/manager/composer/index.ts", - "lib/modules/manager/composer/range.ts", - "lib/modules/manager/composer/update-locked.ts", - "lib/modules/manager/composer/utils.ts", - "lib/modules/manager/git-submodules/artifacts.ts", - "lib/modules/manager/git-submodules/extract.ts", - "lib/modules/manager/git-submodules/index.ts", - "lib/modules/manager/git-submodules/update.ts", - "lib/modules/manager/gomod/artifacts.ts", - "lib/modules/manager/gomod/extract.ts", - "lib/modules/manager/gomod/index.ts", - "lib/modules/manager/gomod/update.ts", - "lib/modules/manager/gradle-wrapper/artifacts.ts", - "lib/modules/manager/gradle-wrapper/extract.ts", - "lib/modules/manager/gradle-wrapper/index.ts", - "lib/modules/manager/gradle-wrapper/utils.ts", - "lib/modules/manager/gradle/index.ts", - "lib/modules/manager/gradle/extract.ts", - "lib/modules/manager/gradle/extract/catalog.ts", - "lib/modules/manager/gradle/index.ts", - "lib/modules/manager/gradle/parser.ts", - "lib/modules/manager/gradle/update.ts", - "lib/modules/manager/gradle/__testutil__/gradle.ts", "lib/modules/manager/index.ts", "lib/modules/manager/npm/detect.ts", "lib/modules/manager/npm/extract/index.ts", @@ -93,30 +68,6 @@ "lib/modules/manager/npm/update/locked-dependency/yarn-lock/index.ts", "lib/modules/manager/npm/update/locked-dependency/yarn-lock/replace.ts", "lib/modules/manager/npm/update/package-version/index.ts", - "lib/modules/manager/nuget/artifacts.ts", - "lib/modules/manager/nuget/extract.ts", - "lib/modules/manager/nuget/extract/global-manifest.ts", - "lib/modules/manager/nuget/index.ts", - "lib/modules/manager/nuget/package-tree.ts", - "lib/modules/manager/nuget/util.ts", - "lib/modules/manager/terraform-version/extract.ts", - "lib/modules/manager/terraform-version/index.ts", - "lib/modules/manager/terraform/extract.ts", - "lib/modules/manager/terraform/index.ts", - "lib/modules/manager/terraform/lockfile/hash.ts", - "lib/modules/manager/terraform/lockfile/index.ts", - "lib/modules/manager/terraform/lockfile/util.ts", - "lib/modules/manager/terraform/modules.ts", - "lib/modules/manager/terraform/providers.ts", - "lib/modules/manager/terraform/required-providers.ts", - "lib/modules/manager/terraform/required-version.ts", - "lib/modules/manager/terraform/resources.ts", - "lib/modules/manager/terraform/util.ts", - "lib/modules/manager/terragrunt-version/extract.ts", - "lib/modules/manager/terragrunt-version/index.ts", - "lib/modules/manager/terragrunt/extract.ts", - "lib/modules/manager/terragrunt/index.ts", - "lib/modules/manager/terragrunt/modules.ts", "lib/modules/platform/api.ts", "lib/modules/platform/azure/azure-got-wrapper.ts", "lib/modules/platform/azure/azure-helper.ts", -- GitLab