diff --git a/lib/config/__snapshots__/migration.spec.ts.snap b/lib/config/__snapshots__/migration.spec.ts.snap index 0efd4474e95449f1e69b8a14774bc219d50a93ad..868ca5d47a459811a516a825f59740173ce5e54c 100644 --- a/lib/config/__snapshots__/migration.spec.ts.snap +++ b/lib/config/__snapshots__/migration.spec.ts.snap @@ -100,13 +100,6 @@ Object { } `; -exports[`config/migration migrateConfig(config, parentConfig) migrates before and after schedules 2`] = ` -Array [ - "after 10pm every weekday", - "before 7am every weekday", -] -`; - exports[`config/migration migrateConfig(config, parentConfig) migrates config 1`] = ` Object { "additionalBranchPrefix": "{{parentDir}}-", diff --git a/lib/config/decrypt.spec.ts b/lib/config/decrypt.spec.ts index 92365f2ef43d1b1eac010c7044257c6fee2ecc0e..b90ed948b07e5acb14612214f9729d298e45a808 100644 --- a/lib/config/decrypt.spec.ts +++ b/lib/config/decrypt.spec.ts @@ -92,7 +92,8 @@ describe('config/decrypt', () => { }, 'backend/package.json', ]; - const res = await decryptConfig(config, repository); + // TODO: fix types #7154 + const res = (await decryptConfig(config, repository)) as any; expect(res.encrypted).toBeUndefined(); expect(res.packageFiles[0].devDependencies.encrypted).toBeUndefined(); expect(res.packageFiles[0].devDependencies.branchPrefix).toBe( diff --git a/lib/config/defaults.ts b/lib/config/defaults.ts index 4a971b49b8e4a0e4c80e3204d9fcb7ce162383f9..b4e4b7241c697e774ba49daca94dc19b804df760 100644 --- a/lib/config/defaults.ts +++ b/lib/config/defaults.ts @@ -6,7 +6,8 @@ const defaultValues = { array: [], string: null, object: null, -}; + integer: null, +} as const; export function getDefault(option: RenovateOptions): any { return option.default === undefined diff --git a/lib/config/index.ts b/lib/config/index.ts index 4a0356283f5a7d91fa17e906f82737733619e9e2..076ef08bae98f1383670ce28b69642a9af5eaea0 100644 --- a/lib/config/index.ts +++ b/lib/config/index.ts @@ -17,9 +17,11 @@ export function getManagerConfig( }; const language = get(manager, 'language'); if (language) { - managerConfig = mergeChildConfig(managerConfig, config[language]); + // TODO: fix types #7154 + managerConfig = mergeChildConfig(managerConfig, config[language] as any); } - managerConfig = mergeChildConfig(managerConfig, config[manager]); + // TODO: fix types #7154 + managerConfig = mergeChildConfig(managerConfig, config[manager] as any); for (const i of getLanguageList().concat(getManagerList())) { delete managerConfig[i]; } @@ -34,7 +36,13 @@ export function filterConfig( ): AllConfig { logger.trace({ config: inputConfig }, `filterConfig('${targetStage}')`); const outputConfig: RenovateConfig = { ...inputConfig }; - const stages = ['global', 'repository', 'package', 'branch', 'pr']; + const stages: (string | undefined)[] = [ + 'global', + 'repository', + 'package', + 'branch', + 'pr', + ]; const targetIndex = stages.indexOf(targetStage); for (const option of options.getOptions()) { const optionIndex = stages.indexOf(option.stage); diff --git a/lib/config/migration.spec.ts b/lib/config/migration.spec.ts index 54a9199024cbb3c35f26badfcdc301f990cd3b48..832efc62aeccc967992cba62c5a81435fde8a8c2 100644 --- a/lib/config/migration.spec.ts +++ b/lib/config/migration.spec.ts @@ -178,13 +178,12 @@ describe('config/migration', () => { configMigration.migrateConfig(config); expect(migratedConfig).toMatchSnapshot(); expect(isMigrated).toBeTrue(); - expect(migratedConfig.major.schedule).toHaveLength(2); - expect(migratedConfig.major.schedule[0]).toBe('after 10pm'); - expect(migratedConfig.major.schedule[1]).toBe('before 7am'); - expect(migratedConfig.minor.schedule).toMatchSnapshot(); - expect(migratedConfig.minor.schedule).toHaveLength(2); - expect(migratedConfig.minor.schedule[0]).toBe('after 10pm every weekday'); - expect(migratedConfig.minor.schedule[1]).toBe('before 7am every weekday'); + expect(migratedConfig.major).toMatchObject({ + schedule: ['after 10pm', 'before 7am'], + }); + expect(migratedConfig.minor).toMatchObject({ + schedule: ['after 10pm every weekday', 'before 7am every weekday'], + }); }); it('migrates every friday', () => { @@ -274,7 +273,7 @@ describe('config/migration', () => { configMigration.migrateConfig(config); expect(isMigrated).toBeTrue(); expect(migratedConfig).toMatchSnapshot(); - expect(migratedConfig.packageRules[0].minor.automerge).toBeFalse(); + expect(migratedConfig.packageRules?.[0].minor?.automerge).toBeFalse(); }); it('does not migrate config', () => { @@ -304,9 +303,9 @@ describe('config/migration', () => { configMigration.migrateConfig(config); expect(isMigrated).toBeTrue(); expect(migratedConfig).toMatchSnapshot(); - expect(migratedConfig.lockFileMaintenance.packageRules).toHaveLength(1); + expect(migratedConfig.lockFileMaintenance?.packageRules).toHaveLength(1); expect( - migratedConfig.lockFileMaintenance.packageRules[0].respectLatest + migratedConfig.lockFileMaintenance?.packageRules[0].respectLatest ).toBeFalse(); }); @@ -349,8 +348,8 @@ describe('config/migration', () => { expect(migratedConfig.includePaths).toHaveLength(4); expect(migratedConfig.packageFiles).toBeUndefined(); expect(migratedConfig.packageRules).toHaveLength(4); - expect(migratedConfig.packageRules[0].rangeStrategy).toBe('replace'); - expect(migratedConfig.packageRules[1].rangeStrategy).toBe('pin'); + expect(migratedConfig.packageRules?.[0].rangeStrategy).toBe('replace'); + expect(migratedConfig.packageRules?.[1].rangeStrategy).toBe('pin'); }); it('migrates more packageFiles', () => { diff --git a/lib/config/migration.ts b/lib/config/migration.ts index d77d4136da646229b5d7ecb17c5a97bac43d71a0..3567714432be516d50cc926409a672a0cbd50da7 100644 --- a/lib/config/migration.ts +++ b/lib/config/migration.ts @@ -154,11 +154,15 @@ export function migrateConfig(config: RenovateConfig): MigratedConfig { ) { migratedConfig[key] = String(val[0]); } else if (key === 'node' && (val as RenovateConfig).enabled === true) { - delete migratedConfig.node.enabled; + // validated non-null + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + delete migratedConfig.node!.enabled; migratedConfig.travis = migratedConfig.travis || {}; migratedConfig.travis.enabled = true; - if (Object.keys(migratedConfig.node).length) { - const subMigrate = migrateConfig(migratedConfig.node); + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + if (Object.keys(migratedConfig.node!).length) { + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + const subMigrate = migrateConfig(migratedConfig.node!); migratedConfig.node = subMigrate.migratedConfig; } else { delete migratedConfig.node; @@ -212,10 +216,10 @@ export function migrateConfig(config: RenovateConfig): MigratedConfig { packagePatterns: 'matchPackagePatterns', sourceUrlPrefixes: 'matchSourceUrlPrefixes', updateTypes: 'matchUpdateTypes', - }; + } as const; for (const packageRule of migratedConfig.packageRules) { for (const [oldKey, ruleVal] of Object.entries(packageRule)) { - const newKey = renameMap[oldKey]; + const newKey = renameMap[oldKey as keyof typeof renameMap]; if (newKey) { packageRule[newKey] = ruleVal; delete packageRule[oldKey]; @@ -232,7 +236,8 @@ export function migrateConfig(config: RenovateConfig): MigratedConfig { logger.debug('Flattening nested packageRules'); // merge each subrule and add to the parent list for (const subrule of packageRule.packageRules) { - const combinedRule = mergeChildConfig(packageRule, subrule); + // TODO: fix types #7154 + const combinedRule = mergeChildConfig(packageRule, subrule as any); delete combinedRule.packageRules; migratedConfig.packageRules.push(combinedRule); } diff --git a/lib/config/options/index.spec.ts b/lib/config/options/index.spec.ts index c5387f98fa6fd8006758aad68f62887cc0d10c6f..27277a8b0222e6f3633c18b1f0fbc4dbd6d8ec86 100644 --- a/lib/config/options/index.spec.ts +++ b/lib/config/options/index.spec.ts @@ -23,7 +23,8 @@ describe('config/options/index', () => { .filter((option) => option.supportedManagers) .forEach((option) => { expect(option.supportedManagers).toBeNonEmptyArray(); - for (const item of option.supportedManagers) { + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + for (const item of option.supportedManagers!) { expect(managerList).toContain(item); } }); @@ -38,7 +39,8 @@ describe('config/options/index', () => { .filter((option) => option.supportedPlatforms) .forEach((option) => { expect(option.supportedPlatforms).toBeNonEmptyArray(); - for (const item of option.supportedPlatforms) { + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + for (const item of option.supportedPlatforms!) { expect(platformList).toContain(item); } }); diff --git a/lib/config/presets/bitbucket-server/index.ts b/lib/config/presets/bitbucket-server/index.ts index 949a824a23ef2dfbaf12fd266934690258817c8d..a5892f8fd47fe47c53325224a3e1b297f5937f86 100644 --- a/lib/config/presets/bitbucket-server/index.ts +++ b/lib/config/presets/bitbucket-server/index.ts @@ -18,8 +18,8 @@ export async function fetchJSONFile( repo: string, fileName: string, endpoint: string, - branchOrTag?: string -): Promise<Preset> { + branchOrTag?: string | null +): Promise<Preset | null> { const [projectKey, repositorySlug] = repo.split('/'); setBaseUrl(endpoint); let url = `rest/api/1.0/projects/${projectKey}/repos/${repositorySlug}/browse/${fileName}?limit=20000`; @@ -57,14 +57,16 @@ export async function fetchJSONFile( export function getPresetFromEndpoint( repo: string, filePreset: string, - presetPath: string, - endpoint: string -): Promise<Preset> { + presetPath: string | undefined, + endpoint: string, + tag?: string | null +): Promise<Preset | undefined> { return fetchPreset({ repo, filePreset, presetPath, endpoint, + tag, fetch: fetchJSONFile, }); } diff --git a/lib/config/presets/gitea/index.ts b/lib/config/presets/gitea/index.ts index 691b12c1ea1f1a40652aedfddb66cd14329ca3c5..86068bccc7388b682cccedb7549bd4a79e1418ae 100644 --- a/lib/config/presets/gitea/index.ts +++ b/lib/config/presets/gitea/index.ts @@ -18,7 +18,7 @@ export async function fetchJSONFile( repo: string, fileName: string, endpoint: string, - tag?: string + tag?: string | null ): Promise<Preset> { let res: RepoContents; try { @@ -37,7 +37,9 @@ export async function fetchJSONFile( throw new Error(PRESET_DEP_NOT_FOUND); } try { - const content = fromBase64(res.content); + // TODO: undefiend content ? #7154 + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + const content = fromBase64(res.content!); const parsed = JSON.parse(content); return parsed; } catch (err) { @@ -48,10 +50,10 @@ export async function fetchJSONFile( export function getPresetFromEndpoint( repo: string, filePreset: string, - presetPath: string, + presetPath?: string, endpoint = Endpoint, tag?: string -): Promise<Preset> { +): Promise<Preset | undefined> { return fetchPreset({ repo, filePreset, @@ -66,7 +68,7 @@ export function getPreset({ repo, presetName = 'default', presetPath, - tag = null, -}: PresetConfig): Promise<Preset> { + tag = undefined, +}: PresetConfig): Promise<Preset | undefined> { return getPresetFromEndpoint(repo, presetName, presetPath, Endpoint, tag); } diff --git a/lib/config/presets/github/index.ts b/lib/config/presets/github/index.ts index 68dfae1475dd4c341e00de2a33e94845143ddc53..d90f9bb19f9bd502f78af6a924f3ba5bfccfc451 100644 --- a/lib/config/presets/github/index.ts +++ b/lib/config/presets/github/index.ts @@ -17,7 +17,7 @@ export async function fetchJSONFile( repo: string, fileName: string, endpoint: string, - tag?: string + tag?: string | null ): Promise<Preset> { let ref = ''; if (is.nonEmptyString(tag)) { @@ -51,10 +51,10 @@ export async function fetchJSONFile( export function getPresetFromEndpoint( repo: string, filePreset: string, - presetPath: string, + presetPath?: string, endpoint = Endpoint, tag?: string -): Promise<Preset> { +): Promise<Preset | undefined> { return fetchPreset({ repo, filePreset, @@ -69,7 +69,7 @@ export function getPreset({ repo, presetName = 'default', presetPath, - tag = null, -}: PresetConfig): Promise<Preset> { + tag = undefined, +}: PresetConfig): Promise<Preset | undefined> { return getPresetFromEndpoint(repo, presetName, presetPath, Endpoint, tag); } diff --git a/lib/config/presets/gitlab/index.spec.ts b/lib/config/presets/gitlab/index.spec.ts index cd4c65f85fa9e9420ee41f0b9ecf5447445d4c6e..6ab2e65dede2bc2824121b549a2b5e9f44a0e900 100644 --- a/lib/config/presets/gitlab/index.spec.ts +++ b/lib/config/presets/gitlab/index.spec.ts @@ -29,9 +29,9 @@ describe('config/presets/gitlab/index', () => { .twice() .reply(200, []) .get(`${basePath}/files/default.json/raw?ref=master`) - .reply(404, null) + .reply(404) .get(`${basePath}/files/renovate.json/raw?ref=master`) - .reply(404, null); + .reply(404); await expect(gitlab.getPreset({ repo: 'some/repo' })).rejects.toThrow( PRESET_DEP_NOT_FOUND ); diff --git a/lib/config/presets/gitlab/index.ts b/lib/config/presets/gitlab/index.ts index cf1be1b4c1b84613817ab0fffef41437aec512b7..dfd80bd95d45aa0a5dd241f66d59b7bef920955b 100644 --- a/lib/config/presets/gitlab/index.ts +++ b/lib/config/presets/gitlab/index.ts @@ -32,7 +32,7 @@ export async function fetchJSONFile( repo: string, fileName: string, endpoint: string, - tag?: string + tag?: string | null ): Promise<Preset> { let url = endpoint; let ref = ''; @@ -66,10 +66,10 @@ export async function fetchJSONFile( export function getPresetFromEndpoint( repo: string, presetName: string, - presetPath: string, + presetPath?: string, endpoint = Endpoint, - tag?: string -): Promise<Preset> { + tag?: string | null +): Promise<Preset | undefined> { return fetchPreset({ repo, filePreset: presetName, @@ -84,7 +84,7 @@ export function getPreset({ repo, presetPath, presetName = 'default', - tag = null, -}: PresetConfig): Promise<Preset> { + tag = undefined, +}: PresetConfig): Promise<Preset | undefined> { return getPresetFromEndpoint(repo, presetName, presetPath, Endpoint, tag); } diff --git a/lib/config/presets/index.spec.ts b/lib/config/presets/index.spec.ts index 5c662c02450ff8c09cb369341676006b7e4674c3..6fa528c27b99e53732fdf342cf8c363332d52622 100644 --- a/lib/config/presets/index.spec.ts +++ b/lib/config/presets/index.spec.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-unnecessary-type-assertion */ import { loadJsonFixture, mocked } from '../../../test/util'; import type { RenovateConfig } from '../types'; import * as _local from './local'; @@ -23,7 +24,7 @@ npm.getPreset = jest.fn(({ repo, presetName }) => { if (repo === 'renovate-config-ikatyang') { return presetIkatyang.versions[presetIkatyang['dist-tags'].latest][ 'renovate-config' - ][presetName]; + ][presetName!]; } if (repo === 'renovate-config-notfound') { throw new Error(PRESET_DEP_NOT_FOUND); @@ -59,71 +60,73 @@ describe('config/presets/index', () => { it('throws if invalid preset file', async () => { config.foo = 1; config.extends = ['notfound']; - let e: Error; + let e: Error | undefined; try { await presets.resolveConfigPresets(config); } catch (err) { e = err; } expect(e).toBeDefined(); - expect(e.validationSource).toBeUndefined(); - expect(e.validationError).toBe("Cannot find preset's package (notfound)"); - expect(e.validationMessage).toBeUndefined(); + expect(e!.validationSource).toBeUndefined(); + expect(e!.validationError).toBe( + "Cannot find preset's package (notfound)" + ); + expect(e!.validationMessage).toBeUndefined(); }); it('throws if invalid preset', async () => { config.foo = 1; config.extends = ['wrongpreset:invalid-preset']; - let e: Error; + let e: Error | undefined; try { await presets.resolveConfigPresets(config); } catch (err) { e = err; } expect(e).toBeDefined(); - expect(e.validationSource).toBeUndefined(); - expect(e.validationError).toBe( + expect(e!.validationSource).toBeUndefined(); + expect(e!.validationError).toBe( 'Preset name not found within published preset config (wrongpreset:invalid-preset)' ); - expect(e.validationMessage).toBeUndefined(); + expect(e!.validationMessage).toBeUndefined(); }); it('throws if path + invalid syntax', async () => { config.foo = 1; config.extends = ['github>user/repo//']; - let e: Error; + let e: Error | undefined; try { await presets.resolveConfigPresets(config); } catch (err) { e = err; } expect(e).toBeDefined(); - expect(e.validationSource).toBeUndefined(); - expect(e.validationError).toBe('Preset is invalid (github>user/repo//)'); - expect(e.validationMessage).toBeUndefined(); + expect(e!.validationSource).toBeUndefined(); + expect(e!.validationError).toBe('Preset is invalid (github>user/repo//)'); + expect(e!.validationMessage).toBeUndefined(); }); it('throws if path + sub-preset', async () => { config.foo = 1; config.extends = ['github>user/repo//path:subpreset']; - let e: Error; + let e: Error | undefined; try { await presets.resolveConfigPresets(config); } catch (err) { e = err; } expect(e).toBeDefined(); - expect(e.validationSource).toBeUndefined(); - expect(e.validationError).toBe( + expect(e!.validationSource).toBeUndefined(); + expect(e!.validationError).toBe( 'Sub-presets cannot be combined with a custom path (github>user/repo//path:subpreset)' ); - expect(e.validationMessage).toBeUndefined(); + expect(e!.validationMessage).toBeUndefined(); }); it('throws if invalid preset json', async () => { config.foo = 1; config.extends = ['org/repo']; - let e: Error; + let e: Error | undefined; local.getPreset.mockRejectedValueOnce(new Error(PRESET_INVALID_JSON)); try { await presets.resolveConfigPresets(config); @@ -131,43 +134,43 @@ describe('config/presets/index', () => { e = err; } expect(e).toBeDefined(); - expect(e.validationSource).toBeUndefined(); - expect(e.validationError).toBe('Preset is invalid JSON (org/repo)'); - expect(e.validationMessage).toBeUndefined(); + expect(e!.validationSource).toBeUndefined(); + expect(e!.validationError).toBe('Preset is invalid JSON (org/repo)'); + expect(e!.validationMessage).toBeUndefined(); }); it('throws noconfig', async () => { config.foo = 1; config.extends = ['noconfig:base']; - let e: Error; + let e: Error | undefined; try { await presets.resolveConfigPresets(config); } catch (err) { e = err; } expect(e).toBeDefined(); - expect(e.validationSource).toBeUndefined(); - expect(e.validationError).toBe( + expect(e!.validationSource).toBeUndefined(); + expect(e!.validationError).toBe( 'Preset package is missing a renovate-config entry (noconfig:base)' ); - expect(e.validationMessage).toBeUndefined(); + expect(e!.validationMessage).toBeUndefined(); }); it('throws throw', async () => { config.foo = 1; config.extends = ['throw:base']; - let e: Error; + let e: Error | undefined; try { await presets.resolveConfigPresets(config); } catch (err) { e = err; } expect(e).toBeDefined(); - expect(e.validationSource).toBeUndefined(); - expect(e.validationError).toBe( + expect(e!.validationSource).toBeUndefined(); + expect(e!.validationError).toBe( 'Preset caused unexpected error (throw:base)' ); - expect(e.validationMessage).toBeUndefined(); + expect(e!.validationMessage).toBeUndefined(); }); it('works with valid', async () => { @@ -186,18 +189,18 @@ describe('config/presets/index', () => { it('throws if valid and invalid', async () => { config.foo = 1; config.extends = ['wrongpreset:invalid-preset', ':pinVersions']; - let e: Error; + let e: Error | undefined; try { await presets.resolveConfigPresets(config); } catch (err) { e = err; } expect(e).toBeDefined(); - expect(e.validationSource).toBeUndefined(); - expect(e.validationError).toBe( + expect(e!.validationSource).toBeUndefined(); + expect(e!.validationError).toBe( 'Preset name not found within published preset config (wrongpreset:invalid-preset)' ); - expect(e.validationMessage).toBeUndefined(); + expect(e!.validationMessage).toBeUndefined(); }); it('combines two package alls', async () => { @@ -248,7 +251,7 @@ describe('config/presets/index', () => { config.extends = [':automergeLinters']; const res = await presets.resolveConfigPresets(config); expect(res).toMatchSnapshot(); - const rule = res.packageRules[0]; + const rule = res.packageRules![0]; expect(rule.automerge).toBeTrue(); expect(rule.matchPackageNames).toHaveLength(4); expect(rule.matchPackagePatterns).toHaveLength(1); @@ -260,7 +263,7 @@ describe('config/presets/index', () => { const res = await presets.resolveConfigPresets(config); expect(res).toMatchSnapshot(); expect(res.automerge).toBeUndefined(); - expect(res.minor.automerge).toBeTrue(); + expect(res.minor!.automerge).toBeTrue(); }); it('ignores presets', async () => { @@ -832,55 +835,55 @@ Object { }); it('handles 404 packages', async () => { - let e: Error; + let e: Error | undefined; try { await presets.getPreset('notfound:foo', {}); } catch (err) { e = err; } expect(e).toBeDefined(); - expect(e.validationSource).toMatchSnapshot(); - expect(e.validationError).toMatchSnapshot(); - expect(e.validationMessage).toMatchSnapshot(); + expect(e!.validationSource).toMatchSnapshot(); + expect(e!.validationError).toMatchSnapshot(); + expect(e!.validationMessage).toMatchSnapshot(); }); it('handles no config', async () => { - let e: Error; + let e: Error | undefined; try { await presets.getPreset('noconfig:foo', {}); } catch (err) { e = err; } expect(e).toBeDefined(); - expect(e.validationSource).toBeUndefined(); - expect(e.validationError).toBeUndefined(); - expect(e.validationMessage).toBeUndefined(); + expect(e!.validationSource).toBeUndefined(); + expect(e!.validationError).toBeUndefined(); + expect(e!.validationMessage).toBeUndefined(); }); it('handles throw errors', async () => { - let e: Error; + let e: Error | undefined; try { await presets.getPreset('throw:foo', {}); } catch (err) { e = err; } expect(e).toBeDefined(); - expect(e.validationSource).toBeUndefined(); - expect(e.validationError).toBeUndefined(); - expect(e.validationMessage).toBeUndefined(); + expect(e!.validationSource).toBeUndefined(); + expect(e!.validationError).toBeUndefined(); + expect(e!.validationMessage).toBeUndefined(); }); it('handles preset not found', async () => { - let e: Error; + let e: Error | undefined; try { await presets.getPreset('wrongpreset:foo', {}); } catch (err) { e = err; } expect(e).toBeDefined(); - expect(e.validationSource).toBeUndefined(); - expect(e.validationError).toBeUndefined(); - expect(e.validationMessage).toBeUndefined(); + expect(e!.validationSource).toBeUndefined(); + expect(e!.validationError).toBeUndefined(); + expect(e!.validationMessage).toBeUndefined(); }); }); }); diff --git a/lib/config/presets/index.ts b/lib/config/presets/index.ts index 04d1b0e84569c0b74d6d1c5762a249227bbed69f..53ad6987beb80f544b1bfb26036a01281fb68741 100644 --- a/lib/config/presets/index.ts +++ b/lib/config/presets/index.ts @@ -44,6 +44,29 @@ const gitPresetRegex = regEx( /^(?<repo>~?[\w\-. /]+)(?::(?<presetName>[\w\-.+/]+))?(?:#(?<tag>[\w\-./]+?))?$/ ); +export function replaceArgs( + obj: string, + argMapping: Record<string, any> +): string; +export function replaceArgs( + obj: string[], + argMapping: Record<string, any> +): string[]; +export function replaceArgs( + obj: Record<string, any>, + argMapping: Record<string, any> +): Record<string, any>; +export function replaceArgs( + obj: Record<string, any>[], + argMapping: Record<string, any> +): Record<string, any>[]; + +/** + * TODO: fix me #7154 + * @param obj + * @param argMapping + */ +export function replaceArgs(obj: any, argMapping: Record<string, any>): any; export function replaceArgs( obj: string | string[] | Record<string, any> | Record<string, any>[], argMapping: Record<string, any> @@ -64,7 +87,7 @@ export function replaceArgs( return returnArray; } if (is.object(obj)) { - const returnObj = {}; + const returnObj: Record<string, any> = {}; for (const [key, val] of Object.entries(obj)) { returnObj[key] = replaceArgs(val, argMapping); } @@ -75,12 +98,12 @@ export function replaceArgs( export function parsePreset(input: string): ParsedPreset { let str = input; - let presetSource: string; + let presetSource: string | undefined; let presetPath: string | undefined; let repo: string; let presetName: string; let tag: string | undefined; - let params: string[]; + let params: string[] | undefined; if (str.startsWith('github>')) { presetSource = 'github'; str = str.substring('github>'.length); @@ -101,7 +124,7 @@ export function parsePreset(input: string): ParsedPreset { presetSource = 'local'; } str = str.replace(regEx(/^npm>/), ''); - presetSource = presetSource || 'npm'; + presetSource = presetSource ?? 'npm'; if (str.includes('(')) { params = str .slice(str.indexOf('(') + 1, -1) @@ -137,7 +160,7 @@ export function parsePreset(input: string): ParsedPreset { presetName = str.slice(1); } else if (str.startsWith('@')) { // scoped namespace - [, repo] = regEx(/(@.*?)(:|$)/).exec(str); + [, repo] = regEx(/(@.*?)(:|$)/).exec(str)!; str = str.slice(repo.length); if (!repo.includes('/')) { repo += '/renovate-config'; @@ -207,7 +230,7 @@ export async function getPreset( } logger.trace({ presetConfig }, `Found preset ${preset}`); if (params) { - const argMapping = {}; + const argMapping: Record<string, string> = {}; for (const [index, value] of params.entries()) { argMapping[`arg${index}`] = value; } diff --git a/lib/config/presets/internal/index.spec.ts b/lib/config/presets/internal/index.spec.ts index 012c95ca7feeebee919c8c5b7b9ceb10281321c6..e33a64f449dd82036ac569575ec76203d2044ec1 100644 --- a/lib/config/presets/internal/index.spec.ts +++ b/lib/config/presets/internal/index.spec.ts @@ -1,16 +1,14 @@ -import { mocked } from '../../../../test/util'; +import { resolveConfigPresets } from '../'; import { CONFIG_VALIDATION } from '../../../constants/error-messages'; import { massageConfig } from '../../massage'; import { validateConfig } from '../../validation'; -import { resolveConfigPresets } from '../index'; -import * as _npm from '../npm'; +import * as npm from '../npm'; import * as internal from '.'; jest.mock('./npm'); jest.mock('../../../modules/datasource/npm'); -const npm = mocked(_npm); -npm.getPreset = jest.fn((_) => null); +jest.spyOn(npm, 'getPreset').mockResolvedValue(undefined); const ignoredPresets = ['default:group', 'default:timezone']; diff --git a/lib/config/presets/local/common.ts b/lib/config/presets/local/common.ts index a273aa313f5f7e46a18cffffdcee2ba86ac0fa23..9c4560084501f95976bddddca010daabb7e8c6ea 100644 --- a/lib/config/presets/local/common.ts +++ b/lib/config/presets/local/common.ts @@ -11,9 +11,9 @@ import { export async function fetchJSONFile( repo: string, fileName: string, - _endpoint: string = null + _endpoint?: string ): Promise<Preset> { - let raw: string; + let raw: string | null; try { raw = await platform.getRawFile(fileName, repo); } catch (err) { @@ -31,7 +31,9 @@ export async function fetchJSONFile( } try { - return JSON.parse(raw); + // TODO: null check #7154 + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + return JSON.parse(raw!); } catch (err) { throw new Error(PRESET_INVALID_JSON); } @@ -40,14 +42,16 @@ export async function fetchJSONFile( export function getPresetFromEndpoint( repo: string, filePreset: string, - presetPath: string, - endpoint: string -): Promise<Preset> { + presetPath: string | undefined, + endpoint: string, + tag?: string | null +): Promise<Preset | undefined> { return fetchPreset({ repo, filePreset, presetPath, endpoint, + tag, fetch: fetchJSONFile, }); } diff --git a/lib/config/presets/local/index.ts b/lib/config/presets/local/index.ts index a00c2ce1f81709f20dade11906042dd4e4d1987a..57aff34349d9bdc47c280b10191d4325168d527f 100644 --- a/lib/config/presets/local/index.ts +++ b/lib/config/presets/local/index.ts @@ -14,7 +14,7 @@ const resolvers = { [PlatformId.Gitea]: gitea, [PlatformId.Github]: github, [PlatformId.Gitlab]: gitlab, -}; +} as const; export function getPreset({ repo, @@ -22,22 +22,26 @@ export function getPreset({ presetPath, tag, baseConfig, -}: PresetConfig): Promise<Preset> { - const { platform, endpoint } = baseConfig; +}: PresetConfig): Promise<Preset | undefined> { + const { platform, endpoint } = baseConfig ?? {}; if (!platform) { throw new Error(`Missing platform config for local preset.`); } - const resolver = resolvers[platform.toLowerCase()]; + const resolver = resolvers[platform.toLowerCase() as PlatformId]; if (!resolver) { throw new Error( - `Unsupported platform '${baseConfig.platform}' for local preset.` + // TODO: can be undefined? #7154 + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + `Unsupported platform '${baseConfig!.platform}' for local preset.` ); } return resolver.getPresetFromEndpoint( repo, presetName, presetPath, - endpoint, + // TODO: fix type #7154 + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + endpoint!, tag ); } diff --git a/lib/config/presets/npm/index.ts b/lib/config/presets/npm/index.ts index d78e5dd3b8628f0538a74f9dc9084cd39e5d536e..4cff9788cbbf961819658b04b6edd2bdec8be9ec 100644 --- a/lib/config/presets/npm/index.ts +++ b/lib/config/presets/npm/index.ts @@ -3,7 +3,10 @@ import { resolvePackageUrl, resolveRegistryUrl, } from '../../../modules/datasource/npm/npmrc'; -import type { NpmResponse } from '../../../modules/datasource/npm/types'; +import type { + NpmResponse, + NpmResponseVersion, +} from '../../../modules/datasource/npm/types'; import { Http } from '../../../util/http'; import type { Preset, PresetConfig } from '../types'; import { @@ -19,8 +22,8 @@ const http = new Http(id); export async function getPreset({ repo: pkg, presetName = 'default', -}: PresetConfig): Promise<Preset> { - let dep; +}: PresetConfig): Promise<Preset | undefined> { + let dep: (NpmResponseVersion & { 'renovate-config'?: any }) | undefined; try { const registryUrl = resolveRegistryUrl(pkg); const packageUrl = resolvePackageUrl(registryUrl, pkg); @@ -31,7 +34,9 @@ export async function getPreset({ ); } const body = (await http.getJson<NpmResponse>(packageUrl)).body; - dep = body.versions[body['dist-tags']?.latest]; + // TODO: check null #7154 + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + dep = body.versions![body['dist-tags']!.latest]; } catch (err) { throw new Error(PRESET_DEP_NOT_FOUND); } diff --git a/lib/config/presets/types.ts b/lib/config/presets/types.ts index 24c4159dffbe2efcd1bf735636e78ee7d00f4f0d..ce920d8f9a10215d286f7ae7b049b3eb86d78695 100644 --- a/lib/config/presets/types.ts +++ b/lib/config/presets/types.ts @@ -12,7 +12,9 @@ export type PresetConfig = { }; export interface PresetApi { - getPreset(config: PresetConfig): Promise<Preset> | Preset; + getPreset( + config: PresetConfig + ): Promise<Preset | null | undefined> | Preset | null | undefined; } export interface ParsedPreset { @@ -28,14 +30,14 @@ export type PresetFetcher = ( repo: string, fileName: string, endpoint: string, - tag?: string -) => Promise<Preset>; + tag?: string | null +) => Promise<Preset | null | undefined>; export type FetchPresetConfig = { repo: string; filePreset: string; presetPath?: string; endpoint: string; - tag?: string; + tag?: string | null; fetch: PresetFetcher; }; diff --git a/lib/config/presets/util.spec.ts b/lib/config/presets/util.spec.ts index 93c1fc6b73a937951235930cc92378765071cc64..1f522fa6be7049dc2027a5a092695b39db9bfbc0 100644 --- a/lib/config/presets/util.spec.ts +++ b/lib/config/presets/util.spec.ts @@ -5,10 +5,10 @@ const config: FetchPresetConfig = { repo: 'some/repo', filePreset: 'default', endpoint: 'endpoint', - fetch: undefined, + fetch: undefined as never, }; -const fetch = jest.fn(() => Promise.resolve<Preset>({})); +const fetch = jest.fn(() => Promise.resolve<Preset | null>({})); describe('config/presets/util', () => { beforeEach(() => { diff --git a/lib/config/presets/util.ts b/lib/config/presets/util.ts index c3deaf415f5d43ae681e3bbe0c5402f92b1756e9..d9a6a9d0d5cd92c1e4ba721b22fc476f78f88f9d 100644 --- a/lib/config/presets/util.ts +++ b/lib/config/presets/util.ts @@ -18,7 +18,9 @@ export async function fetchPreset({ tag = null, fetch, }: FetchPresetConfig): Promise<Preset | undefined> { - const endpoint = ensureTrailingSlash(_endpoint); + // TODO: fix me, can be undefiend #7154 + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + const endpoint = ensureTrailingSlash(_endpoint!); const [fileName, presetName, subPresetName] = filePreset.split('/'); const pathPrefix = presetPath ? `${presetPath}/` : ''; const buildFilePath = (name: string): string => `${pathPrefix}${name}`; diff --git a/lib/config/secrets.spec.ts b/lib/config/secrets.spec.ts index ea5b1b10c8b5a46b37a2ff4eb383a5c9aa46eb50..e937dc5151c4ee9328bf09e7547066fa2da832f2 100644 --- a/lib/config/secrets.spec.ts +++ b/lib/config/secrets.spec.ts @@ -174,7 +174,8 @@ describe('config/secrets', () => { secrets: { SECRET_MANAGER: 'npm' }, allowedManagers: ['{{ secrets.SECRET_MANAGER }}'], }; - expect(() => applySecretsToConfig(config, null, false)).toThrow( + // TODO fix me? #7154 + expect(() => applySecretsToConfig(config, null as never, false)).toThrow( CONFIG_VALIDATION ); }); diff --git a/lib/config/types.ts b/lib/config/types.ts index bd1dfa9efd7953e4eb2b5b876a8a1118a0e66644..6d8b7c7cc39a58cf8f2e30a434234d3913750c99 100644 --- a/lib/config/types.ts +++ b/lib/config/types.ts @@ -26,7 +26,7 @@ export interface RenovateSharedConfig { pruneBranchAfterAutomerge?: boolean; branchPrefix?: string; branchName?: string; - manager?: string; + manager?: string | null; commitMessage?: string; commitMessagePrefix?: string; confidential?: boolean; @@ -145,7 +145,7 @@ export type PostUpgradeTasks = { }; type UpdateConfig<T extends RenovateSharedConfig = RenovateSharedConfig> = - Partial<Record<UpdateType, T>>; + Partial<Record<UpdateType, T | null>>; export type RenovateRepository = | string @@ -328,7 +328,7 @@ export interface RenovateOptionBase { export interface RenovateArrayOption< T extends string | number | Record<string, unknown> = Record<string, unknown> > extends RenovateOptionBase { - default?: T[]; + default?: T[] | null; mergeable?: boolean; type: 'array'; subType?: 'string' | 'object' | 'number'; @@ -350,21 +350,21 @@ export interface RenovateNumberArrayOption extends RenovateArrayOption<number> { } export interface RenovateBooleanOption extends RenovateOptionBase { - default?: boolean; + default?: boolean | null; type: 'boolean'; supportedManagers?: string[] | 'all'; supportedPlatforms?: string[] | 'all'; } export interface RenovateIntegerOption extends RenovateOptionBase { - default?: number; + default?: number | null; type: 'integer'; supportedManagers?: string[] | 'all'; supportedPlatforms?: string[] | 'all'; } export interface RenovateStringOption extends RenovateOptionBase { - default?: string; + default?: string | null; format?: 'regex'; // Not used @@ -375,7 +375,7 @@ export interface RenovateStringOption extends RenovateOptionBase { } export interface RenovateObjectOption extends RenovateOptionBase { - default?: any; + default?: any | null; additionalProperties?: Record<string, unknown> | boolean; mergeable?: boolean; type: 'object'; @@ -423,6 +423,7 @@ export interface MigratedRenovateConfig extends RenovateConfig { node?: RenovateConfig; travis?: RenovateConfig; + gradle?: RenovateConfig; } export interface ValidationResult { diff --git a/lib/config/utils.ts b/lib/config/utils.ts index f6a96e1c95f77c3d5ce85ee44756bdf592165123..4c891e21c14bd76b4eb5a14dbb28b53f1a38bbef 100644 --- a/lib/config/utils.ts +++ b/lib/config/utils.ts @@ -3,16 +3,17 @@ import { clone } from '../util/clone'; import * as options from './options'; import type { RenovateConfig } from './types'; -export function mergeChildConfig<T, TChild>( - parent: T, - child: TChild -): T & TChild { +export function mergeChildConfig< + T extends Record<string, any>, + TChild extends Record<string, any> | undefined +>(parent: T, child: TChild): T & TChild { logger.trace({ parent, child }, `mergeChildConfig`); if (!child) { return parent as never; } const parentConfig = clone(parent); - const childConfig = clone(child); + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + const childConfig = clone(child!); const config: Record<string, any> = { ...parentConfig, ...childConfig }; for (const option of options.getOptions()) { if ( diff --git a/lib/config/validation.ts b/lib/config/validation.ts index 912e887f6281213fbf0dcee3c7c9768e15766e30..1ca4e9157eac6998507f064cfa005f58ecd5d518 100644 --- a/lib/config/validation.ts +++ b/lib/config/validation.ts @@ -77,8 +77,8 @@ function getUnsupportedEnabledManagers(enabledManagers: string[]): string[] { ); } -function getDeprecationMessage(option: string): string { - const deprecatedOptions = { +function getDeprecationMessage(option: string): string | undefined { + const deprecatedOptions: Record<string, string | undefined> = { branchName: `Direct editing of branchName is now deprecated. Please edit branchPrefix, additionalBranchPrefix, or branchTopic instead`, commitMessage: `Direct editing of commitMessage is now deprecated. Please edit commitMessage's subcomponents instead.`, prTitle: `Direct editing of prTitle is now deprecated. Please edit commitMessage subcomponents instead as they will be passed through to prTitle.`, @@ -86,13 +86,13 @@ function getDeprecationMessage(option: string): string { return deprecatedOptions[option]; } -export function getParentName(parentPath: string): string { +export function getParentName(parentPath: string | undefined): string { return parentPath ? parentPath .replace(regEx(/\.?encrypted$/), '') .replace(regEx(/\[\d+\]$/), '') .split('.') - .pop() + .pop()! : '.'; } @@ -167,7 +167,7 @@ export async function validateConfig( if (getDeprecationMessage(key)) { warnings.push({ topic: 'Deprecation Warning', - message: getDeprecationMessage(key), + message: getDeprecationMessage(key)!, }); } const templateKeys = [ @@ -179,7 +179,8 @@ export async function validateConfig( ]; if ((key.endsWith('Template') || templateKeys.includes(key)) && val) { try { - let res = template.compile(val.toString(), config, false); + // TODO: validate string #7154 + let res = template.compile((val as string).toString(), config, false); res = template.compile(res, config, false); template.compile(res, config, false); } catch (err) { @@ -278,7 +279,7 @@ export async function validateConfig( }); } if (tzRe.test(subval)) { - const [, timezone] = tzRe.exec(subval); + const [, timezone] = tzRe.exec(subval)!; const [validTimezone, errorMessage] = hasValidTimezone(timezone); if (!validTimezone) { @@ -319,6 +320,7 @@ export async function validateConfig( if (key === 'packageRules') { for (const [subIndex, packageRule] of val.entries()) { if (is.object(packageRule)) { + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion const resolvedRule = migrateConfig({ packageRules: [ await resolveConfigPresets( @@ -326,7 +328,7 @@ export async function validateConfig( config ), ], - }).migratedConfig.packageRules[0]; + }).migratedConfig.packageRules![0]; errors.push( ...managerValidator.check({ resolvedRule, currentPath }) ); @@ -404,7 +406,7 @@ export async function validateConfig( 'autoReplaceStringTemplate', 'depTypeTemplate', ]; - // TODO: fix types + // TODO: fix types #7154 for (const regexManager of val as any[]) { if ( Object.keys(regexManager).some( @@ -445,8 +447,9 @@ export async function validateConfig( for (const field of mandatoryFields) { if ( !regexManager[`${field}Template`] && - !regexManager.matchStrings.some((matchString) => - matchString.includes(`(?<${field}>`) + !regexManager.matchStrings.some( + (matchString: string) => + matchString.includes(`(?<${field}>`) ) ) { errors.push({ @@ -501,7 +504,9 @@ export async function validateConfig( } if ( (selectors.includes(key) || key === 'matchCurrentVersion') && - !rulesRe.test(parentPath) && // Inside a packageRule + // TODO: can be undefined ? #7154 + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + !rulesRe.test(parentPath!) && // Inside a packageRule (parentPath || !isPreset) // top level in a preset ) { errors.push({ diff --git a/lib/modules/platform/azure/index.spec.ts b/lib/modules/platform/azure/index.spec.ts index 555d01016bd30af19c3fabb6bc286e30c342ab1c..d5466a0af4f4ec669376c2ccfa3995abe60f290f 100644 --- a/lib/modules/platform/azure/index.spec.ts +++ b/lib/modules/platform/azure/index.spec.ts @@ -920,7 +920,8 @@ describe('modules/platform/azure/index', () => { }); describe('ensureCommentRemoval', () => { - let gitApiMock; + // TODO: fix types #7154 + let gitApiMock: any; beforeEach(() => { gitApiMock = { diff --git a/lib/modules/platform/azure/util.spec.ts b/lib/modules/platform/azure/util.spec.ts index 85a7395ae278276c471f1e1f5bc1dd1e61116c0f..0516a3128f4cc13cef6228255f09fc419de5e605 100644 --- a/lib/modules/platform/azure/util.spec.ts +++ b/lib/modules/platform/azure/util.spec.ts @@ -235,8 +235,9 @@ describe('modules/platform/azure/util', () => { }); it('throws when repo name is invalid', () => { - expect(() => getRepoByName(undefined, [])).toThrow(); - expect(() => getRepoByName(null, [])).toThrow(); + // TODO: better error handling #7154 + expect(() => getRepoByName(undefined as never, [])).toThrow(); + expect(() => getRepoByName(null as never, [])).toThrow(); expect(() => getRepoByName('foo/bar/baz', [])).toThrow(); }); }); diff --git a/lib/modules/platform/azure/util.ts b/lib/modules/platform/azure/util.ts index 0730431b7c940a68f84cd50c27f7fb9a2a44063a..a235fff75ab7db7068bfe087e2036e3a0ebc6ec4 100644 --- a/lib/modules/platform/azure/util.ts +++ b/lib/modules/platform/azure/util.ts @@ -32,7 +32,7 @@ export function getGitStatusContextCombinedName( } export function getGitStatusContextFromCombinedName( - context: string + context: string | undefined | null ): GitStatusContext | undefined { if (!context) { return undefined; @@ -182,7 +182,7 @@ export function getProjectAndRepo(str: string): { export function getRepoByName( name: string, - repos: GitRepository[] + repos: (GitRepository | null | undefined)[] | undefined | null ): GitRepository | null { logger.trace(`getRepoByName(${name})`); diff --git a/lib/modules/platform/bitbucket-server/index.spec.ts b/lib/modules/platform/bitbucket-server/index.spec.ts index 35940110fac325abc6d4c8a4b9308d414de594d1..4883352ff9648c32dfa506f9b3efcbe79fa351be 100644 --- a/lib/modules/platform/bitbucket-server/index.spec.ts +++ b/lib/modules/platform/bitbucket-server/index.spec.ts @@ -1181,7 +1181,7 @@ describe('modules/platform/bitbucket-server/index', () => { ) .reply(200, prMock(url, 'SOME', 'repo')); - const { number: id } = await bitbucket.createPr({ + const pr = await bitbucket.createPr({ sourceBranch: 'branch', targetBranch: 'master', prTitle: 'title', @@ -1190,7 +1190,7 @@ describe('modules/platform/bitbucket-server/index', () => { bbUseDefaultReviewers: true, }, }); - expect(id).toBe(5); + expect(pr?.number).toBe(5); }); it('posts PR default branch', async () => { @@ -1207,7 +1207,7 @@ describe('modules/platform/bitbucket-server/index', () => { ) .reply(200, prMock(url, 'SOME', 'repo')); - const { number: id } = await bitbucket.createPr({ + const pr = await bitbucket.createPr({ sourceBranch: 'branch', targetBranch: 'master', prTitle: 'title', @@ -1217,7 +1217,7 @@ describe('modules/platform/bitbucket-server/index', () => { bbUseDefaultReviewers: true, }, }); - expect(id).toBe(5); + expect(pr?.number).toBe(5); }); }); diff --git a/lib/modules/platform/bitbucket/index.spec.ts b/lib/modules/platform/bitbucket/index.spec.ts index 6d8d1f712fc60f913a86bbc477ce75b041c6d525..306a5d385f834f8aef708501d63912d4a3ff0f0c 100644 --- a/lib/modules/platform/bitbucket/index.spec.ts +++ b/lib/modules/platform/bitbucket/index.spec.ts @@ -615,7 +615,7 @@ describe('modules/platform/bitbucket/index', () => { const scope = httpMock.scope(baseUrl); scope.get('/2.0/user').reply(200, { uuid: '12345' }); await bitbucket.initPlatform({ username: 'renovate', password: 'pass' }); - await initRepoMock(null, null, scope); + await initRepoMock(undefined, null, scope); scope .get( '/2.0/repositories/some/repo/pullrequests?state=OPEN&state=MERGED&state=DECLINED&state=SUPERSEDED&q=author.uuid="12345"&pagelen=50' @@ -666,7 +666,7 @@ describe('modules/platform/bitbucket/index', () => { }) .post('/2.0/repositories/some/repo/pullrequests') .reply(200, { id: 5 }); - const { number } = await bitbucket.createPr({ + const pr = await bitbucket.createPr({ sourceBranch: 'branch', targetBranch: 'master', prTitle: 'title', @@ -675,7 +675,7 @@ describe('modules/platform/bitbucket/index', () => { bbUseDefaultReviewers: true, }, }); - expect(number).toBe(5); + expect(pr?.number).toBe(5); }); it('removes inactive reviewers when updating pr', async () => { @@ -715,7 +715,7 @@ describe('modules/platform/bitbucket/index', () => { }) .post('/2.0/repositories/some/repo/pullrequests') .reply(200, { id: 5 }); - const { number } = await bitbucket.createPr({ + const pr = await bitbucket.createPr({ sourceBranch: 'branch', targetBranch: 'master', prTitle: 'title', @@ -724,7 +724,7 @@ describe('modules/platform/bitbucket/index', () => { bbUseDefaultReviewers: true, }, }); - expect(number).toBe(5); + expect(pr?.number).toBe(5); }); it('removes default reviewers no longer member of the workspace when creating pr', async () => { @@ -767,7 +767,7 @@ describe('modules/platform/bitbucket/index', () => { .reply(200) .post('/2.0/repositories/some/repo/pullrequests') .reply(200, { id: 5 }); - const { number } = await bitbucket.createPr({ + const pr = await bitbucket.createPr({ sourceBranch: 'branch', targetBranch: 'master', prTitle: 'title', @@ -776,7 +776,7 @@ describe('modules/platform/bitbucket/index', () => { bbUseDefaultReviewers: true, }, }); - expect(number).toBe(5); + expect(pr?.number).toBe(5); }); it('throws exception when unable to check default reviewers workspace membership', async () => { diff --git a/lib/modules/platform/bitbucket/utils.spec.ts b/lib/modules/platform/bitbucket/utils.spec.ts index 99b81a95af62512bf79621175f864f0ccb1bb20c..9506ef1503b0efb21a3017ce81f0997d484659b8 100644 --- a/lib/modules/platform/bitbucket/utils.spec.ts +++ b/lib/modules/platform/bitbucket/utils.spec.ts @@ -29,7 +29,7 @@ describe('modules/platform/bitbucket/utils', () => { values: range(5), }); - const res = await utils.accumulateValues('some-url', 'get', null, 10); + const res = await utils.accumulateValues('some-url', 'get', undefined, 10); expect(res).toHaveLength(25); }); }); diff --git a/lib/modules/platform/gitea/gitea-helper.ts b/lib/modules/platform/gitea/gitea-helper.ts index adaa53a985957e6aef99a9a048d13e3403982c34..f51167c5232230b3f9db15a0f8bac8bc1bd1b81d 100644 --- a/lib/modules/platform/gitea/gitea-helper.ts +++ b/lib/modules/platform/gitea/gitea-helper.ts @@ -245,7 +245,7 @@ export async function getRepo( export async function getRepoContents( repoPath: string, filePath: string, - ref?: string, + ref?: string | null, options?: GiteaHttpOptions ): Promise<RepoContents> { const query = getQueryString(ref ? { ref } : {}); diff --git a/lib/modules/platform/github/index.spec.ts b/lib/modules/platform/github/index.spec.ts index 573e9c5fdeb66bac7d8051467e1150232be1a022..d63167080a8260ae18380ddf6da374d3c79fe7eb 100644 --- a/lib/modules/platform/github/index.spec.ts +++ b/lib/modules/platform/github/index.spec.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-unnecessary-type-assertion */ import { DateTime } from 'luxon'; import * as httpMock from '../../../../test/http-mock'; import { logger, mocked } from '../../../../test/util'; @@ -677,14 +678,15 @@ describe('modules/platform/github/index', () => { await github.initRepo({ repository: 'some/repo' } as never); await github.getPrList(); - const cache = repository.getCache().platform.github + const cache = repository.getCache().platform!.github! .prCache as ApiPageCache<GhRestPr>; const item = cache.items['1']; expect(item['_links']).toBeUndefined(); - expect(item['url']).toBeUndefined(); - expect(item['example_url']).toBeUndefined(); - expect(item['repo']['example_url']).toBeUndefined(); + // TODO: fix types #7154 + expect((item as any)['url']).toBeUndefined(); + expect((item as any)['example_url']).toBeUndefined(); + expect((item as any)['repo']['example_url']).toBeUndefined(); }); it('removes url data from existing cache', async () => { @@ -717,7 +719,8 @@ describe('modules/platform/github/index', () => { expect(item['_links']).toBeUndefined(); expect(item['url']).toBeUndefined(); - expect(item['example_url']).toBeUndefined(); + // TODO: fix types #7154 + expect((item as any)['example_url']).toBeUndefined(); expect(item['repo']['example_url']).toBeUndefined(); }); }); diff --git a/lib/modules/platform/types.ts b/lib/modules/platform/types.ts index 8a984c41e8a5e7343f42c49212d58f9d630d4415..e6de7e8852e34ab9ea788b904b9475b0c6cdba8a 100644 --- a/lib/modules/platform/types.ts +++ b/lib/modules/platform/types.ts @@ -180,7 +180,8 @@ export interface Platform { setBranchStatus(branchStatusConfig: BranchStatusConfig): Promise<void>; getBranchStatusCheck( branchName: string, - context: string + // TODO: can be undefined or null ? #7154 + context: string | null | undefined ): Promise<BranchStatus | null>; ensureCommentRemoval( ensureCommentRemoval: diff --git a/lib/workers/repository/update/pr/changelog/github/index.ts b/lib/workers/repository/update/pr/changelog/github/index.ts index 9d6675ca414ea42bfb5bbd07dd3c60dd6ca6a00d..4ced3f393b1c193ad927fa08bcf2f5830e2290c5 100644 --- a/lib/workers/repository/update/pr/changelog/github/index.ts +++ b/lib/workers/repository/update/pr/changelog/github/index.ts @@ -51,7 +51,7 @@ export async function getReleaseNotesMd( repository: string, apiBaseUrl: string, sourceDirectory: string -): Promise<ChangeLogFile> | null { +): Promise<ChangeLogFile | null> { logger.trace('github.getReleaseNotesMd()'); const apiPrefix = `${ensureTrailingSlash(apiBaseUrl)}repos/${repository}`; const { default_branch: defaultBranch = 'HEAD' } = ( @@ -88,7 +88,7 @@ export async function getReleaseNotesMd( logger.trace('no changelog file found'); return null; } - const { path: changelogFile, sha } = files.shift(); + const { path: changelogFile, sha } = files.shift()!; /* istanbul ignore if */ if (files.length !== 0) { logger.debug( diff --git a/lib/workers/repository/update/pr/changelog/gitlab/index.ts b/lib/workers/repository/update/pr/changelog/gitlab/index.ts index 34cc7e1126a54efb81b1c243d7c89df4b51cceb6..d20be75218d91839bd057d75519111a29e56408c 100644 --- a/lib/workers/repository/update/pr/changelog/gitlab/index.ts +++ b/lib/workers/repository/update/pr/changelog/gitlab/index.ts @@ -49,7 +49,7 @@ export async function getReleaseNotesMd( repository: string, apiBaseUrl: string, sourceDirectory?: string -): Promise<ChangeLogFile> | null { +): Promise<ChangeLogFile | null> { logger.trace('gitlab.getReleaseNotesMd()'); const urlEncodedRepo = encodeURIComponent(repository); const apiPrefix = `${ensureTrailingSlash( @@ -76,7 +76,7 @@ export async function getReleaseNotesMd( logger.trace('no changelog file found'); return null; } - const { path: changelogFile, id } = files.shift(); + const { path: changelogFile, id } = files.shift()!; /* istanbul ignore if */ if (files.length !== 0) { logger.debug( diff --git a/test/website-docs.spec.ts b/test/website-docs.spec.ts index 436c0836bf7d5149bbc858ae037d36209dbc52cc..98195ba353ce3be833f828abe60bbdb239e2cb7d 100644 --- a/test/website-docs.spec.ts +++ b/test/website-docs.spec.ts @@ -1,4 +1,6 @@ +/* eslint-disable @typescript-eslint/no-unnecessary-type-assertion */ import fs from 'fs'; +import is from '@sindresorhus/is'; import { getOptions } from '../lib/config/options'; declare global { @@ -26,10 +28,10 @@ describe('website-docs', () => { ); const headers = doc .match(/\n## (.*?)\n/g) - .map((match) => match.substring(4, match.length - 1)); + ?.map((match) => match.substring(4, match.length - 1)); const selfHostHeaders = selfHostDoc .match(/\n## (.*?)\n/g) - .map((match) => match.substring(4, match.length - 1)); + ?.map((match) => match.substring(4, match.length - 1)); const expectedOptions = options .filter((option) => option.stage !== 'global') .filter((option) => option.releaseStatus !== 'unpublished') @@ -45,7 +47,7 @@ describe('website-docs', () => { .sort(); it('has doc headers sorted alphabetically', () => { - expect(headers).toEqual([...headers].sort()); + expect(headers).toEqual([...headers!].sort()); }); it('has headers for every required option', () => { @@ -53,7 +55,7 @@ describe('website-docs', () => { }); it('has self hosted doc headers sorted alphabetically', () => { - expect(selfHostHeaders).toEqual([...selfHostHeaders].sort()); + expect(selfHostHeaders).toEqual([...selfHostHeaders!].sort()); }); it('has headers (self hosted) for every required option', () => { @@ -62,8 +64,8 @@ describe('website-docs', () => { const headers3 = doc .match(/\n### (.*?)\n/g) - .map((match) => match.substring(5, match.length - 1)); - headers3.sort(); + ?.map((match) => match.substring(5, match.length - 1)); + headers3!.sort(); const expectedOptions3 = options .filter((option) => option.stage !== 'global') .filter((option) => !option.globalOnly) @@ -78,11 +80,11 @@ describe('website-docs', () => { // Checking relatedOptions field in options const relatedOptionsMatrix = options - .filter((option) => option.relatedOptions) .map((option) => option.relatedOptions) + .filter(is.truthy) .sort(); - let relatedOptions: string[] = [].concat(...relatedOptionsMatrix); // Converts the matrix to an 1D array + let relatedOptions = ([] as string[]).concat(...relatedOptionsMatrix!); // Converts the matrix to an 1D array relatedOptions = [...new Set(relatedOptions)]; // Makes all options unique /* diff --git a/tsconfig.json b/tsconfig.json index c6ffee806cd56de50ae4e69fc1c9bf216106bdd1..8b013189c8dd52ef69619d97eff031867104cff2 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,8 +1,8 @@ { "compilerOptions": { "strict": true, - "noImplicitAny": false /* required for js files */, - "strictNullChecks": false /* required for js files */, + "noImplicitAny": false /* TODO: fix me */, + "strictNullChecks": false /* TODO: fix me */, "outDir": "./dist", /* https://github.com/microsoft/TypeScript/wiki/Node-Target-Mapping */ "target": "es2020", diff --git a/tsconfig.strict.json b/tsconfig.strict.json index 95474e96e967fc20e6c909069ce4ba4b8d7f4be8..6b8ffdfc2135d1d005a09232cdabb8be3ba42272 100644 --- a/tsconfig.strict.json +++ b/tsconfig.strict.json @@ -2,8 +2,7 @@ "extends": "./tsconfig.json", "compilerOptions": { "strictNullChecks": true, - "noImplicitAny": true, - "lib": ["es2020"] + "noImplicitAny": true }, "exclude": [ // tsconfig.json @@ -16,42 +15,13 @@ "tmp", // TODO: fixme - "**/*.spec.ts", - "lib/config-validator.ts", - "lib/config/defaults.ts", - "lib/config/index.ts", - "lib/config/massage.ts", - "lib/config/migrate-validate.ts", - "lib/config/migration.ts", - "lib/config/options/index.ts", - "lib/config/presets/azure/index.ts", - "lib/config/presets/bitbucket-server/index.ts", - "lib/config/presets/bitbucket/index.ts", - "lib/config/presets/gitea/index.ts", - "lib/config/presets/github/index.ts", - "lib/config/presets/gitlab/index.ts", - "lib/config/presets/index.ts", - "lib/config/presets/local/common.ts", - "lib/config/presets/local/index.ts", - "lib/config/presets/npm/index.ts", - "lib/config/presets/util.ts", - "lib/config/utils.ts", - "lib/config/validation.ts", - "lib/modules/datasource/github-releases/test/index.ts", + "lib/util/**/*.spec.ts", + "lib/workers/**/*.spec.ts", + "lib/modules/datasource/**/*.spec.ts", + "lib/modules/manager/**/*.spec.ts", + "lib/modules/versioning/**/*.spec.ts", "lib/renovate.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", - "lib/workers/repository/update/branch/check-existing.ts", - "lib/workers/repository/update/branch/commit.ts", - "lib/workers/repository/update/branch/execute-post-upgrade-commands.ts", - "lib/workers/repository/update/branch/get-updated.ts", - "lib/workers/repository/update/branch/handle-existing.ts", - "lib/workers/repository/update/branch/index.ts", - "lib/workers/repository/update/branch/reuse.ts", - "lib/workers/repository/update/branch/schedule.ts", - "lib/workers/repository/update/branch/status-checks.ts", + "lib/renovate.spec.ts", "lib/workers/global/autodiscover.ts", "lib/workers/global/config/parse/cli.ts", "lib/workers/global/config/parse/env.ts", @@ -60,20 +30,6 @@ "lib/workers/global/config/parse/index.ts", "lib/workers/global/index.ts", "lib/workers/global/initialize.ts", - "lib/workers/repository/update/pr/automerge.ts", - "lib/workers/repository/update/pr/body/changelogs.ts", - "lib/workers/repository/update/pr/body/config-description.ts", - "lib/workers/repository/update/pr/body/controls.ts", - "lib/workers/repository/update/pr/body/index.ts", - "lib/workers/repository/update/pr/changelog/github/index.ts", - "lib/workers/repository/update/pr/changelog/gitlab/index.ts", - "lib/workers/repository/update/pr/changelog/index.ts", - "lib/workers/repository/update/pr/changelog/release-notes.ts", - "lib/workers/repository/update/pr/changelog/releases.ts", - "lib/workers/repository/update/pr/changelog/source-github.ts", - "lib/workers/repository/update/pr/changelog/source-gitlab.ts", - "lib/workers/repository/update/pr/code-owners.ts", - "lib/workers/repository/update/pr/index.ts", "lib/workers/repository/cache.ts", "lib/workers/repository/changelog/index.ts", "lib/workers/repository/dependency-dashboard.ts", @@ -124,11 +80,31 @@ "lib/workers/repository/updates/branchify.ts", "lib/workers/repository/updates/flatten.ts", "lib/workers/repository/updates/generate.ts", - "test/util.ts", - "tools/docs/config.ts", - "tools/docs/platforms.ts", - "tools/docs/schema.ts", - "tools/generate-docs.ts", - "tools/generate-schema.ts" + "lib/workers/repository/update/branch/artifacts.ts", + "lib/workers/repository/update/branch/auto-replace.ts", + "lib/workers/repository/update/branch/automerge.ts", + "lib/workers/repository/update/branch/check-existing.ts", + "lib/workers/repository/update/branch/commit.ts", + "lib/workers/repository/update/branch/execute-post-upgrade-commands.ts", + "lib/workers/repository/update/branch/get-updated.ts", + "lib/workers/repository/update/branch/handle-existing.ts", + "lib/workers/repository/update/branch/index.ts", + "lib/workers/repository/update/branch/reuse.ts", + "lib/workers/repository/update/branch/schedule.ts", + "lib/workers/repository/update/branch/status-checks.ts", + "lib/workers/repository/update/pr/automerge.ts", + "lib/workers/repository/update/pr/body/changelogs.ts", + "lib/workers/repository/update/pr/body/config-description.ts", + "lib/workers/repository/update/pr/body/controls.ts", + "lib/workers/repository/update/pr/body/index.ts", + "lib/workers/repository/update/pr/changelog/github/index.ts", + "lib/workers/repository/update/pr/changelog/gitlab/index.ts", + "lib/workers/repository/update/pr/changelog/index.ts", + "lib/workers/repository/update/pr/changelog/release-notes.ts", + "lib/workers/repository/update/pr/changelog/releases.ts", + "lib/workers/repository/update/pr/changelog/source-github.ts", + "lib/workers/repository/update/pr/changelog/source-gitlab.ts", + "lib/workers/repository/update/pr/code-owners.ts", + "lib/workers/repository/update/pr/index.ts" ] }