2020-10-27 12:23:21 +00:00
|
|
|
import later from '@breejs/later';
|
2019-07-17 08:14:56 +00:00
|
|
|
import is from '@sindresorhus/is';
|
2021-03-10 22:04:12 +00:00
|
|
|
import { dequal } from 'dequal';
|
2019-08-23 13:46:31 +00:00
|
|
|
import { logger } from '../logger';
|
2020-05-01 16:03:48 +00:00
|
|
|
import { clone } from '../util/clone';
|
2021-10-19 12:53:34 +00:00
|
|
|
import { regEx } from '../util/regex';
|
2021-11-23 20:10:45 +00:00
|
|
|
import { GlobalConfig } from './global';
|
2021-11-17 15:43:55 +00:00
|
|
|
import { MigrationsService } from './migrations';
|
2021-08-15 05:25:30 +00:00
|
|
|
import { getOptions } from './options';
|
2021-04-19 14:42:29 +00:00
|
|
|
import { removedPresets } from './presets/common';
|
2021-05-11 10:51:21 +00:00
|
|
|
import type {
|
|
|
|
MigratedConfig,
|
|
|
|
MigratedRenovateConfig,
|
|
|
|
RenovateConfig,
|
|
|
|
RenovateOptions,
|
|
|
|
} from './types';
|
2021-04-11 16:00:29 +00:00
|
|
|
import { mergeChildConfig } from './utils';
|
2019-07-17 08:14:56 +00:00
|
|
|
|
2019-08-23 13:46:31 +00:00
|
|
|
const options = getOptions();
|
2021-12-29 06:26:13 +00:00
|
|
|
export function fixShortHours(input: string): string {
|
|
|
|
return input.replace(regEx(/( \d?\d)((a|p)m)/g), '$1:00$2');
|
|
|
|
}
|
2017-08-14 05:49:33 +00:00
|
|
|
|
2019-08-23 13:46:31 +00:00
|
|
|
let optionTypes: Record<string, RenovateOptions['type']>;
|
2017-08-02 06:54:42 +00:00
|
|
|
// Returns a migrated config
|
2019-08-23 13:46:31 +00:00
|
|
|
export function migrateConfig(
|
|
|
|
config: RenovateConfig,
|
2021-04-26 20:19:30 +00:00
|
|
|
// TODO: remove any type (#9611)
|
2019-08-23 13:46:31 +00:00
|
|
|
parentKey?: string | any
|
|
|
|
): MigratedConfig {
|
2018-03-08 06:28:06 +00:00
|
|
|
try {
|
|
|
|
if (!optionTypes) {
|
|
|
|
optionTypes = {};
|
2020-04-12 16:09:36 +00:00
|
|
|
options.forEach((option) => {
|
2018-03-08 06:28:06 +00:00
|
|
|
optionTypes[option.name] = option.type;
|
|
|
|
});
|
|
|
|
}
|
2022-01-10 21:01:57 +00:00
|
|
|
const newConfig = MigrationsService.run(config);
|
2021-11-17 15:43:55 +00:00
|
|
|
const migratedConfig = clone(newConfig) as MigratedRenovateConfig;
|
2018-04-30 06:21:48 +00:00
|
|
|
const depTypes = [
|
|
|
|
'dependencies',
|
|
|
|
'devDependencies',
|
2020-02-22 15:31:01 +00:00
|
|
|
'engines',
|
2018-04-30 06:21:48 +00:00
|
|
|
'optionalDependencies',
|
|
|
|
'peerDependencies',
|
|
|
|
];
|
2021-11-23 20:10:45 +00:00
|
|
|
const { migratePresets } = GlobalConfig.get();
|
2018-03-08 06:28:06 +00:00
|
|
|
for (const [key, val] of Object.entries(config)) {
|
2021-11-17 15:43:55 +00:00
|
|
|
if (key === 'pathRules') {
|
2018-06-04 18:07:22 +00:00
|
|
|
if (is.array(val)) {
|
2020-12-16 08:08:39 +00:00
|
|
|
migratedConfig.packageRules = is.array(migratedConfig.packageRules)
|
|
|
|
? migratedConfig.packageRules
|
|
|
|
: [];
|
|
|
|
migratedConfig.packageRules = val.concat(migratedConfig.packageRules);
|
2018-04-29 21:07:39 +00:00
|
|
|
}
|
|
|
|
delete migratedConfig.pathRules;
|
2020-07-07 12:30:45 +00:00
|
|
|
} else if (key === 'suppressNotifications') {
|
|
|
|
if (is.nonEmptyArray(val) && val.includes('prEditNotification')) {
|
2021-05-17 08:06:24 +00:00
|
|
|
migratedConfig.suppressNotifications =
|
|
|
|
migratedConfig.suppressNotifications.filter(
|
|
|
|
(item) => item !== 'prEditNotification'
|
|
|
|
);
|
2020-07-07 12:30:45 +00:00
|
|
|
}
|
2020-07-11 09:55:30 +00:00
|
|
|
} else if (key.startsWith('masterIssue')) {
|
2020-07-22 17:11:38 +00:00
|
|
|
const newKey = key.replace('masterIssue', 'dependencyDashboard');
|
|
|
|
migratedConfig[newKey] = val;
|
|
|
|
if (optionTypes[newKey] === 'boolean' && val === 'true') {
|
|
|
|
migratedConfig[newKey] = true;
|
|
|
|
}
|
2020-07-11 09:55:30 +00:00
|
|
|
delete migratedConfig[key];
|
2020-09-11 11:15:04 +00:00
|
|
|
} else if (key === 'semanticCommits') {
|
|
|
|
if (val === true) {
|
|
|
|
migratedConfig.semanticCommits = 'enabled';
|
|
|
|
} else if (val === false) {
|
|
|
|
migratedConfig.semanticCommits = 'disabled';
|
2020-09-12 09:36:41 +00:00
|
|
|
} else if (val !== 'enabled' && val !== 'disabled') {
|
2020-09-11 11:15:04 +00:00
|
|
|
migratedConfig.semanticCommits = 'auto';
|
|
|
|
}
|
2021-10-20 14:56:28 +00:00
|
|
|
} else if (key === 'enabledManagers' && is.array(val)) {
|
|
|
|
// Replace yarn with npm, since yarn actually uses npm as package manager
|
|
|
|
migratedConfig.enabledManagers = migratedConfig.enabledManagers.map(
|
|
|
|
(element) => (element === 'yarn' ? 'npm' : element)
|
|
|
|
);
|
2019-05-21 11:20:09 +00:00
|
|
|
} else if (parentKey === 'hostRules' && key === 'platform') {
|
|
|
|
migratedConfig.hostType = val;
|
|
|
|
delete migratedConfig.platform;
|
2019-05-24 15:40:39 +00:00
|
|
|
} else if (parentKey === 'hostRules' && key === 'endpoint') {
|
2021-05-13 20:53:18 +00:00
|
|
|
migratedConfig.matchHost ||= val;
|
2019-05-24 15:40:39 +00:00
|
|
|
delete migratedConfig.endpoint;
|
|
|
|
} else if (parentKey === 'hostRules' && key === 'host') {
|
2021-05-13 20:53:18 +00:00
|
|
|
migratedConfig.matchHost ||= val;
|
2019-05-24 15:40:39 +00:00
|
|
|
delete migratedConfig.host;
|
2021-05-13 20:53:18 +00:00
|
|
|
} else if (parentKey === 'hostRules' && key === 'baseUrl') {
|
|
|
|
migratedConfig.matchHost ||= val;
|
|
|
|
delete migratedConfig.baseUrl;
|
|
|
|
} else if (parentKey === 'hostRules' && key === 'hostName') {
|
|
|
|
migratedConfig.matchHost ||= val;
|
2021-05-14 07:40:07 +00:00
|
|
|
delete migratedConfig.hostName;
|
2021-05-13 20:53:18 +00:00
|
|
|
} else if (parentKey === 'hostRules' && key === 'domainName') {
|
|
|
|
migratedConfig.matchHost ||= val;
|
|
|
|
delete migratedConfig.domainName;
|
2020-12-13 09:16:37 +00:00
|
|
|
} else if (key === 'packageRules' && is.plainObject(val)) {
|
2020-12-16 08:08:39 +00:00
|
|
|
migratedConfig.packageRules = is.array(migratedConfig.packageRules)
|
|
|
|
? migratedConfig.packageRules
|
|
|
|
: [];
|
|
|
|
migratedConfig.packageRules.push(val);
|
2018-06-04 18:07:22 +00:00
|
|
|
} else if (key === 'packageFiles' && is.array(val)) {
|
2018-05-01 07:21:15 +00:00
|
|
|
const fileList = [];
|
|
|
|
for (const packageFile of val) {
|
2018-06-04 18:07:22 +00:00
|
|
|
if (is.object(packageFile) && !is.array(packageFile)) {
|
2019-08-28 04:46:48 +00:00
|
|
|
fileList.push((packageFile as any).packageFile);
|
2018-05-01 07:21:15 +00:00
|
|
|
if (Object.keys(packageFile).length > 1) {
|
2020-12-16 08:08:39 +00:00
|
|
|
migratedConfig.packageRules = is.array(
|
|
|
|
migratedConfig.packageRules
|
|
|
|
)
|
|
|
|
? migratedConfig.packageRules
|
|
|
|
: [];
|
2021-05-17 08:06:24 +00:00
|
|
|
const payload = migrateConfig(
|
|
|
|
packageFile as RenovateConfig,
|
|
|
|
key
|
|
|
|
).migratedConfig;
|
2018-05-01 07:21:15 +00:00
|
|
|
for (const subrule of payload.packageRules || []) {
|
2019-08-28 04:46:48 +00:00
|
|
|
subrule.paths = [(packageFile as any).packageFile];
|
2018-05-01 07:21:15 +00:00
|
|
|
migratedConfig.packageRules.push(subrule);
|
|
|
|
}
|
|
|
|
delete payload.packageFile;
|
|
|
|
delete payload.packageRules;
|
|
|
|
if (Object.keys(payload).length) {
|
|
|
|
migratedConfig.packageRules.push({
|
|
|
|
...payload,
|
2019-08-28 04:46:48 +00:00
|
|
|
paths: [(packageFile as any).packageFile],
|
2018-05-01 07:21:15 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
fileList.push(packageFile);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
migratedConfig.includePaths = fileList;
|
|
|
|
delete migratedConfig.packageFiles;
|
2018-04-30 06:21:48 +00:00
|
|
|
} else if (depTypes.includes(key)) {
|
2020-12-16 08:08:39 +00:00
|
|
|
migratedConfig.packageRules = is.array(migratedConfig.packageRules)
|
|
|
|
? migratedConfig.packageRules
|
|
|
|
: [];
|
2021-05-17 08:06:24 +00:00
|
|
|
const depTypePackageRule = migrateConfig(
|
|
|
|
val as RenovateConfig,
|
|
|
|
key
|
|
|
|
).migratedConfig;
|
2018-04-30 06:21:48 +00:00
|
|
|
depTypePackageRule.depTypeList = [key];
|
|
|
|
delete depTypePackageRule.packageRules;
|
|
|
|
migratedConfig.packageRules.push(depTypePackageRule);
|
|
|
|
delete migratedConfig[key];
|
feat: rangeStrategy (#1954)
This PR replaces the existing `pinVersions`, `upgradeInRange` and `versionStrategy` settings with a single one: `rangeStrategy`.
Previously:
- `pinVersions` could be `true` or `false`, but defaulted to `null`, which meant that Renovate would decide. `true` meant that Renovate would replace existing ranges like `^1.0.0` with an exact/pinned version such as `1.2.0`.
- `upgradeInRange` could be true or false, default to false. If `true`, it would mean Renovate would replace an existing range like `^1.0.0` with something like `^1.2.0`
- `versionStrategy` could be `replace` or `widen` and was mainly used for `peerDependencies` to widen existing ranges, e.g. from `^1.0.0` to `^1.0.0 || ^2.0.0`
It was possible to set conflicting settings, e.g. configuring `pinVersions=true` and `upgradeInRange=true`.
Now, we combine them into a single setting: `rangeStrategy`:
- `auto` = Renovate decides (this will be done on a manager-by-manager basis)
- `pin` = convert ranges to exact versions
- `bump` = same as `upgradeInRange` previously, e.g. bump the range even if the new version satisifies the existing range
- `replace` = Same as pinVersions === false && upgradeInRange === false, i.e. only replace the range if the new version falls outside it
- `widen` = Same as previous versionStrategy==='widen'
2018-05-17 05:16:13 +00:00
|
|
|
} else if (key === 'pinVersions') {
|
|
|
|
delete migratedConfig.pinVersions;
|
|
|
|
if (val === true) {
|
|
|
|
migratedConfig.rangeStrategy = 'pin';
|
|
|
|
} else if (val === false) {
|
|
|
|
migratedConfig.rangeStrategy = 'replace';
|
|
|
|
}
|
2021-02-10 23:39:06 +00:00
|
|
|
} else if (is.string(val) && val.includes('{{baseDir}}')) {
|
2021-10-19 12:53:34 +00:00
|
|
|
migratedConfig[key] = val.replace(
|
2021-12-29 06:26:13 +00:00
|
|
|
regEx(/{{baseDir}}/g),
|
2021-10-19 12:53:34 +00:00
|
|
|
'{{packageFileDir}}'
|
|
|
|
);
|
2021-03-13 13:28:46 +00:00
|
|
|
} else if (is.string(val) && val.includes('{{depNameShort}}')) {
|
2021-10-19 12:53:34 +00:00
|
|
|
migratedConfig[key] = val.replace(
|
2021-12-29 06:26:13 +00:00
|
|
|
regEx(/{{depNameShort}}/g),
|
2021-10-19 12:53:34 +00:00
|
|
|
'{{depName}}'
|
|
|
|
);
|
2019-05-25 04:59:46 +00:00
|
|
|
} else if (key === 'gitFs') {
|
|
|
|
delete migratedConfig.gitFs;
|
2020-02-22 15:31:50 +00:00
|
|
|
} else if (key === 'rebaseStalePrs') {
|
|
|
|
delete migratedConfig.rebaseStalePrs;
|
|
|
|
if (!migratedConfig.rebaseWhen) {
|
2020-03-17 11:15:22 +00:00
|
|
|
if (val === null) {
|
|
|
|
migratedConfig.rebaseWhen = 'auto';
|
|
|
|
}
|
|
|
|
if (val === true) {
|
|
|
|
migratedConfig.rebaseWhen = 'behind-base-branch';
|
|
|
|
}
|
|
|
|
if (val === false) {
|
|
|
|
migratedConfig.rebaseWhen = 'conflicted';
|
|
|
|
}
|
2020-02-22 15:31:50 +00:00
|
|
|
}
|
|
|
|
} else if (key === 'rebaseConflictedPrs') {
|
|
|
|
delete migratedConfig.rebaseConflictedPrs;
|
2020-03-17 11:15:22 +00:00
|
|
|
if (val === false) {
|
|
|
|
migratedConfig.rebaseWhen = 'never';
|
|
|
|
}
|
2021-04-06 11:06:40 +00:00
|
|
|
} else if (key === 'ignoreNpmrcFile') {
|
|
|
|
delete migratedConfig.ignoreNpmrcFile;
|
2021-04-07 07:55:22 +00:00
|
|
|
if (!is.string(migratedConfig.npmrc)) {
|
|
|
|
migratedConfig.npmrc = '';
|
|
|
|
}
|
2021-02-03 14:02:36 +00:00
|
|
|
} else if (
|
|
|
|
key === 'branchName' &&
|
|
|
|
is.string(val) &&
|
|
|
|
val?.includes('{{managerBranchPrefix}}')
|
|
|
|
) {
|
|
|
|
migratedConfig.branchName = val.replace(
|
|
|
|
'{{managerBranchPrefix}}',
|
|
|
|
'{{additionalBranchPrefix}}'
|
|
|
|
);
|
2020-09-01 12:28:18 +00:00
|
|
|
} else if (key === 'managerBranchPrefix') {
|
|
|
|
delete migratedConfig.managerBranchPrefix;
|
|
|
|
migratedConfig.additionalBranchPrefix = val;
|
2020-09-01 12:37:09 +00:00
|
|
|
} else if (
|
|
|
|
key === 'branchPrefix' &&
|
|
|
|
is.string(val) &&
|
|
|
|
val.includes('{{')
|
|
|
|
) {
|
|
|
|
const templateIndex = val.indexOf(`{{`);
|
|
|
|
migratedConfig.branchPrefix = val.substring(0, templateIndex);
|
|
|
|
migratedConfig.additionalBranchPrefix = val.substring(templateIndex);
|
feat: rangeStrategy (#1954)
This PR replaces the existing `pinVersions`, `upgradeInRange` and `versionStrategy` settings with a single one: `rangeStrategy`.
Previously:
- `pinVersions` could be `true` or `false`, but defaulted to `null`, which meant that Renovate would decide. `true` meant that Renovate would replace existing ranges like `^1.0.0` with an exact/pinned version such as `1.2.0`.
- `upgradeInRange` could be true or false, default to false. If `true`, it would mean Renovate would replace an existing range like `^1.0.0` with something like `^1.2.0`
- `versionStrategy` could be `replace` or `widen` and was mainly used for `peerDependencies` to widen existing ranges, e.g. from `^1.0.0` to `^1.0.0 || ^2.0.0`
It was possible to set conflicting settings, e.g. configuring `pinVersions=true` and `upgradeInRange=true`.
Now, we combine them into a single setting: `rangeStrategy`:
- `auto` = Renovate decides (this will be done on a manager-by-manager basis)
- `pin` = convert ranges to exact versions
- `bump` = same as `upgradeInRange` previously, e.g. bump the range even if the new version satisifies the existing range
- `replace` = Same as pinVersions === false && upgradeInRange === false, i.e. only replace the range if the new version falls outside it
- `widen` = Same as previous versionStrategy==='widen'
2018-05-17 05:16:13 +00:00
|
|
|
} else if (key === 'upgradeInRange') {
|
|
|
|
delete migratedConfig.upgradeInRange;
|
|
|
|
if (val === true) {
|
|
|
|
migratedConfig.rangeStrategy = 'bump';
|
|
|
|
}
|
|
|
|
} else if (key === 'versionStrategy') {
|
|
|
|
delete migratedConfig.versionStrategy;
|
|
|
|
if (val === 'widen') {
|
|
|
|
migratedConfig.rangeStrategy = 'widen';
|
|
|
|
}
|
2020-03-02 11:06:16 +00:00
|
|
|
} else if (key === 'semanticPrefix' && is.string(val)) {
|
2018-03-08 06:28:06 +00:00
|
|
|
delete migratedConfig.semanticPrefix;
|
2020-03-02 11:06:16 +00:00
|
|
|
let [text] = val.split(':') as any; // TODO: fixme
|
2018-03-08 06:28:06 +00:00
|
|
|
text = text.split('(');
|
|
|
|
[migratedConfig.semanticCommitType] = text;
|
|
|
|
if (text.length > 1) {
|
|
|
|
[migratedConfig.semanticCommitScope] = text[1].split(')');
|
|
|
|
} else {
|
|
|
|
migratedConfig.semanticCommitScope = null;
|
2018-03-08 05:02:16 +00:00
|
|
|
}
|
2020-10-27 15:39:11 +00:00
|
|
|
} else if (
|
|
|
|
key === 'extends' &&
|
|
|
|
(is.array<string>(val) || is.string(val))
|
|
|
|
) {
|
|
|
|
if (is.string(migratedConfig.extends)) {
|
|
|
|
migratedConfig.extends = [migratedConfig.extends];
|
|
|
|
}
|
|
|
|
const presets = migratedConfig.extends;
|
|
|
|
for (let i = 0; i < presets.length; i += 1) {
|
2021-04-19 14:42:29 +00:00
|
|
|
const preset = presets[i];
|
2020-10-27 15:39:11 +00:00
|
|
|
if (is.string(preset)) {
|
2021-05-22 21:47:28 +00:00
|
|
|
let newPreset = removedPresets[preset];
|
|
|
|
if (newPreset !== undefined) {
|
|
|
|
presets[i] = newPreset;
|
|
|
|
}
|
|
|
|
newPreset = migratePresets?.[preset];
|
2021-04-19 14:42:29 +00:00
|
|
|
if (newPreset !== undefined) {
|
|
|
|
presets[i] = newPreset;
|
2020-10-27 15:39:11 +00:00
|
|
|
}
|
2018-03-08 06:28:06 +00:00
|
|
|
}
|
|
|
|
}
|
2021-04-19 14:42:29 +00:00
|
|
|
migratedConfig.extends = migratedConfig.extends.filter(Boolean);
|
2020-12-11 09:09:58 +00:00
|
|
|
} else if (key === 'unpublishSafe') {
|
|
|
|
if (val === true) {
|
|
|
|
migratedConfig.extends = migratedConfig.extends || [];
|
|
|
|
if (is.string(migratedConfig.extends)) {
|
|
|
|
migratedConfig.extends = [migratedConfig.extends];
|
|
|
|
}
|
2020-12-13 17:43:27 +00:00
|
|
|
if (
|
|
|
|
![
|
|
|
|
':unpublishSafe',
|
|
|
|
'default:unpublishSafe',
|
|
|
|
'npm:unpublishSafe',
|
|
|
|
].some((x) => migratedConfig.extends.includes(x))
|
|
|
|
) {
|
2020-12-11 09:09:58 +00:00
|
|
|
migratedConfig.extends.push('npm:unpublishSafe');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
delete migratedConfig.unpublishSafe;
|
2019-05-12 04:46:16 +00:00
|
|
|
} else if (
|
|
|
|
key === 'automergeType' &&
|
|
|
|
is.string(val) &&
|
|
|
|
val.startsWith('branch-')
|
|
|
|
) {
|
2018-06-26 11:51:50 +00:00
|
|
|
migratedConfig.automergeType = 'branch';
|
2018-03-08 06:28:06 +00:00
|
|
|
} else if (key === 'automergeMinor') {
|
2018-03-08 06:12:31 +00:00
|
|
|
migratedConfig.minor = migratedConfig.minor || {};
|
2021-11-09 07:02:59 +00:00
|
|
|
migratedConfig.minor.automerge = !!val;
|
2018-03-08 06:28:06 +00:00
|
|
|
delete migratedConfig[key];
|
|
|
|
} else if (key === 'automergeMajor') {
|
2018-03-08 06:12:31 +00:00
|
|
|
migratedConfig.major = migratedConfig.major || {};
|
2021-11-09 07:02:59 +00:00
|
|
|
migratedConfig.major.automerge = !!val;
|
2018-03-08 06:28:06 +00:00
|
|
|
delete migratedConfig[key];
|
2020-03-02 11:06:16 +00:00
|
|
|
} else if (key === 'renovateFork' && is.boolean(val)) {
|
2018-12-31 05:46:00 +00:00
|
|
|
delete migratedConfig.renovateFork;
|
|
|
|
migratedConfig.includeForks = val;
|
2018-05-17 05:36:13 +00:00
|
|
|
} else if (key === 'separateMajorReleases') {
|
|
|
|
delete migratedConfig.separateMultipleMajor;
|
|
|
|
migratedConfig.separateMajorMinor = val;
|
2018-03-08 06:28:06 +00:00
|
|
|
} else if (key === 'automergePatch') {
|
|
|
|
migratedConfig.patch = migratedConfig.patch || {};
|
2021-11-09 07:02:59 +00:00
|
|
|
migratedConfig.patch.automerge = !!val;
|
2018-03-08 06:28:06 +00:00
|
|
|
delete migratedConfig[key];
|
|
|
|
} else if (
|
|
|
|
key === 'automerge' &&
|
2018-06-04 18:07:22 +00:00
|
|
|
is.string(val) &&
|
2018-06-04 18:44:32 +00:00
|
|
|
['none', 'patch', 'minor', 'any'].includes(val)
|
2018-03-08 06:28:06 +00:00
|
|
|
) {
|
|
|
|
delete migratedConfig.automerge;
|
|
|
|
if (val === 'none') {
|
|
|
|
migratedConfig.automerge = false;
|
|
|
|
} else if (val === 'patch') {
|
|
|
|
migratedConfig.patch = migratedConfig.patch || {};
|
|
|
|
migratedConfig.patch.automerge = true;
|
|
|
|
migratedConfig.minor = migratedConfig.minor || {};
|
|
|
|
migratedConfig.minor.automerge = false;
|
|
|
|
migratedConfig.major = migratedConfig.major || {};
|
|
|
|
migratedConfig.major.automerge = false;
|
|
|
|
} else if (val === 'minor') {
|
|
|
|
migratedConfig.minor = migratedConfig.minor || {};
|
|
|
|
migratedConfig.minor.automerge = true;
|
|
|
|
migratedConfig.major = migratedConfig.major || {};
|
|
|
|
migratedConfig.major.automerge = false;
|
2020-03-07 10:27:10 +00:00
|
|
|
} /* istanbul ignore else: we can never go to else */ else if (
|
|
|
|
val === 'any'
|
|
|
|
) {
|
2018-03-08 06:28:06 +00:00
|
|
|
migratedConfig.automerge = true;
|
|
|
|
}
|
|
|
|
} else if (key === 'packages') {
|
2020-12-16 08:08:39 +00:00
|
|
|
migratedConfig.packageRules = is.array(migratedConfig.packageRules)
|
|
|
|
? migratedConfig.packageRules
|
|
|
|
: [];
|
|
|
|
migratedConfig.packageRules = migratedConfig.packageRules.concat(
|
|
|
|
migratedConfig.packages
|
|
|
|
);
|
2018-03-08 06:28:06 +00:00
|
|
|
delete migratedConfig.packages;
|
|
|
|
} else if (key === 'packageName') {
|
|
|
|
migratedConfig.packageNames = [val];
|
|
|
|
delete migratedConfig.packageName;
|
|
|
|
} else if (key === 'packagePattern') {
|
|
|
|
migratedConfig.packagePatterns = [val];
|
|
|
|
delete migratedConfig.packagePattern;
|
|
|
|
} else if (key === 'baseBranch') {
|
2020-07-30 04:54:20 +00:00
|
|
|
migratedConfig.baseBranches = (is.array(val) ? val : [val]) as string[];
|
2018-03-08 06:28:06 +00:00
|
|
|
delete migratedConfig.baseBranch;
|
2018-10-05 07:59:32 +00:00
|
|
|
} else if (key === 'schedule' && val) {
|
2018-03-08 06:28:06 +00:00
|
|
|
// massage to array first
|
2020-03-02 11:06:16 +00:00
|
|
|
const schedules = is.string(val) ? [val] : [...(val as string[])];
|
2018-03-08 06:28:06 +00:00
|
|
|
// split 'and'
|
2018-12-05 04:39:24 +00:00
|
|
|
const schedulesLength = schedules.length;
|
2021-12-29 06:26:13 +00:00
|
|
|
const afterBeforeRe = regEx(
|
|
|
|
/^(.*?)(after|before) (.*?) and (after|before) (.*?)( |$)(.*)/
|
|
|
|
);
|
2018-12-05 04:39:24 +00:00
|
|
|
for (let i = 0; i < schedulesLength; i += 1) {
|
2018-03-08 06:28:06 +00:00
|
|
|
if (
|
|
|
|
schedules[i].includes(' and ') &&
|
|
|
|
schedules[i].includes('before ') &&
|
|
|
|
schedules[i].includes('after ')
|
|
|
|
) {
|
|
|
|
const parsedSchedule = later.parse.text(
|
|
|
|
// We need to massage short hours first before we can parse it
|
2021-12-29 06:26:13 +00:00
|
|
|
fixShortHours(schedules[i])
|
2018-03-08 06:28:06 +00:00
|
|
|
).schedules[0];
|
|
|
|
// Only migrate if the after time is greater than before, e.g. "after 10pm and before 5am"
|
2020-07-18 06:42:32 +00:00
|
|
|
if (parsedSchedule?.t_a?.[0] > parsedSchedule?.t_b?.[0]) {
|
2018-03-08 06:28:06 +00:00
|
|
|
const toSplit = schedules[i];
|
|
|
|
schedules[i] = toSplit
|
2021-12-29 06:26:13 +00:00
|
|
|
.replace(afterBeforeRe, '$1$2 $3 $7')
|
2018-03-08 06:28:06 +00:00
|
|
|
.trim();
|
|
|
|
schedules.push(
|
2021-12-29 06:26:13 +00:00
|
|
|
toSplit.replace(afterBeforeRe, '$1$4 $5 $7').trim()
|
2018-03-08 06:28:06 +00:00
|
|
|
);
|
|
|
|
}
|
2018-03-08 05:02:16 +00:00
|
|
|
}
|
2017-10-14 05:03:44 +00:00
|
|
|
}
|
2018-03-08 06:28:06 +00:00
|
|
|
for (let i = 0; i < schedules.length; i += 1) {
|
2018-06-04 18:44:32 +00:00
|
|
|
if (schedules[i].includes('on the last day of the month')) {
|
2018-03-08 06:28:06 +00:00
|
|
|
schedules[i] = schedules[i].replace(
|
|
|
|
'on the last day of the month',
|
|
|
|
'on the first day of the month'
|
|
|
|
);
|
|
|
|
}
|
2018-06-04 18:44:32 +00:00
|
|
|
if (schedules[i].includes('on every weekday')) {
|
2018-03-08 06:28:06 +00:00
|
|
|
schedules[i] = schedules[i].replace(
|
|
|
|
'on every weekday',
|
|
|
|
'every weekday'
|
|
|
|
);
|
|
|
|
}
|
|
|
|
if (schedules[i].endsWith(' every day')) {
|
|
|
|
schedules[i] = schedules[i].replace(' every day', '');
|
|
|
|
}
|
|
|
|
if (
|
2021-10-19 12:53:34 +00:00
|
|
|
regEx(/every (mon|tues|wednes|thurs|fri|satur|sun)day$/).test(
|
|
|
|
schedules[i]
|
2021-12-29 06:26:13 +00:00
|
|
|
)
|
2018-03-08 06:28:06 +00:00
|
|
|
) {
|
2021-10-19 12:53:34 +00:00
|
|
|
schedules[i] = schedules[i].replace(
|
2021-12-29 06:26:13 +00:00
|
|
|
regEx(/every ([a-z]*day)$/),
|
2021-10-19 12:53:34 +00:00
|
|
|
'on $1'
|
|
|
|
);
|
2018-03-08 06:28:06 +00:00
|
|
|
}
|
|
|
|
if (schedules[i].endsWith('days')) {
|
|
|
|
schedules[i] = schedules[i].replace('days', 'day');
|
|
|
|
}
|
2017-08-23 09:50:05 +00:00
|
|
|
}
|
2020-12-11 13:08:24 +00:00
|
|
|
if (is.string(val) && schedules.length === 1) {
|
|
|
|
[migratedConfig.schedule] = schedules as any; // TODO: fixme
|
|
|
|
} else {
|
|
|
|
migratedConfig.schedule = schedules;
|
2017-08-02 12:05:45 +00:00
|
|
|
}
|
2018-06-04 18:44:32 +00:00
|
|
|
} else if (is.string(val) && val.startsWith('{{semanticPrefix}}')) {
|
2018-04-17 10:08:13 +00:00
|
|
|
migratedConfig[key] = val.replace(
|
|
|
|
'{{semanticPrefix}}',
|
2018-04-17 12:40:00 +00:00
|
|
|
'{{#if semanticCommitType}}{{semanticCommitType}}{{#if semanticCommitScope}}({{semanticCommitScope}}){{/if}}: {{/if}}'
|
2018-04-17 10:08:13 +00:00
|
|
|
);
|
2018-06-04 18:07:22 +00:00
|
|
|
} else if (key === 'depTypes' && is.array(val)) {
|
2020-04-12 16:09:36 +00:00
|
|
|
val.forEach((depType) => {
|
2018-06-04 18:07:22 +00:00
|
|
|
if (is.object(depType) && !is.array(depType)) {
|
2019-08-28 04:46:48 +00:00
|
|
|
const depTypeName = (depType as any).depType;
|
2018-03-08 06:28:06 +00:00
|
|
|
if (depTypeName) {
|
2020-12-16 08:08:39 +00:00
|
|
|
migratedConfig.packageRules = is.array(
|
|
|
|
migratedConfig.packageRules
|
|
|
|
)
|
|
|
|
? migratedConfig.packageRules
|
|
|
|
: [];
|
2020-03-02 11:06:16 +00:00
|
|
|
const newPackageRule = migrateConfig(
|
|
|
|
depType as RenovateConfig,
|
|
|
|
key
|
|
|
|
).migratedConfig;
|
2018-04-29 21:07:39 +00:00
|
|
|
delete newPackageRule.depType;
|
|
|
|
newPackageRule.depTypeList = [depTypeName];
|
|
|
|
migratedConfig.packageRules.push(newPackageRule);
|
2018-03-08 06:28:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
delete migratedConfig.depTypes;
|
2019-03-31 06:01:06 +00:00
|
|
|
} else if (optionTypes[key] === 'object' && is.boolean(val)) {
|
2018-03-08 06:28:06 +00:00
|
|
|
migratedConfig[key] = { enabled: val };
|
|
|
|
} else if (optionTypes[key] === 'boolean') {
|
|
|
|
if (val === 'true') {
|
|
|
|
migratedConfig[key] = true;
|
|
|
|
} else if (val === 'false') {
|
|
|
|
migratedConfig[key] = false;
|
2018-03-08 06:12:31 +00:00
|
|
|
}
|
2018-03-08 06:28:06 +00:00
|
|
|
} else if (
|
|
|
|
optionTypes[key] === 'string' &&
|
2018-06-04 18:07:22 +00:00
|
|
|
is.array(val) &&
|
2018-03-08 06:28:06 +00:00
|
|
|
val.length === 1
|
|
|
|
) {
|
2020-08-26 12:59:50 +00:00
|
|
|
migratedConfig[key] = String(val[0]);
|
2020-03-02 11:06:16 +00:00
|
|
|
} else if (key === 'node' && (val as RenovateConfig).enabled === true) {
|
2018-03-08 06:28:06 +00:00
|
|
|
delete migratedConfig.node.enabled;
|
|
|
|
migratedConfig.travis = migratedConfig.travis || {};
|
|
|
|
migratedConfig.travis.enabled = true;
|
2021-03-04 05:21:55 +00:00
|
|
|
if (Object.keys(migratedConfig.node).length) {
|
2019-05-21 11:20:09 +00:00
|
|
|
const subMigrate = migrateConfig(migratedConfig.node, key);
|
2018-03-08 06:28:06 +00:00
|
|
|
migratedConfig.node = subMigrate.migratedConfig;
|
2021-03-04 05:21:55 +00:00
|
|
|
} else {
|
|
|
|
delete migratedConfig.node;
|
2018-03-08 06:12:31 +00:00
|
|
|
}
|
2018-06-04 18:07:22 +00:00
|
|
|
} else if (is.array(val)) {
|
2021-09-13 13:27:01 +00:00
|
|
|
if (is.array(migratedConfig?.[key])) {
|
|
|
|
const newArray = [];
|
|
|
|
for (const item of migratedConfig[key] as unknown[]) {
|
|
|
|
if (is.object(item) && !is.array(item)) {
|
|
|
|
const arrMigrate = migrateConfig(item as RenovateConfig, key);
|
|
|
|
newArray.push(arrMigrate.migratedConfig);
|
|
|
|
} else {
|
|
|
|
newArray.push(item);
|
|
|
|
}
|
2018-03-08 06:12:31 +00:00
|
|
|
}
|
2021-09-13 13:27:01 +00:00
|
|
|
migratedConfig[key] = newArray;
|
2018-03-08 06:12:31 +00:00
|
|
|
}
|
2020-09-30 09:02:25 +00:00
|
|
|
} else if (key === 'compatibility' && is.object(val)) {
|
|
|
|
migratedConfig.constraints = migratedConfig.compatibility;
|
|
|
|
delete migratedConfig.compatibility;
|
2018-06-04 18:07:22 +00:00
|
|
|
} else if (is.object(val)) {
|
2020-03-02 11:06:16 +00:00
|
|
|
const subMigrate = migrateConfig(
|
|
|
|
migratedConfig[key] as RenovateConfig,
|
|
|
|
key
|
|
|
|
);
|
2018-06-04 18:07:22 +00:00
|
|
|
if (subMigrate.isMigrated) {
|
|
|
|
migratedConfig[key] = subMigrate.migratedConfig;
|
|
|
|
}
|
2018-12-09 10:39:35 +00:00
|
|
|
} else if (key === 'raiseDeprecationWarnings') {
|
|
|
|
delete migratedConfig.raiseDeprecationWarnings;
|
|
|
|
if (val === false) {
|
2018-12-09 12:17:37 +00:00
|
|
|
migratedConfig.suppressNotifications =
|
|
|
|
migratedConfig.suppressNotifications || [];
|
2018-12-09 10:39:35 +00:00
|
|
|
migratedConfig.suppressNotifications.push('deprecationWarningIssues');
|
|
|
|
}
|
2021-08-23 18:13:30 +00:00
|
|
|
} else if (key === 'composerIgnorePlatformReqs') {
|
|
|
|
if (val === true) {
|
|
|
|
migratedConfig.composerIgnorePlatformReqs = [];
|
|
|
|
} else if (val === false) {
|
|
|
|
migratedConfig.composerIgnorePlatformReqs = null;
|
|
|
|
}
|
2021-10-11 06:36:07 +00:00
|
|
|
} else if (key === 'azureAutoComplete' || key === 'gitLabAutomerge') {
|
|
|
|
if (migratedConfig[key] !== undefined) {
|
|
|
|
migratedConfig.platformAutomerge = migratedConfig[key];
|
|
|
|
}
|
|
|
|
delete migratedConfig[key];
|
2017-08-18 17:47:13 +00:00
|
|
|
}
|
2021-10-20 14:56:28 +00:00
|
|
|
|
2021-02-16 08:17:26 +00:00
|
|
|
const migratedTemplates = {
|
2021-02-16 09:52:05 +00:00
|
|
|
fromVersion: 'currentVersion',
|
2021-02-16 08:17:26 +00:00
|
|
|
newValueMajor: 'newMajor',
|
|
|
|
newValueMinor: 'newMinor',
|
|
|
|
newVersionMajor: 'newMajor',
|
|
|
|
newVersionMinor: 'newMinor',
|
2021-02-16 11:33:44 +00:00
|
|
|
toVersion: 'newVersion',
|
2021-02-16 08:17:26 +00:00
|
|
|
};
|
|
|
|
if (is.string(migratedConfig[key])) {
|
|
|
|
for (const [from, to] of Object.entries(migratedTemplates)) {
|
|
|
|
migratedConfig[key] = (migratedConfig[key] as string).replace(
|
2021-12-29 06:26:13 +00:00
|
|
|
regEx(from, 'g'),
|
2021-02-16 08:17:26 +00:00
|
|
|
to
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
2017-08-02 06:54:42 +00:00
|
|
|
}
|
2018-09-12 10:16:17 +00:00
|
|
|
if (migratedConfig.endpoints) {
|
|
|
|
migratedConfig.hostRules = migratedConfig.endpoints;
|
|
|
|
delete migratedConfig.endpoints;
|
|
|
|
}
|
2021-01-29 10:43:42 +00:00
|
|
|
if (is.array(migratedConfig.packageRules)) {
|
|
|
|
const renameMap = {
|
|
|
|
paths: 'matchPaths',
|
|
|
|
languages: 'matchLanguages',
|
|
|
|
baseBranchList: 'matchBaseBranches',
|
|
|
|
managers: 'matchManagers',
|
|
|
|
datasources: 'matchDatasources',
|
|
|
|
depTypeList: 'matchDepTypes',
|
|
|
|
packageNames: 'matchPackageNames',
|
|
|
|
packagePatterns: 'matchPackagePatterns',
|
|
|
|
sourceUrlPrefixes: 'matchSourceUrlPrefixes',
|
|
|
|
updateTypes: 'matchUpdateTypes',
|
|
|
|
};
|
|
|
|
for (const packageRule of migratedConfig.packageRules) {
|
|
|
|
for (const [oldKey, ruleVal] of Object.entries(packageRule)) {
|
|
|
|
const newKey = renameMap[oldKey];
|
|
|
|
if (newKey) {
|
|
|
|
packageRule[newKey] = ruleVal;
|
|
|
|
delete packageRule[oldKey];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-04-11 16:00:29 +00:00
|
|
|
// Migrate nested packageRules
|
|
|
|
if (is.nonEmptyArray(migratedConfig.packageRules)) {
|
2021-05-01 21:01:26 +00:00
|
|
|
const existingRules = migratedConfig.packageRules;
|
|
|
|
migratedConfig.packageRules = [];
|
|
|
|
for (const packageRule of existingRules) {
|
2021-04-11 16:00:29 +00:00
|
|
|
if (is.array(packageRule.packageRules)) {
|
|
|
|
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);
|
|
|
|
delete combinedRule.packageRules;
|
|
|
|
migratedConfig.packageRules.push(combinedRule);
|
|
|
|
}
|
2021-05-01 21:01:26 +00:00
|
|
|
} else {
|
|
|
|
migratedConfig.packageRules.push(packageRule);
|
2021-04-11 16:00:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-08-13 07:38:53 +00:00
|
|
|
if (is.nonEmptyArray(migratedConfig.matchManagers)) {
|
|
|
|
if (migratedConfig.matchManagers.includes('gradle-lite')) {
|
|
|
|
if (!migratedConfig.matchManagers.includes('gradle')) {
|
|
|
|
migratedConfig.matchManagers.push('gradle');
|
|
|
|
}
|
|
|
|
migratedConfig.matchManagers = migratedConfig.matchManagers.filter(
|
|
|
|
(manager) => manager !== 'gradle-lite'
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (is.nonEmptyObject(migratedConfig['gradle-lite'])) {
|
|
|
|
migratedConfig.gradle = mergeChildConfig(
|
|
|
|
migratedConfig.gradle || {},
|
|
|
|
migratedConfig['gradle-lite']
|
|
|
|
);
|
|
|
|
}
|
|
|
|
delete migratedConfig['gradle-lite'];
|
2021-03-10 22:04:12 +00:00
|
|
|
const isMigrated = !dequal(config, migratedConfig);
|
2020-12-11 13:49:27 +00:00
|
|
|
if (isMigrated) {
|
|
|
|
// recursive call in case any migrated configs need further migrating
|
|
|
|
return {
|
|
|
|
isMigrated,
|
|
|
|
migratedConfig: migrateConfig(migratedConfig).migratedConfig,
|
|
|
|
};
|
|
|
|
}
|
2018-03-08 06:28:06 +00:00
|
|
|
return { isMigrated, migratedConfig };
|
|
|
|
} catch (err) /* istanbul ignore next */ {
|
2020-12-16 08:08:39 +00:00
|
|
|
logger.debug({ config, err }, 'migrateConfig() error');
|
2018-03-08 06:28:06 +00:00
|
|
|
throw err;
|
2017-08-02 06:54:42 +00:00
|
|
|
}
|
|
|
|
}
|