mirror of
https://github.com/renovatebot/renovate.git
synced 2025-01-11 14:36:25 +00:00
refactor: move config/parse into global worker (#10282)
This commit is contained in:
parent
1af4d80a5a
commit
11694e9294
23 changed files with 272 additions and 246 deletions
|
@ -4,12 +4,12 @@ import { dequal } from 'dequal';
|
||||||
import { readFileSync } from 'fs-extra';
|
import { readFileSync } from 'fs-extra';
|
||||||
import JSON5 from 'json5';
|
import JSON5 from 'json5';
|
||||||
import { configFileNames } from './config/app-strings';
|
import { configFileNames } from './config/app-strings';
|
||||||
import { getConfig as getFileConfig } from './config/file';
|
|
||||||
import { massageConfig } from './config/massage';
|
import { massageConfig } from './config/massage';
|
||||||
import { migrateConfig } from './config/migration';
|
import { migrateConfig } from './config/migration';
|
||||||
import type { RenovateConfig } from './config/types';
|
import type { RenovateConfig } from './config/types';
|
||||||
import { validateConfig } from './config/validation';
|
import { validateConfig } from './config/validation';
|
||||||
import { logger } from './logger';
|
import { logger } from './logger';
|
||||||
|
import { getConfig as getFileConfig } from './workers/global/config/parse/file';
|
||||||
|
|
||||||
/* eslint-disable no-console */
|
/* eslint-disable no-console */
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { setAdminConfig } from './admin';
|
||||||
import { decryptConfig } from './decrypt';
|
import { decryptConfig } from './decrypt';
|
||||||
import type { RenovateConfig } from './types';
|
import type { RenovateConfig } from './types';
|
||||||
|
|
||||||
const privateKey = loadFixture('private.pem', 'keys');
|
const privateKey = loadFixture('private.pem', '.');
|
||||||
|
|
||||||
describe(getName(), () => {
|
describe(getName(), () => {
|
||||||
describe('decryptConfig()', () => {
|
describe('decryptConfig()', () => {
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
import upath from 'upath';
|
|
||||||
import { getName } from '../../test/util';
|
import { getName } from '../../test/util';
|
||||||
import { readFile } from '../util/fs';
|
|
||||||
import getArgv from './config/__fixtures__/argv';
|
|
||||||
import { getConfig } from './defaults';
|
import { getConfig } from './defaults';
|
||||||
|
|
||||||
jest.mock('../datasource/npm');
|
jest.mock('../datasource/npm');
|
||||||
|
@ -14,111 +11,6 @@ try {
|
||||||
const defaultConfig = getConfig();
|
const defaultConfig = getConfig();
|
||||||
|
|
||||||
describe(getName(), () => {
|
describe(getName(), () => {
|
||||||
describe('.parseConfigs(env, defaultArgv)', () => {
|
|
||||||
let configParser: typeof import('.');
|
|
||||||
let defaultArgv: string[];
|
|
||||||
let defaultEnv: NodeJS.ProcessEnv;
|
|
||||||
beforeEach(async () => {
|
|
||||||
jest.resetModules();
|
|
||||||
configParser = await import('./index');
|
|
||||||
defaultArgv = getArgv();
|
|
||||||
defaultEnv = { RENOVATE_CONFIG_FILE: 'abc' };
|
|
||||||
jest.mock('delay', () => Promise.resolve());
|
|
||||||
});
|
|
||||||
it('supports token in env', async () => {
|
|
||||||
const env: NodeJS.ProcessEnv = { ...defaultEnv, RENOVATE_TOKEN: 'abc' };
|
|
||||||
const parsedConfig = await configParser.parseConfigs(env, defaultArgv);
|
|
||||||
expect(parsedConfig).toContainEntries([['token', 'abc']]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('supports token in CLI options', async () => {
|
|
||||||
defaultArgv = defaultArgv.concat([
|
|
||||||
'--token=abc',
|
|
||||||
'--pr-footer=custom',
|
|
||||||
'--log-context=abc123',
|
|
||||||
]);
|
|
||||||
const parsedConfig = await configParser.parseConfigs(
|
|
||||||
defaultEnv,
|
|
||||||
defaultArgv
|
|
||||||
);
|
|
||||||
expect(parsedConfig).toContainEntries([
|
|
||||||
['token', 'abc'],
|
|
||||||
['prFooter', 'custom'],
|
|
||||||
['logContext', 'abc123'],
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('supports forceCli', async () => {
|
|
||||||
defaultArgv = defaultArgv.concat(['--force-cli=false']);
|
|
||||||
const env: NodeJS.ProcessEnv = {
|
|
||||||
...defaultEnv,
|
|
||||||
RENOVATE_TOKEN: 'abc',
|
|
||||||
};
|
|
||||||
const parsedConfig = await configParser.parseConfigs(env, defaultArgv);
|
|
||||||
expect(parsedConfig).toContainEntries([
|
|
||||||
['token', 'abc'],
|
|
||||||
['force', null],
|
|
||||||
]);
|
|
||||||
expect(parsedConfig).not.toContainKey('configFile');
|
|
||||||
});
|
|
||||||
it('supports config.force', async () => {
|
|
||||||
const configPath = upath.join(
|
|
||||||
__dirname,
|
|
||||||
'config/__fixtures__/with-force.js'
|
|
||||||
);
|
|
||||||
const env: NodeJS.ProcessEnv = {
|
|
||||||
...defaultEnv,
|
|
||||||
RENOVATE_CONFIG_FILE: configPath,
|
|
||||||
};
|
|
||||||
const parsedConfig = await configParser.parseConfigs(env, defaultArgv);
|
|
||||||
expect(parsedConfig).toContainEntries([
|
|
||||||
['token', 'abcdefg'],
|
|
||||||
[
|
|
||||||
'force',
|
|
||||||
{
|
|
||||||
schedule: null,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
it('reads private key from file', async () => {
|
|
||||||
const privateKeyPath = upath.join(
|
|
||||||
__dirname,
|
|
||||||
'keys/__fixtures__/private.pem'
|
|
||||||
);
|
|
||||||
const env: NodeJS.ProcessEnv = {
|
|
||||||
...defaultEnv,
|
|
||||||
RENOVATE_PRIVATE_KEY_PATH: privateKeyPath,
|
|
||||||
};
|
|
||||||
const expected = await readFile(privateKeyPath);
|
|
||||||
const parsedConfig = await configParser.parseConfigs(env, defaultArgv);
|
|
||||||
|
|
||||||
expect(parsedConfig).toContainEntries([['privateKey', expected]]);
|
|
||||||
});
|
|
||||||
it('supports Bitbucket username/passwod', async () => {
|
|
||||||
defaultArgv = defaultArgv.concat([
|
|
||||||
'--platform=bitbucket',
|
|
||||||
'--username=user',
|
|
||||||
'--password=pass',
|
|
||||||
]);
|
|
||||||
const parsedConfig = await configParser.parseConfigs(
|
|
||||||
defaultEnv,
|
|
||||||
defaultArgv
|
|
||||||
);
|
|
||||||
expect(parsedConfig).toContainEntries([
|
|
||||||
['platform', 'bitbucket'],
|
|
||||||
['username', 'user'],
|
|
||||||
['password', 'pass'],
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
it('massages trailing slash into endpoint', async () => {
|
|
||||||
defaultArgv = defaultArgv.concat([
|
|
||||||
'--endpoint=https://github.renovatebot.com/api/v3',
|
|
||||||
]);
|
|
||||||
const parsed = await configParser.parseConfigs(defaultEnv, defaultArgv);
|
|
||||||
expect(parsed.endpoint).toEqual('https://github.renovatebot.com/api/v3/');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
describe('mergeChildConfig(parentConfig, childConfig)', () => {
|
describe('mergeChildConfig(parentConfig, childConfig)', () => {
|
||||||
it('merges', async () => {
|
it('merges', async () => {
|
||||||
const parentConfig = { ...defaultConfig };
|
const parentConfig = { ...defaultConfig };
|
||||||
|
|
|
@ -1,12 +1,6 @@
|
||||||
import { addStream, logger, setContext } from '../logger';
|
import { logger } from '../logger';
|
||||||
import { get, getLanguageList, getManagerList } from '../manager';
|
import { get, getLanguageList, getManagerList } from '../manager';
|
||||||
import { ensureDir, getSubDirectory, readFile } from '../util/fs';
|
|
||||||
import { ensureTrailingSlash } from '../util/url';
|
|
||||||
import * as cliParser from './cli';
|
|
||||||
import * as defaultsParser from './defaults';
|
|
||||||
import * as definitions from './definitions';
|
import * as definitions from './definitions';
|
||||||
import * as envParser from './env';
|
|
||||||
import * as fileParser from './file';
|
|
||||||
import type {
|
import type {
|
||||||
AllConfig,
|
AllConfig,
|
||||||
ManagerConfig,
|
ManagerConfig,
|
||||||
|
@ -39,85 +33,6 @@ export function getManagerConfig(
|
||||||
return managerConfig;
|
return managerConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function parseConfigs(
|
|
||||||
env: NodeJS.ProcessEnv,
|
|
||||||
argv: string[]
|
|
||||||
): Promise<AllConfig> {
|
|
||||||
logger.debug('Parsing configs');
|
|
||||||
|
|
||||||
// Get configs
|
|
||||||
const defaultConfig = defaultsParser.getConfig();
|
|
||||||
const fileConfig = fileParser.getConfig(env);
|
|
||||||
const cliConfig = cliParser.getConfig(argv);
|
|
||||||
const envConfig = envParser.getConfig(env);
|
|
||||||
|
|
||||||
let config: AllConfig = mergeChildConfig(fileConfig, envConfig);
|
|
||||||
config = mergeChildConfig(config, cliConfig);
|
|
||||||
|
|
||||||
const combinedConfig = config;
|
|
||||||
|
|
||||||
config = mergeChildConfig(defaultConfig, config);
|
|
||||||
|
|
||||||
if (config.forceCli) {
|
|
||||||
const forcedCli = { ...cliConfig };
|
|
||||||
delete forcedCli.token;
|
|
||||||
delete forcedCli.hostRules;
|
|
||||||
if (config.force) {
|
|
||||||
config.force = { ...config.force, ...forcedCli };
|
|
||||||
} else {
|
|
||||||
config.force = forcedCli;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!config.privateKey && config.privateKeyPath) {
|
|
||||||
config.privateKey = await readFile(config.privateKeyPath);
|
|
||||||
delete config.privateKeyPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config.logContext) {
|
|
||||||
// This only has an effect if logContext was defined via file or CLI, otherwise it would already have been detected in env
|
|
||||||
setContext(config.logContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add file logger
|
|
||||||
// istanbul ignore if
|
|
||||||
if (config.logFile) {
|
|
||||||
logger.debug(
|
|
||||||
`Enabling ${config.logFileLevel} logging to ${config.logFile}`
|
|
||||||
);
|
|
||||||
await ensureDir(getSubDirectory(config.logFile));
|
|
||||||
addStream({
|
|
||||||
name: 'logfile',
|
|
||||||
path: config.logFile,
|
|
||||||
level: config.logFileLevel,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.trace({ config: defaultConfig }, 'Default config');
|
|
||||||
logger.debug({ config: fileConfig }, 'File config');
|
|
||||||
logger.debug({ config: cliConfig }, 'CLI config');
|
|
||||||
logger.debug({ config: envConfig }, 'Env config');
|
|
||||||
logger.debug({ config: combinedConfig }, 'Combined config');
|
|
||||||
|
|
||||||
// Get global config
|
|
||||||
logger.trace({ config }, 'Full config');
|
|
||||||
|
|
||||||
// Print config
|
|
||||||
logger.trace({ config }, 'Global config');
|
|
||||||
|
|
||||||
// Massage endpoint to have a trailing slash
|
|
||||||
if (config.endpoint) {
|
|
||||||
logger.debug('Adding trailing slash to endpoint');
|
|
||||||
config.endpoint = ensureTrailingSlash(config.endpoint);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove log file entries
|
|
||||||
delete config.logFile;
|
|
||||||
delete config.logFileLevel;
|
|
||||||
|
|
||||||
return config;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function filterConfig(
|
export function filterConfig(
|
||||||
inputConfig: AllConfig,
|
inputConfig: AllConfig,
|
||||||
targetStage: RenovateConfigStage
|
targetStage: RenovateConfigStage
|
||||||
|
|
|
@ -370,10 +370,6 @@ export interface ManagerConfig extends RenovateConfig {
|
||||||
manager: string;
|
manager: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RenovateCliConfig extends Record<string, any> {
|
|
||||||
repositories?: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface MigratedConfig {
|
export interface MigratedConfig {
|
||||||
isMigrated: boolean;
|
isMigrated: boolean;
|
||||||
migratedConfig: RenovateConfig;
|
migratedConfig: RenovateConfig;
|
||||||
|
|
27
lib/workers/global/config/parse/__fixtures__/private.pem
Normal file
27
lib/workers/global/config/parse/__fixtures__/private.pem
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIEpQIBAAKCAQEAzVLc1KmhWxcLnoPTPpQwxVHySFx4vY+0Sk+2AdnlJvrTFlNR
|
||||||
|
8XgBPdgU9SDwHFFTYyXRQ/msm0YMOBRoIdz4/psz6IzRV80aOtDIkUPAU+cdqnje
|
||||||
|
3rusrPnqCykDuIHGoBZ8zlt57t/8OVNOduUflrQRqMFors8iLWcNjuGJfZAusI5B
|
||||||
|
M8KYYDPL2oUo/8AV0bWN8MdNnxDSwGtan4bbzrtG6dpNzyntsG5DkL1h8OZRki4S
|
||||||
|
kHf+71ZzJFz1KcyrzBVJ9DBxdiJdmLLkv9caLLc2QS0VFmtfLnlrga3Sahy6YNwc
|
||||||
|
rN33aaNOXwFPSErsKWIgIf16eOaSUQCFusXY9QIDAQABAoIBAQCkltMM6nm9Ikkf
|
||||||
|
JX9V/8bkth7o4K+tDSAyHZnB/CBUUeaaU+oxDci5AZkzMtcnbA3TQcJxohg6VDmB
|
||||||
|
TuJ2msNCnblLpm492t023pyYzd3DpFXEjKXjmEAAXUm+7n7cDbPiKoSbivrAgO6Y
|
||||||
|
KW6RonPjA6/QPlIjJ0m3aY+VxLfJXTYVfFBk+0HGEAvmrSSSEezXej8Qzs9CRKtz
|
||||||
|
cQkR5Bs749SS509MHxaslP7n366EvJBJkqrjUxA6kbxOxUkuuOWF9jfduDAG+NYc
|
||||||
|
pe4IXFOYMpK/w29wqvkNulKYs+FHXr1sGjkztGjyNnjP0NnX+r0EYU07xLJ26krD
|
||||||
|
KMWQG8sBAoGBAO93iFrPnEBnnKojI8b+u3YowVCz0HVuHHIStHd9uUgfsn/Bxfls
|
||||||
|
HRIlg8l1MJd69TT0knOhkJxBCP+b/qBvid7YLbTxIVELCAfLAzsmGgY+DEN/TTUb
|
||||||
|
FDvHGa/drCnkSR/O/RbtHvMQISzTja1siYrdwwY+wpwzR2tB7ZH/9iO1AoGBANt/
|
||||||
|
3Srpv4BbP7JZ+cNte4JfI2gZq41mo+DF5ryuFZzsP3R5SZ1BOapQGyLEATQaoxsJ
|
||||||
|
QZsI73KPBzab0/+E75qJuXckIGmFftHXgoQpClGvPaEDF9M21QW5Y3vKVa/45qhy
|
||||||
|
3wpb8gEYqrt1x0rmzyumCtCD8J470Er64gE1eKhBAoGBALW6ScFYwqRhvROkvTb8
|
||||||
|
A7mE7kfXXgBwAqhTJ59yytRAMc8gd6R0do9Z5uxQwgKDLmj0ndugpcTe2fxZHuAU
|
||||||
|
JVX3SqCBSZ5eN8bqOtZ9cMyB8/6ZMjd2CGHhE85R9KCJ/TBlfc4TPySIfhStq1wL
|
||||||
|
/UlkR+eKY1f01mNAUhE1ZU7tAoGBAKwS/B51KsSERFYcRToYbRfSX55vaVarnVNL
|
||||||
|
scw+qQDhEAnOP5CBHqTOscc6YzsmmrFKO10/zv8+80ezN6n73B6JU5T8BFDU74uv
|
||||||
|
6EiVJ9rLh4PfOeFB/hPDtyLHhw8yEBkEHKgxVnHXlZjqBzdH5Cdyvs2icZKKj4sI
|
||||||
|
TP7nnVRBAoGAPZBjjTn9HgB9et5Kdovp+7nr842WboxwklVyTpbNGAjIxNXIXex+
|
||||||
|
TST21UbquTIpIrpYRk1WMIu9T5PndAagDWVEsmUYQZeuhmuY64K+iviRsfdGthws
|
||||||
|
nbbR8sMEkn4XEtPZfrEBq27g01RNmIIMW5Es2O5N2AjLlyeBOh099Fw=
|
||||||
|
-----END RSA PRIVATE KEY-----
|
|
@ -1,6 +1,6 @@
|
||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`config/env .getConfig(env) supports Azure DevOps 1`] = `
|
exports[`workers/global/config/parse/env .getConfig(env) supports Azure DevOps 1`] = `
|
||||||
Object {
|
Object {
|
||||||
"endpoint": "an Azure DevOps endpoint",
|
"endpoint": "an Azure DevOps endpoint",
|
||||||
"hostRules": Array [],
|
"hostRules": Array [],
|
||||||
|
@ -9,7 +9,7 @@ Object {
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`config/env .getConfig(env) supports Bitbucket token 1`] = `
|
exports[`workers/global/config/parse/env .getConfig(env) supports Bitbucket token 1`] = `
|
||||||
Object {
|
Object {
|
||||||
"endpoint": "a bitbucket endpoint",
|
"endpoint": "a bitbucket endpoint",
|
||||||
"hostRules": Array [],
|
"hostRules": Array [],
|
||||||
|
@ -19,7 +19,7 @@ Object {
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`config/env .getConfig(env) supports Bitbucket username/password 1`] = `
|
exports[`workers/global/config/parse/env .getConfig(env) supports Bitbucket username/password 1`] = `
|
||||||
Object {
|
Object {
|
||||||
"endpoint": "a bitbucket endpoint",
|
"endpoint": "a bitbucket endpoint",
|
||||||
"hostRules": Array [],
|
"hostRules": Array [],
|
||||||
|
@ -29,14 +29,14 @@ Object {
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`config/env .getConfig(env) supports GitHub custom endpoint 1`] = `
|
exports[`workers/global/config/parse/env .getConfig(env) supports GitHub custom endpoint 1`] = `
|
||||||
Object {
|
Object {
|
||||||
"endpoint": "a ghe endpoint",
|
"endpoint": "a ghe endpoint",
|
||||||
"hostRules": Array [],
|
"hostRules": Array [],
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`config/env .getConfig(env) supports GitHub custom endpoint and github.com 1`] = `
|
exports[`workers/global/config/parse/env .getConfig(env) supports GitHub custom endpoint and github.com 1`] = `
|
||||||
Object {
|
Object {
|
||||||
"endpoint": "a ghe endpoint",
|
"endpoint": "a ghe endpoint",
|
||||||
"hostRules": Array [
|
"hostRules": Array [
|
||||||
|
@ -50,7 +50,7 @@ Object {
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`config/env .getConfig(env) supports GitHub custom endpoint and gitlab.com 1`] = `
|
exports[`workers/global/config/parse/env .getConfig(env) supports GitHub custom endpoint and gitlab.com 1`] = `
|
||||||
Object {
|
Object {
|
||||||
"endpoint": "a ghe endpoint",
|
"endpoint": "a ghe endpoint",
|
||||||
"hostRules": Array [],
|
"hostRules": Array [],
|
||||||
|
@ -58,14 +58,14 @@ Object {
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`config/env .getConfig(env) supports GitHub token 1`] = `
|
exports[`workers/global/config/parse/env .getConfig(env) supports GitHub token 1`] = `
|
||||||
Object {
|
Object {
|
||||||
"hostRules": Array [],
|
"hostRules": Array [],
|
||||||
"token": "github.com token",
|
"token": "github.com token",
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`config/env .getConfig(env) supports GitLab custom endpoint 1`] = `
|
exports[`workers/global/config/parse/env .getConfig(env) supports GitLab custom endpoint 1`] = `
|
||||||
Object {
|
Object {
|
||||||
"endpoint": "a gitlab endpoint",
|
"endpoint": "a gitlab endpoint",
|
||||||
"hostRules": Array [],
|
"hostRules": Array [],
|
||||||
|
@ -74,7 +74,7 @@ Object {
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`config/env .getConfig(env) supports GitLab token 1`] = `
|
exports[`workers/global/config/parse/env .getConfig(env) supports GitLab token 1`] = `
|
||||||
Object {
|
Object {
|
||||||
"hostRules": Array [],
|
"hostRules": Array [],
|
||||||
"platform": "gitlab",
|
"platform": "gitlab",
|
||||||
|
@ -82,7 +82,7 @@ Object {
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`config/env .getConfig(env) supports datasource env token 1`] = `
|
exports[`workers/global/config/parse/env .getConfig(env) supports datasource env token 1`] = `
|
||||||
Object {
|
Object {
|
||||||
"hostRules": Array [
|
"hostRules": Array [
|
||||||
Object {
|
Object {
|
||||||
|
@ -93,7 +93,7 @@ Object {
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`config/env .getConfig(env) supports docker username/password 1`] = `
|
exports[`workers/global/config/parse/env .getConfig(env) supports docker username/password 1`] = `
|
||||||
Object {
|
Object {
|
||||||
"hostRules": Array [
|
"hostRules": Array [
|
||||||
Object {
|
Object {
|
||||||
|
@ -105,7 +105,7 @@ Object {
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`config/env .getConfig(env) supports domain and host names with case insensitivity 1`] = `
|
exports[`workers/global/config/parse/env .getConfig(env) supports domain and host names with case insensitivity 1`] = `
|
||||||
Object {
|
Object {
|
||||||
"hostRules": Array [
|
"hostRules": Array [
|
||||||
Object {
|
Object {
|
||||||
|
@ -122,7 +122,7 @@ Object {
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`config/env .getConfig(env) supports password-only 1`] = `
|
exports[`workers/global/config/parse/env .getConfig(env) supports password-only 1`] = `
|
||||||
Object {
|
Object {
|
||||||
"hostRules": Array [
|
"hostRules": Array [
|
||||||
Object {
|
Object {
|
|
@ -1,6 +1,6 @@
|
||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`config/file .getConfig() migrates 1`] = `
|
exports[`workers/global/config/parse/file .getConfig() migrates 1`] = `
|
||||||
Object {
|
Object {
|
||||||
"rangeStrategy": "bump",
|
"rangeStrategy": "bump",
|
||||||
}
|
}
|
|
@ -1,8 +1,8 @@
|
||||||
import { getName } from '../../test/util';
|
import { getName } from '../../../../../test/util';
|
||||||
import * as datasourceDocker from '../datasource/docker';
|
import type { RenovateOptions } from '../../../../config/types';
|
||||||
|
import * as datasourceDocker from '../../../../datasource/docker';
|
||||||
|
import getArgv from './__fixtures__/argv';
|
||||||
import * as cli from './cli';
|
import * as cli from './cli';
|
||||||
import getArgv from './config/__fixtures__/argv';
|
|
||||||
import type { RenovateOptions } from './types';
|
|
||||||
|
|
||||||
describe(getName(), () => {
|
describe(getName(), () => {
|
||||||
let argv: string[];
|
let argv: string[];
|
|
@ -1,7 +1,7 @@
|
||||||
import { Command } from 'commander';
|
import { Command } from 'commander';
|
||||||
import { version } from '../../package.json';
|
import { version } from '../../../../../package.json';
|
||||||
import { getOptions } from './definitions';
|
import { getOptions } from '../../../../config/definitions';
|
||||||
import type { AllConfig, RenovateCliConfig, RenovateOptions } from './types';
|
import type { AllConfig, RenovateOptions } from '../../../../config/types';
|
||||||
|
|
||||||
export function getCliName(option: Partial<RenovateOptions>): string {
|
export function getCliName(option: Partial<RenovateOptions>): string {
|
||||||
if (option.cli === false) {
|
if (option.cli === false) {
|
||||||
|
@ -27,7 +27,7 @@ export function getConfig(input: string[]): AllConfig {
|
||||||
.filter((a) => !a.startsWith('--git-fs'));
|
.filter((a) => !a.startsWith('--git-fs'));
|
||||||
const options = getOptions();
|
const options = getOptions();
|
||||||
|
|
||||||
const config: RenovateCliConfig = {};
|
const config: Record<string, any> = {};
|
||||||
|
|
||||||
const coersions: Record<string, (arg: string) => unknown> = {
|
const coersions: Record<string, (arg: string) => unknown> = {
|
||||||
boolean: (val: string): boolean => {
|
boolean: (val: string): boolean => {
|
|
@ -1,10 +1,10 @@
|
||||||
import { getName } from '../../test/util';
|
import { getName } from '../../../../../test/util';
|
||||||
|
import type { RenovateOptions } from '../../../../config/types';
|
||||||
import {
|
import {
|
||||||
PLATFORM_TYPE_BITBUCKET,
|
PLATFORM_TYPE_BITBUCKET,
|
||||||
PLATFORM_TYPE_GITLAB,
|
PLATFORM_TYPE_GITLAB,
|
||||||
} from '../constants/platforms';
|
} from '../../../../constants/platforms';
|
||||||
import * as env from './env';
|
import * as env from './env';
|
||||||
import type { RenovateOptions } from './types';
|
|
||||||
|
|
||||||
describe(getName(), () => {
|
describe(getName(), () => {
|
||||||
describe('.getConfig(env)', () => {
|
describe('.getConfig(env)', () => {
|
|
@ -1,11 +1,11 @@
|
||||||
import is from '@sindresorhus/is';
|
import is from '@sindresorhus/is';
|
||||||
|
|
||||||
import { PLATFORM_TYPE_GITHUB } from '../constants/platforms';
|
import { getOptions } from '../../../../config/definitions';
|
||||||
import { getDatasourceList } from '../datasource';
|
import type { AllConfig, RenovateOptions } from '../../../../config/types';
|
||||||
import { logger } from '../logger';
|
import { PLATFORM_TYPE_GITHUB } from '../../../../constants/platforms';
|
||||||
import type { HostRule } from '../types';
|
import { getDatasourceList } from '../../../../datasource';
|
||||||
import { getOptions } from './definitions';
|
import { logger } from '../../../../logger';
|
||||||
import type { AllConfig, RenovateOptions } from './types';
|
import type { HostRule } from '../../../../types';
|
||||||
|
|
||||||
// istanbul ignore if
|
// istanbul ignore if
|
||||||
if (process.env.ENV_PREFIX) {
|
if (process.env.ENV_PREFIX) {
|
|
@ -1,8 +1,8 @@
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import { DirectoryResult, dir } from 'tmp-promise';
|
import { DirectoryResult, dir } from 'tmp-promise';
|
||||||
import upath from 'upath';
|
import upath from 'upath';
|
||||||
import { getName } from '../../test/util';
|
import { getName } from '../../../../../test/util';
|
||||||
import customConfig from './config/__fixtures__/file';
|
import customConfig from './__fixtures__/file';
|
||||||
import * as file from './file';
|
import * as file from './file';
|
||||||
|
|
||||||
describe(getName(), () => {
|
describe(getName(), () => {
|
||||||
|
@ -23,19 +23,13 @@ describe(getName(), () => {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it('parses custom config file', () => {
|
it('parses custom config file', () => {
|
||||||
const configFile = upath.resolve(
|
const configFile = upath.resolve(__dirname, './__fixtures__/file.js');
|
||||||
__dirname,
|
|
||||||
'./config/__fixtures__/file.js'
|
|
||||||
);
|
|
||||||
expect(file.getConfig({ RENOVATE_CONFIG_FILE: configFile })).toEqual(
|
expect(file.getConfig({ RENOVATE_CONFIG_FILE: configFile })).toEqual(
|
||||||
customConfig
|
customConfig
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it('migrates', () => {
|
it('migrates', () => {
|
||||||
const configFile = upath.resolve(
|
const configFile = upath.resolve(__dirname, './__fixtures__/file2.js');
|
||||||
__dirname,
|
|
||||||
'./config/__fixtures__/file2.js'
|
|
||||||
);
|
|
||||||
const res = file.getConfig({ RENOVATE_CONFIG_FILE: configFile });
|
const res = file.getConfig({ RENOVATE_CONFIG_FILE: configFile });
|
||||||
expect(res).toMatchSnapshot();
|
expect(res).toMatchSnapshot();
|
||||||
expect(res.rangeStrategy).toEqual('bump');
|
expect(res.rangeStrategy).toEqual('bump');
|
|
@ -1,7 +1,7 @@
|
||||||
import upath from 'upath';
|
import upath from 'upath';
|
||||||
import { logger } from '../logger';
|
import { migrateConfig } from '../../../../config/migration';
|
||||||
import { migrateConfig } from './migration';
|
import type { AllConfig } from '../../../../config/types';
|
||||||
import type { AllConfig } from './types';
|
import { logger } from '../../../../logger';
|
||||||
|
|
||||||
export function getConfig(env: NodeJS.ProcessEnv): AllConfig {
|
export function getConfig(env: NodeJS.ProcessEnv): AllConfig {
|
||||||
let configFile = env.RENOVATE_CONFIG_FILE || 'config';
|
let configFile = env.RENOVATE_CONFIG_FILE || 'config';
|
113
lib/workers/global/config/parse/index.spec.ts
Normal file
113
lib/workers/global/config/parse/index.spec.ts
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
import upath from 'upath';
|
||||||
|
import { getName } from '../../../../../test/util';
|
||||||
|
import { readFile } from '../../../../util/fs';
|
||||||
|
import getArgv from './__fixtures__/argv';
|
||||||
|
|
||||||
|
jest.mock('../../../../datasource/npm');
|
||||||
|
try {
|
||||||
|
jest.mock('../../config.js');
|
||||||
|
} catch (err) {
|
||||||
|
// file does not exist
|
||||||
|
}
|
||||||
|
|
||||||
|
describe(getName(), () => {
|
||||||
|
describe('.parseConfigs(env, defaultArgv)', () => {
|
||||||
|
let configParser: typeof import('.');
|
||||||
|
let defaultArgv: string[];
|
||||||
|
let defaultEnv: NodeJS.ProcessEnv;
|
||||||
|
beforeEach(async () => {
|
||||||
|
jest.resetModules();
|
||||||
|
configParser = await import('./index');
|
||||||
|
defaultArgv = getArgv();
|
||||||
|
defaultEnv = { RENOVATE_CONFIG_FILE: 'abc' };
|
||||||
|
jest.mock('delay', () => Promise.resolve());
|
||||||
|
});
|
||||||
|
it('supports token in env', async () => {
|
||||||
|
const env: NodeJS.ProcessEnv = { ...defaultEnv, RENOVATE_TOKEN: 'abc' };
|
||||||
|
const parsedConfig = await configParser.parseConfigs(env, defaultArgv);
|
||||||
|
expect(parsedConfig).toContainEntries([['token', 'abc']]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('supports token in CLI options', async () => {
|
||||||
|
defaultArgv = defaultArgv.concat([
|
||||||
|
'--token=abc',
|
||||||
|
'--pr-footer=custom',
|
||||||
|
'--log-context=abc123',
|
||||||
|
]);
|
||||||
|
const parsedConfig = await configParser.parseConfigs(
|
||||||
|
defaultEnv,
|
||||||
|
defaultArgv
|
||||||
|
);
|
||||||
|
expect(parsedConfig).toContainEntries([
|
||||||
|
['token', 'abc'],
|
||||||
|
['prFooter', 'custom'],
|
||||||
|
['logContext', 'abc123'],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('supports forceCli', async () => {
|
||||||
|
defaultArgv = defaultArgv.concat(['--force-cli=false']);
|
||||||
|
const env: NodeJS.ProcessEnv = {
|
||||||
|
...defaultEnv,
|
||||||
|
RENOVATE_TOKEN: 'abc',
|
||||||
|
};
|
||||||
|
const parsedConfig = await configParser.parseConfigs(env, defaultArgv);
|
||||||
|
expect(parsedConfig).toContainEntries([
|
||||||
|
['token', 'abc'],
|
||||||
|
['force', null],
|
||||||
|
]);
|
||||||
|
expect(parsedConfig).not.toContainKey('configFile');
|
||||||
|
});
|
||||||
|
it('supports config.force', async () => {
|
||||||
|
const configPath = upath.join(__dirname, '__fixtures__/with-force.js');
|
||||||
|
const env: NodeJS.ProcessEnv = {
|
||||||
|
...defaultEnv,
|
||||||
|
RENOVATE_CONFIG_FILE: configPath,
|
||||||
|
};
|
||||||
|
const parsedConfig = await configParser.parseConfigs(env, defaultArgv);
|
||||||
|
expect(parsedConfig).toContainEntries([
|
||||||
|
['token', 'abcdefg'],
|
||||||
|
[
|
||||||
|
'force',
|
||||||
|
{
|
||||||
|
schedule: null,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
it('reads private key from file', async () => {
|
||||||
|
const privateKeyPath = upath.join(__dirname, '__fixtures__/private.pem');
|
||||||
|
const env: NodeJS.ProcessEnv = {
|
||||||
|
...defaultEnv,
|
||||||
|
RENOVATE_PRIVATE_KEY_PATH: privateKeyPath,
|
||||||
|
};
|
||||||
|
const expected = await readFile(privateKeyPath);
|
||||||
|
const parsedConfig = await configParser.parseConfigs(env, defaultArgv);
|
||||||
|
|
||||||
|
expect(parsedConfig).toContainEntries([['privateKey', expected]]);
|
||||||
|
});
|
||||||
|
it('supports Bitbucket username/passwod', async () => {
|
||||||
|
defaultArgv = defaultArgv.concat([
|
||||||
|
'--platform=bitbucket',
|
||||||
|
'--username=user',
|
||||||
|
'--password=pass',
|
||||||
|
]);
|
||||||
|
const parsedConfig = await configParser.parseConfigs(
|
||||||
|
defaultEnv,
|
||||||
|
defaultArgv
|
||||||
|
);
|
||||||
|
expect(parsedConfig).toContainEntries([
|
||||||
|
['platform', 'bitbucket'],
|
||||||
|
['username', 'user'],
|
||||||
|
['password', 'pass'],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
it('massages trailing slash into endpoint', async () => {
|
||||||
|
defaultArgv = defaultArgv.concat([
|
||||||
|
'--endpoint=https://github.renovatebot.com/api/v3',
|
||||||
|
]);
|
||||||
|
const parsed = await configParser.parseConfigs(defaultEnv, defaultArgv);
|
||||||
|
expect(parsed.endpoint).toEqual('https://github.renovatebot.com/api/v3/');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
88
lib/workers/global/config/parse/index.ts
Normal file
88
lib/workers/global/config/parse/index.ts
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
import * as defaultsParser from '../../../../config/defaults';
|
||||||
|
import { AllConfig } from '../../../../config/types';
|
||||||
|
import { mergeChildConfig } from '../../../../config/utils';
|
||||||
|
import { addStream, logger, setContext } from '../../../../logger';
|
||||||
|
import { ensureDir, getSubDirectory, readFile } from '../../../../util/fs';
|
||||||
|
import { ensureTrailingSlash } from '../../../../util/url';
|
||||||
|
import * as cliParser from './cli';
|
||||||
|
import * as envParser from './env';
|
||||||
|
import * as fileParser from './file';
|
||||||
|
|
||||||
|
export async function parseConfigs(
|
||||||
|
env: NodeJS.ProcessEnv,
|
||||||
|
argv: string[]
|
||||||
|
): Promise<AllConfig> {
|
||||||
|
logger.debug('Parsing configs');
|
||||||
|
|
||||||
|
// Get configs
|
||||||
|
const defaultConfig = defaultsParser.getConfig();
|
||||||
|
const fileConfig = fileParser.getConfig(env);
|
||||||
|
const cliConfig = cliParser.getConfig(argv);
|
||||||
|
const envConfig = envParser.getConfig(env);
|
||||||
|
|
||||||
|
let config: AllConfig = mergeChildConfig(fileConfig, envConfig);
|
||||||
|
config = mergeChildConfig(config, cliConfig);
|
||||||
|
|
||||||
|
const combinedConfig = config;
|
||||||
|
|
||||||
|
config = mergeChildConfig(defaultConfig, config);
|
||||||
|
|
||||||
|
if (config.forceCli) {
|
||||||
|
const forcedCli = { ...cliConfig };
|
||||||
|
delete forcedCli.token;
|
||||||
|
delete forcedCli.hostRules;
|
||||||
|
if (config.force) {
|
||||||
|
config.force = { ...config.force, ...forcedCli };
|
||||||
|
} else {
|
||||||
|
config.force = forcedCli;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!config.privateKey && config.privateKeyPath) {
|
||||||
|
config.privateKey = await readFile(config.privateKeyPath);
|
||||||
|
delete config.privateKeyPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.logContext) {
|
||||||
|
// This only has an effect if logContext was defined via file or CLI, otherwise it would already have been detected in env
|
||||||
|
setContext(config.logContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add file logger
|
||||||
|
// istanbul ignore if
|
||||||
|
if (config.logFile) {
|
||||||
|
logger.debug(
|
||||||
|
`Enabling ${config.logFileLevel} logging to ${config.logFile}`
|
||||||
|
);
|
||||||
|
await ensureDir(getSubDirectory(config.logFile));
|
||||||
|
addStream({
|
||||||
|
name: 'logfile',
|
||||||
|
path: config.logFile,
|
||||||
|
level: config.logFileLevel,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.trace({ config: defaultConfig }, 'Default config');
|
||||||
|
logger.debug({ config: fileConfig }, 'File config');
|
||||||
|
logger.debug({ config: cliConfig }, 'CLI config');
|
||||||
|
logger.debug({ config: envConfig }, 'Env config');
|
||||||
|
logger.debug({ config: combinedConfig }, 'Combined config');
|
||||||
|
|
||||||
|
// Get global config
|
||||||
|
logger.trace({ config }, 'Full config');
|
||||||
|
|
||||||
|
// Print config
|
||||||
|
logger.trace({ config }, 'Global config');
|
||||||
|
|
||||||
|
// Massage endpoint to have a trailing slash
|
||||||
|
if (config.endpoint) {
|
||||||
|
logger.debug('Adding trailing slash to endpoint');
|
||||||
|
config.endpoint = ensureTrailingSlash(config.endpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove log file entries
|
||||||
|
delete config.logFile;
|
||||||
|
delete config.logFileLevel;
|
||||||
|
|
||||||
|
return config;
|
||||||
|
}
|
|
@ -1,6 +1,5 @@
|
||||||
import { ERROR, WARN } from 'bunyan';
|
import { ERROR, WARN } from 'bunyan';
|
||||||
import { getName, logger } from '../../../test/util';
|
import { getName, logger } from '../../../test/util';
|
||||||
import * as _configParser from '../../config';
|
|
||||||
import {
|
import {
|
||||||
PLATFORM_TYPE_GITHUB,
|
PLATFORM_TYPE_GITHUB,
|
||||||
PLATFORM_TYPE_GITLAB,
|
PLATFORM_TYPE_GITLAB,
|
||||||
|
@ -8,6 +7,7 @@ import {
|
||||||
import * as datasourceDocker from '../../datasource/docker';
|
import * as datasourceDocker from '../../datasource/docker';
|
||||||
import * as _platform from '../../platform';
|
import * as _platform from '../../platform';
|
||||||
import * as _repositoryWorker from '../repository';
|
import * as _repositoryWorker from '../repository';
|
||||||
|
import * as _configParser from './config/parse';
|
||||||
import * as _limits from './limits';
|
import * as _limits from './limits';
|
||||||
import * as globalWorker from '.';
|
import * as globalWorker from '.';
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ import { getProblems, logger, setMeta } from '../../logger';
|
||||||
import * as hostRules from '../../util/host-rules';
|
import * as hostRules from '../../util/host-rules';
|
||||||
import * as repositoryWorker from '../repository';
|
import * as repositoryWorker from '../repository';
|
||||||
import { autodiscoverRepositories } from './autodiscover';
|
import { autodiscoverRepositories } from './autodiscover';
|
||||||
|
import { parseConfigs } from './config/parse';
|
||||||
import { globalFinalize, globalInitialize } from './initialize';
|
import { globalFinalize, globalInitialize } from './initialize';
|
||||||
import { Limit, isLimitReached } from './limits';
|
import { Limit, isLimitReached } from './limits';
|
||||||
|
|
||||||
|
@ -38,7 +39,7 @@ export async function getRepositoryConfig(
|
||||||
}
|
}
|
||||||
|
|
||||||
function getGlobalConfig(): Promise<RenovateConfig> {
|
function getGlobalConfig(): Promise<RenovateConfig> {
|
||||||
return configParser.parseConfigs(process.env, process.argv);
|
return parseConfigs(process.env, process.argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
function haveReachedLimits(): boolean {
|
function haveReachedLimits(): boolean {
|
||||||
|
|
Loading…
Reference in a new issue