From ec32776802dec08d9999dbbee52613b51690db06 Mon Sep 17 00:00:00 2001 From: Nejc Habjan Date: Sun, 14 Nov 2021 11:17:10 +0100 Subject: [PATCH 01/10] feat: parse JSON5/YAML self-hosted admin config --- lib/config-validator.ts | 19 ++++---- .../config/parse/__fixtures__/config.json5 | 4 ++ .../config/parse/__fixtures__/config.yaml | 3 ++ lib/workers/global/config/parse/file.spec.ts | 44 ++++++++++++------- lib/workers/global/config/parse/file.ts | 21 ++++++++- 5 files changed, 63 insertions(+), 28 deletions(-) create mode 100644 lib/workers/global/config/parse/__fixtures__/config.json5 create mode 100644 lib/workers/global/config/parse/__fixtures__/config.yaml diff --git a/lib/config-validator.ts b/lib/config-validator.ts index fadf2c9b4b2021..b491d2872f63ab 100644 --- a/lib/config-validator.ts +++ b/lib/config-validator.ts @@ -2,14 +2,16 @@ // istanbul ignore file import { dequal } from 'dequal'; import { readFileSync } from 'fs-extra'; -import JSON5 from 'json5'; import { configFileNames } from './config/app-strings'; import { massageConfig } from './config/massage'; import { migrateConfig } from './config/migration'; import type { RenovateConfig } from './config/types'; import { validateConfig } from './config/validation'; import { logger } from './logger'; -import { getConfig as getFileConfig } from './workers/global/config/parse/file'; +import { + getConfig as getFileConfig, + getParsedContent, +} from './workers/global/config/parse/file'; let returnVal = 0; @@ -52,22 +54,17 @@ type PackageJson = { (name) => name !== 'package.json' )) { try { - const rawContent = readFileSync(file, 'utf8'); - logger.info(`Validating ${file}`); + const parsedContent = getParsedContent(file); try { - let jsonContent: RenovateConfig; - if (file.endsWith('.json5')) { - jsonContent = JSON5.parse(rawContent); - } else { - jsonContent = JSON.parse(rawContent); - } - await validate(file, jsonContent); + logger.info(`Validating ${file}`); + await validate(file, parsedContent); } catch (err) { logger.info({ err }, `${file} is not valid Renovate config`); returnVal = 1; } } catch (err) { // file does not exist + continue; } } try { diff --git a/lib/workers/global/config/parse/__fixtures__/config.json5 b/lib/workers/global/config/parse/__fixtures__/config.json5 new file mode 100644 index 00000000000000..05d6407ca7b492 --- /dev/null +++ b/lib/workers/global/config/parse/__fixtures__/config.json5 @@ -0,0 +1,4 @@ +{ + // comment + "token": "abcdefg", +} diff --git a/lib/workers/global/config/parse/__fixtures__/config.yaml b/lib/workers/global/config/parse/__fixtures__/config.yaml new file mode 100644 index 00000000000000..30bd5dbba13bb0 --- /dev/null +++ b/lib/workers/global/config/parse/__fixtures__/config.yaml @@ -0,0 +1,3 @@ +--- +# comment +token: abcdefg diff --git a/lib/workers/global/config/parse/file.spec.ts b/lib/workers/global/config/parse/file.spec.ts index f2a78c48d07e8c..236d3ba48572fe 100644 --- a/lib/workers/global/config/parse/file.spec.ts +++ b/lib/workers/global/config/parse/file.spec.ts @@ -16,12 +16,17 @@ describe('workers/global/config/parse/file', () => { }); describe('.getConfig()', () => { - it('parses custom config file', () => { - const configFile = upath.resolve(__dirname, './__fixtures__/file.js'); + it.each([ + ['custom file', 'file.js'], + ['JSON5 config file', 'config.json5'], + ['YAML config file', 'config.yaml'], + ])('parses %s', (fileType, filePath) => { + const configFile = upath.resolve(__dirname, './__fixtures__/', filePath); expect(file.getConfig({ RENOVATE_CONFIG_FILE: configFile })).toEqual( customConfig ); }); + it('migrates', () => { const configFile = upath.resolve(__dirname, './__fixtures__/file2.js'); const res = file.getConfig({ RENOVATE_CONFIG_FILE: configFile }); @@ -33,12 +38,10 @@ describe('workers/global/config/parse/file', () => { expect(file.getConfig({})).toBeDefined(); }); - it('fatal error and exit if error in parsing config.js', () => { - const mockProcessExit = jest - .spyOn(process, 'exit') - .mockImplementation(() => undefined as never); - const configFile = upath.resolve(tmp.path, './file3.js'); - const fileContent = `module.exports = { + it.each([ + [ + 'config.js', + `module.exports = { "platform": "github", "token":"abcdef", "logFileLevel": "warn", @@ -48,13 +51,24 @@ describe('workers/global/config/parse/file', () => { "extends": ["config:base"], }, "repositories": [ "test/test" ], - };`; - fs.writeFileSync(configFile, fileContent, { encoding: 'utf8' }); - file.getConfig({ RENOVATE_CONFIG_FILE: configFile }); - expect(mockProcessExit).toHaveBeenCalledWith(1); - - fs.unlinkSync(configFile); - }); + };`, + ], + ['config.json5', `"invalid":`], + ['config.yaml', `invalid: -`], + ])( + 'fatal error and exit if error in parsing %s', + (fileName, fileContent) => { + const mockProcessExit = jest + .spyOn(process, 'exit') + .mockImplementation(() => undefined as never); + const configFile = upath.resolve(tmp.path, fileName); + fs.writeFileSync(configFile, fileContent, { encoding: 'utf8' }); + file.getConfig({ RENOVATE_CONFIG_FILE: configFile }); + expect(mockProcessExit).toHaveBeenCalledWith(1); + mockProcessExit.mockRestore(); + fs.unlinkSync(configFile); + } + ); it('fatal error and exit if custom config file does not exist', () => { const mockProcessExit = jest diff --git a/lib/workers/global/config/parse/file.ts b/lib/workers/global/config/parse/file.ts index 5cab40ee0e5b6d..44fe086d046590 100644 --- a/lib/workers/global/config/parse/file.ts +++ b/lib/workers/global/config/parse/file.ts @@ -1,8 +1,25 @@ +import { readFileSync } from 'fs-extra'; +import { load } from 'js-yaml'; +import JSON5 from 'json5'; import upath from 'upath'; import { migrateConfig } from '../../../../config/migration'; -import type { AllConfig } from '../../../../config/types'; +import type { AllConfig, RenovateConfig } from '../../../../config/types'; import { logger } from '../../../../logger'; +export function getParsedContent(file: string): RenovateConfig { + const rawContent = readFileSync(file, 'utf8'); + switch (upath.extname(file)) { + case '.yaml': + case '.yml': + return load(rawContent, { json: true }) as RenovateConfig; + case '.json5': + return JSON5.parse(rawContent); + default: + // .json and .js + return require(file); + } +} + export function getConfig(env: NodeJS.ProcessEnv): AllConfig { let configFile = env.RENOVATE_CONFIG_FILE || 'config'; if (!upath.isAbsolute(configFile)) { @@ -11,7 +28,7 @@ export function getConfig(env: NodeJS.ProcessEnv): AllConfig { } let config: AllConfig = {}; try { - config = require(configFile); + config = getParsedContent(configFile); } catch (err) { // istanbul ignore if if (err instanceof SyntaxError || err instanceof TypeError) { From 42acf832e91312e98790da6be1ce8548104c6a9a Mon Sep 17 00:00:00 2001 From: Nejc Habjan Date: Wed, 17 Nov 2021 22:11:28 +0100 Subject: [PATCH 02/10] chore(config): apply review suggestions --- lib/workers/global/config/parse/file.ts | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/lib/workers/global/config/parse/file.ts b/lib/workers/global/config/parse/file.ts index c57b49cdbc54d1..68262910c02c9a 100644 --- a/lib/workers/global/config/parse/file.ts +++ b/lib/workers/global/config/parse/file.ts @@ -1,5 +1,6 @@ import { readFile } from 'fs-extra'; import { load } from 'js-yaml'; +import fs from 'fs-extra'; import JSON5 from 'json5'; import upath from 'upath'; import { migrateConfig } from '../../../../config/migration'; @@ -14,21 +15,35 @@ export async function getParsedContent(file: string): Promise { json: true, }) as RenovateConfig; case '.json5': + case '.json': return JSON5.parse(await readFile(file, 'utf8')); - default: { - // .json and .js + case '.js': { const tmpConfig = await import(file); return tmpConfig.default ? tmpConfig.default : tmpConfig; } + default: + throw new Error(`Unsupported file type: ${file}`); } } export async function getConfig(env: NodeJS.ProcessEnv): Promise { - let configFile = env.RENOVATE_CONFIG_FILE || 'config'; + let configFile = env.RENOVATE_CONFIG_FILE || 'config.js'; if (!upath.isAbsolute(configFile)) { configFile = `${process.cwd()}/${configFile}`; - logger.debug('Checking for config file in ' + configFile); } + if (!upath.extname(configFile)) { + logger.info( + 'Providing a config file without an extension is deprecated. Please use explicit file extensions.' + ); + for (const ext of ['.js', '.json']) { + const resolved = upath.addExt(configFile, ext); + if (fs.exists(resolved)) { + configFile = resolved; + break; + } + } + } + logger.debug('Checking for config file in ' + configFile); let config: AllConfig = {}; try { config = await getParsedContent(configFile); From 0470ba686acfb7ed6e85d7ec6a7877e5a48ac3cb Mon Sep 17 00:00:00 2001 From: Nejc Habjan Date: Wed, 17 Nov 2021 22:17:51 +0100 Subject: [PATCH 03/10] chore(config): add missing await --- lib/workers/global/config/parse/file.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/workers/global/config/parse/file.ts b/lib/workers/global/config/parse/file.ts index 68262910c02c9a..bfb8c81653dbcb 100644 --- a/lib/workers/global/config/parse/file.ts +++ b/lib/workers/global/config/parse/file.ts @@ -1,6 +1,5 @@ -import { readFile } from 'fs-extra'; +import fs, { readFile } from 'fs-extra'; import { load } from 'js-yaml'; -import fs from 'fs-extra'; import JSON5 from 'json5'; import upath from 'upath'; import { migrateConfig } from '../../../../config/migration'; @@ -37,7 +36,7 @@ export async function getConfig(env: NodeJS.ProcessEnv): Promise { ); for (const ext of ['.js', '.json']) { const resolved = upath.addExt(configFile, ext); - if (fs.exists(resolved)) { + if (await fs.exists(resolved)) { configFile = resolved; break; } From 1ccc4d6bb939146aef85d0355ee1b01e6ac95d01 Mon Sep 17 00:00:00 2001 From: Nejc Habjan Date: Wed, 17 Nov 2021 22:34:10 +0100 Subject: [PATCH 04/10] test(config): test resolving and deprecating empty extension --- lib/workers/global/config/parse/file.spec.ts | 10 +++++++++- lib/workers/global/config/parse/file.ts | 7 ++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/lib/workers/global/config/parse/file.spec.ts b/lib/workers/global/config/parse/file.spec.ts index b2d7054786893c..8a325625ee2772 100644 --- a/lib/workers/global/config/parse/file.spec.ts +++ b/lib/workers/global/config/parse/file.spec.ts @@ -1,6 +1,7 @@ import fs from 'fs'; import { DirectoryResult, dir } from 'tmp-promise'; import upath from 'upath'; +import { logger } from '../../../../logger'; import customConfig from './__fixtures__/file'; import * as file from './file'; @@ -16,8 +17,15 @@ describe('workers/global/config/parse/file', () => { }); describe('.getConfig()', () => { + it('raises deprecation warning when no extension given', async () => { + const configFile = upath.resolve(__dirname, './__fixtures__/file'); + await file.getConfig({ RENOVATE_CONFIG_FILE: configFile }); + expect(logger.info).toHaveBeenCalledWith(file.fileDeprecationMessage); + }); + it.each([ - ['custom config file', 'file.js'], + ['custom config file without extension', 'file'], + ['custom config file with extension', 'file.js'], ['JSON5 config file', 'config.json5'], ['YAML config file', 'config.yaml'], ])('parses %s', async (fileType, filePath) => { diff --git a/lib/workers/global/config/parse/file.ts b/lib/workers/global/config/parse/file.ts index bfb8c81653dbcb..81a65148fec29e 100644 --- a/lib/workers/global/config/parse/file.ts +++ b/lib/workers/global/config/parse/file.ts @@ -6,6 +6,9 @@ import { migrateConfig } from '../../../../config/migration'; import type { AllConfig, RenovateConfig } from '../../../../config/types'; import { logger } from '../../../../logger'; +export const fileDeprecationMessage = + 'Providing a config file without an extension is deprecated. Please use explicit file extensions.'; + export async function getParsedContent(file: string): Promise { switch (upath.extname(file)) { case '.yaml': @@ -31,9 +34,7 @@ export async function getConfig(env: NodeJS.ProcessEnv): Promise { configFile = `${process.cwd()}/${configFile}`; } if (!upath.extname(configFile)) { - logger.info( - 'Providing a config file without an extension is deprecated. Please use explicit file extensions.' - ); + logger.info(fileDeprecationMessage); for (const ext of ['.js', '.json']) { const resolved = upath.addExt(configFile, ext); if (await fs.exists(resolved)) { From 88fc8249ffd5598587f9d26dc134a761a379d154 Mon Sep 17 00:00:00 2001 From: Nejc Habjan Date: Thu, 18 Nov 2021 01:15:34 +0100 Subject: [PATCH 05/10] chore(config): fail explicitly on invalid file type --- lib/workers/global/config/parse/file.spec.ts | 14 ++++++++++++++ lib/workers/global/config/parse/file.ts | 3 +++ 2 files changed, 17 insertions(+) diff --git a/lib/workers/global/config/parse/file.spec.ts b/lib/workers/global/config/parse/file.spec.ts index 8a325625ee2772..d713389fb89f3d 100644 --- a/lib/workers/global/config/parse/file.spec.ts +++ b/lib/workers/global/config/parse/file.spec.ts @@ -88,5 +88,19 @@ describe('workers/global/config/parse/file', () => { expect(mockProcessExit).toHaveBeenCalledWith(1); }); + it('fatal error and exit if invalid config file type', async () => { + const mockProcessExit = jest + .spyOn(process, 'exit') + .mockImplementation(() => undefined as never); + const configFile = upath.resolve(tmp.path, './file.txt'); + fs.writeFileSync(configFile, `{"token": "abc"}`, { encoding: 'utf8' }); + await file.getConfig({ RENOVATE_CONFIG_FILE: configFile }); + expect(mockProcessExit).toHaveBeenCalledWith(1); + expect(logger.fatal).toHaveBeenCalledWith( + `Unsupported file type: ${configFile}` + ); + mockProcessExit.mockRestore(); + fs.unlinkSync(configFile); + }); }); }); diff --git a/lib/workers/global/config/parse/file.ts b/lib/workers/global/config/parse/file.ts index 81a65148fec29e..8bdf9c01dd2738 100644 --- a/lib/workers/global/config/parse/file.ts +++ b/lib/workers/global/config/parse/file.ts @@ -52,6 +52,9 @@ export async function getConfig(env: NodeJS.ProcessEnv): Promise { if (err instanceof SyntaxError || err instanceof TypeError) { logger.fatal(`Could not parse config file \n ${err.stack}`); process.exit(1); + } else if (err.message.startsWith(`Unsupported file type`)) { + logger.fatal(err.message); + process.exit(1); } else if (env.RENOVATE_CONFIG_FILE) { logger.fatal('No custom config file found on disk'); process.exit(1); From 20a35aaad4710231416ae251488a7e2a98c6301a Mon Sep 17 00:00:00 2001 From: Nejc Habjan Date: Sat, 27 Nov 2021 15:43:49 +0100 Subject: [PATCH 06/10] feat(config): explicitly fail if no config file extension BREAKING CHANGE: Renovate will now fail if RENOVATE_CONFIG_FILE does have a file extension provided. --- docs/development/configuration.md | 3 +++ lib/workers/global/config/parse/file.spec.ts | 19 +++++++------------ lib/workers/global/config/parse/file.ts | 19 +++---------------- 3 files changed, 13 insertions(+), 28 deletions(-) diff --git a/docs/development/configuration.md b/docs/development/configuration.md index d3bfca3b7f6edd..7dc2ab479eead7 100644 --- a/docs/development/configuration.md +++ b/docs/development/configuration.md @@ -20,6 +20,9 @@ Options which have `"globalOnly": true` are reserved only for bot global configu You can override default configuration using a configuration file, with default name `config.js` in the working directory. If you need an alternate location or name, set it in the environment variable `RENOVATE_CONFIG_FILE`. +**Note:** `RENOVATE_CONFIG_FILE` must be provided with an explicit file extension. +If none is provided, or the file type is invalid, Renovate will fail. + Using a configuration file gives you very granular configuration options. For instance, you can override most settings at the global (file), repository, or package level. e.g. apply one set of labels for `backend/package.json` and a different set of labels for `frontend/package.json` in the same repository. diff --git a/lib/workers/global/config/parse/file.spec.ts b/lib/workers/global/config/parse/file.spec.ts index d713389fb89f3d..2e19367faf5381 100644 --- a/lib/workers/global/config/parse/file.spec.ts +++ b/lib/workers/global/config/parse/file.spec.ts @@ -17,14 +17,7 @@ describe('workers/global/config/parse/file', () => { }); describe('.getConfig()', () => { - it('raises deprecation warning when no extension given', async () => { - const configFile = upath.resolve(__dirname, './__fixtures__/file'); - await file.getConfig({ RENOVATE_CONFIG_FILE: configFile }); - expect(logger.info).toHaveBeenCalledWith(file.fileDeprecationMessage); - }); - it.each([ - ['custom config file without extension', 'file'], ['custom config file with extension', 'file.js'], ['JSON5 config file', 'config.json5'], ['YAML config file', 'config.yaml'], @@ -88,17 +81,19 @@ describe('workers/global/config/parse/file', () => { expect(mockProcessExit).toHaveBeenCalledWith(1); }); - it('fatal error and exit if invalid config file type', async () => { + + it.each([ + ['invalid config file type', './file.txt'], + ['missing config file type', './file'], + ])('fatal error and exit if %s', async (fileType, filePath) => { const mockProcessExit = jest .spyOn(process, 'exit') .mockImplementation(() => undefined as never); - const configFile = upath.resolve(tmp.path, './file.txt'); + const configFile = upath.resolve(tmp.path, filePath); fs.writeFileSync(configFile, `{"token": "abc"}`, { encoding: 'utf8' }); await file.getConfig({ RENOVATE_CONFIG_FILE: configFile }); expect(mockProcessExit).toHaveBeenCalledWith(1); - expect(logger.fatal).toHaveBeenCalledWith( - `Unsupported file type: ${configFile}` - ); + expect(logger.fatal).toHaveBeenCalledWith('Unsupported file type'); mockProcessExit.mockRestore(); fs.unlinkSync(configFile); }); diff --git a/lib/workers/global/config/parse/file.ts b/lib/workers/global/config/parse/file.ts index 8bdf9c01dd2738..ae77c3f136a4e9 100644 --- a/lib/workers/global/config/parse/file.ts +++ b/lib/workers/global/config/parse/file.ts @@ -1,4 +1,4 @@ -import fs, { readFile } from 'fs-extra'; +import { readFile } from 'fs-extra'; import { load } from 'js-yaml'; import JSON5 from 'json5'; import upath from 'upath'; @@ -6,9 +6,6 @@ import { migrateConfig } from '../../../../config/migration'; import type { AllConfig, RenovateConfig } from '../../../../config/types'; import { logger } from '../../../../logger'; -export const fileDeprecationMessage = - 'Providing a config file without an extension is deprecated. Please use explicit file extensions.'; - export async function getParsedContent(file: string): Promise { switch (upath.extname(file)) { case '.yaml': @@ -24,7 +21,7 @@ export async function getParsedContent(file: string): Promise { return tmpConfig.default ? tmpConfig.default : tmpConfig; } default: - throw new Error(`Unsupported file type: ${file}`); + throw new Error('Unsupported file type'); } } @@ -33,16 +30,6 @@ export async function getConfig(env: NodeJS.ProcessEnv): Promise { if (!upath.isAbsolute(configFile)) { configFile = `${process.cwd()}/${configFile}`; } - if (!upath.extname(configFile)) { - logger.info(fileDeprecationMessage); - for (const ext of ['.js', '.json']) { - const resolved = upath.addExt(configFile, ext); - if (await fs.exists(resolved)) { - configFile = resolved; - break; - } - } - } logger.debug('Checking for config file in ' + configFile); let config: AllConfig = {}; try { @@ -52,7 +39,7 @@ export async function getConfig(env: NodeJS.ProcessEnv): Promise { if (err instanceof SyntaxError || err instanceof TypeError) { logger.fatal(`Could not parse config file \n ${err.stack}`); process.exit(1); - } else if (err.message.startsWith(`Unsupported file type`)) { + } else if (err.message === 'Unsupported file type') { logger.fatal(err.message); process.exit(1); } else if (env.RENOVATE_CONFIG_FILE) { From 696ab045ea2be8dab3b6258c36474ec3e95f87ef Mon Sep 17 00:00:00 2001 From: Rhys Arkins Date: Wed, 8 Dec 2021 11:26:49 +0100 Subject: [PATCH 07/10] Update docs/development/configuration.md --- docs/development/configuration.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/development/configuration.md b/docs/development/configuration.md index 7dc2ab479eead7..a98d05be8e6863 100644 --- a/docs/development/configuration.md +++ b/docs/development/configuration.md @@ -21,6 +21,7 @@ You can override default configuration using a configuration file, with default If you need an alternate location or name, set it in the environment variable `RENOVATE_CONFIG_FILE`. **Note:** `RENOVATE_CONFIG_FILE` must be provided with an explicit file extension. +For example `RENOVATE_CONFIG_FILE=myconfig.js` or `RENOVATE_CONFIG_FILE=myconfig.json` and not `RENOVATE_CONFIG_FILE=myconfig`. If none is provided, or the file type is invalid, Renovate will fail. Using a configuration file gives you very granular configuration options. From ab5357ac4c760c1648a505f2ced52678d28eb78c Mon Sep 17 00:00:00 2001 From: Nejc Habjan Date: Wed, 8 Dec 2021 13:28:10 +0100 Subject: [PATCH 08/10] chore(config): fix fs import Co-authored-by: Michael Kriese --- lib/workers/global/config/parse/file.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/workers/global/config/parse/file.ts b/lib/workers/global/config/parse/file.ts index ae77c3f136a4e9..6c372148ddf872 100644 --- a/lib/workers/global/config/parse/file.ts +++ b/lib/workers/global/config/parse/file.ts @@ -1,4 +1,4 @@ -import { readFile } from 'fs-extra'; +import { readFile } from '../../../../util/fs'; import { load } from 'js-yaml'; import JSON5 from 'json5'; import upath from 'upath'; From 5542d5e7101d519fb20419aba3222a3479a9f62d Mon Sep 17 00:00:00 2001 From: Rhys Arkins Date: Thu, 9 Dec 2021 11:40:13 +0100 Subject: [PATCH 09/10] lint --- lib/workers/global/config/parse/file.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/workers/global/config/parse/file.ts b/lib/workers/global/config/parse/file.ts index 6c372148ddf872..103d24d8692f4e 100644 --- a/lib/workers/global/config/parse/file.ts +++ b/lib/workers/global/config/parse/file.ts @@ -1,10 +1,10 @@ -import { readFile } from '../../../../util/fs'; import { load } from 'js-yaml'; import JSON5 from 'json5'; import upath from 'upath'; import { migrateConfig } from '../../../../config/migration'; import type { AllConfig, RenovateConfig } from '../../../../config/types'; import { logger } from '../../../../logger'; +import { readFile } from '../../../../util/fs'; export async function getParsedContent(file: string): Promise { switch (upath.extname(file)) { From f5a5cd5e35bc26106c6c5190a67fb3d805c741bb Mon Sep 17 00:00:00 2001 From: Michael Kriese Date: Thu, 9 Dec 2021 12:01:21 +0100 Subject: [PATCH 10/10] Apply suggestions from code review --- lib/workers/global/config/parse/file.spec.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/workers/global/config/parse/file.spec.ts b/lib/workers/global/config/parse/file.spec.ts index 2e19367faf5381..cf497566a42a59 100644 --- a/lib/workers/global/config/parse/file.spec.ts +++ b/lib/workers/global/config/parse/file.spec.ts @@ -61,12 +61,11 @@ describe('workers/global/config/parse/file', () => { async (fileName, fileContent) => { const mockProcessExit = jest .spyOn(process, 'exit') - .mockImplementation(() => undefined as never); + .mockImplementationOnce(() => undefined as never); const configFile = upath.resolve(tmp.path, fileName); fs.writeFileSync(configFile, fileContent, { encoding: 'utf8' }); await file.getConfig({ RENOVATE_CONFIG_FILE: configFile }); expect(mockProcessExit).toHaveBeenCalledWith(1); - mockProcessExit.mockRestore(); fs.unlinkSync(configFile); } ); @@ -88,13 +87,12 @@ describe('workers/global/config/parse/file', () => { ])('fatal error and exit if %s', async (fileType, filePath) => { const mockProcessExit = jest .spyOn(process, 'exit') - .mockImplementation(() => undefined as never); + .mockImplementationOnce(() => undefined as never); const configFile = upath.resolve(tmp.path, filePath); fs.writeFileSync(configFile, `{"token": "abc"}`, { encoding: 'utf8' }); await file.getConfig({ RENOVATE_CONFIG_FILE: configFile }); expect(mockProcessExit).toHaveBeenCalledWith(1); expect(logger.fatal).toHaveBeenCalledWith('Unsupported file type'); - mockProcessExit.mockRestore(); fs.unlinkSync(configFile); }); });