diff --git a/lib/config/app-strings.js b/lib/config/app-strings.ts similarity index 50% rename from lib/config/app-strings.js rename to lib/config/app-strings.ts index 2e55d95da607f40e020b894e45c681ffef9facd1..48f45622bfb67c65e9a14de9f5f1f264b4e3e76e 100644 --- a/lib/config/app-strings.js +++ b/lib/config/app-strings.ts @@ -1,8 +1,8 @@ -const appName = 'Renovate'; +export const appName = 'Renovate'; -const appSlug = 'renovate'; +export const appSlug = 'renovate'; -const configFileNames = [ +export const configFileNames = [ 'renovate.json', 'renovate.json5', '.github/renovate.json', @@ -12,20 +12,11 @@ const configFileNames = [ 'package.json', ]; -const onboardingBranch = 'renovate/configure'; -const onboardingPrTitle = 'Configure Renovate'; +export const onboardingBranch = 'renovate/configure'; +export const onboardingPrTitle = 'Configure Renovate'; -const urls = { +export const urls = { documentation: 'https://renovatebot.com/docs/', help: 'https://github.com/renovatebot/config-help/issues', homepage: 'https://renovatebot.com', }; - -module.exports = { - appName, - appSlug, - configFileNames, - onboardingBranch, - onboardingPrTitle, - urls, -}; diff --git a/lib/config/cli.js b/lib/config/cli.ts similarity index 80% rename from lib/config/cli.js rename to lib/config/cli.ts index 50da603b4c2dbd20cbbc640be23ca5f6c68fd4a5..7666b70f7b2d92ecdd572fce087d8f6cfb838f28 100644 --- a/lib/config/cli.js +++ b/lib/config/cli.ts @@ -1,13 +1,8 @@ -const commander = require('commander'); -const configDefinitions = require('./definitions'); -const { version } = require('../../package.json'); +import { Command } from 'commander'; +import { getOptions, RenovateOptions } from './definitions'; +import { version } from '../../package.json'; -module.exports = { - getCliName, - getConfig, -}; - -function getCliName(option) { +export function getCliName(option: Partial<RenovateOptions>): string { if (option.cli === false) { return ''; } @@ -15,7 +10,11 @@ function getCliName(option) { return `--${nameWithHyphens.toLowerCase()}`; } -function getConfig(input) { +export interface RenovateCliConfig extends Record<string, any> { + repositories?: string[]; +} + +export function getConfig(input: string[]): RenovateCliConfig { // massage migrated configuration keys const argv = input .map(a => @@ -29,12 +28,12 @@ function getConfig(input) { .replace('"host":"', '"hostName":"') ) .filter(a => !a.startsWith('--git-fs')); - const options = configDefinitions.getOptions(); + const options = getOptions(); - const config = {}; + const config: RenovateCliConfig = {}; const coersions = { - boolean: val => { + boolean: (val: string) => { if (val === 'true' || val === '') return true; if (val === 'false') return false; throw new Error( @@ -43,7 +42,7 @@ function getConfig(input) { "'" ); }, - array: val => { + array: (val: string) => { if (val === '') { return []; } @@ -53,7 +52,7 @@ function getConfig(input) { return val.split(',').map(el => el.trim()); } }, - object: val => { + object: (val: string) => { if (val === '') { return {}; } @@ -63,11 +62,11 @@ function getConfig(input) { throw new Error("Invalid JSON value: '" + val + "'"); } }, - string: val => val, + string: (val: string) => val, integer: parseInt, }; - let program = new commander.Command().arguments('[repositories...]'); + let program = new Command().arguments('[repositories...]'); options.forEach(option => { if (option.cli !== false) { @@ -82,7 +81,7 @@ function getConfig(input) { }); /* istanbul ignore next */ - function helpConsole() { + function helpConsole(): void { /* eslint-disable no-console */ console.log(' Examples:'); console.log(''); diff --git a/lib/config/common.ts b/lib/config/common.ts new file mode 100644 index 0000000000000000000000000000000000000000..bb706a8dc69b06f5acf8962d7f1cd45756877886 --- /dev/null +++ b/lib/config/common.ts @@ -0,0 +1,73 @@ +import { Range } from 'semver'; + +export type RenovateConfigStage = + | 'global' + | 'repository' + | 'package' + | 'branch' + | 'pr'; + +// TODO: Proper typings +export interface RenovateSharedConfig { + automerge?: boolean; + enabled?: boolean; + managers?: string | string[]; + + schedule?: string | string[]; + + semanticCommitType?: string; +} + +type UpdateConfig< + T extends RenovateSharedConfig = RenovateSharedConfig +> = Partial<Record<UpdateType, T>>; + +// TODO: Proper typings +export interface RenovateConfig + extends RenovateSharedConfig, + UpdateConfig<PackageRule>, + Record<string, any> { + baseBranches?: string[]; + + errors?: ValidationMessage[]; + packageRules?: PackageRule[]; + + privateKey?: string | Buffer; + + warnings?: ValidationMessage[]; +} + +export type UpdateType = + | 'major' + | 'minor' + | 'patch' + | 'pin' + | 'digest' + | 'lockFileMaintenance' + | 'rollback' + | 'bump'; + +// TODO: Proper typings +export interface PackageRule + extends RenovateSharedConfig, + UpdateConfig, + Record<string, any> { + paths?: string[]; + languages?: string[]; + baseBranchList?: string[]; + datasources?: string[]; + depTypeList?: string[]; + packageNames?: string[]; + packagePatterns?: string[]; + excludePackageNames?: string[]; + excludePackagePatterns?: string[]; + matchCurrentVersion?: string | Range; + sourceUrlPrefixes?: string[]; + + updateTypes?: UpdateType[]; +} + +export interface ValidationMessage { + depName: string; + message: string; +} diff --git a/lib/config/decrypt.js b/lib/config/decrypt.ts similarity index 92% rename from lib/config/decrypt.js rename to lib/config/decrypt.ts index c5b353a02c5a01e675d986bd4bc9eecd935bbfe4..b80ba4f0c9a3c88f5a7d281af12094f574dae047 100644 --- a/lib/config/decrypt.js +++ b/lib/config/decrypt.ts @@ -1,12 +1,13 @@ import is from '@sindresorhus/is'; +import crypto from 'crypto'; +import { logger } from '../logger'; +import { maskToken } from '../util/mask'; +import { RenovateConfig } from './common'; -const crypto = require('crypto'); -const { logger } = require('../logger'); -const { maskToken } = require('../util/mask'); - -export { decryptConfig }; - -function decryptConfig(config, privateKey) { +export function decryptConfig( + config: RenovateConfig, + privateKey?: string | Buffer +): RenovateConfig { logger.trace({ config }, 'decryptConfig()'); const decryptedConfig = { ...config }; for (const [key, val] of Object.entries(config)) { @@ -15,7 +16,7 @@ function decryptConfig(config, privateKey) { if (privateKey) { for (const [eKey, eVal] of Object.entries(val)) { try { - let decryptedStr; + let decryptedStr: string; try { logger.debug('Trying default padding for ' + eKey); decryptedStr = crypto diff --git a/lib/config/defaults.js b/lib/config/defaults.ts similarity index 53% rename from lib/config/defaults.js rename to lib/config/defaults.ts index 443c0c72b42f38364a06505d3213938575b30aa7..1748362b45b6dbbf323f341ed17fa2bde6fb1a4a 100644 --- a/lib/config/defaults.js +++ b/lib/config/defaults.ts @@ -1,9 +1,5 @@ -const configDefinitions = require('./definitions'); - -module.exports = { - getDefault, - getConfig, -}; +import { getOptions, RenovateOptions } from './definitions'; +import { RenovateConfig } from './common'; const defaultValues = { boolean: true, @@ -12,15 +8,15 @@ const defaultValues = { object: null, }; -function getDefault(option) { +export function getDefault(option: RenovateOptions): any { return option.default === undefined ? defaultValues[option.type] : option.default; } -function getConfig() { - const options = configDefinitions.getOptions(); - const config = {}; +export function getConfig(): RenovateConfig { + const options = getOptions(); + const config: RenovateConfig = {}; options.forEach(option => { if (!option.parent) { config[option.name] = getDefault(option); diff --git a/lib/config/definitions.js b/lib/config/definitions.ts similarity index 96% rename from lib/config/definitions.js rename to lib/config/definitions.ts index ed67cbb85be82fe1dc65cbbf3941bae608161138..1f9941c2c22a47f5d82f1d11c59e598171d6c8c6 100644 --- a/lib/config/definitions.js +++ b/lib/config/definitions.ts @@ -1,10 +1,80 @@ -const { appName, appSlug, urls } = require('./app-strings'); +import { appName, appSlug, urls } from './app-strings'; +import { RenovateConfigStage } from './common'; -module.exports = { - getOptions, -}; +export interface RenovateOptionBase { + admin?: boolean; -const options = [ + allowedValues?: string[]; + + allowString?: boolean; + + cli?: boolean; + + description: string; + + env?: false | string; + + freeChoice?: boolean; + mergeable?: boolean; + + name: string; + + parent?: 'hostRules' | 'packageRules'; + + // used by tests + relatedOptions?: string[]; + + releaseStatus?: 'alpha' | 'beta' | 'unpublished'; + + stage?: RenovateConfigStage; +} + +export interface RenovateArrayOption<T extends string | object = any> + extends RenovateOptionBase { + default?: T; + mergeable?: boolean; + type: 'array'; +} + +export interface RenovateStringArrayOption extends RenovateArrayOption<string> { + format?: 'regex'; + subType: 'string'; +} + +export interface RenovateBooleanOption extends RenovateOptionBase { + default?: boolean; + type: 'boolean'; +} + +export interface RenovateIntegerOption extends RenovateOptionBase { + default?: number; + type: 'integer'; +} + +export interface RenovateStringOption extends RenovateOptionBase { + default?: string; + format?: 'regex'; + + // Not used + replaceLineReturns?: boolean; + type: 'string'; +} + +export interface RenovateObjectOption extends RenovateOptionBase { + default?: any; + mergeable?: boolean; + type: 'object'; +} + +export type RenovateOptions = + | RenovateStringOption + | RenovateStringArrayOption + | RenovateIntegerOption + | RenovateBooleanOption + | RenovateArrayOption + | RenovateObjectOption; + +const options: RenovateOptions[] = [ { name: 'extends', description: @@ -1887,6 +1957,6 @@ const options = [ }, ]; -function getOptions() { +export function getOptions() { return options; } diff --git a/lib/config/env.js b/lib/config/env.ts similarity index 70% rename from lib/config/env.js rename to lib/config/env.ts index 8c0b2e1f110a712277e7da23cccaaf33c1073316..e6250321e76712fcd8b8ee6070bcfaef3fb9ebbf 100644 --- a/lib/config/env.js +++ b/lib/config/env.ts @@ -1,11 +1,7 @@ -const configDefinitions = require('./definitions'); +import { getOptions, RenovateOptions } from './definitions'; +import { RenovateConfig } from './common'; -module.exports = { - getEnvName, - getConfig, -}; - -function getEnvName(option) { +export function getEnvName(option: Partial<RenovateOptions>): string { if (option.env === false) { return ''; } @@ -16,16 +12,16 @@ function getEnvName(option) { return `RENOVATE_${nameWithUnderscores.toUpperCase()}`; } -function getConfig(env) { - const options = configDefinitions.getOptions(); +export function getConfig(env: NodeJS.ProcessEnv): RenovateConfig { + const options = getOptions(); - const config = { hostRules: [] }; + const config: RenovateConfig = { hostRules: [] }; const coersions = { - boolean: val => val === 'true', - array: val => val.split(',').map(el => el.trim()), - string: val => val.replace(/\\n/g, '\n'), - object: val => JSON.parse(val), + boolean: (val: string) => val === 'true', + array: (val: string) => val.split(',').map(el => el.trim()), + string: (val: string) => val.replace(/\\n/g, '\n'), + object: (val: string) => JSON.parse(val), integer: parseInt, }; diff --git a/lib/config/file.js b/lib/config/file.ts similarity index 72% rename from lib/config/file.js rename to lib/config/file.ts index 5dbda4be65d32cb56f0a3a0f8b913b7aab687631..2082c9687790e93b35dc4ea116de4c9fe640ab62 100644 --- a/lib/config/file.js +++ b/lib/config/file.ts @@ -1,18 +1,15 @@ -const path = require('path'); -const { logger } = require('../logger'); -const { migrateConfig } = require('./migration'); +import path from 'path'; +import { logger } from '../logger'; +import { migrateConfig } from './migration'; +import { RenovateConfig } from './common'; -module.exports = { - getConfig, -}; - -function getConfig(env) { +export function getConfig(env: NodeJS.ProcessEnv): RenovateConfig { let configFile = env.RENOVATE_CONFIG_FILE || 'config'; if (!path.isAbsolute(configFile)) { configFile = `${process.cwd()}/${configFile}`; logger.debug('Checking for config file in ' + configFile); } - let config = {}; + let config: RenovateConfig = {}; try { // eslint-disable-next-line global-require,import/no-dynamic-require config = require(configFile); diff --git a/lib/config/index.js b/lib/config/index.ts similarity index 70% rename from lib/config/index.js rename to lib/config/index.ts index d5b4aefa70d029d6a5b53d0f945f23d2aaa3f9ac..e9223f521c87df6aedc00d96f125e136913553d7 100644 --- a/lib/config/index.js +++ b/lib/config/index.ts @@ -1,23 +1,35 @@ -const { logger, levels, addStream } = require('../logger'); -const definitions = require('./definitions'); - -const defaultsParser = require('./defaults'); -const fileParser = require('./file'); -const cliParser = require('./cli'); -const envParser = require('./env'); - -const { resolveConfigPresets } = require('./presets'); -const { get, getLanguageList, getManagerList } = require('../manager'); - -const clone = input => JSON.parse(JSON.stringify(input)); +import { logger, levels, addStream } from '../logger'; +import * as definitions from './definitions'; +import * as defaultsParser from './defaults'; +import * as fileParser from './file'; +import * as cliParser from './cli'; +import * as envParser from './env'; + +// eslint-disable-next-line import/no-cycle +import { resolveConfigPresets } from './presets'; +import { get, getLanguageList, getManagerList } from '../manager'; +import { RenovateConfig, RenovateConfigStage } from './common'; + +export * from './common'; + +function clone<T>(input: T): T { + return JSON.parse(JSON.stringify(input)); +} -exports.parseConfigs = parseConfigs; -exports.mergeChildConfig = mergeChildConfig; -exports.filterConfig = filterConfig; -exports.getManagerConfig = getManagerConfig; +export interface ManagerConfig extends RenovateConfig { + language: string; + manager: string; +} -function getManagerConfig(config, manager) { - let managerConfig = config; +export function getManagerConfig( + config: RenovateConfig, + manager: string +): ManagerConfig { + let managerConfig: ManagerConfig = { + ...config, + language: null, + manager: null, + }; const language = get(manager, 'language'); if (language) { managerConfig = mergeChildConfig(managerConfig, config[language]); @@ -31,7 +43,10 @@ function getManagerConfig(config, manager) { return managerConfig; } -async function parseConfigs(env, argv) { +export async function parseConfigs( + env: NodeJS.ProcessEnv, + argv: string[] +): Promise<RenovateConfig> { logger.debug('Parsing configs'); // Get configs @@ -88,14 +103,17 @@ async function parseConfigs(env, argv) { return config; } -function mergeChildConfig(parent, child) { +export function mergeChildConfig<T extends RenovateConfig = RenovateConfig>( + parent: T, + child: RenovateConfig +): T { logger.trace({ parent, child }, `mergeChildConfig`); if (!child) { return parent; } const parentConfig = clone(parent); const childConfig = clone(child); - const config = { ...parentConfig, ...childConfig }; + const config: Record<string, any> = { ...parentConfig, ...childConfig }; for (const option of definitions.getOptions()) { if ( option.mergeable && @@ -122,9 +140,12 @@ function mergeChildConfig(parent, child) { return Object.assign(config, config.force); } -function filterConfig(inputConfig, targetStage) { +export function filterConfig( + inputConfig: RenovateConfig, + targetStage: RenovateConfigStage +): RenovateConfig { logger.trace({ config: inputConfig }, `filterConfig('${targetStage}')`); - const outputConfig = { ...inputConfig }; + const outputConfig: RenovateConfig = { ...inputConfig }; const stages = ['global', 'repository', 'package', 'branch', 'pr']; const targetIndex = stages.indexOf(targetStage); for (const option of definitions.getOptions()) { diff --git a/lib/config/massage.js b/lib/config/massage.ts similarity index 78% rename from lib/config/massage.js rename to lib/config/massage.ts index 72b43f3277b45922f3a055f6541bd1b3436cb80e..d5cfe23955f8341dfcb2c87ebe6f1088ebebf0c4 100644 --- a/lib/config/massage.js +++ b/lib/config/massage.ts @@ -1,15 +1,14 @@ import is from '@sindresorhus/is'; +import { clone } from './util'; +import { RenovateConfig, UpdateType, PackageRule } from './common'; +import { getOptions } from './definitions'; -const options = require('./definitions').getOptions(); +const options = getOptions(); -const clone = input => JSON.parse(JSON.stringify(input)); - -let allowedStrings; - -export { massageConfig }; +let allowedStrings: string[]; // Returns a massaged config -function massageConfig(config) { +export function massageConfig(config: RenovateConfig): RenovateConfig { if (!allowedStrings) { allowedStrings = []; options.forEach(option => { @@ -39,8 +38,8 @@ function massageConfig(config) { } } if (is.nonEmptyArray(massagedConfig.packageRules)) { - const newRules = []; - const updateTypes = [ + const newRules: PackageRule[] = []; + const updateTypes: UpdateType[] = [ 'major', 'minor', 'patch', @@ -51,7 +50,10 @@ function massageConfig(config) { ]; for (const rule of massagedConfig.packageRules) { newRules.push(rule); - for (const [key, val] of Object.entries(rule)) { + for (const [key, val] of Object.entries(rule) as [ + UpdateType, + PackageRule + ][]) { if (updateTypes.includes(key)) { const newRule = clone(rule); newRule.updateTypes = rule.updateTypes || []; diff --git a/lib/config/migrate-validate.js b/lib/config/migrate-validate.ts similarity index 67% rename from lib/config/migrate-validate.js rename to lib/config/migrate-validate.ts index 72a29c18d40fd11aa661809001106ff5a64ce999..7ba8c83ee275f2df663f877a5a46f489d01bade4 100644 --- a/lib/config/migrate-validate.js +++ b/lib/config/migrate-validate.ts @@ -1,13 +1,14 @@ import is from '@sindresorhus/is'; +import { logger } from '../logger'; +import * as configMigration from './migration'; +import * as configMassage from './massage'; +import * as configValidation from './validation'; +import { RenovateConfig, ValidationMessage } from './common'; -const { logger } = require('../logger'); -const configMigration = require('./migration'); -const configMassage = require('./massage'); -const configValidation = require('./validation'); - -export { migrateAndValidate }; - -async function migrateAndValidate(config, input) { +export async function migrateAndValidate( + config: RenovateConfig, + input: RenovateConfig +): Promise<RenovateConfig> { logger.debug('migrateAndValidate()'); try { const { isMigrated, migratedConfig } = configMigration.migrateConfig(input); @@ -21,9 +22,13 @@ async function migrateAndValidate(config, input) { } const massagedConfig = configMassage.massageConfig(migratedConfig); logger.debug({ config: massagedConfig }, 'massaged config'); - const { warnings, errors } = await configValidation.validateConfig( - massagedConfig - ); + const { + warnings, + errors, + }: { + warnings: ValidationMessage[]; + errors: ValidationMessage[]; + } = await configValidation.validateConfig(massagedConfig); // istanbul ignore if if (is.nonEmptyArray(warnings)) { logger.info({ warnings }, 'Found renovate config warnings'); diff --git a/lib/config/migration.js b/lib/config/migration.ts similarity index 96% rename from lib/config/migration.js rename to lib/config/migration.ts index d9724eb0d728ac0b6379bcd474ddf68685c3004a..67d2e6515416cda031cb212fb1c7fb890197df83 100644 --- a/lib/config/migration.js +++ b/lib/config/migration.ts @@ -1,14 +1,13 @@ import is from '@sindresorhus/is'; +import later from 'later'; +import { logger } from '../logger'; +import { clone } from './util'; +import { getOptions, RenovateOptions } from './definitions'; +import { RenovateConfig } from './common'; -const later = require('later'); -const { logger } = require('../logger'); -const options = require('./definitions').getOptions(); +const options = getOptions(); -const clone = input => JSON.parse(JSON.stringify(input)); - -let optionTypes; - -export { migrateConfig }; +let optionTypes: Record<string, RenovateOptions['type']>; const removedOptions = [ 'maintainYarnLock', @@ -24,8 +23,17 @@ const removedOptions = [ 'groupPrBody', ]; +export interface MigratedConfig { + isMigrated: boolean; + migratedConfig: RenovateConfig; +} + // Returns a migrated config -function migrateConfig(config, parentKey) { +export function migrateConfig( + config: RenovateConfig, + // TODO: remove any type + parentKey?: string | any +): MigratedConfig { try { if (!optionTypes) { optionTypes = {}; diff --git a/lib/config/presets.js b/lib/config/presets.ts similarity index 86% rename from lib/config/presets.js rename to lib/config/presets.ts index 809c43a2a78b3148ab273717f1cbaecbd0f0fd95..59cb1037a97bb440a505dce3c5d811a143e0bbb1 100644 --- a/lib/config/presets.js +++ b/lib/config/presets.ts @@ -1,12 +1,13 @@ import is from '@sindresorhus/is'; - -const { logger } = require('../logger'); -const configParser = require('./index'); -const massage = require('./massage'); -const migration = require('./migration'); -const github = require('../datasource/github'); -const npm = require('../datasource/npm'); -const gitlab = require('../datasource/gitlab'); +import { logger } from '../logger'; +// eslint-disable-next-line import/no-cycle +import * as configParser from './index'; +import * as massage from './massage'; +import * as migration from './migration'; +import * as github from '../datasource/github'; +import * as npm from '../datasource/npm'; +import * as gitlab from '../datasource/gitlab'; +import { RenovateConfig } from './common'; const datasources = { github, @@ -14,13 +15,11 @@ const datasources = { gitlab, }; -export { resolveConfigPresets, replaceArgs, parsePreset, getPreset }; - -async function resolveConfigPresets( - inputConfig, - ignorePresets, - existingPresets = [] -) { +export async function resolveConfigPresets( + inputConfig: RenovateConfig, + ignorePresets?: string[], + existingPresets: string[] = [] +): Promise<RenovateConfig> { if (!ignorePresets) { ignorePresets = inputConfig.ignorePresets || []; // eslint-disable-line } @@ -28,7 +27,7 @@ async function resolveConfigPresets( { config: inputConfig, existingPresets }, 'resolveConfigPresets' ); - let config = {}; + let config: RenovateConfig = {}; // First, merge all the preset configs from left to right if (inputConfig.extends && inputConfig.extends.length) { for (const preset of inputConfig.extends) { @@ -121,7 +120,10 @@ async function resolveConfigPresets( return config; } -function replaceArgs(obj, argMapping) { +export function replaceArgs( + obj: string | string[] | object | object[], + argMapping: Record<string, any> +) { if (is.string(obj)) { let returnStr = obj; for (const [arg, argVal] of Object.entries(argMapping)) { @@ -147,12 +149,19 @@ function replaceArgs(obj, argMapping) { return obj; } -function parsePreset(input) { +export interface ParsedPreset { + datasource: string; + packageName: string; + presetName: string; + params?: string[]; +} + +export function parsePreset(input: string): ParsedPreset { let str = input; - let datasource; - let packageName; - let presetName; - let params; + let datasource: string; + let packageName: string; + let presetName: string; + let params: string[]; if (str.startsWith('github>')) { datasource = 'github'; str = str.substring('github>'.length); @@ -199,7 +208,7 @@ function parsePreset(input) { return { datasource, packageName, presetName, params }; } -async function getPreset(preset) { +export async function getPreset(preset: string): Promise<RenovateConfig> { logger.trace(`getPreset(${preset})`); const { datasource, packageName, presetName, params } = parsePreset(preset); let presetConfig = await datasources[datasource].getPreset( diff --git a/lib/config/util.ts b/lib/config/util.ts new file mode 100644 index 0000000000000000000000000000000000000000..075e35be3a44b8c0cf2f31e0efc2e8122def72ce --- /dev/null +++ b/lib/config/util.ts @@ -0,0 +1,3 @@ +export function clone<T>(input: T): T { + return JSON.parse(JSON.stringify(input)); +} diff --git a/lib/config/validation-helpers/managers.js b/lib/config/validation-helpers/managers.ts similarity index 72% rename from lib/config/validation-helpers/managers.js rename to lib/config/validation-helpers/managers.ts index 500dec3ca2439ba01b02f32f945511f8ac56c6a4..6709db9dc932794354515a674f1229e36784cd85 100644 --- a/lib/config/validation-helpers/managers.js +++ b/lib/config/validation-helpers/managers.ts @@ -1,11 +1,19 @@ -const { getManagerList } = require('../../manager'); +import { getManagerList } from '../../manager'; +import { ValidationMessage, PackageRule } from '../common'; + +export interface CheckManagerArgs { + resolvedRule: PackageRule; + currentPath: string; +} + /** * Only if type condition or context condition violated then errors array will be mutated to store metadata - * @param {{resolvedRule:any, currentPath: string}} param - * @returns {Array} with finded error or empty array */ -const check = ({ resolvedRule, currentPath }) => { - let managersErrMessage; +export function check({ + resolvedRule, + currentPath, +}: CheckManagerArgs): ValidationMessage[] { + let managersErrMessage: string; if (Array.isArray(resolvedRule.managers)) { if ( resolvedRule.managers.find( @@ -29,6 +37,4 @@ const check = ({ resolvedRule, currentPath }) => { }, ] : []; -}; - -module.exports = { check }; +} diff --git a/lib/config/validation.js b/lib/config/validation.ts similarity index 89% rename from lib/config/validation.js rename to lib/config/validation.ts index 88d88ed09617da3c8511af50f790ceba2a6fcef7..12460bbfab3a2d697e7ce8202b46c1c88bf917c2 100644 --- a/lib/config/validation.js +++ b/lib/config/validation.ts @@ -1,24 +1,23 @@ import is from '@sindresorhus/is'; +import safe from 'safe-regex'; +import { getOptions, RenovateOptions } from './definitions'; +import { resolveConfigPresets } from './presets'; +import { hasValidSchedule, hasValidTimezone } from '../workers/branch/schedule'; +import * as managerValidator from './validation-helpers/managers'; +import { RenovateConfig, ValidationMessage } from './common'; -const safe = require('safe-regex'); -const options = require('./definitions').getOptions(); -const { resolveConfigPresets } = require('./presets'); -const { - hasValidSchedule, - hasValidTimezone, -} = require('../workers/branch/schedule'); -const managerValidator = require('./validation-helpers/managers'); +const options = getOptions(); -let optionTypes; - -export { validateConfig }; +let optionTypes: Record<string, RenovateOptions['type']>; // istanbul ignore next -async function validateBaseBranches(config) { +async function validateBaseBranches( + config: RenovateConfig +): Promise<ValidationMessage[]> { if (!is.nonEmptyArray(config.baseBranches)) { return []; } - const missingBranches = []; + const missingBranches: string[] = []; for (const baseBranch of config.baseBranches) { if (!(await platform.branchExists(baseBranch))) { missingBranches.push(baseBranch); @@ -37,19 +36,28 @@ async function validateBaseBranches(config) { return []; } -async function validateConfig(config, isPreset, parentPath) { +export interface ValidationResult { + errors: ValidationMessage[]; + warnings: ValidationMessage[]; +} + +export async function validateConfig( + config: RenovateConfig, + isPreset?: boolean, + parentPath?: string +): Promise<ValidationResult> { if (!optionTypes) { optionTypes = {}; options.forEach(option => { optionTypes[option.name] = option.type; }); } - let errors = []; - let warnings = []; + let errors: ValidationMessage[] = []; + let warnings: ValidationMessage[] = []; errors = errors.concat(await validateBaseBranches(config)); - function getDeprecationMessage(option) { + function getDeprecationMessage(option: string): string { const deprecatedOptions = { branchName: `Direct editing of branchName is now deprecated. Please edit branchPrefix, managerBranchPrefix, or branchTopic instead`, commitMessage: `Direct editing of commitMessage is now deprecated. Please edit commitMessage's subcomponents instead.`, @@ -58,7 +66,7 @@ async function validateConfig(config, isPreset, parentPath) { return deprecatedOptions[option]; } - function isIgnored(key) { + function isIgnored(key: string): boolean { const ignoredNodes = [ '$schema', 'prBanner', @@ -205,6 +213,7 @@ async function validateConfig(config, isPreset, parentPath) { try { // @ts-ignore RegExp(val); + // @ts-ignore if (!safe(val)) { errors.push({ depName: 'Configuration Error', @@ -278,7 +287,7 @@ async function validateConfig(config, isPreset, parentPath) { } } } - function sortAll(a, b) { + function sortAll(a: ValidationMessage, b: ValidationMessage): number { if (a.depName === b.depName) { return a.message > b.message ? 1 : -1; } diff --git a/lib/types.d.ts b/lib/types.d.ts index c07b0a454338177b75ad25b06d47507a8957d3c2..f548e00436a851109de08a1fe20ff68b0058c14a 100644 --- a/lib/types.d.ts +++ b/lib/types.d.ts @@ -46,6 +46,6 @@ declare let renovateCache: Renovate.Cache; // can't use `resolveJsonModule` because it will copy json files and change dist path declare module '*.json' { - const value: any; + const value: { version: string } & Record<string, any>; export = value; } diff --git a/lib/util/package-rules.ts b/lib/util/package-rules.ts index 23a4a3e6f471347f710508e4cd95208059d72ce2..7a4974e9d6ceb40787d615926c77ed9d4731c1e9 100644 --- a/lib/util/package-rules.ts +++ b/lib/util/package-rules.ts @@ -1,11 +1,10 @@ import minimatch from 'minimatch'; -import { Range } from 'semver'; import { logger } from '../logger'; import * as versioning from '../versioning'; -import { mergeChildConfig } from '../config'; +import { mergeChildConfig, PackageRule, UpdateType } from '../config'; // TODO: move to `../config` -interface Config extends Record<string, any> { +export interface Config extends Record<string, any> { versionScheme?: string; packageFile?: string; depType?: string; @@ -14,7 +13,7 @@ interface Config extends Record<string, any> { currentValue?: string; fromVersion?: string; lockedVersion?: string; - updateType?: string; + updateType?: UpdateType; isBump?: boolean; sourceUrl?: string; language?: string; @@ -24,23 +23,6 @@ interface Config extends Record<string, any> { packageRules?: (PackageRule & Config)[]; } -// TODO: move to `../config` -interface PackageRule { - paths?: string[]; - languages?: string[]; - baseBranchList?: string[]; - managers?: string[]; - datasources?: string[]; - depTypeList?: string[]; - packageNames?: string[]; - packagePatterns?: string[]; - excludePackageNames?: string[]; - excludePackagePatterns?: string[]; - matchCurrentVersion?: string | Range; - sourceUrlPrefixes?: string[]; - updateTypes?: string[]; -} - function matchesRule(inputConfig: Config, packageRule: PackageRule): boolean { const { versionScheme, @@ -226,7 +208,7 @@ function matchesRule(inputConfig: Config, packageRule: PackageRule): boolean { return positiveMatch; } -export function applyPackageRules(inputConfig: Config): Config { +export function applyPackageRules<T extends Config>(inputConfig: T): T { let config = { ...inputConfig }; const packageRules = config.packageRules || []; logger.trace( diff --git a/package.json b/package.json index d6bbf830881f76c305373330ef5c88aba48859ce..decd1f51e7286eea4297bb8be004373fa6052423 100644 --- a/package.json +++ b/package.json @@ -172,12 +172,14 @@ "@types/ini": "1.3.30", "@types/jest": "24.0.18", "@types/js-yaml": "3.12.1", + "@types/later": "1.2.5", "@types/lodash": "4.14.137", "@types/luxon": "1.15.2", "@types/nock": "10.0.3", "@types/node": "11.13.19", "@types/parse-link-header": "1.0.0", "@types/registry-auth-token": "3.3.0", + "@types/safe-regex": "1.1.2", "@types/semver": "6.0.1", "@types/shelljs": "0.8.5", "@types/tmp": "0.1.0", diff --git a/test/config/__snapshots__/decrypt.spec.js.snap b/test/config/__snapshots__/decrypt.spec.ts.snap similarity index 100% rename from test/config/__snapshots__/decrypt.spec.js.snap rename to test/config/__snapshots__/decrypt.spec.ts.snap diff --git a/test/config/__snapshots__/env.spec.js.snap b/test/config/__snapshots__/env.spec.ts.snap similarity index 100% rename from test/config/__snapshots__/env.spec.js.snap rename to test/config/__snapshots__/env.spec.ts.snap diff --git a/test/config/__snapshots__/file.spec.js.snap b/test/config/__snapshots__/file.spec.ts.snap similarity index 100% rename from test/config/__snapshots__/file.spec.js.snap rename to test/config/__snapshots__/file.spec.ts.snap diff --git a/test/config/__snapshots__/index.spec.js.snap b/test/config/__snapshots__/index.spec.ts.snap similarity index 100% rename from test/config/__snapshots__/index.spec.js.snap rename to test/config/__snapshots__/index.spec.ts.snap diff --git a/test/config/__snapshots__/massage.spec.js.snap b/test/config/__snapshots__/massage.spec.ts.snap similarity index 100% rename from test/config/__snapshots__/massage.spec.js.snap rename to test/config/__snapshots__/massage.spec.ts.snap diff --git a/test/config/__snapshots__/migrate-validate.spec.js.snap b/test/config/__snapshots__/migrate-validate.spec.ts.snap similarity index 100% rename from test/config/__snapshots__/migrate-validate.spec.js.snap rename to test/config/__snapshots__/migrate-validate.spec.ts.snap diff --git a/test/config/__snapshots__/migration.spec.js.snap b/test/config/__snapshots__/migration.spec.ts.snap similarity index 100% rename from test/config/__snapshots__/migration.spec.js.snap rename to test/config/__snapshots__/migration.spec.ts.snap diff --git a/test/config/__snapshots__/presets.spec.js.snap b/test/config/__snapshots__/presets.spec.ts.snap similarity index 100% rename from test/config/__snapshots__/presets.spec.js.snap rename to test/config/__snapshots__/presets.spec.ts.snap diff --git a/test/config/__snapshots__/validation.spec.js.snap b/test/config/__snapshots__/validation.spec.ts.snap similarity index 100% rename from test/config/__snapshots__/validation.spec.js.snap rename to test/config/__snapshots__/validation.spec.ts.snap diff --git a/test/config/cli.spec.js b/test/config/cli.spec.ts similarity index 93% rename from test/config/cli.spec.js rename to test/config/cli.spec.ts index 5d329df90f2050a8ce0aefa246baa1276e9d1512..e18b434c26dabc7d0b0e956c9f479f5876e71780 100644 --- a/test/config/cli.spec.js +++ b/test/config/cli.spec.ts @@ -1,21 +1,21 @@ -/** @type any */ -const cli = require('../../lib/config/cli.js'); -const getArgv = require('./config/_fixtures/argv'); +import * as cli from '../../lib/config/cli'; +import getArgv from './config/_fixtures/argv'; +import { RenovateOptions } from '../../lib/config/definitions'; describe('config/cli', () => { - let argv; + let argv: string[]; beforeEach(() => { argv = getArgv(); }); describe('.getCliName(definition)', () => { it('generates CLI value', () => { - const option = { + const option: Partial<RenovateOptions> = { name: 'oneTwoThree', }; cli.getCliName(option).should.eql('--one-two-three'); }); it('generates returns empty if CLI false', () => { - const option = { + const option: Partial<RenovateOptions> = { name: 'oneTwoThree', cli: false, }; diff --git a/test/config/decrypt.spec.js b/test/config/decrypt.spec.ts similarity index 96% rename from test/config/decrypt.spec.js rename to test/config/decrypt.spec.ts index 7ef19d060fe592bb1db2d255e547510df17c2f4c..6dea41dfd6ff1caefcffe3f1bb30f4cadb176973 100644 --- a/test/config/decrypt.spec.js +++ b/test/config/decrypt.spec.ts @@ -1,11 +1,12 @@ -const fs = require('fs'); -const { decryptConfig } = require('../../lib/config/decrypt.js'); +import fs from 'fs'; +import { decryptConfig } from '../../lib/config/decrypt'; +import { RenovateConfig } from '../../lib/config'; const privateKey = fs.readFileSync('test/config/keys/_fixtures/private.pem'); describe('config/decrypt', () => { describe('decryptConfig()', () => { - let config; + let config: RenovateConfig; beforeEach(() => { config = {}; }); diff --git a/test/config/env.spec.js b/test/config/env.spec.ts similarity index 72% rename from test/config/env.spec.js rename to test/config/env.spec.ts index 3068f749dc84f5906b10128404dbd60de468252d..e7886e79167a94cc1126c503bbc247a2d13da281 100644 --- a/test/config/env.spec.js +++ b/test/config/env.spec.ts @@ -1,4 +1,5 @@ -const env = require('../../lib/config/env.js'); +import * as env from '../../lib/config/env'; +import { RenovateOptions } from '../../lib/config/definitions'; describe('config/env', () => { describe('.getConfig(env)', () => { @@ -6,44 +7,50 @@ describe('config/env', () => { expect(env.getConfig({})).toEqual({ hostRules: [] }); }); it('supports boolean true', () => { - const envParam = { RENOVATE_RECREATE_CLOSED: 'true' }; + const envParam: NodeJS.ProcessEnv = { RENOVATE_RECREATE_CLOSED: 'true' }; expect(env.getConfig(envParam).recreateClosed).toBe(true); }); it('supports boolean false', () => { - const envParam = { RENOVATE_RECREATE_CLOSED: 'false' }; + const envParam: NodeJS.ProcessEnv = { RENOVATE_RECREATE_CLOSED: 'false' }; expect(env.getConfig(envParam).recreateClosed).toBe(false); }); it('supports boolean nonsense as false', () => { - const envParam = { RENOVATE_RECREATE_CLOSED: 'foo' }; + const envParam: NodeJS.ProcessEnv = { RENOVATE_RECREATE_CLOSED: 'foo' }; expect(env.getConfig(envParam).recreateClosed).toBe(false); }); delete process.env.RENOVATE_RECREATE_CLOSED; it('supports list single', () => { - const envParam = { RENOVATE_LABELS: 'a' }; + const envParam: NodeJS.ProcessEnv = { RENOVATE_LABELS: 'a' }; expect(env.getConfig(envParam).labels).toEqual(['a']); }); it('supports list multiple', () => { - const envParam = { RENOVATE_LABELS: 'a,b,c' }; + const envParam: NodeJS.ProcessEnv = { RENOVATE_LABELS: 'a,b,c' }; expect(env.getConfig(envParam).labels).toEqual(['a', 'b', 'c']); }); it('supports string', () => { - const envParam = { RENOVATE_TOKEN: 'a' }; + const envParam: NodeJS.ProcessEnv = { RENOVATE_TOKEN: 'a' }; expect(env.getConfig(envParam).token).toBe('a'); }); it('supports json', () => { - const envParam = { RENOVATE_LOCK_FILE_MAINTENANCE: '{}' }; + const envParam: NodeJS.ProcessEnv = { + RENOVATE_LOCK_FILE_MAINTENANCE: '{}', + }; expect(env.getConfig(envParam).lockFileMaintenance).toEqual({}); }); it('supports GitHub token', () => { - const envParam = { RENOVATE_TOKEN: 'github.com token' }; + const envParam: NodeJS.ProcessEnv = { + RENOVATE_TOKEN: 'github.com token', + }; expect(env.getConfig(envParam)).toMatchSnapshot(); }); it('supports GitHub custom endpoint', () => { - const envParam = { RENOVATE_ENDPOINT: 'a ghe endpoint' }; + const envParam: NodeJS.ProcessEnv = { + RENOVATE_ENDPOINT: 'a ghe endpoint', + }; expect(env.getConfig(envParam)).toMatchSnapshot(); }); it('supports GitHub custom endpoint and github.com', () => { - const envParam = { + const envParam: NodeJS.ProcessEnv = { GITHUB_COM_TOKEN: 'a github.com token', RENOVATE_ENDPOINT: 'a ghe endpoint', RENOVATE_TOKEN: 'a ghe token', @@ -51,14 +58,14 @@ describe('config/env', () => { expect(env.getConfig(envParam)).toMatchSnapshot(); }); it('supports GitLab token', () => { - const envParam = { + const envParam: NodeJS.ProcessEnv = { RENOVATE_PLATFORM: 'gitlab', RENOVATE_TOKEN: 'a gitlab.com token', }; expect(env.getConfig(envParam)).toMatchSnapshot(); }); it('supports GitLab custom endpoint', () => { - const envParam = { + const envParam: NodeJS.ProcessEnv = { RENOVATE_PLATFORM: 'gitlab', RENOVATE_TOKEN: 'a gitlab token', RENOVATE_ENDPOINT: 'a gitlab endpoint', @@ -66,7 +73,7 @@ describe('config/env', () => { expect(env.getConfig(envParam)).toMatchSnapshot(); }); it('supports Azure DevOps', () => { - const envParam = { + const envParam: NodeJS.ProcessEnv = { RENOVATE_PLATFORM: 'azure', RENOVATE_TOKEN: 'an Azure DevOps token', RENOVATE_ENDPOINT: 'an Azure DevOps endpoint', @@ -74,14 +81,14 @@ describe('config/env', () => { expect(env.getConfig(envParam)).toMatchSnapshot(); }); it('supports docker username/password', () => { - const envParam = { + const envParam: NodeJS.ProcessEnv = { DOCKER_USERNAME: 'some-username', DOCKER_PASSWORD: 'some-password', }; expect(env.getConfig(envParam)).toMatchSnapshot(); }); it('supports Bitbucket token', () => { - const envParam = { + const envParam: NodeJS.ProcessEnv = { RENOVATE_PLATFORM: 'bitbucket', RENOVATE_ENDPOINT: 'a bitbucket endpoint', RENOVATE_USERNAME: 'some-username', @@ -90,7 +97,7 @@ describe('config/env', () => { expect(env.getConfig(envParam)).toMatchSnapshot(); }); it('supports Bitbucket username/password', () => { - const envParam = { + const envParam: NodeJS.ProcessEnv = { RENOVATE_PLATFORM: 'bitbucket', RENOVATE_ENDPOINT: 'a bitbucket endpoint', RENOVATE_USERNAME: 'some-username', @@ -101,21 +108,21 @@ describe('config/env', () => { }); describe('.getEnvName(definition)', () => { it('returns empty', () => { - const option = { + const option: Partial<RenovateOptions> = { name: 'foo', env: false, }; env.getEnvName(option).should.eql(''); }); it('returns existing env', () => { - const option = { + const option: Partial<RenovateOptions> = { name: 'foo', env: 'FOO', }; env.getEnvName(option).should.eql('FOO'); }); it('generates RENOVATE_ env', () => { - const option = { + const option: Partial<RenovateOptions> = { name: 'oneTwoThree', }; env.getEnvName(option).should.eql('RENOVATE_ONE_TWO_THREE'); diff --git a/test/config/file.spec.js b/test/config/file.spec.ts similarity index 84% rename from test/config/file.spec.js rename to test/config/file.spec.ts index 6c127cf201797929715f26570966e44ca4390b5f..86c8d1feae32a3a29fe094e0b502a83bfed31c7d 100644 --- a/test/config/file.spec.js +++ b/test/config/file.spec.ts @@ -1,6 +1,6 @@ -const path = require('path'); -const file = require('../../lib/config/file.js'); -const customConfig = require('./config/_fixtures/file'); +import path from 'path'; +import * as file from '../../lib/config/file'; +import customConfig from './config/_fixtures/file'; describe('config/file', () => { describe('.getConfig()', () => { diff --git a/test/config/index.spec.js b/test/config/index.spec.ts similarity index 77% rename from test/config/index.spec.js rename to test/config/index.spec.ts index 1d24ce3ce473635bd07d94955d333d056131cb72..3f78baa3d07523b4b71decbf9f702e8b7c4b0f0b 100644 --- a/test/config/index.spec.js +++ b/test/config/index.spec.ts @@ -1,12 +1,13 @@ -const argv = require('./config/_fixtures/argv'); -/** @type any */ -const defaultConfig = require('../../lib/config/defaults').getConfig(); -/** @type any */ -const npm = require('../../lib/datasource/npm'); -const presetDefaults = require('./npm/_fixtures/renovate-config-default.json'); +import argv from './config/_fixtures/argv'; +import { getConfig } from '../../lib/config/defaults'; +import * as _npm from '../../lib/datasource/npm'; +import presetDefaults from './npm/_fixtures/renovate-config-default.json'; jest.mock('../../lib/datasource/npm'); +const npm: any = _npm; +const defaultConfig = getConfig(); + npm.getPkgReleases = jest.fn(() => ({ 'renovate-config': presetDefaults.versions[presetDefaults['dist-tags'].latest][ @@ -16,28 +17,28 @@ npm.getPkgReleases = jest.fn(() => ({ describe('config/index', () => { describe('.parseConfigs(env, defaultArgv)', () => { - let configParser; - let defaultArgv; + let configParser: typeof import('../../lib/config'); + let defaultArgv: string[]; beforeEach(() => { jest.resetModules(); - configParser = require('../../lib/config/index.js'); + configParser = require('../../lib/config/index'); defaultArgv = argv(); jest.mock('delay'); // @ts-ignore require('delay').mockImplementation(() => Promise.resolve()); }); it('supports token in env', async () => { - const env = { RENOVATE_TOKEN: 'abc' }; + const env: NodeJS.ProcessEnv = { RENOVATE_TOKEN: 'abc' }; await configParser.parseConfigs(env, defaultArgv); }); it('supports token in CLI options', async () => { defaultArgv = defaultArgv.concat(['--token=abc', '--pr-footer=custom']); - const env = {}; + const env: NodeJS.ProcessEnv = {}; await configParser.parseConfigs(env, defaultArgv); }); it('supports forceCli', async () => { defaultArgv = defaultArgv.concat(['--force-cli=true']); - const env = { RENOVATE_TOKEN: 'abc' }; + const env: NodeJS.ProcessEnv = { RENOVATE_TOKEN: 'abc' }; await configParser.parseConfigs(env, defaultArgv); }); it('supports Bitbucket username/passwod', async () => { @@ -46,7 +47,7 @@ describe('config/index', () => { '--username=user', '--password=pass', ]); - const env = {}; + const env: NodeJS.ProcessEnv = {}; await configParser.parseConfigs(env, defaultArgv); }); }); @@ -60,7 +61,7 @@ describe('config/index', () => { schedule: ['on monday'], }, }; - const configParser = require('../../lib/config/index.js'); + const configParser = require('../../lib/config/index'); const config = configParser.mergeChildConfig(parentConfig, childConfig); expect(config.foo).toEqual('bar'); expect(config.rangeStrategy).toEqual('replace'); @@ -75,7 +76,7 @@ describe('config/index', () => { const childConfig = { packageRules: [{ a: 3 }, { a: 4 }], }; - const configParser = require('../../lib/config/index.js'); + const configParser = require('../../lib/config/index'); const config = configParser.mergeChildConfig(parentConfig, childConfig); expect(config.packageRules.map(rule => rule.a)).toMatchObject([ 1, @@ -92,20 +93,20 @@ describe('config/index', () => { const childConfig = { packageRules: [{ a: 3 }, { a: 4 }], }; - const configParser = require('../../lib/config/index.js'); + const configParser = require('../../lib/config/index'); const config = configParser.mergeChildConfig(parentConfig, childConfig); expect(config.packageRules).toHaveLength(2); }); it('handles null child packageRules', () => { const parentConfig = { ...defaultConfig }; parentConfig.packageRules = [{ a: 3 }, { a: 4 }]; - const configParser = require('../../lib/config/index.js'); + const configParser = require('../../lib/config/index'); const config = configParser.mergeChildConfig(parentConfig, {}); expect(config.packageRules).toHaveLength(2); }); it('handles undefined childConfig', () => { const parentConfig = { ...defaultConfig }; - const configParser = require('../../lib/config/index.js'); + const configParser = require('../../lib/config/index'); const config = configParser.mergeChildConfig(parentConfig, undefined); expect(config).toMatchObject(parentConfig); }); diff --git a/test/config/massage.spec.js b/test/config/massage.spec.ts similarity index 79% rename from test/config/massage.spec.js rename to test/config/massage.spec.ts index c06ffb73297d795bc5723cbc40ef0e004df38676..8e0a7ab029adc3214ba43544e5ac9e87aeca4e7b 100644 --- a/test/config/massage.spec.js +++ b/test/config/massage.spec.ts @@ -1,27 +1,28 @@ -const massage = require('../../lib/config/massage.js'); +import * as massage from '../../lib/config/massage'; +import { RenovateConfig } from '../../lib/config'; describe('config/massage', () => { describe('massageConfig', () => { it('returns empty', () => { - const config = {}; + const config: RenovateConfig = {}; const res = massage.massageConfig(config); expect(res).toMatchSnapshot(); }); it('massages strings to array', () => { - const config = { + const config: RenovateConfig = { schedule: 'before 5am', }; const res = massage.massageConfig(config); expect(Array.isArray(res.schedule)).toBe(true); }); it('massages npmToken', () => { - const config = { + const config: RenovateConfig = { npmToken: 'some-token', }; expect(massage.massageConfig(config)).toMatchSnapshot(); }); it('massages packageRules updateTypes', () => { - const config = { + const config: RenovateConfig = { packageRules: [ { packageNames: ['foo'], diff --git a/test/config/migrate-validate.spec.js b/test/config/migrate-validate.spec.ts similarity index 71% rename from test/config/migrate-validate.spec.js rename to test/config/migrate-validate.spec.ts index 0511dd2b68b7f78d17b0dd13cab5d3a550960aaa..40e6ba1416e49a003da313ea9f79626c479fecd1 100644 --- a/test/config/migrate-validate.spec.js +++ b/test/config/migrate-validate.spec.ts @@ -1,6 +1,7 @@ -const { migrateAndValidate } = require('../../lib/config/migrate-validate'); +import { migrateAndValidate } from '../../lib/config/migrate-validate'; +import { RenovateConfig } from '../../lib/config'; -let config; +let config: RenovateConfig; beforeEach(() => { jest.resetAllMocks(); config = { ...require('./config/_fixtures') }; @@ -13,12 +14,12 @@ describe('config/migrate-validate', () => { expect(res).toMatchSnapshot(); }); it('handles migration', async () => { - const input = { automerge: 'none' }; + const input: RenovateConfig = { automerge: 'none' as any }; const res = await migrateAndValidate(config, input); expect(res).toMatchSnapshot(); }); it('handles invalid', async () => { - const input = { foo: 'none' }; + const input: RenovateConfig = { foo: 'none' }; const res = await migrateAndValidate(config, input); expect(res).toMatchSnapshot(); expect(res.errors).toHaveLength(1); diff --git a/test/config/migration.spec.js b/test/config/migration.spec.ts similarity index 94% rename from test/config/migration.spec.js rename to test/config/migration.spec.ts index a86a201153838bb641738654db68dc6ebe96427e..710e73f5c0a6ad9ce16039fd88199032547687c5 100644 --- a/test/config/migration.spec.js +++ b/test/config/migration.spec.ts @@ -1,10 +1,13 @@ -const configMigration = require('../../lib/config/migration.js'); -const defaultConfig = require('../../lib/config/defaults').getConfig(); +import * as configMigration from '../../lib/config/migration'; +import { getConfig } from '../../lib/config/defaults'; +import { RenovateConfig } from '../../lib/config'; + +const defaultConfig = getConfig(); describe('config/migration', () => { describe('migrateConfig(config, parentConfig)', () => { it('it migrates config', () => { - const config = { + const config: RenovateConfig = { endpoints: [{}], enabled: true, platform: 'github', @@ -24,7 +27,7 @@ describe('config/migration', () => { gitFs: false, separateMajorReleases: true, separatePatchReleases: true, - automerge: 'none', + automerge: 'none' as any, automergeMajor: false, automergeMinor: true, automergePatch: true, @@ -55,7 +58,7 @@ describe('config/migration', () => { }, packageRules: [ { - packagePatterns: '^(@angular|typescript)', + packagePatterns: '^(@angular|typescript)' as any, groupName: ['angular packages'], excludedPackageNames: 'foo', }, @@ -73,7 +76,7 @@ describe('config/migration', () => { lockFileMaintenance: { exposeEnv: false, gitFs: true, - automerge: 'any', + automerge: 'any' as any, schedule: 'before 5am every day', }, devDependencies: { @@ -218,8 +221,8 @@ describe('config/migration', () => { expect(migratedConfig).toMatchSnapshot(); }); it('it overrides existing automerge setting', () => { - const config = { - automerge: 'minor', + const config: RenovateConfig = { + automerge: 'minor' as any, packages: [ { packagePatterns: '^(@angular|typescript)', @@ -237,7 +240,7 @@ describe('config/migration', () => { expect(migratedConfig.packageRules[0].minor.automerge).toBe(false); }); it('it does not migrate config', () => { - const config = { + const config: RenovateConfig = { enabled: true, semanticCommits: true, separateMinorPatch: true, @@ -249,7 +252,7 @@ describe('config/migration', () => { expect(migratedConfig).toMatchObject(config); }); it('it migrates subconfig', () => { - const config = { + const config: RenovateConfig = { lockFileMaintenance: { depTypes: [ 'dependencies', @@ -272,7 +275,7 @@ describe('config/migration', () => { ).toBe(false); }); it('it migrates node to travis', () => { - const config = { + const config: RenovateConfig = { node: { enabled: true, supportPolicy: ['lts'], @@ -290,7 +293,7 @@ describe('config/migration', () => { expect(migratedConfig.node.supportPolicy).toBeDefined(); }); it('it migrates packageFiles', () => { - const config = { + const config: RenovateConfig = { packageFiles: [ 'package.json', { packageFile: 'backend/package.json', pinVersions: false }, @@ -315,7 +318,7 @@ describe('config/migration', () => { expect(migratedConfig.packageRules[1].rangeStrategy).toBe('pin'); }); it('it migrates more packageFiles', () => { - const config = { + const config: RenovateConfig = { packageFiles: [ { packageFile: 'package.json', diff --git a/test/config/presets.spec.js b/test/config/presets.spec.ts similarity index 95% rename from test/config/presets.spec.js rename to test/config/presets.spec.ts index 93956e03e2b03467cff59a72b5bf1dd547622f35..cb3889c56cdd871115e5feb660aa0513734cc73d 100644 --- a/test/config/presets.spec.js +++ b/test/config/presets.spec.ts @@ -1,13 +1,16 @@ -const npm = require('../../lib/datasource/npm'); -const presets = require('../../lib/config/presets'); -const presetDefaults = require('./npm/_fixtures/renovate-config-default.json'); -const presetPackages = require('./npm/_fixtures/renovate-config-packages.json'); -const presetGroup = require('./npm/_fixtures/renovate-config-group.json'); -const presetMonorepo = require('./npm/_fixtures/renovate-config-monorepo.json'); -const presetIkatyang = require('./npm/_fixtures/renovate-config-ikatyang.json'); +import * as _npm from '../../lib/datasource/npm'; +import * as presets from '../../lib/config/presets'; +import presetDefaults from './npm/_fixtures/renovate-config-default.json'; +import presetPackages from './npm/_fixtures/renovate-config-packages.json'; +import presetGroup from './npm/_fixtures/renovate-config-group.json'; +import presetMonorepo from './npm/_fixtures/renovate-config-monorepo.json'; +import presetIkatyang from './npm/_fixtures/renovate-config-ikatyang.json'; +import { RenovateConfig } from '../../lib/config'; jest.mock('../../lib/datasource/npm'); +const npm: any = _npm; + npm.getPreset = jest.fn((dep, presetName) => { if (dep === 'renovate-config-default') { return presetDefaults.versions[presetDefaults['dist-tags'].latest][ @@ -51,7 +54,7 @@ npm.getPreset = jest.fn((dep, presetName) => { describe('config/presets', () => { describe('resolvePreset', () => { - let config; + let config: RenovateConfig; beforeEach(() => { config = {}; }); diff --git a/test/config/validation.spec.js b/test/config/validation.spec.ts similarity index 93% rename from test/config/validation.spec.js rename to test/config/validation.spec.ts index 267e766a533fd4e7bb1ec1e5b69f0edbef3a9cbf..add260d228020bd36faaf898baebf095352bed87 100644 --- a/test/config/validation.spec.js +++ b/test/config/validation.spec.ts @@ -1,4 +1,5 @@ -const configValidation = require('../../lib/config/validation.js'); +import * as configValidation from '../../lib/config/validation'; +import { RenovateConfig } from '../../lib/config'; describe('config/validation', () => { describe('validateConfig(config)', () => { @@ -11,6 +12,7 @@ describe('config/validation', () => { expect(warnings).toMatchSnapshot(); }); it('returns nested errors', async () => { + /** @type any */ const config = { foo: 1, schedule: ['after 5pm'], @@ -63,14 +65,14 @@ describe('config/validation', () => { expect(errors).toMatchSnapshot(); }); it('errors for all types', async () => { - const config = { + const config: RenovateConfig = { allowedVersions: 'foo', - enabled: 1, + enabled: 1 as any, schedule: ['every 15 mins every weekday'], timezone: 'Asia', labels: 5, - semanticCommitType: 7, - lockFileMaintenance: false, + semanticCommitType: 7 as any, + lockFileMaintenance: false as any, extends: [':timezone(Europe/Brussel)'], packageRules: [ { @@ -80,7 +82,7 @@ describe('config/validation', () => { { foo: 1, }, - 'what?', + 'what?' as any, { packagePatterns: 'abc ([a-z]+) ([a-z]+))', excludePackagePatterns: ['abc ([a-z]+) ([a-z]+))'], diff --git a/test/manager/npm/extract/index.spec.ts b/test/manager/npm/extract/index.spec.ts index e3e20b8484287f2bf45f642141739c547b1ecd05..8c3a402b10a78262a820b23a1b59bb9ea8af35dc 100644 --- a/test/manager/npm/extract/index.spec.ts +++ b/test/manager/npm/extract/index.spec.ts @@ -3,7 +3,8 @@ import path from 'path'; import * as npmExtract from '../../../../lib/manager/npm/extract'; import { getConfig } from '../../../../lib/config/defaults'; -const defaultConfig = getConfig(); +// TODO: fix types +const defaultConfig = getConfig() as any; const platform: any = global.platform; function readFixture(fixture) { diff --git a/test/util/package-rules.spec.ts b/test/util/package-rules.spec.ts index 3f6b1057b5cde074fabbfc40cea3325f06ba4e78..793778c2d62a425625366d0e16d8d74f91855321 100644 --- a/test/util/package-rules.spec.ts +++ b/test/util/package-rules.spec.ts @@ -1,7 +1,10 @@ -import { applyPackageRules } from '../../lib/util/package-rules'; +import { applyPackageRules, Config } from '../../lib/util/package-rules'; +import { UpdateType } from '../../lib/config'; + +type TestConfig = Config & { x?: number; y?: number }; describe('applyPackageRules()', () => { - const config1 = { + const config1: TestConfig = { foo: 'bar', packageRules: [ @@ -18,7 +21,7 @@ describe('applyPackageRules()', () => { ], }; it('applies', () => { - const config = { + const config: Config = { depName: 'a', isBump: true, currentValue: '1.0.0', @@ -98,7 +101,7 @@ describe('applyPackageRules()', () => { expect(res.y).toBeUndefined(); }); it('matches anything if missing inclusive rules', () => { - const config = { + const config: TestConfig = { packageRules: [ { excludePackageNames: ['foo'], @@ -118,7 +121,7 @@ describe('applyPackageRules()', () => { expect(res2.x).toBeDefined(); }); it('supports inclusive or', () => { - const config = { + const config: TestConfig = { packageRules: [ { packageNames: ['neutrino'], @@ -136,7 +139,7 @@ describe('applyPackageRules()', () => { expect(res2.x).toBeDefined(); }); it('filters depType', () => { - const config = { + const config: TestConfig = { packageRules: [ { depTypeList: ['dependencies', 'peerDependencies'], @@ -153,7 +156,7 @@ describe('applyPackageRules()', () => { expect(res.x).toBe(1); }); it('filters depTypes', () => { - const config = { + const config: TestConfig = { packageRules: [ { depTypeList: ['test'], @@ -170,7 +173,7 @@ describe('applyPackageRules()', () => { expect(res.x).toBe(1); }); it('filters managers with matching manager', () => { - const config = { + const config: TestConfig = { packageRules: [ { managers: ['npm', 'meteor'], @@ -189,7 +192,7 @@ describe('applyPackageRules()', () => { expect(res.x).toBe(1); }); it('filters managers with non-matching manager', () => { - const config = { + const config: TestConfig = { packageRules: [ { managers: ['dockerfile', 'npm'], @@ -208,7 +211,7 @@ describe('applyPackageRules()', () => { expect(res.x).toBeUndefined(); }); it('filters languages with matching language', () => { - const config = { + const config: TestConfig = { packageRules: [ { languages: ['js', 'node'], @@ -227,7 +230,7 @@ describe('applyPackageRules()', () => { expect(res.x).toBe(1); }); it('filters languages with non-matching language', () => { - const config = { + const config: TestConfig = { packageRules: [ { languages: ['docker'], @@ -246,7 +249,7 @@ describe('applyPackageRules()', () => { expect(res.x).toBeUndefined(); }); it('filters datasources with matching datasource', () => { - const config = { + const config: TestConfig = { packageRules: [ { datasources: ['orb', 'docker'], @@ -263,7 +266,7 @@ describe('applyPackageRules()', () => { expect(res.x).toBe(1); }); it('filters branches with matching branch', () => { - const config = { + const config: TestConfig = { packageRules: [ { baseBranchList: ['master', 'staging'], @@ -280,7 +283,7 @@ describe('applyPackageRules()', () => { expect(res.x).toBe(1); }); it('filters datasources with non-matching datasource', () => { - const config = { + const config: TestConfig = { packageRules: [ { datasources: ['orb'], @@ -296,7 +299,7 @@ describe('applyPackageRules()', () => { expect(res.x).toBeUndefined(); }); it('filters branches with non-matching branch', () => { - const config = { + const config: TestConfig = { packageRules: [ { baseBranchList: ['master'], @@ -312,7 +315,7 @@ describe('applyPackageRules()', () => { expect(res.x).toBeUndefined(); }); it('filters updateType', () => { - const config = { + const config: TestConfig = { packageRules: [ { updateTypes: ['minor', 'patch'], @@ -323,13 +326,13 @@ describe('applyPackageRules()', () => { const dep = { depType: 'dependencies', depName: 'a', - updateType: 'patch', + updateType: 'patch' as UpdateType, }; const res = applyPackageRules({ ...config, ...dep }); expect(res.x).toBe(1); }); it('matches sourceUrlPrefixes', () => { - const config = { + const config: TestConfig = { packageRules: [ { sourceUrlPrefixes: [ @@ -343,14 +346,14 @@ describe('applyPackageRules()', () => { const dep = { depType: 'dependencies', depName: 'a', - updateType: 'patch', + updateType: 'patch' as UpdateType, sourceUrl: 'https://github.com/renovatebot/presets', }; const res = applyPackageRules({ ...config, ...dep }); expect(res.x).toBe(1); }); it('non-matches sourceUrlPrefixes', () => { - const config = { + const config: TestConfig = { packageRules: [ { sourceUrlPrefixes: [ @@ -364,14 +367,14 @@ describe('applyPackageRules()', () => { const dep = { depType: 'dependencies', depName: 'a', - updateType: 'patch', + updateType: 'patch' as UpdateType, sourceUrl: 'https://github.com/vuejs/vue', }; const res = applyPackageRules({ ...config, ...dep }); expect(res.x).toBeUndefined(); }); it('handles sourceUrlPrefixes when missing sourceUrl', () => { - const config = { + const config: TestConfig = { packageRules: [ { sourceUrlPrefixes: [ @@ -385,13 +388,13 @@ describe('applyPackageRules()', () => { const dep = { depType: 'dependencies', depName: 'a', - updateType: 'patch', + updateType: 'patch' as UpdateType, }; const res = applyPackageRules({ ...config, ...dep }); expect(res.x).toBeUndefined(); }); it('filters naked depType', () => { - const config = { + const config: TestConfig = { packageRules: [ { depTypeList: ['dependencies', 'peerDependencies'], @@ -407,7 +410,7 @@ describe('applyPackageRules()', () => { expect(res.x).toBe(1); }); it('filters depType', () => { - const config = { + const config: TestConfig = { packageRules: [ { depTypeList: ['dependencies', 'peerDependencies'], @@ -424,7 +427,7 @@ describe('applyPackageRules()', () => { expect(res.x).toBeUndefined(); }); it('checks if matchCurrentVersion selector is valid and satisfies the condition on range overlap', () => { - const config = { + const config: TestConfig = { packageRules: [ { packageNames: ['test'], @@ -452,7 +455,7 @@ describe('applyPackageRules()', () => { expect(res2.x).toBeUndefined(); }); it('checks if matchCurrentVersion selector is valid and satisfies the condition on pinned to range overlap', () => { - const config = { + const config: TestConfig = { packageRules: [ { packageNames: ['test'], @@ -472,7 +475,7 @@ describe('applyPackageRules()', () => { expect(res1.x).toBeDefined(); }); it('checks if matchCurrentVersion selector works with static values', () => { - const config = { + const config: TestConfig = { packageRules: [ { packageNames: ['test'], @@ -492,7 +495,7 @@ describe('applyPackageRules()', () => { expect(res1.x).toBeDefined(); }); it('matches paths', () => { - const config = { + const config: TestConfig = { packageFile: 'examples/foo/package.json', packageRules: [ { diff --git a/yarn.lock b/yarn.lock index 66ad0e869fa229b7958750125650f4674aaeb3b9..2035554c612bd4d163b866271f605371c4acc040 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1194,6 +1194,11 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.3.tgz#bdfd69d61e464dcc81b25159c270d75a73c1a636" integrity sha512-Il2DtDVRGDcqjDtE+rF8iqg1CArehSK84HZJCT7AMITlyXRBpuPhqGLDQMowraqqu1coEaimg4ZOqggt6L6L+A== +"@types/later@1.2.5": + version "1.2.5" + resolved "https://registry.yarnpkg.com/@types/later/-/later-1.2.5.tgz#56297f82ea0002549159219d75844a9380ad18bd" + integrity sha512-oROpXZfXR+6uQyz4wBs2gZYxvZJ5Zp+iSEJWrIWgvipSnzLcHCpR9br4XUqRBPFS1EP971JlnWfXhr5so5E1sg== + "@types/lodash@4.14.137": version "4.14.137" resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.137.tgz#8a4804937dc6462274ffcc088df8f14fc1b368e2" @@ -1246,6 +1251,11 @@ resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.0.tgz#2b35eccfcee7d38cd72ad99232fbd58bffb3c84d" integrity sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA== +"@types/safe-regex@1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@types/safe-regex/-/safe-regex-1.1.2.tgz#0434f128255fe79c34ff21ffd18c706b2bad8856" + integrity sha512-wuS9LVpgIiTYaGKd+s6Dj0kRXBkttaXjVxzaXmviCACi8RO+INPayND+VNjAcall/l1Jkyhh9lyPfKW/aP/Yug== + "@types/semver@6.0.1": version "6.0.1" resolved "https://registry.yarnpkg.com/@types/semver/-/semver-6.0.1.tgz#a984b405c702fa5a7ec6abc56b37f2ba35ef5af6"