diff --git a/docs/usage/configuration-options.md b/docs/usage/configuration-options.md index 54401fae23e3a0..fda83b664f807f 100644 --- a/docs/usage/configuration-options.md +++ b/docs/usage/configuration-options.md @@ -62,7 +62,7 @@ Consider this example: "labels": ["dependencies"], "packageRules": [ { - "matchPackagePatterns": ["eslint"], + "matchPackageNames": ["/eslint/"], "labels": ["linting"] }, { @@ -1080,7 +1080,7 @@ If you want to approve _specific_ packages, set `dependencyDashboardApproval` to { "packageRules": [ { - "matchPackagePatterns": ["^@package-name"], + "matchPackageNames": ["/^@package-name/"], "dependencyDashboardApproval": true } ] @@ -1161,7 +1161,7 @@ To disable Renovate for all `eslint` packages, you can configure a package rule { "packageRules": [ { - "matchPackagePatterns": ["^eslint"], + "matchPackageNames": ["eslint**"], "enabled": false } ] @@ -2170,7 +2170,7 @@ Consider this example: "labels": ["dependencies"], "packageRules": [ { - "matchPackagePatterns": ["eslint"], + "matchPackageNames": ["/eslint/"], "labels": ["linting"] } ] @@ -2408,14 +2408,14 @@ Here is an example if you want to group together all packages starting with `esl { "packageRules": [ { - "matchPackagePatterns": ["^eslint"], + "matchPackageNames": ["eslint**"], "groupName": "eslint packages" } ] } ``` -Note how the above uses `matchPackagePatterns` with a regex value. +Note how the above uses `matchPackageNames` with a prefix pattern. Here's an example config to limit the "noisy" `aws-sdk` package to weekly updates: @@ -2432,24 +2432,22 @@ Here's an example config to limit the "noisy" `aws-sdk` package to weekly update For Maven dependencies, the package name is ``, e.g. `"matchPackageNames": ["com.thoughtworks.xstream:xstream"]` -Note how the above uses `matchPackageNames` instead of `matchPackagePatterns` because it is an exact match package name. -This is the equivalent of defining `"matchPackagePatterns": ["^aws\-sdk$"]`. -However you can mix together both `matchPackageNames` and `matchPackagePatterns` in the same package rule and the rule will be applied if _either_ match. +Note how the above uses an exact match string for `matchPackageNames` instead of a pattern +However you can mix together both patterns and exact matches in the same package rule and the rule will be applied if _either_ match. Example: ```json { "packageRules": [ { - "matchPackageNames": ["neutrino"], - "matchPackagePatterns": ["^@neutrino/"], + "matchPackageNames": ["neutrino", "@neutrino/**"], "groupName": "neutrino monorepo" } ] } ``` -The above rule will group together the `neutrino` package and any package matching `@neutrino/*`. +The above rule will group together the `neutrino` package and any package starting with `@neutrino/`. File name matches are convenient to use if you wish to apply configuration rules to certain package or lock files using patterns. For example, if you have an `examples` directory and you want all updates to those examples to use the `chore` prefix instead of `fix`, then you could add this configuration: @@ -2574,88 +2572,6 @@ Instead you should do `> 13 months`. Use this field if you want to limit a `packageRule` to certain `depType` values. Invalid if used outside of a `packageRule`. -For more details on supported syntax see Renovate's [string pattern matching documentation](./string-pattern-matching.md). - -### excludeDepNames - -### excludeDepPatterns - -### excludeDepPrefixes - -### excludePackageNames - -**Important**: Do not mix this up with the option `ignoreDeps`. -Use `ignoreDeps` instead if all you want to do is have a list of package names for Renovate to ignore. - -Use `excludePackageNames` if you want to have one or more exact name matches excluded in your package rule. -See also `matchPackageNames`. - -```json -{ - "packageRules": [ - { - "matchPackagePatterns": ["^eslint"], - "excludePackageNames": ["eslint-foo"] - } - ] -} -``` - -The above will match all package names starting with `eslint` but exclude the specific package `eslint-foo`. - -### excludePackagePatterns - -Use this field if you want to have one or more package name patterns excluded in your package rule. -See also `matchPackagePatterns`. - -```json -{ - "packageRules": [ - { - "matchPackagePatterns": ["^eslint"], - "excludePackagePatterns": ["^eslint-foo"] - } - ] -} -``` - -The above will match all package names starting with `eslint` but exclude ones starting with `eslint-foo`. - -### excludePackagePrefixes - -Use this field if you want to have one or more package name prefixes excluded in your package rule, without needing to write a regex. -See also `matchPackagePrefixes`. - -```json -{ - "packageRules": [ - { - "matchPackagePrefixes": ["eslint"], - "excludePackagePrefixes": ["eslint-foo"] - } - ] -} -``` - -The above will match all package names starting with `eslint` but exclude ones starting with `eslint-foo`. - -### excludeRepositories - -Use this field to restrict rules to a particular repository. e.g. - -```json -{ - "packageRules": [ - { - "excludeRepositories": ["literal/repo", "/^some/.*$/", "**/*-archived"], - "enabled": false - } - ] -} -``` - -This field supports Regular Expressions if they begin and end with `/`, otherwise it will use `minimatch`. - ### matchCategories Use `matchCategories` to restrict rules to a particular language or group. @@ -2706,7 +2622,7 @@ Use this field to restrict rules to a particular branch. e.g. "packageRules": [ { "matchBaseBranches": ["main"], - "excludePackagePatterns": ["^eslint"], + "matchPackageNames": ["eslint**"], "enabled": false } ] @@ -2720,7 +2636,7 @@ This field also supports Regular Expressions if they begin and end with `/`. e.g "packageRules": [ { "matchBaseBranches": ["/^release/.*/"], - "excludePackagePatterns": ["^eslint"], + "matchPackageNames": ["eslint**"], "enabled": false } ] @@ -2796,7 +2712,7 @@ Regular Expressions must begin and end with `/`. { "packageRules": [ { - "matchPackagePatterns": ["io.github.resilience4j"], + "matchPackageNames": ["io.github.resilience4j**"], "matchCurrentValue": "/^1\\./" } ] @@ -2810,7 +2726,7 @@ Use the syntax `!/ /` like this: { "packageRules": [ { - "matchPackagePatterns": ["io.github.resilience4j"], + "matchPackageNames": ["io.github.resilience4j**"], "matchCurrentValue": "!/^0\\./" } ] @@ -2851,7 +2767,7 @@ For example, the following enforces that only `1.*` versions will be used: { "packageRules": [ { - "matchPackagePatterns": ["io.github.resilience4j"], + "matchPackageNames": ["io.github.resilience4j**"], "matchCurrentVersion": "/^1\\./" } ] @@ -2865,7 +2781,7 @@ Use the syntax `!/ /` like this: { "packageRules": [ { - "matchPackagePatterns": ["io.github.resilience4j"], + "matchPackageNames": ["io.github.resilience4j**"], "matchCurrentVersion": "!/^0\\./" } ] @@ -2925,20 +2841,6 @@ For more details on supported syntax see Renovate's [string pattern matching doc This field behaves the same as `matchPackageNames` except it matches against `depName` instead of `packageName`. -### matchDepPatterns - - -!!! note - `matchDepNames` now supports pattern matching and should be used instead. - Use of `matchDepPatterns` is now deprecated and will be migrated in future. - -### matchDepPrefixes - - -!!! note - `matchDepNames` now supports pattern matching and should be used instead. - Use of `matchDepPrefixes` is now deprecated and will be migrated in future. - ### matchNewValue This option is matched against the `newValue` field of a dependency. @@ -2963,7 +2865,7 @@ Regular Expressions must begin and end with `/`. { "packageRules": [ { - "matchPackagePatterns": ["io.github.resilience4j"], + "matchPackageNames": ["io.github.resilience4j**"], "matchNewValue": "/^1\\./" } ] @@ -2977,7 +2879,7 @@ Use the syntax `!/ /` like this: { "packageRules": [ { - "matchPackagePatterns": ["io.github.resilience4j"], + "matchPackageNames": ["io.github.resilience4j**"], "matchNewValue": "!/^0\\./" } ] @@ -3012,15 +2914,14 @@ The above will configure `rangeStrategy` to `pin` only for the npm package `angu { "packageRules": [ { - "matchDatasources": ["npm"], - "matchPackageNames": ["@angular/*", "!@angular/abc"], - "groupName": "Angular" + "matchPackagePatterns": ["^angular", "!@angular/abc"], + "rangeStrategy": "replace" } ] } ``` -The above will group together any npm package which starts with `@angular/` except `@angular/abc`. +The above will set a replaceStrategy for any npm package which starts with `@angular/` except `@angular/abc`. ```json title="pattern match using RegEx" { @@ -3036,51 +2937,6 @@ The above will group together any npm package which starts with `@angular/` exce The above will group together any npm package which starts with the string `angular`. -### matchPackagePatterns - - -!!! note - `matchPackageNames` now supports pattern matching and should be used instead. - Use of `matchPackagePatterns` is now deprecated and will be migrated in future. - -### matchPackagePrefixes - - -!!! note - `matchPackageNames` now supports pattern matching and should be used instead. - Use of `matchPackagePrefixes` is now deprecated and will be migrated in future. - -Use this field to match a package prefix without needing to write a regex expression. -See also `excludePackagePrefixes`. - -```json -{ - "packageRules": [ - { - "matchPackagePrefixes": ["angular"], - "rangeStrategy": "replace" - } - ] -} -``` - -Like the earlier `matchPackagePatterns` example, the above will configure `rangeStrategy` to `replace` for any package starting with `angular`. - -### matchSourceUrlPrefixes - -Here's an example of where you use this to group together all packages from the `renovatebot` GitHub org: - -```json -{ - "packageRules": [ - { - "matchSourceUrlPrefixes": ["https://github.com/renovatebot/"], - "groupName": "All renovate packages" - } - ] -} -``` - ### matchSourceUrls Here's an example of where you use this to group together all packages from the Vue monorepo: @@ -3213,7 +3069,7 @@ For example, the following package rule can be used to replace the registry for "packageRules": [ { "matchDatasources": ["docker"], - "matchPackagePatterns": ["^docker\\.io/.+"], + "matchPackageNames": ["docker.io/**"], "replacementNameTemplate": "{{{replace 'docker\\.io/' 'ghcr.io/' packageName}}}" } ] @@ -3228,13 +3084,13 @@ Or, to add a registry prefix to any `docker` images that do not contain an expli { "description": "official images", "matchDatasources": ["docker"], - "matchPackagePatterns": ["^[a-z-]+$"], + "matchPackageNames": ["/^[a-z-]+$/"], "replacementNameTemplate": "some.registry.org/library/{{{packageName}}}" }, { "description": "non-official images", "matchDatasources": ["docker"], - "matchPackagePatterns": ["^[a-z-]+/[a-z-]+$"], + "matchPackageNames": ["/^[a-z-]+/[a-z-]+$/"], "replacementNameTemplate": "some.registry.org/{{{packageName}}}" } ] diff --git a/docs/usage/faq.md b/docs/usage/faq.md index 6ee4c111693683..3ff913c2d72c84 100644 --- a/docs/usage/faq.md +++ b/docs/usage/faq.md @@ -120,7 +120,7 @@ The basic idea is that you create a new `packageRules` entry and describe what k { "packageRules": [ { - "matchPackagePatterns": ["^jest"], + "matchPackageNames": ["jest"], "matchUpdateTypes": ["major"], "dependencyDashboardApproval": true } @@ -223,13 +223,13 @@ e.g. ### Apply a rule, but only for packages starting with `abc` -Do the same as above, but instead of using `matchPackageNames`, use `matchPackagePatterns` and a regex: +Do the same as above, but instead of an exact match, use a glob prefix: ```json { "packageRules": [ { - "matchPackagePatterns": "^abc", + "matchPackageNames": "abc**", "assignees": ["importantreviewer"] } ] @@ -244,7 +244,7 @@ As above, but apply a `groupName`: { "packageRules": [ { - "matchPackagePatterns": "^abc", + "matchPackageNames": "abc**", "groupName": ["abc packages"] } ] diff --git a/docs/usage/key-concepts/automerge.md b/docs/usage/key-concepts/automerge.md index 43095d66b7ded7..2f24b7ae2ebb04 100644 --- a/docs/usage/key-concepts/automerge.md +++ b/docs/usage/key-concepts/automerge.md @@ -56,7 +56,7 @@ But in many cases the new version(s) will pass tests, and if so then there's rea "packageRules": [ { "matchDepTypes": ["devDependencies"], - "matchPackagePatterns": ["lint", "prettier"], + "matchPackageNames": ["lint", "prettier"], "automerge": true } ] @@ -263,7 +263,7 @@ To turn off automerge for all dependencies of a selected repository, you need to "extends": ["local>org-name/.github:renovate-config"], "packageRules": [ { - "matchPackagePatterns": ["*"], + "matchPackageNames": ["*"], "automerge": false } ] diff --git a/docs/usage/key-concepts/dashboard.md b/docs/usage/key-concepts/dashboard.md index a564d63dc9f41f..1a20881912a1f1 100644 --- a/docs/usage/key-concepts/dashboard.md +++ b/docs/usage/key-concepts/dashboard.md @@ -121,7 +121,7 @@ If you want to approve specific packages, set `dependencyDashboardApproval` to ` { "packageRules": [ { - "matchPackagePatterns": ["^@somescope"], + "matchPackageName": ["@somescope/**"], "dependencyDashboardApproval": true } ] diff --git a/docs/usage/modules/versioning/index.md b/docs/usage/modules/versioning/index.md index eab2373bcb1b40..e9bad3fa2cc8a2 100644 --- a/docs/usage/modules/versioning/index.md +++ b/docs/usage/modules/versioning/index.md @@ -23,7 +23,7 @@ Configuring or overriding the default `versioning` can be extra helpful for ecos - Although you can reconfigure versioning per-manager or per-datasource, you probably don't need such a broad change - More commonly you would need to configure `versioning` for individual packages or potentially package patterns -- The best way to do this is with `packageRules`, with a combination of `matchManagers`, `matchDatasources`, `matchPackageNames` and `matchPackagePatterns`. +- The best way to do this is with `packageRules`, with a combination of `matchManagers`, `matchDatasources`, and `matchPackageNames`. Avoid configuring `versioning` in a rule that also uses `matchUpdateTypes`, as the update types aren't known at the time the `versioning` is applied ## Examples of versioning overrides diff --git a/docs/usage/noise-reduction.md b/docs/usage/noise-reduction.md index 468c5383dc5747..d88a39671a5eff 100644 --- a/docs/usage/noise-reduction.md +++ b/docs/usage/noise-reduction.md @@ -31,14 +31,14 @@ In that case you might create a config like this: { "packageRules": [ { - "matchPackagePatterns": ["eslint"], + "matchPackageNames": ["/eslint/"], "groupName": "eslint" } ] } ``` -By setting `matchPackagePatterns` to "eslint", it means that any package with ESLint anywhere in its name will be grouped into a `renovate/eslint` branch and related PR. +By setting `matchPackageNames` to `/eslint/`, it means that any package with eslint anywhere in its name will be grouped into a `renovate/eslint` branch and related PR. ### Be smart about grouping dependencies @@ -91,7 +91,7 @@ You don't want to get too far behind, so how about we update `eslint` packages o { "packageRules": [ { - "matchPackagePatterns": ["eslint"], + "matchPackageNames": ["/eslint/"], "groupName": "eslint", "schedule": ["on the first day of the month"] } @@ -105,7 +105,7 @@ Or perhaps at least weekly: { "packageRules": [ { - "matchPackagePatterns": ["eslint"], + "matchPackageNames": ["/eslint/"], "groupName": "eslint", "schedule": ["before 4am on monday"] } @@ -165,7 +165,7 @@ Let's automerge it if all the linting updates pass: { "packageRules": [ { - "matchPackagePatterns": ["eslint"], + "matchPackageNames": ["/eslint/"], "groupName": "eslint", "schedule": ["before 4am on monday"], "automerge": true, diff --git a/lib/config/__snapshots__/migration.spec.ts.snap b/lib/config/__snapshots__/migration.spec.ts.snap index b3f0b3deb66552..56119458e67a1e 100644 --- a/lib/config/__snapshots__/migration.spec.ts.snap +++ b/lib/config/__snapshots__/migration.spec.ts.snap @@ -58,22 +58,20 @@ exports[`config/migration it migrates nested packageRules 1`] = ` }, { "automerge": true, - "excludePackageNames": [ - "@types/react-table", - ], "groupName": "definitelyTyped", - "matchPackagePrefixes": [ - "@types/", + "matchPackageNames": [ + "!@types/react-table", + "@types/**", ], }, { "automerge": false, - "excludePackageNames": [ - "@types/react-table", - ], "matchDepTypes": [ "dependencies", ], + "matchPackageNames": [ + "!@types/react-table", + ], }, ], } @@ -190,23 +188,22 @@ exports[`config/migration migrateConfig(config, parentConfig) migrates config 1` ], }, { - "excludePackageNames": "foo", "groupName": "angular packages", - "matchPackagePatterns": "^(@angular|typescript)", + "matchPackageNames": [ + "/^(@angular|typescript)/", + ], }, { "groupName": "foo", - "matchPackagePatterns": [ - "^foo", + "matchPackageNames": [ + "/^foo/", ], }, { "enabled": false, "matchPackageNames": [ "angular", - ], - "matchPackagePatterns": [ - "ang", + "/ang/", ], }, { @@ -399,7 +396,9 @@ exports[`config/migration migrateConfig(config, parentConfig) overrides existing "major": { "automerge": false, }, - "matchPackagePatterns": "^(@angular|typescript)", + "matchPackageNames": [ + "/^(@angular|typescript)/", + ], "minor": { "automerge": false, }, diff --git a/lib/config/__snapshots__/validation.spec.ts.snap b/lib/config/__snapshots__/validation.spec.ts.snap index 3887cf94919695..4bfe7e328db719 100644 --- a/lib/config/__snapshots__/validation.spec.ts.snap +++ b/lib/config/__snapshots__/validation.spec.ts.snap @@ -54,11 +54,7 @@ exports[`config/validation validateConfig(config) errors for all types 1`] = ` "topic": "Configuration Error", }, { - "message": "Configuration option \`packageRules[3].matchDepPatterns\` should be a list (Array)", - "topic": "Configuration Error", - }, - { - "message": "Configuration option \`packageRules[3].matchPackagePatterns\` should be a list (Array)", + "message": "Configuration option \`packageRules[2].matchPackageNames\` should be a list (Array)", "topic": "Configuration Error", }, { @@ -66,15 +62,7 @@ exports[`config/validation validateConfig(config) errors for all types 1`] = ` "topic": "Configuration Error", }, { - "message": "Invalid configuration option: packageRules[1].foo", - "topic": "Configuration Error", - }, - { - "message": "Invalid regExp for packageRules[3].excludeDepPatterns: \`abc ([a-z]+) ([a-z]+))\`", - "topic": "Configuration Error", - }, - { - "message": "Invalid regExp for packageRules[3].excludePackagePatterns: \`abc ([a-z]+) ([a-z]+))\`", + "message": "Invalid configuration option: packageRules[0].foo", "topic": "Configuration Error", }, { @@ -90,7 +78,7 @@ exports[`config/validation validateConfig(config) errors for all types 1`] = ` "topic": "Configuration Error", }, { - "message": "packageRules[1]: Each packageRule must contain at least one match* or exclude* selector. Rule: {"foo":1}", + "message": "packageRules[0]: Each packageRule must contain at least one match* or exclude* selector. Rule: {"foo":1}", "topic": "Configuration Error", }, { @@ -220,7 +208,11 @@ exports[`config/validation validateConfig(config) returns nested errors 1`] = ` "topic": "Configuration Error", }, { - "message": "Invalid regExp for packageRules[0].excludePackagePatterns: \`abc ([a-z]+) ([a-z]+))\`", + "message": "Invalid regExp for packageRules[0].matchPackageNames: \`!/abc ([a-z]+) ([a-z]+))/\`", + "topic": "Configuration Error", + }, + { + "message": "Invalid regExp for packageRules[0].matchPackageNames: \`/abc ([a-z]+) ([a-z]+))/\`", "topic": "Configuration Error", }, ] @@ -268,7 +260,7 @@ exports[`config/validation validateConfig(config) warns if hostType has the wron exports[`config/validation validateConfig(config) warns if only selectors in packageRules 1`] = ` [ { - "message": "packageRules[0]: Each packageRule must contain at least one non-match* or non-exclude* field. Rule: {"matchDepTypes":["foo"],"excludePackageNames":["bar"]}", + "message": "packageRules[0]: Each packageRule must contain at least one non-match* or non-exclude* field. Rule: {"matchDepTypes":["foo"],"matchPackageNames":["bar"]}", "topic": "Configuration Error", }, ] diff --git a/lib/config/migration.spec.ts b/lib/config/migration.spec.ts index baa90a4aa50dbc..ce96ade5f02d37 100644 --- a/lib/config/migration.spec.ts +++ b/lib/config/migration.spec.ts @@ -254,14 +254,14 @@ describe('config/migration', () => { groupName: ['angular packages'], }, ], - }; + } as unknown as RenovateConfig; const { isMigrated, migratedConfig } = configMigration.migrateConfig(config); expect(isMigrated).toBeTrue(); expect(migratedConfig).toEqual({ packageRules: [ { - matchPackagePatterns: '^(@angular|typescript)', + matchPackageNames: ['/^(@angular|typescript)/'], groupName: 'angular packages', }, ], @@ -540,6 +540,7 @@ describe('config/migration', () => { packagePatterns: ['^bar'], excludePackageNames: ['baz'], excludePackagePatterns: ['^baz'], + excludeRepositories: ['abc/def'], sourceUrlPrefixes: ['https://github.com/lodash'], updateTypes: ['major'], }, @@ -551,17 +552,15 @@ describe('config/migration', () => { expect(migratedConfig).toEqual({ packageRules: [ { - excludePackageNames: ['baz'], - excludePackagePatterns: ['^baz'], matchBaseBranches: ['master'], matchDatasources: ['orb'], matchDepTypes: ['peerDependencies'], matchCategories: ['python'], matchManagers: ['dockerfile'], - matchPackageNames: ['foo'], - matchPackagePatterns: ['^bar'], + matchPackageNames: ['foo', '/^bar/', '!baz', '!/^baz/'], + matchRepositories: ['!abc/def'], matchFileNames: ['package.json'], - matchSourceUrlPrefixes: ['https://github.com/lodash'], + matchSourceUrls: ['https://github.com/lodash**'], matchUpdateTypes: ['major'], }, ], @@ -610,7 +609,7 @@ describe('config/migration', () => { packageRules: [ { groupName: 'definitelyTyped', - matchPackagePrefixes: ['@types/'], + matchPackageNames: ['@types/**'], }, { matchDepTypes: ['dependencies'], diff --git a/lib/config/migrations/custom/package-rules-migration.spec.ts b/lib/config/migrations/custom/package-rules-migration.spec.ts index 592e361005aba7..2075a5727420fc 100644 --- a/lib/config/migrations/custom/package-rules-migration.spec.ts +++ b/lib/config/migrations/custom/package-rules-migration.spec.ts @@ -16,8 +16,6 @@ describe('config/migrations/custom/package-rules-migration', () => { depTypeList: [], addLabels: [], packageNames: [], - packagePatterns: [], - sourceUrlPrefixes: [], updateTypes: [], }, ], @@ -107,4 +105,117 @@ describe('config/migrations/custom/package-rules-migration', () => { }, ); }); + + it('should migrate excludePackageNames to matchPackageNames', () => { + expect(PackageRulesMigration).toMigrate( + { + packageRules: [ + { + excludePackageNames: ['foo', 'bar'], + automerge: true, + }, + { + matchPackageNames: ['baz'], + excludePackageNames: ['foo', 'bar'], + automerge: true, + }, + ], + }, + { + packageRules: [ + { + automerge: true, + matchPackageNames: ['!foo', '!bar'], + }, + { + automerge: true, + matchPackageNames: ['baz', '!foo', '!bar'], + }, + ], + }, + ); + }); + + it('should migrate matchPackagePatterns to matchPackageNames', () => { + expect(PackageRulesMigration).toMigrate( + { + packageRules: [ + { + matchPackagePatterns: ['foo', 'bar'], + automerge: true, + }, + { + matchPackageNames: ['baz'], + matchPackagePatterns: ['foo', 'bar'], + automerge: true, + }, + ], + }, + { + packageRules: [ + { + automerge: true, + matchPackageNames: ['/foo/', '/bar/'], + }, + { + automerge: true, + matchPackageNames: ['baz', '/foo/', '/bar/'], + }, + ], + }, + ); + }); + + it('should migrate all match/exclude at once', () => { + expect(PackageRulesMigration).toMigrate( + { + packageRules: [ + { + matchPackagePatterns: ['pattern'], + matchPackagePrefixes: ['prefix1', 'prefix2'], + matchSourceUrlPrefixes: ['prefix1', 'prefix2'], + excludePackageNames: ['excluded'], + excludePackagePatterns: ['excludepattern'], + excludePackagePrefixes: ['prefix1b'], + matchPackageNames: ['mpn1', 'mpn2'], + matchDepPatterns: ['pattern'], + matchDepPrefixes: ['prefix1', 'prefix2'], + excludeDepNames: ['excluded'], + excludeDepPatterns: ['excludepattern'], + excludeDepPrefixes: ['prefix1b'], + matchDepNames: ['mpn1', 'mpn2'], + automerge: true, + }, + ], + }, + { + packageRules: [ + { + matchPackageNames: [ + 'mpn1', + 'mpn2', + '/pattern/', + 'prefix1**', + 'prefix2**', + '!excluded', + '!/excludepattern/', + '!prefix1b**', + ], + matchDepNames: [ + 'mpn1', + 'mpn2', + '/pattern/', + 'prefix1**', + 'prefix2**', + '!excluded', + '!/excludepattern/', + '!prefix1b**', + ], + matchSourceUrls: ['prefix1**', 'prefix2**'], + automerge: true, + }, + ], + }, + ); + }); }); diff --git a/lib/config/migrations/custom/package-rules-migration.ts b/lib/config/migrations/custom/package-rules-migration.ts index 3e6450956a9b70..6b8aea4780ebba 100644 --- a/lib/config/migrations/custom/package-rules-migration.ts +++ b/lib/config/migrations/custom/package-rules-migration.ts @@ -27,6 +27,102 @@ function renameKeys(packageRule: PackageRule): PackageRule { return newPackageRule; } +function mergeMatchers(packageRule: PackageRule): PackageRule { + const newPackageRule: PackageRule = { ...packageRule }; + for (const [key, val] of Object.entries(packageRule)) { + // depName + if (key === 'matchDepPrefixes') { + if (is.array(val, is.string)) { + newPackageRule.matchDepNames ??= []; + newPackageRule.matchDepNames.push(...val.map((v) => `${v}**`)); + } + delete newPackageRule.matchDepPrefixes; + } + if (key === 'matchDepPatterns') { + if (is.array(val, is.string)) { + newPackageRule.matchDepNames ??= []; + newPackageRule.matchDepNames.push(...val.map((v) => `/${v}/`)); + } + delete newPackageRule.matchDepPatterns; + } + if (key === 'excludeDepNames') { + if (is.array(val, is.string)) { + newPackageRule.matchDepNames ??= []; + newPackageRule.matchDepNames.push(...val.map((v) => `!${v}`)); + } + delete newPackageRule.excludeDepNames; + } + if (key === 'excludeDepPrefixes') { + if (is.array(val, is.string)) { + newPackageRule.matchDepNames ??= []; + newPackageRule.matchDepNames.push(...val.map((v) => `!${v}**`)); + } + delete newPackageRule.excludeDepPrefixes; + } + if (key === 'excludeDepPatterns') { + if (is.array(val, is.string)) { + newPackageRule.matchDepNames ??= []; + newPackageRule.matchDepNames.push(...val.map((v) => `!/${v}/`)); + } + delete newPackageRule.excludeDepPatterns; + } + // packageName + if (key === 'matchPackagePrefixes') { + if (is.array(val, is.string)) { + newPackageRule.matchPackageNames ??= []; + newPackageRule.matchPackageNames.push(...val.map((v) => `${v}**`)); + } + delete newPackageRule.matchPackagePrefixes; + } + if (key === 'matchPackagePatterns') { + const patterns = is.string(val) ? [val] : val; + if (is.array(patterns, is.string)) { + newPackageRule.matchPackageNames ??= []; + newPackageRule.matchPackageNames.push(...patterns.map((v) => `/${v}/`)); + } + delete newPackageRule.matchPackagePatterns; + } + if (key === 'excludePackageNames') { + if (is.array(val, is.string)) { + newPackageRule.matchPackageNames ??= []; + newPackageRule.matchPackageNames.push(...val.map((v) => `!${v}`)); + } + delete newPackageRule.excludePackageNames; + } + if (key === 'excludePackagePrefixes') { + if (is.array(val, is.string)) { + newPackageRule.matchPackageNames ??= []; + newPackageRule.matchPackageNames.push(...val.map((v) => `!${v}**`)); + } + delete newPackageRule.excludePackagePrefixes; + } + if (key === 'excludePackagePatterns') { + if (is.array(val, is.string)) { + newPackageRule.matchPackageNames ??= []; + newPackageRule.matchPackageNames.push(...val.map((v) => `!/${v}/`)); + } + delete newPackageRule.excludePackagePatterns; + } + // sourceUrl + if (key === 'matchSourceUrlPrefixes') { + if (is.array(val, is.string)) { + newPackageRule.matchSourceUrls ??= []; + newPackageRule.matchSourceUrls.push(...val.map((v) => `${v}**`)); + } + delete newPackageRule.matchSourceUrlPrefixes; + } + // repository + if (key === 'excludeRepositories') { + if (is.array(val, is.string)) { + newPackageRule.matchRepositories ??= []; + newPackageRule.matchRepositories.push(...val.map((v) => `!${v}`)); + } + delete newPackageRule.excludeRepositories; + } + } + return newPackageRule; +} + export class PackageRulesMigration extends AbstractMigration { override readonly propertyName = 'packageRules'; @@ -34,7 +130,7 @@ export class PackageRulesMigration extends AbstractMigration { let packageRules = this.get('packageRules') as PackageRule[]; if (is.nonEmptyArray(packageRules)) { packageRules = packageRules.map(renameKeys); - + packageRules = packageRules.map(mergeMatchers); this.rewrite(packageRules); } } diff --git a/lib/config/migrations/custom/packages-migration.spec.ts b/lib/config/migrations/custom/packages-migration.spec.ts index 255f9561c777c4..666c8627769fda 100644 --- a/lib/config/migrations/custom/packages-migration.spec.ts +++ b/lib/config/migrations/custom/packages-migration.spec.ts @@ -4,10 +4,10 @@ describe('config/migrations/custom/packages-migration', () => { it('should migrate to package rules', () => { expect(PackagesMigration).toMigrate( { - packages: [{ matchPackagePatterns: ['*'] }], + packages: [{ matchPackageNames: ['*'] }], }, { - packageRules: [{ matchPackagePatterns: ['*'] }], + packageRules: [{ matchPackageNames: ['*'] }], }, ); }); @@ -15,14 +15,11 @@ describe('config/migrations/custom/packages-migration', () => { it('should concat with existing package rules', () => { expect(PackagesMigration).toMigrate( { - packages: [{ matchPackagePatterns: ['*'] }], + packages: [{ matchPackageNames: ['*'] }], packageRules: [{ matchPackageNames: [] }], }, { - packageRules: [ - { matchPackageNames: [] }, - { matchPackagePatterns: ['*'] }, - ], + packageRules: [{ matchPackageNames: [] }, { matchPackageNames: ['*'] }], }, ); }); @@ -30,7 +27,7 @@ describe('config/migrations/custom/packages-migration', () => { it('should ignore non array value', () => { expect(PackagesMigration).toMigrate( { - packages: { matchPackagePatterns: ['*'] }, + packages: { matchPackageNames: ['*'] }, packageRules: [{ matchPackageNames: [] }], }, { diff --git a/lib/config/options/index.ts b/lib/config/options/index.ts index 7a6ec1c60e9474..c5966f690632d7 100644 --- a/lib/config/options/index.ts +++ b/lib/config/options/index.ts @@ -1305,19 +1305,6 @@ const options: RenovateOptions[] = [ env: false, patternMatch: true, }, - { - name: 'excludeRepositories', - description: - 'List of repositories to exclude (e.g. `["**/*-archived"]`). Valid only within a `packageRules` object.', - type: 'array', - subType: 'string', - allowString: true, - stage: 'package', - parents: ['packageRules'], - mergeable: true, - cli: false, - env: false, - }, { name: 'matchBaseBranches', description: @@ -1383,19 +1370,6 @@ const options: RenovateOptions[] = [ cli: false, env: false, }, - { - name: 'excludePackageNames', - description: - 'Package names to exclude. Valid only within a `packageRules` object.', - type: 'array', - subType: 'string', - allowString: true, - stage: 'package', - parents: ['packageRules'], - mergeable: true, - cli: false, - env: false, - }, { name: 'matchDepNames', description: @@ -1409,132 +1383,6 @@ const options: RenovateOptions[] = [ cli: false, env: false, }, - { - name: 'excludeDepNames', - description: - 'Dep names to exclude. Valid only within a `packageRules` object.', - type: 'array', - subType: 'string', - allowString: true, - stage: 'package', - parents: ['packageRules'], - mergeable: true, - cli: false, - env: false, - advancedUse: true, - }, - { - name: 'matchPackagePrefixes', - description: - 'Package name prefixes to match. Valid only within a `packageRules` object.', - type: 'array', - subType: 'string', - allowString: true, - stage: 'package', - parents: ['packageRules'], - mergeable: true, - cli: false, - env: false, - }, - { - name: 'excludePackagePrefixes', - description: - 'Package name prefixes to exclude. Valid only within a `packageRules` object.', - type: 'array', - subType: 'string', - allowString: true, - stage: 'package', - parents: ['packageRules'], - mergeable: true, - cli: false, - env: false, - }, - { - name: 'matchDepPrefixes', - description: - 'Dep names prefixes to match. Valid only within a `packageRules` object.', - type: 'array', - subType: 'string', - allowString: true, - stage: 'package', - parents: ['packageRules'], - mergeable: true, - cli: false, - env: false, - advancedUse: true, - }, - { - name: 'excludeDepPrefixes', - description: - 'Dep names prefixes to exclude. Valid only within a `packageRules` object.', - type: 'array', - subType: 'string', - allowString: true, - stage: 'package', - parents: ['packageRules'], - mergeable: true, - cli: false, - env: false, - advancedUse: true, - }, - { - name: 'matchPackagePatterns', - description: - 'Package name patterns to match. Valid only within a `packageRules` object.', - type: 'array', - subType: 'string', - format: 'regex', - allowString: true, - stage: 'package', - parents: ['packageRules'], - mergeable: true, - cli: false, - env: false, - }, - { - name: 'excludePackagePatterns', - description: - 'Package name patterns to exclude. Valid only within a `packageRules` object.', - type: 'array', - subType: 'string', - format: 'regex', - allowString: true, - stage: 'package', - parents: ['packageRules'], - mergeable: true, - cli: false, - env: false, - }, - { - name: 'matchDepPatterns', - description: - 'Dep name patterns to match. Valid only within a `packageRules` object.', - type: 'array', - subType: 'string', - format: 'regex', - allowString: true, - stage: 'package', - parents: ['packageRules'], - mergeable: true, - cli: false, - env: false, - advancedUse: true, - }, - { - name: 'excludeDepPatterns', - description: - 'Dep name patterns to exclude. Valid only within a `packageRules` object.', - type: 'array', - subType: 'string', - format: 'regex', - allowString: true, - stage: 'package', - parents: ['packageRules'], - mergeable: true, - cli: false, - env: false, - advancedUse: true, - }, { name: 'matchCurrentValue', description: @@ -1585,19 +1433,6 @@ const options: RenovateOptions[] = [ cli: false, env: false, }, - { - name: 'matchSourceUrlPrefixes', - description: - 'A list of source URL prefixes to match against, commonly used to group monorepos or packages from the same organization.', - type: 'array', - subType: 'string', - allowString: true, - stage: 'package', - parents: ['packageRules'], - mergeable: true, - cli: false, - env: false, - }, { name: 'matchSourceUrls', description: 'A list of source URLs to exact match against.', diff --git a/lib/config/options/index.ts.orig b/lib/config/options/index.ts.orig new file mode 100644 index 00000000000000..c5d31011950e73 --- /dev/null +++ b/lib/config/options/index.ts.orig @@ -0,0 +1,2994 @@ +import { getManagers } from '../../modules/manager'; +import { getCustomManagers } from '../../modules/manager/custom'; +import { getPlatformList } from '../../modules/platform'; +import { getVersioningList } from '../../modules/versioning'; +import { supportedDatasources } from '../presets/internal/merge-confidence'; +import type { RenovateOptions } from '../types'; + +const options: RenovateOptions[] = [ + { + name: 'mode', + description: 'Mode of operation.', + type: 'string', + default: 'full', + allowedValues: ['full', 'silent'], + }, + { + name: 'allowedHeaders', + description: + 'List of allowed patterns for header names in repository hostRules config.', + type: 'array', + default: ['X-*'], + subType: 'string', + globalOnly: true, + patternMatch: true, + }, + { + name: 'autodiscoverRepoOrder', + description: + 'The order method for autodiscover server side repository search.', + type: 'string', + default: null, + globalOnly: true, + allowedValues: ['asc', 'desc'], + supportedPlatforms: ['gitea'], + }, + { + name: 'autodiscoverRepoSort', + description: + 'The sort method for autodiscover server side repository search.', + type: 'string', + default: null, + globalOnly: true, + allowedValues: ['alpha', 'created', 'updated', 'size', 'id'], + supportedPlatforms: ['gitea'], + }, + { + name: 'allowedEnv', + description: + 'List of allowed patterns for environment variable names in repository env config.', + type: 'array', + default: [], + subType: 'string', + globalOnly: true, + patternMatch: true, + }, + { + name: 'detectGlobalManagerConfig', + description: + 'If `true`, Renovate tries to detect global manager configuration from the file system.', + type: 'boolean', + default: false, + globalOnly: true, + }, + { + name: 'detectHostRulesFromEnv', + description: + 'If `true`, Renovate tries to detect host rules from environment variables.', + type: 'boolean', + default: false, + globalOnly: true, + }, + { + name: 'mergeConfidenceEndpoint', + description: + 'If set, Renovate will query this API for Merge Confidence data.', + stage: 'global', + type: 'string', + default: 'https://developer.mend.io/', + advancedUse: true, + globalOnly: true, + }, + { + name: 'mergeConfidenceDatasources', + description: + 'If set, Renovate will query the merge-confidence JSON API only for datasources that are part of this list.', + stage: 'global', + allowedValues: supportedDatasources, + default: supportedDatasources, + type: 'array', + subType: 'string', + globalOnly: true, + }, + { + name: 'useCloudMetadataServices', + description: + 'If `false`, Renovate does not try to access cloud metadata services.', + type: 'boolean', + default: true, + globalOnly: true, + }, + { + name: 'userAgent', + description: + 'If set to any string, Renovate will use this as the `user-agent` it sends with HTTP requests.', + type: 'string', + default: null, + globalOnly: true, + }, + { + name: 'allowPostUpgradeCommandTemplating', + description: + 'Set this to `false` to disable template compilation for post-upgrade commands.', + type: 'boolean', + default: true, + globalOnly: true, + }, + { + name: 'allowedPostUpgradeCommands', + description: + 'A list of regular expressions that decide which post-upgrade tasks are allowed.', + type: 'array', + subType: 'string', + default: [], + globalOnly: true, + }, + { + name: 'postUpgradeTasks', + description: + 'Post-upgrade tasks that are executed before a commit is made by Renovate.', + type: 'object', + default: { + commands: [], + fileFilters: [], + executionMode: 'update', + }, + }, + { + name: 'commands', + description: + 'A list of post-upgrade commands that are executed before a commit is made by Renovate.', + type: 'array', + subType: 'string', + parents: ['postUpgradeTasks'], + default: [], + cli: false, + }, + { + name: 'fileFilters', + description: + 'Files that match the glob pattern will be committed after running a post-upgrade task.', + type: 'array', + subType: 'string', + parents: ['postUpgradeTasks'], + default: ['**/*'], + cli: false, + }, + { + name: 'format', + description: 'Format of the custom datasource.', + type: 'string', + parents: ['customDatasources'], + default: 'json', + allowedValues: ['json', 'plain'], + cli: false, + env: false, + }, + { + name: 'executionMode', + description: + 'Controls when the post upgrade tasks run: on every update, or once per upgrade branch.', + type: 'string', + parents: ['postUpgradeTasks'], + allowedValues: ['update', 'branch'], + default: 'update', + cli: false, + }, + { + name: 'onboardingBranch', + description: + 'Change this value to override the default onboarding branch name.', + type: 'string', + default: 'renovate/configure', + globalOnly: true, + inheritConfigSupport: true, + cli: false, + }, + { + name: 'onboardingCommitMessage', + description: + 'Change this value to override the default onboarding commit message.', + type: 'string', + default: null, + globalOnly: true, + inheritConfigSupport: true, + cli: false, + }, + { + name: 'onboardingConfigFileName', + description: + 'Change this value to override the default onboarding config file name.', + type: 'string', + default: 'renovate.json', + globalOnly: true, + inheritConfigSupport: true, + cli: false, + }, + { + name: 'onboardingNoDeps', + description: 'Onboard the repository even if no dependencies are found.', + type: 'string', + default: 'auto', + allowedValues: ['auto', 'enabled', 'disabled'], + globalOnly: true, + inheritConfigSupport: true, + }, + { + name: 'onboardingPrTitle', + description: + 'Change this value to override the default onboarding PR title.', + type: 'string', + default: 'Configure Renovate', + globalOnly: true, + inheritConfigSupport: true, + cli: false, + }, + { + name: 'configMigration', + description: 'Enable this to get config migration PRs when needed.', + stage: 'repository', + type: 'boolean', + default: false, + experimental: true, + experimentalDescription: + 'Config migration PRs are still being improved, in particular to reduce the amount of reordering and whitespace changes.', + experimentalIssues: [16359], + }, + { + name: 'productLinks', + description: 'Links which are used in PRs, issues and comments.', + type: 'object', + globalOnly: true, + mergeable: true, + default: { + documentation: 'https://docs.renovatebot.com/', + help: 'https://github.com/renovatebot/renovate/discussions', + homepage: 'https://github.com/renovatebot/renovate', + }, + additionalProperties: { + type: 'string', + format: 'uri', + }, + }, + { + name: 'secrets', + description: 'Object which holds secret name/value pairs.', + type: 'object', + globalOnly: true, + mergeable: true, + default: {}, + additionalProperties: { + type: 'string', + }, + }, + { + name: 'statusCheckNames', + description: 'Custom strings to use as status check names.', + type: 'object', + mergeable: true, + advancedUse: true, + default: { + artifactError: 'renovate/artifacts', + configValidation: 'renovate/config-validation', + mergeConfidence: 'renovate/merge-confidence', + minimumReleaseAge: 'renovate/stability-days', + }, + }, + { + name: 'extends', + description: 'Configuration presets to use or extend.', + stage: 'package', + type: 'array', + subType: 'string', + allowString: true, + cli: false, + }, + { + name: 'ignorePresets', + description: + 'A list of presets to ignore, including any that are nested inside an `extends` array.', + stage: 'package', + type: 'array', + subType: 'string', + allowString: true, + cli: false, + }, + { + name: 'migratePresets', + description: + 'Define presets here which have been removed or renamed and should be migrated automatically.', + type: 'object', + globalOnly: true, + default: {}, + additionalProperties: { + type: 'string', + }, + }, + { + name: 'presetCachePersistence', + description: 'Cache resolved presets in package cache.', + type: 'boolean', + default: false, + globalOnly: true, + }, + { + name: 'globalExtends', + description: + 'Configuration presets to use or extend for a self-hosted config.', + type: 'array', + subType: 'string', + globalOnly: true, + }, + { + name: 'description', + description: 'Plain text description for a config or preset.', + type: 'array', + subType: 'string', + stage: 'repository', + allowString: true, + mergeable: true, + cli: false, + env: false, + }, + { + name: 'enabled', + description: `Enable or disable Renovate bot.`, + stage: 'package', + type: 'boolean', + default: true, + }, + { + name: 'constraintsFiltering', + description: 'Perform release filtering based on language constraints.', + type: 'string', + allowedValues: ['none', 'strict'], + cli: false, + default: 'none', + }, + { + name: 'repositoryCache', + description: + 'This option decides if Renovate uses a JSON cache to speed up extractions.', + globalOnly: true, + type: 'string', + allowedValues: ['disabled', 'enabled', 'reset'], + stage: 'repository', + default: 'disabled', + }, + { + name: 'repositoryCacheType', + description: + 'Set the type of renovate repository cache if `repositoryCache` is enabled.', + globalOnly: true, + type: 'string', + stage: 'repository', + default: 'local', + }, + { + name: 'reportType', + description: 'Set how, or if, reports should be generated.', + globalOnly: true, + type: 'string', + default: null, + experimental: true, + allowedValues: ['logging', 'file', 's3'], + }, + { + name: 'reportPath', + description: + 'Path to where the file should be written. In case of `s3` this has to be a full S3 URI.', + globalOnly: true, + type: 'string', + default: null, + experimental: true, + }, + { + name: 'force', + description: + 'Any configuration set in this object will force override existing settings.', + stage: 'package', + globalOnly: true, + type: 'object', + cli: false, + mergeable: true, + }, + { + name: 'forceCli', + description: + 'Decides if CLI configuration options are moved to the `force` config section.', + stage: 'global', + type: 'boolean', + default: true, + globalOnly: true, + }, + { + name: 'draftPR', + description: + 'If set to `true` then Renovate creates draft PRs, instead of normal status PRs.', + type: 'boolean', + default: false, + supportedPlatforms: ['azure', 'gitea', 'github', 'gitlab'], + }, + { + name: 'dryRun', + description: + 'If enabled, perform a dry run by logging messages instead of creating/updating/deleting branches and PRs.', + type: 'string', + globalOnly: true, + allowedValues: ['extract', 'lookup', 'full'], + default: null, + }, + { + name: 'printConfig', + description: + 'If enabled, Renovate logs the fully resolved config for each repository, plus the fully resolved presets.', + type: 'boolean', + default: false, + }, + { + name: 'binarySource', + description: + 'Controls how third-party tools like npm or Gradle are called: directly, via Docker sidecar containers, or via dynamic install.', + globalOnly: true, + type: 'string', + allowedValues: ['global', 'docker', 'install', 'hermit'], + default: 'install', + }, + { + name: 'redisUrl', + description: + 'If set, this Redis URL will be used for caching instead of the file system.', + stage: 'global', + type: 'string', + globalOnly: true, + }, + { + name: 'redisPrefix', + description: 'Key prefix for redis cache entries.', + stage: 'global', + type: 'string', + globalOnly: true, + }, + { + name: 'baseDir', + description: + 'The base directory for Renovate to store local files, including repository files and cache. If left empty, Renovate will create its own temporary directory to use.', + stage: 'global', + type: 'string', + globalOnly: true, + }, + { + name: 'cacheDir', + description: + 'The directory where Renovate stores its cache. If left empty, Renovate creates a subdirectory within the `baseDir`.', + globalOnly: true, + type: 'string', + }, + { + name: 'containerbaseDir', + description: + 'The directory where Renovate stores its containerbase cache. If left empty, Renovate creates a subdirectory within the `cacheDir`.', + globalOnly: true, + type: 'string', + }, + { + name: 'customEnvVariables', + description: + 'Custom environment variables for child processes and sidecar Docker containers.', + globalOnly: true, + type: 'object', + default: {}, + }, + { + name: 'env', + description: + 'Environment variables that Renovate uses when executing package manager commands.', + type: 'object', + default: {}, + }, + { + name: 'customDatasources', + description: 'Defines custom datasources for usage by managers.', + type: 'object', + experimental: true, + experimentalIssues: [23286], + default: {}, + mergeable: true, + }, + { + name: 'dockerChildPrefix', + description: + 'Change this value to add a prefix to the Renovate Docker sidecar container names and labels.', + type: 'string', + globalOnly: true, + default: 'renovate_', + }, + { + name: 'dockerCliOptions', + description: + 'Pass CLI flags to `docker run` command when `binarySource=docker`.', + type: 'string', + globalOnly: true, + }, + { + name: 'dockerSidecarImage', + description: + 'Change this value to override the default Renovate sidecar image.', + type: 'string', + default: 'ghcr.io/containerbase/sidecar:10.11.1', + globalOnly: true, + }, + { + name: 'dockerUser', + description: + 'Set the `UID` and `GID` for Docker-based binaries if you use `binarySource=docker`.', + globalOnly: true, + type: 'string', + }, + { + name: 'composerIgnorePlatformReqs', + description: + 'Configure use of `--ignore-platform-reqs` or `--ignore-platform-req` for the Composer package manager.', + type: 'array', + subType: 'string', + default: [], + }, + { + name: 'goGetDirs', + description: 'Directory pattern to run `go get` on.', + type: 'array', + subType: 'string', + default: ['./...'], + supportedManagers: ['gomod'], + }, + // Log options + { + name: 'logFile', + description: 'Log file path.', + stage: 'global', + type: 'string', + globalOnly: true, + deprecationMsg: + 'Instead of configuring log file path in the file config. Use the `LOG_FILE` environment variable instead.', + }, + { + name: 'logFileLevel', + description: 'Set the log file log level.', + stage: 'global', + type: 'string', + default: 'debug', + globalOnly: true, + deprecationMsg: + 'Instead of configuring log file level in the file config. Use the `LOG_FILE_LEVEL` environment variable instead.', + }, + { + name: 'logContext', + description: 'Add a global or per-repo log context to each log entry.', + globalOnly: true, + type: 'string', + default: null, + stage: 'global', + }, + // Onboarding + { + name: 'onboarding', + description: 'Require a Configuration PR first.', + stage: 'repository', + type: 'boolean', + globalOnly: true, + inheritConfigSupport: true, + }, + { + name: 'onboardingConfig', + description: 'Configuration to use for onboarding PRs.', + stage: 'repository', + type: 'object', + default: { $schema: 'https://docs.renovatebot.com/renovate-schema.json' }, + globalOnly: true, + inheritConfigSupport: true, + mergeable: true, + }, + { + name: 'onboardingRebaseCheckbox', + description: + 'Set to enable rebase/retry markdown checkbox for onboarding PRs.', + type: 'boolean', + default: false, + supportedPlatforms: ['gitea', 'github', 'gitlab'], + globalOnly: true, + experimental: true, + experimentalIssues: [17633], + }, + { + name: 'forkProcessing', + description: + 'Whether to process forked repositories. By default, all forked repositories are skipped when in `autodiscover` mode.', + stage: 'repository', + type: 'string', + allowedValues: ['auto', 'enabled', 'disabled'], + default: 'auto', + }, + { + name: 'includeMirrors', + description: + 'Whether to process repositories that are mirrors. By default, repositories that are mirrors are skipped.', + type: 'boolean', + default: false, + supportedPlatforms: ['gitlab'], + globalOnly: true, + }, + { + name: 'forkCreation', + description: + 'Whether to create forks as needed at runtime when running in "fork mode".', + stage: 'repository', + type: 'boolean', + globalOnly: true, + supportedPlatforms: ['github'], + experimental: true, + default: true, + }, + { + name: 'forkToken', + description: 'Set a personal access token here to enable "fork mode".', + stage: 'repository', + type: 'string', + globalOnly: true, + supportedPlatforms: ['github'], + experimental: true, + }, + { + name: 'forkOrg', + description: + 'The preferred organization to create or find forked repositories, when in fork mode.', + stage: 'repository', + type: 'string', + globalOnly: true, + supportedPlatforms: ['github'], + experimental: true, + }, + { + name: 'githubTokenWarn', + description: 'Display warnings about GitHub token not being set.', + type: 'boolean', + default: true, + globalOnly: true, + }, + { + name: 'encryptedWarning', + description: 'Warning text to use if encrypted config is found.', + type: 'string', + globalOnly: true, + advancedUse: true, + }, + { + name: 'inheritConfig', + description: + 'If `true`, Renovate will inherit configuration from the `inheritConfigFileName` file in `inheritConfigRepoName`.', + type: 'boolean', + default: false, + globalOnly: true, + }, + { + name: 'inheritConfigRepoName', + description: + 'Renovate will look in this repo for the `inheritConfigFileName`.', + type: 'string', + default: '{{parentOrg}}/renovate-config', + globalOnly: true, + }, + { + name: 'inheritConfigFileName', + description: + 'Renovate will look for this config file name in the `inheritConfigRepoName`.', + type: 'string', + default: 'org-inherited-config.json', + globalOnly: true, + }, + { + name: 'inheritConfigStrict', + description: + 'If `true`, any `inheritedConfig` fetch error will result in an aborted run.', + type: 'boolean', + default: false, + globalOnly: true, + }, + { + name: 'requireConfig', + description: + "Controls Renovate's behavior regarding repository config files such as `renovate.json`.", + stage: 'repository', + type: 'string', + default: 'required', + allowedValues: ['required', 'optional', 'ignored'], + globalOnly: true, + inheritConfigSupport: true, + }, + { + name: 'optimizeForDisabled', + description: + 'Set to `true` to perform a check for disabled config prior to cloning.', + stage: 'repository', + type: 'boolean', + default: false, + globalOnly: true, + }, + // Dependency Dashboard + { + name: 'dependencyDashboard', + description: + 'Whether to create a "Dependency Dashboard" issue in the repository.', + type: 'boolean', + default: false, + }, + { + name: 'dependencyDashboardApproval', + description: + 'Controls if updates need manual approval from the Dependency Dashboard issue before PRs are created.', + type: 'boolean', + default: false, + }, + { + name: 'dependencyDashboardAutoclose', + description: + 'Set to `true` to let Renovate close the Dependency Dashboard issue if there are no more updates.', + type: 'boolean', + default: false, + }, + { + name: 'dependencyDashboardTitle', + description: 'Title for the Dependency Dashboard issue.', + type: 'string', + default: `Dependency Dashboard`, + }, + { + name: 'dependencyDashboardHeader', + description: + 'Any text added here will be placed first in the Dependency Dashboard issue body.', + type: 'string', + default: + 'This issue lists Renovate updates and detected dependencies. Read the [Dependency Dashboard](https://docs.renovatebot.com/key-concepts/dashboard/) docs to learn more.', + }, + { + name: 'dependencyDashboardFooter', + description: + 'Any text added here will be placed last in the Dependency Dashboard issue body, with a divider separator before it.', + type: 'string', + }, + { + name: 'dependencyDashboardLabels', + description: + 'These labels will always be applied on the Dependency Dashboard issue, even when they have been removed manually.', + type: 'array', + subType: 'string', + default: null, + }, + { + name: 'dependencyDashboardOSVVulnerabilitySummary', + description: + 'Control if the Dependency Dashboard issue lists CVEs supplied by [osv.dev](https://osv.dev).', + type: 'string', + allowedValues: ['none', 'all', 'unresolved'], + default: 'none', + experimental: true, + }, + { + name: 'configWarningReuseIssue', + description: + 'Set this to `false` to make Renovate create a new issue for each config warning, instead of reopening or reusing an existing issue.', + type: 'boolean', + default: true, + }, + + // encryption + { + name: 'privateKey', + description: 'Server-side private key.', + stage: 'repository', + type: 'string', + replaceLineReturns: true, + globalOnly: true, + }, + { + name: 'privateKeyOld', + description: 'Secondary or old private key to try.', + stage: 'repository', + type: 'string', + replaceLineReturns: true, + globalOnly: true, + }, + { + name: 'privateKeyPath', + description: 'Path to the Server-side private key.', + stage: 'repository', + type: 'string', + globalOnly: true, + }, + { + name: 'privateKeyPathOld', + description: 'Path to the Server-side old private key.', + stage: 'repository', + type: 'string', + globalOnly: true, + }, + { + name: 'encrypted', + description: + 'An object containing configuration encrypted with project key.', + stage: 'repository', + type: 'object', + default: null, + }, + // Scheduling + { + name: 'timezone', + description: + 'Must conform to [IANA Time Zone](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) format.', + type: 'string', + }, + { + name: 'schedule', + description: 'Limit branch creation to these times of day or week.', + type: 'array', + subType: 'string', + allowString: true, + cli: true, + env: false, + default: ['at any time'], + }, + { + name: 'automergeSchedule', + description: 'Limit automerge to these times of day or week.', + type: 'array', + subType: 'string', + allowString: true, + cli: true, + env: false, + default: ['at any time'], + }, + { + name: 'updateNotScheduled', + description: + 'Whether to update branches when not scheduled. Renovate will not create branches outside of the schedule.', + stage: 'branch', + type: 'boolean', + default: true, + }, + // Bot administration + { + name: 'persistRepoData', + description: + 'If set to `true`: keep repository data between runs instead of deleting the data.', + type: 'boolean', + default: false, + globalOnly: true, + }, + { + name: 'exposeAllEnv', + description: + 'Set this to `true` to allow passing of all environment variables to package managers.', + globalOnly: true, + type: 'boolean', + default: false, + }, + { + name: 'allowPlugins', + description: + 'Set this to `true` if repositories are allowed to run install plugins.', + globalOnly: true, + type: 'boolean', + default: false, + }, + { + name: 'allowScripts', + description: + 'Set this to `true` if repositories are allowed to run install scripts.', + globalOnly: true, + type: 'boolean', + default: false, + }, + { + name: 'allowCustomCrateRegistries', + description: 'Set this to `true` to allow custom crate registries.', + globalOnly: true, + type: 'boolean', + default: false, + }, + { + name: 'ignorePlugins', + description: + 'Set this to `true` if `allowPlugins=true` but you wish to skip running plugins when updating lock files.', + type: 'boolean', + default: false, + }, + { + name: 'ignoreScripts', + description: + 'Set this to `false` if `allowScripts=true` and you wish to run scripts when updating lock files.', + type: 'boolean', + default: true, + supportedManagers: ['npm', 'composer'], + }, + { + name: 'platform', + description: 'Platform type of repository.', + type: 'string', + allowedValues: getPlatformList(), + default: 'github', + globalOnly: true, + }, + { + name: 'endpoint', + description: 'Custom endpoint to use.', + type: 'string', + globalOnly: true, + default: null, + }, + { + name: 'token', + description: 'Repository Auth Token.', + stage: 'repository', + type: 'string', + globalOnly: true, + }, + { + name: 'username', + description: 'Username for authentication.', + stage: 'repository', + type: 'string', + supportedPlatforms: ['azure', 'bitbucket', 'bitbucket-server'], + globalOnly: true, + }, + { + name: 'password', + description: 'Password for authentication.', + stage: 'repository', + type: 'string', + supportedPlatforms: ['azure', 'bitbucket', 'bitbucket-server'], + globalOnly: true, + }, + { + name: 'npmrc', + description: + 'String copy of `.npmrc` file. Use `\\n` instead of line breaks.', + stage: 'branch', + type: 'string', + }, + { + name: 'npmrcMerge', + description: + 'Whether to merge `config.npmrc` with repo `.npmrc` content if both are found.', + stage: 'branch', + type: 'boolean', + default: false, + }, + { + name: 'npmToken', + description: 'npm token used to authenticate with the default registry.', + stage: 'branch', + type: 'string', + }, + { + name: 'updateLockFiles', + description: 'Set to `false` to disable lock file updating.', + type: 'boolean', + default: true, + supportedManagers: ['npm'], + }, + { + name: 'skipInstalls', + description: + 'Skip installing modules/dependencies if lock file updating is possible without a full install.', + type: 'boolean', + default: null, + }, + { + name: 'autodiscover', + description: 'Autodiscover all repositories.', + stage: 'global', + type: 'boolean', + default: false, + globalOnly: true, + }, + { + name: 'autodiscoverFilter', + description: 'Filter the list of autodiscovered repositories.', + stage: 'global', + type: 'array', + subType: 'string', + allowString: true, + default: null, + globalOnly: true, + }, + { + name: 'autodiscoverNamespaces', + description: + 'Filter the list of autodiscovered repositories by namespaces.', + stage: 'global', + type: 'array', + subType: 'string', + default: null, + globalOnly: true, + supportedPlatforms: ['gitea', 'gitlab'], + }, + { + name: 'autodiscoverProjects', + description: + 'Filter the list of autodiscovered repositories by project names.', + stage: 'global', + type: 'array', + subType: 'string', + default: null, + globalOnly: true, + supportedPlatforms: ['bitbucket'], + patternMatch: true, + }, + { + name: 'autodiscoverTopics', + description: 'Filter the list of autodiscovered repositories by topics.', + stage: 'global', + type: 'array', + subType: 'string', + default: null, + globalOnly: true, + supportedPlatforms: ['gitea', 'github', 'gitlab'], + }, + { + name: 'prCommitsPerRunLimit', + description: + 'Set the maximum number of commits per Renovate run. By default there is no limit.', + stage: 'global', + type: 'integer', + default: 0, + globalOnly: true, + }, + { + name: 'repositories', + description: 'List of Repositories.', + stage: 'global', + type: 'array', + subType: 'string', + cli: false, + globalOnly: true, + }, + { + name: 'baseBranches', + description: + 'List of one or more custom base branches defined as exact strings and/or via regex expressions.', + type: 'array', + subType: 'string', + stage: 'package', + cli: false, + }, + { + name: 'useBaseBranchConfig', + description: + 'Whether to read configuration from `baseBranches` instead of only the default branch.', + type: 'string', + allowedValues: ['merge', 'none'], + default: 'none', + }, + { + name: 'gitAuthor', + description: + 'Author to use for Git commits. Must conform to [RFC5322](https://datatracker.ietf.org/doc/html/rfc5322).', + type: 'string', + }, + { + name: 'gitPrivateKey', + description: 'PGP key to use for signing Git commits.', + type: 'string', + cli: false, + globalOnly: true, + stage: 'global', + }, + { + name: 'gitIgnoredAuthors', + description: + 'Git authors which are ignored by Renovate. Must conform to [RFC5322](https://datatracker.ietf.org/doc/html/rfc5322).', + type: 'array', + subType: 'string', + stage: 'repository', + }, + { + name: 'gitTimeout', + description: + 'Configure the timeout with a number of milliseconds to wait for a Git task.', + type: 'integer', + globalOnly: true, + default: 0, + }, + { + name: 'enabledManagers', + description: + 'A list of package managers to enable. Only managers on the list are enabled.', + type: 'array', + subType: 'string', + mergeable: false, + stage: 'repository', + }, + { + name: 'includePaths', + description: 'Include package files only within these defined paths.', + type: 'array', + subType: 'string', + stage: 'repository', + default: [], + }, + { + name: 'ignorePaths', + description: + 'Skip any package file whose path matches one of these. Can be a string or glob pattern.', + type: 'array', + mergeable: false, + subType: 'string', + stage: 'repository', + default: ['**/node_modules/**', '**/bower_components/**'], + }, + { + name: 'excludeCommitPaths', + description: + 'A file matching any of these glob patterns will not be committed, even if the file has been updated.', + type: 'array', + subType: 'string', + default: [], + advancedUse: true, + }, + { + name: 'executionTimeout', + description: + 'Default execution timeout in minutes for child processes Renovate creates.', + type: 'integer', + default: 15, + globalOnly: true, + }, + { + name: 'registryAliases', + description: 'Aliases for registries.', + mergeable: true, + type: 'object', + default: {}, + additionalProperties: { + type: 'string', + }, + supportedManagers: [ + 'ansible', + 'bitbucket-pipelines', + 'crossplane', + 'devcontainer', + 'docker-compose', + 'dockerfile', + 'droneci', + 'gitlabci', + 'helm-requirements', + 'helmfile', + 'helmv3', + 'kubernetes', + 'kustomize', + 'terraform', + 'vendir', + 'woodpecker', + ], + }, + { + name: 'defaultRegistryUrls', + description: + 'List of registry URLs to use as the default for a datasource.', + type: 'array', + subType: 'string', + default: null, + stage: 'branch', + cli: false, + env: false, + }, + { + name: 'defaultRegistryUrlTemplate', + description: + 'Template for generating a `defaultRegistryUrl` for custom datasource.', + type: 'string', + default: '', + parents: ['customDatasources'], + cli: false, + env: false, + }, + { + name: 'registryUrls', + description: + 'List of URLs to try for dependency lookup. Package manager specific.', + type: 'array', + subType: 'string', + default: null, + stage: 'branch', + cli: false, + env: false, + }, + { + name: 'extractVersion', + description: + "A regex (`re2`) to extract a version from a datasource's raw version string.", + type: 'string', + format: 'regex', + cli: false, + env: false, + }, + { + name: 'versionCompatibility', + description: + 'A regex (`re2`) with named capture groups to show how version and compatibility are split from a raw version string.', + type: 'string', + format: 'regex', + cli: false, + env: false, + }, + { + name: 'versioning', + description: 'Versioning to use for filtering and comparisons.', + type: 'string', + allowedValues: getVersioningList(), + cli: false, + env: false, + }, + { + name: 'azureWorkItemId', + description: + 'The id of an existing work item on Azure Boards to link to each PR.', + type: 'integer', + default: 0, + supportedPlatforms: ['azure'], + }, + { + name: 'autoApprove', + description: 'Set to `true` to automatically approve PRs.', + type: 'boolean', + default: false, + supportedPlatforms: ['azure', 'gerrit', 'gitlab'], + }, + // depType + { + name: 'ignoreDeps', + description: 'Dependencies to ignore.', + type: 'array', + subType: 'string', + stage: 'package', + mergeable: true, + }, + { + name: 'updateInternalDeps', + description: + 'Whether to update internal dep versions in a monorepo. Works on Yarn Workspaces.', + type: 'boolean', + default: false, + stage: 'package', + }, + { + name: 'packageRules', + description: 'Rules for matching packages.', + type: 'array', + stage: 'package', + mergeable: true, + }, + { + name: 'matchCurrentAge', + description: + 'Matches the current age of the package derived from its release timestamp. Valid only within a `packageRules` object.', + type: 'string', + parents: ['packageRules'], + stage: 'package', + mergeable: true, + cli: false, + env: false, + }, + { + name: 'matchCategories', + description: + 'List of categories to match (for example: `["python"]`). Valid only within a `packageRules` object.', + type: 'array', + subType: 'string', + allowString: true, + parents: ['packageRules'], + stage: 'package', + mergeable: true, + cli: false, + env: false, + }, + { + name: 'matchRepositories', + description: + 'List of repositories to match (e.g. `["**/*-archived"]`). Valid only within a `packageRules` object.', + type: 'array', + subType: 'string', + allowString: true, + stage: 'package', + parents: ['packageRules'], + mergeable: true, + cli: false, + env: false, + patternMatch: true, + }, + { + name: 'matchBaseBranches', + description: + 'List of strings containing exact matches (e.g. `["main"]`) and/or regex expressions (e.g. `["/^release/.*/"]`). Valid only within a `packageRules` object.', + type: 'array', + subType: 'string', + allowString: true, + parents: ['packageRules'], + stage: 'package', + mergeable: true, + cli: false, + env: false, + }, + { + name: 'matchManagers', + description: + 'List of package managers to match (e.g. `["pipenv"]`). Valid only within a `packageRules` object.', + type: 'array', + subType: 'string', + allowString: true, + parents: ['packageRules'], + stage: 'package', + mergeable: true, + cli: false, + env: false, + }, + { + name: 'matchDatasources', + description: + 'List of datasources to match (e.g. `["orb"]`). Valid only within a `packageRules` object.', + type: 'array', + subType: 'string', + allowString: true, + parents: ['packageRules'], + stage: 'package', + mergeable: true, + cli: false, + env: false, + }, + { + name: 'matchDepTypes', + description: + 'List of depTypes to match (e.g. [`peerDependencies`]). Valid only within `packageRules` object.', + type: 'array', + subType: 'string', + allowString: true, + parents: ['packageRules'], + stage: 'package', + mergeable: true, + cli: false, + env: false, + }, + { + name: 'matchPackageNames', + description: + 'Package names to match. Valid only within a `packageRules` object.', + type: 'array', + subType: 'string', + allowString: true, + stage: 'package', + parents: ['packageRules'], + mergeable: true, + cli: false, + env: false, + }, + { + name: 'matchDepNames', + description: + 'Dep names to match. Valid only within a `packageRules` object.', + type: 'array', + subType: 'string', + allowString: true, + stage: 'package', + parents: ['packageRules'], + mergeable: true, + cli: false, + env: false, + }, + { + name: 'matchCurrentValue', + description: + 'A regex or glob pattern to match against the raw `currentValue` string of a dependency. Valid only within a `packageRules` object.', + type: 'string', + stage: 'package', + parents: ['packageRules'], + mergeable: true, + cli: false, + env: false, + }, + { + name: 'matchCurrentVersion', + description: + 'A version, or range of versions, to match against the current version of a package. Valid only within a `packageRules` object.', + type: 'string', + stage: 'package', + parents: ['packageRules'], + mergeable: true, + cli: false, + env: false, + }, + { + name: 'matchNewValue', + description: + 'A regex or glob pattern to match against the raw `newValue` string of a dependency. Valid only within a `packageRules` object.', + type: 'string', + stage: 'package', + parents: ['packageRules'], + mergeable: true, + cli: false, + env: false, + }, + { +<<<<<<< HEAD + name: 'sourceUrl', + description: 'The source URL of the package.', + type: 'string', + parents: ['packageRules'], + cli: false, + env: false, + }, + { + name: 'sourceDirectory', + description: + 'The source directory in which the package is present at its source.', + type: 'string', + parents: ['packageRules'], + cli: false, + env: false, + }, + { + name: 'matchSourceUrlPrefixes', + description: + 'A list of source URL prefixes to match against, commonly used to group monorepos or packages from the same organization.', + type: 'array', + subType: 'string', + allowString: true, + stage: 'package', + parents: ['packageRules'], + mergeable: true, + cli: false, + env: false, + }, + { +======= +>>>>>>> b66597a89 (feat(packageRules): migrate matchers and excludes (#28602)) + name: 'matchSourceUrls', + description: 'A list of source URLs to exact match against.', + type: 'array', + subType: 'string', + allowString: true, + stage: 'package', + parents: ['packageRules'], + mergeable: true, + cli: false, + env: false, + }, + { + name: 'autoReplaceGlobalMatch', + description: + 'Control whether replacement regular expressions are global matches or only the first match.', + type: 'boolean', + default: true, + }, + { + name: 'replacementName', + description: + 'The name of the new dependency that replaces the old deprecated dependency.', + type: 'string', + stage: 'package', + parents: ['packageRules'], + cli: false, + env: false, + }, + { + name: 'replacementNameTemplate', + description: 'Controls what the replacement package name.', + type: 'string', + default: '{{{packageName}}}', + stage: 'package', + parents: ['packageRules'], + cli: false, + env: false, + }, + { + name: 'replacementVersion', + description: + 'The version of the new dependency that replaces the old deprecated dependency.', + type: 'string', + stage: 'package', + parents: ['packageRules'], + cli: false, + env: false, + }, + { + name: 'matchConfidence', + description: + 'Merge confidence levels to match against (`low`, `neutral`, `high`, `very high`). Valid only within `packageRules` object.', + type: 'array', + subType: 'string', + allowedValues: ['low', 'neutral', 'high', 'very high'], + allowString: true, + stage: 'package', + parents: ['packageRules'], + mergeable: true, + cli: false, + env: false, + }, + { + name: 'matchUpdateTypes', + description: + 'Update types to match against (`major`, `minor`, `pin`, `pinDigest`, etc). Valid only within `packageRules` object.', + type: 'array', + subType: 'string', + allowedValues: [ + 'major', + 'minor', + 'patch', + 'pin', + 'pinDigest', + 'digest', + 'lockFileMaintenance', + 'rollback', + 'bump', + 'replacement', + ], + allowString: true, + stage: 'package', + parents: ['packageRules'], + mergeable: true, + cli: false, + env: false, + }, + { + name: 'matchFileNames', + description: + 'List of strings to do an exact match against package and lock files with full path. Only works inside a `packageRules` object.', + type: 'array', + subType: 'string', + stage: 'repository', + parents: ['packageRules'], + cli: false, + env: false, + }, + // Version behavior + { + name: 'allowedVersions', + description: + 'A version range or regex pattern capturing allowed versions for dependencies.', + type: 'string', + parents: ['packageRules'], + stage: 'package', + cli: false, + env: false, + }, + { + name: 'changelogUrl', + description: + 'If set, Renovate will use this URL to fetch changelogs for a matched dependency. Valid only within a `packageRules` object.', + type: 'string', + stage: 'pr', + parents: ['packageRules'], + cli: false, + env: false, + }, + { + name: 'pinDigests', + description: 'Whether to add digests to Dockerfile source images.', + type: 'boolean', + default: false, + }, + { + name: 'separateMajorMinor', + description: + 'If set to `false`, Renovate will upgrade dependencies to their latest release only. Renovate will not separate major or minor branches.', + type: 'boolean', + default: true, + }, + { + name: 'separateMultipleMajor', + description: + 'If set to `true`, PRs will be raised separately for each available `major` upgrade version.', + stage: 'package', + type: 'boolean', + default: false, + }, + { + name: 'separateMultipleMinor', + description: + 'If set to `true`, Renovate creates separate PRs for each `minor` stream.', + stage: 'package', + type: 'boolean', + default: false, + experimental: true, + }, + { + name: 'separateMinorPatch', + description: + 'If set to `true`, Renovate will separate `minor` and `patch` updates into separate branches.', + type: 'boolean', + default: false, + }, + { + name: 'ignoreUnstable', + description: 'Ignore versions with unstable SemVer.', + stage: 'package', + type: 'boolean', + default: true, + }, + { + name: 'ignoreDeprecated', + description: + 'Avoid upgrading from a non-deprecated version to a deprecated one.', + stage: 'package', + type: 'boolean', + default: true, + }, + { + name: 'followTag', + description: 'If defined, packages will follow this release tag exactly.', + stage: 'package', + type: 'string', + cli: false, + env: false, + advancedUse: true, + }, + { + name: 'respectLatest', + description: 'Ignore versions newer than npm "latest" version.', + stage: 'package', + type: 'boolean', + default: true, + }, + { + name: 'rangeStrategy', + description: 'Determines how to modify or update existing ranges.', + type: 'string', + default: 'auto', + allowedValues: [ + 'auto', + 'pin', + 'bump', + 'replace', + 'widen', + 'update-lockfile', + 'in-range-only', + ], + cli: false, + env: false, + }, + { + name: 'branchPrefix', + description: 'Prefix to use for all branch names.', + stage: 'branch', + type: 'string', + default: `renovate/`, + }, + { + name: 'branchPrefixOld', + description: 'Old branchPrefix value to check for existing PRs.', + stage: 'branch', + type: 'string', + default: `renovate/`, + }, + { + name: 'bumpVersion', + description: 'Bump the version in the package file being updated.', + type: 'string', + allowedValues: ['major', 'minor', 'patch', 'prerelease'], + supportedManagers: ['helmv3', 'npm', 'nuget', 'maven', 'sbt'], + }, + // Major/Minor/Patch + { + name: 'major', + description: 'Configuration to apply when an update type is `major`.', + stage: 'package', + type: 'object', + default: {}, + cli: false, + mergeable: true, + }, + { + name: 'minor', + description: 'Configuration to apply when an update type is `minor`.', + stage: 'package', + type: 'object', + default: {}, + cli: false, + mergeable: true, + }, + { + name: 'patch', + description: 'Configuration to apply when an update type is `patch`.', + stage: 'package', + type: 'object', + default: {}, + cli: false, + mergeable: true, + }, + { + name: 'pin', + description: 'Configuration to apply when an update type is `pin`.', + stage: 'package', + type: 'object', + default: { + rebaseWhen: 'behind-base-branch', + groupName: 'Pin Dependencies', + groupSlug: 'pin-dependencies', + commitMessageAction: 'Pin', + group: { + commitMessageTopic: 'dependencies', + commitMessageExtra: '', + }, + }, + cli: false, + mergeable: true, + }, + { + name: 'digest', + description: + 'Configuration to apply when updating a digest (no change in tag/version).', + stage: 'package', + type: 'object', + default: { + branchTopic: '{{{depNameSanitized}}}-digest', + commitMessageExtra: 'to {{newDigestShort}}', + commitMessageTopic: '{{{depName}}} digest', + }, + cli: false, + mergeable: true, + }, + { + name: 'pinDigest', + description: + 'Configuration to apply when pinning a digest (no change in tag/version).', + stage: 'package', + type: 'object', + default: { + groupName: 'Pin Dependencies', + groupSlug: 'pin-dependencies', + commitMessageAction: 'Pin', + group: { + commitMessageTopic: 'dependencies', + commitMessageExtra: '', + }, + }, + cli: false, + mergeable: true, + }, + { + name: 'rollback', + description: 'Configuration to apply when rolling back a version.', + stage: 'package', + type: 'object', + default: { + branchTopic: '{{{depNameSanitized}}}-rollback', + commitMessageAction: 'Roll back', + semanticCommitType: 'fix', + }, + cli: false, + mergeable: true, + }, + { + name: 'replacement', + description: 'Configuration to apply when replacing a dependency.', + stage: 'package', + type: 'object', + default: { + branchTopic: '{{{depNameSanitized}}}-replacement', + commitMessageAction: 'Replace', + commitMessageExtra: + 'with {{newName}} {{#if isMajor}}{{{prettyNewMajor}}}{{else}}{{#if isSingleVersion}}{{{prettyNewVersion}}}{{else}}{{{newValue}}}{{/if}}{{/if}}', + prBodyNotes: [ + 'This is a special PR that replaces `{{{depName}}}` with the community suggested minimal stable replacement version.', + ], + }, + cli: false, + mergeable: true, + }, + // Semantic commit / Semantic release + { + name: 'semanticCommits', + description: 'Enable Semantic Commit prefixes for commits and PR titles.', + type: 'string', + allowedValues: ['auto', 'enabled', 'disabled'], + default: 'auto', + }, + { + name: 'semanticCommitType', + description: 'Commit type to use if Semantic Commits is enabled.', + type: 'string', + default: 'chore', + }, + { + name: 'semanticCommitScope', + description: 'Commit scope to use if Semantic Commits are enabled.', + type: 'string', + default: 'deps', + }, + { + name: 'commitMessageLowerCase', + description: 'Lowercase PR- and commit titles.', + type: 'string', + allowedValues: ['auto', 'never'], + default: 'auto', + }, + // PR Behavior + { + name: 'keepUpdatedLabel', + description: + 'If set, users can add this label to PRs to request they be kept updated with the base branch.', + type: 'string', + supportedPlatforms: ['azure', 'gitea', 'github', 'gitlab'], + }, + { + name: 'rollbackPrs', + description: + 'Create PRs to roll back versions if the current version is not found in the registry.', + type: 'boolean', + default: false, + }, + { + name: 'recreateWhen', + description: 'Recreate PRs even if same ones were closed previously.', + type: 'string', + default: 'auto', + allowedValues: ['auto', 'always', 'never'], + }, + { + name: 'rebaseWhen', + description: 'Controls when Renovate rebases an existing branch.', + type: 'string', + allowedValues: ['auto', 'never', 'conflicted', 'behind-base-branch'], + default: 'auto', + }, + { + name: 'rebaseLabel', + description: 'Label to request a rebase from Renovate bot.', + type: 'string', + default: 'rebase', + }, + { + name: 'stopUpdatingLabel', + description: 'Label to make Renovate stop updating a PR.', + type: 'string', + default: 'stop-updating', + supportedPlatforms: ['azure', 'gitea', 'github', 'gitlab'], + }, + { + name: 'minimumReleaseAge', + description: 'Time required before a new release is considered stable.', + type: 'string', + default: null, + }, + { + name: 'internalChecksAsSuccess', + description: + 'Whether to consider passing internal checks such as `minimumReleaseAge` when determining branch status.', + type: 'boolean', + default: false, + }, + /* + * Undocumented experimental feature + { + name: 'minimumConfidence', + description: + 'Minimum Merge confidence level to filter by. Requires authentication to work.', + type: 'string', + allowedValues: ['low', 'neutral', 'high', 'very high'], + default: 'low', + }, + */ + { + name: 'internalChecksFilter', + description: 'When and how to filter based on internal checks.', + type: 'string', + allowedValues: ['strict', 'flexible', 'none'], + default: 'strict', + }, + { + name: 'prCreation', + description: 'When to create the PR for a branch.', + type: 'string', + allowedValues: ['immediate', 'not-pending', 'status-success', 'approval'], + default: 'immediate', + }, + { + name: 'prNotPendingHours', + description: 'Timeout in hours for when `prCreation=not-pending`.', + type: 'integer', + default: 25, + }, + { + name: 'prHourlyLimit', + description: + 'Rate limit PRs to maximum x created per hour. 0 means no limit.', + type: 'integer', + default: 2, + }, + { + name: 'prConcurrentLimit', + description: + 'Limit to a maximum of x concurrent branches/PRs. 0 means no limit.', + type: 'integer', + default: 10, + }, + { + name: 'branchConcurrentLimit', + description: + 'Limit to a maximum of x concurrent branches. 0 means no limit, `null` (default) inherits value from `prConcurrentLimit`.', + type: 'integer', + default: null, // inherit prConcurrentLimit + }, + { + name: 'prPriority', + description: + 'Set sorting priority for PR creation. PRs with higher priority are created first, negative priority last.', + type: 'integer', + allowNegative: true, + default: 0, + parents: ['packageRules'], + cli: false, + env: false, + }, + { + name: 'bbUseDefaultReviewers', + description: 'Use the default reviewers (Bitbucket only).', + type: 'boolean', + default: true, + supportedPlatforms: ['bitbucket', 'bitbucket-server'], + }, + { + name: 'bbUseDevelopmentBranch', + description: `Use the repository's [development branch](https://support.atlassian.com/bitbucket-cloud/docs/branch-a-repository/#The-branching-model) as the repository's default branch.`, + type: 'boolean', + default: false, + supportedPlatforms: ['bitbucket'], + globalOnly: true, + inheritConfigSupport: true, + }, + // Automatic merging + { + name: 'automerge', + description: + 'Whether to automerge branches/PRs automatically, without human intervention.', + type: 'boolean', + default: false, + }, + { + name: 'automergeType', + description: 'How to automerge, if enabled.', + type: 'string', + allowedValues: ['branch', 'pr', 'pr-comment'], + default: 'pr', + }, + { + name: 'automergeStrategy', + description: + 'The merge strategy to use when automerging PRs. Used only if `automergeType=pr`.', + type: 'string', + allowedValues: ['auto', 'fast-forward', 'merge-commit', 'rebase', 'squash'], + default: 'auto', + supportedPlatforms: ['azure', 'bitbucket', 'gitea'], + }, + { + name: 'automergeComment', + description: + 'PR comment to add to trigger automerge. Only used if `automergeType=pr-comment`.', + type: 'string', + default: 'automergeComment', + }, + { + name: 'ignoreTests', + description: 'Set to `true` to enable automerging without tests.', + type: 'boolean', + default: false, + }, + { + name: 'transformTemplates', + description: 'List of jsonata transformation rules.', + type: 'array', + subType: 'string', + parents: ['customDatasources'], + default: [], + }, + { + name: 'vulnerabilityAlerts', + description: + 'Config to apply when a PR is needed due to a vulnerability in the existing package version.', + type: 'object', + default: { + groupName: null, + schedule: [], + dependencyDashboardApproval: false, + minimumReleaseAge: null, + rangeStrategy: 'update-lockfile', + commitMessageSuffix: '[SECURITY]', + branchTopic: `{{{datasource}}}-{{{depNameSanitized}}}-vulnerability`, + prCreation: 'immediate', + }, + mergeable: true, + cli: false, + env: false, + supportedPlatforms: ['github'], + }, + { + name: 'osvVulnerabilityAlerts', + description: 'Use vulnerability alerts from `osv.dev`.', + type: 'boolean', + default: false, + experimental: true, + experimentalIssues: [20542], + }, + { + name: 'pruneBranchAfterAutomerge', + description: 'Set to `true` to enable branch pruning after automerging.', + type: 'boolean', + default: true, + }, + // Default templates + { + name: 'branchName', + description: 'Branch name template.', + type: 'string', + default: '{{{branchPrefix}}}{{{additionalBranchPrefix}}}{{{branchTopic}}}', + deprecationMsg: + 'We strongly recommended that you avoid configuring this field directly. Please edit `branchPrefix`, `additionalBranchPrefix`, or `branchTopic` instead.', + cli: false, + }, + { + name: 'additionalBranchPrefix', + description: 'Additional string value to be appended to `branchPrefix`.', + type: 'string', + default: '', + cli: false, + }, + { + name: 'branchTopic', + description: 'Branch topic.', + type: 'string', + default: + '{{{depNameSanitized}}}-{{{newMajor}}}{{#if separateMinorPatch}}{{#if isPatch}}.{{{newMinor}}}{{/if}}{{/if}}.x{{#if isLockfileUpdate}}-lockfile{{/if}}', + cli: false, + }, + { + name: 'commitMessage', + description: 'Message to use for commit messages and pull request titles.', + type: 'string', + default: + '{{{commitMessagePrefix}}} {{{commitMessageAction}}} {{{commitMessageTopic}}} {{{commitMessageExtra}}} {{{commitMessageSuffix}}}', + deprecationMsg: + 'We deprecated editing the `commitMessage` directly, and we recommend you stop using this config option. Instead use config options like `commitMessageAction`, `commitMessageExtra`, and so on, to create the commit message you want.', + cli: false, + }, + { + name: 'commitBody', + description: + 'Commit message body template. Will be appended to commit message, separated by two line returns.', + type: 'string', + cli: false, + }, + { + name: 'commitBodyTable', + description: + 'If enabled, append a table in the commit message body describing all updates in the commit.', + type: 'boolean', + default: false, + }, + { + name: 'commitMessagePrefix', + description: + 'Prefix to add to start of commit messages and PR titles. Uses a semantic prefix if `semanticCommits` is enabled.', + type: 'string', + cli: false, + advancedUse: true, + }, + { + name: 'commitMessageAction', + description: 'Action verb to use in commit messages and PR titles.', + type: 'string', + default: 'Update', + cli: false, + advancedUse: true, + }, + { + name: 'commitMessageTopic', + description: + 'The upgrade topic/noun used in commit messages and PR titles.', + type: 'string', + default: 'dependency {{depName}}', + cli: false, + advancedUse: true, + }, + { + name: 'commitMessageExtra', + description: + 'Extra description used after the commit message topic - typically the version.', + type: 'string', + default: + 'to {{#if isPinDigest}}{{{newDigestShort}}}{{else}}{{#if isMajor}}{{prettyNewMajor}}{{else}}{{#if isSingleVersion}}{{prettyNewVersion}}{{else}}{{#if newValue}}{{{newValue}}}{{else}}{{{newDigestShort}}}{{/if}}{{/if}}{{/if}}{{/if}}', + cli: false, + advancedUse: true, + }, + { + name: 'commitMessageSuffix', + description: 'Suffix to add to end of commit messages and PR titles.', + type: 'string', + cli: false, + advancedUse: true, + }, + { + name: 'prBodyTemplate', + description: + 'Pull Request body template. Controls which sections are rendered in the body of the pull request.', + type: 'string', + default: + '{{{header}}}{{{table}}}{{{warnings}}}{{{notes}}}{{{changelogs}}}{{{configDescription}}}{{{controls}}}{{{footer}}}', + cli: false, + }, + { + name: 'prTitle', + description: + 'Pull Request title template. Inherits from `commitMessage` if null.', + type: 'string', + default: null, + deprecationMsg: + 'Direct editing of `prTitle` is now deprecated. Instead use config options like `commitMessageAction`, `commitMessageExtra`, and so on, as they will be passed through to `prTitle`.', + cli: false, + }, + { + name: 'prTitleStrict', + description: + 'Whether to bypass appending extra context to the Pull Request title.', + type: 'boolean', + default: false, + experimental: true, + cli: false, + }, + { + name: 'prHeader', + description: 'Text added here will be placed first in the PR body.', + type: 'string', + }, + { + name: 'prFooter', + description: + 'Text added here will be placed last in the PR body, with a divider separator before it.', + type: 'string', + default: `This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).`, + }, + { + name: 'customizeDashboard', + description: 'Customize sections in the Dependency Dashboard issue.', + type: 'object', + default: {}, + freeChoice: true, + additionalProperties: { + type: 'string', + }, + }, + { + name: 'lockFileMaintenance', + description: 'Configuration for lock file maintenance.', + stage: 'branch', + type: 'object', + default: { + enabled: false, + recreateWhen: 'always', + rebaseStalePrs: true, + branchTopic: 'lock-file-maintenance', + commitMessageAction: 'Lock file maintenance', + commitMessageTopic: null, + commitMessageExtra: null, + schedule: ['before 4am on monday'], + groupName: null, + prBodyDefinitions: { + Change: 'All locks refreshed', + }, + }, + cli: false, + mergeable: true, + }, + { + name: 'hashedBranchLength', + description: + 'If enabled, branch names will use a hashing function to ensure each branch has that length.', + type: 'integer', + default: null, + cli: false, + }, + // Dependency Groups + { + name: 'groupName', + description: 'Human understandable name for the dependency group.', + type: 'string', + default: null, + }, + { + name: 'groupSlug', + description: + 'Slug to use for group (e.g. in branch name). Slug is calculated from `groupName` if `null`.', + type: 'string', + default: null, + cli: false, + env: false, + }, + { + name: 'group', + description: 'Config if `groupName` is enabled.', + type: 'object', + default: { + branchTopic: '{{{groupSlug}}}', + commitMessageTopic: '{{{groupName}}}', + }, + cli: false, + env: false, + mergeable: true, + advancedUse: true, + }, + // Pull Request options + { + name: 'labels', + description: 'Labels to set in Pull Request.', + type: 'array', + subType: 'string', + }, + { + name: 'addLabels', + description: 'Labels to add to Pull Request.', + type: 'array', + subType: 'string', + mergeable: true, + }, + { + name: 'assignees', + description: + 'Assignees for Pull Request (either username or email address depending on the platform).', + type: 'array', + subType: 'string', + }, + { + name: 'assigneesFromCodeOwners', + description: + 'Determine assignees based on configured code owners and changes in PR.', + type: 'boolean', + default: false, + }, + { + name: 'expandCodeOwnersGroups', + description: + 'Expand the configured code owner groups into a full list of group members.', + type: 'boolean', + default: false, + supportedPlatforms: ['gitlab'], + }, + { + name: 'assigneesSampleSize', + description: 'Take a random sample of given size from `assignees`.', + type: 'integer', + default: null, + }, + { + name: 'assignAutomerge', + description: + 'Assign reviewers and assignees even if the PR is to be automerged.', + type: 'boolean', + default: false, + }, + { + name: 'ignoreReviewers', + description: + 'Reviewers to be ignored in PR reviewers presence (either username or email address depending on the platform).', + type: 'array', + subType: 'string', + }, + { + name: 'reviewers', + description: + 'Requested reviewers for Pull Requests (either username or email address depending on the platform).', + type: 'array', + subType: 'string', + }, + { + name: 'reviewersFromCodeOwners', + description: + 'Determine reviewers based on configured code owners and changes in PR.', + type: 'boolean', + default: false, + }, + { + name: 'filterUnavailableUsers', + description: 'Filter reviewers and assignees based on their availability.', + type: 'boolean', + default: false, + supportedPlatforms: ['gitlab'], + }, + { + name: 'forkModeDisallowMaintainerEdits', + description: + 'Disallow maintainers to push to Renovate pull requests when running in fork mode.', + type: 'boolean', + default: false, + supportedPlatforms: ['github'], + }, + { + name: 'confidential', + description: + 'If enabled, issues created by Renovate are set as confidential.', + type: 'boolean', + default: false, + supportedPlatforms: ['gitlab'], + }, + { + name: 'reviewersSampleSize', + description: 'Take a random sample of given size from `reviewers`.', + type: 'integer', + default: null, + }, + { + name: 'additionalReviewers', + description: + 'Additional reviewers for Pull Requests (in contrast to `reviewers`, this option adds to the existing reviewer list, rather than replacing it).', + type: 'array', + subType: 'string', + mergeable: true, + }, + { + name: 'fileMatch', + description: 'RegEx (`re2`) pattern for matching manager files.', + type: 'array', + subType: 'string', + format: 'regex', + stage: 'repository', + allowString: true, + mergeable: true, + cli: false, + env: false, + }, + { + name: 'postUpdateOptions', + description: + 'Enable post-update options to be run after package/artifact updating.', + type: 'array', + default: [], + subType: 'string', + allowedValues: [ + 'bundlerConservative', + 'gomodMassage', + 'gomodTidy', + 'gomodTidy1.17', + 'gomodTidyE', + 'gomodUpdateImportPaths', + 'helmUpdateSubChartArchives', + 'npmDedupe', + 'pnpmDedupe', + 'yarnDedupeFewer', + 'yarnDedupeHighest', + ], + cli: false, + env: false, + mergeable: true, + }, + { + name: 'constraints', + description: + 'Configuration object to define language or manager version constraints.', + type: 'object', + default: {}, + mergeable: true, + cli: false, + supportedManagers: [ + 'bundler', + 'composer', + 'gomod', + 'npm', + 'pep621', + 'pipenv', + 'poetry', + ], + }, + { + name: 'hostRules', + description: 'Host rules/configuration including credentials.', + type: 'array', + subType: 'object', + stage: 'repository', + cli: true, + mergeable: true, + }, + { + name: 'hostType', + description: + 'hostType for a package rule. Can be a platform name or a datasource name.', + type: 'string', + stage: 'repository', + parents: ['hostRules'], + cli: false, + env: false, + }, + { + name: 'matchHost', + description: 'A domain name, host name or base URL to match against.', + type: 'string', + stage: 'repository', + parents: ['hostRules'], + cli: false, + env: false, + }, + { + name: 'readOnly', + description: + 'Match against requests that only read data and do not mutate anything.', + type: 'boolean', + stage: 'repository', + parents: ['hostRules'], + cli: false, + env: false, + }, + { + name: 'timeout', + description: 'Timeout (in milliseconds) for queries to external endpoints.', + type: 'integer', + stage: 'repository', + parents: ['hostRules'], + cli: false, + env: false, + }, + { + name: 'insecureRegistry', + description: 'Explicitly turn on insecure Docker registry access (HTTP).', + type: 'boolean', + default: false, + stage: 'repository', + parents: ['hostRules'], + cli: false, + env: false, + advancedUse: true, + }, + { + name: 'abortOnError', + description: + 'If enabled, Renovate aborts its run when HTTP request errors occur.', + type: 'boolean', + default: false, + stage: 'repository', + parents: ['hostRules'], + cli: false, + env: false, + }, + { + name: 'abortIgnoreStatusCodes', + description: + 'A list of HTTP status codes safe to ignore even when `abortOnError=true`.', + type: 'array', + subType: 'number', + stage: 'repository', + parents: ['hostRules'], + cli: false, + env: false, + }, + { + name: 'enableHttp2', + description: 'Enable got HTTP/2 support.', + type: 'boolean', + default: false, + stage: 'repository', + parents: ['hostRules'], + cli: false, + env: false, + }, + { + name: 'concurrentRequestLimit', + description: 'Limit concurrent requests per host.', + type: 'integer', + stage: 'repository', + parents: ['hostRules'], + default: null, + cli: false, + env: false, + }, + { + name: 'maxRequestsPerSecond', + description: 'Limit requests rate per host.', + type: 'integer', + stage: 'repository', + parents: ['hostRules'], + default: 0, + cli: false, + env: false, + }, + { + name: 'authType', + description: + 'Authentication type for HTTP header. e.g. `"Bearer"` or `"Basic"`. Use `"Token-Only"` to use only the token without an authorization type.', + type: 'string', + stage: 'repository', + parents: ['hostRules'], + default: 'Bearer', + cli: false, + env: false, + }, + { + name: 'dnsCache', + description: 'Enable got DNS cache.', + type: 'boolean', + default: false, + stage: 'repository', + parents: ['hostRules'], + cli: false, + env: false, + experimental: true, + deprecationMsg: + 'This option is deprecated and will be removed in a future release.', + }, + { + name: 'keepAlive', + description: 'Enable HTTP keep-alive for hosts.', + type: 'boolean', + default: false, + stage: 'repository', + parents: ['hostRules'], + cli: false, + env: false, + advancedUse: true, + }, + { + name: 'headers', + description: + 'Put fields to be forwarded to the HTTP request headers in the headers config option.', + type: 'object', + parents: ['hostRules'], + cli: false, + env: false, + advancedUse: true, + }, + { + name: 'artifactAuth', + description: + 'A list of package managers to enable artifact auth. Only managers on the list are enabled. All are enabled if `null`.', + experimental: true, + type: 'array', + subType: 'string', + stage: 'repository', + parents: ['hostRules'], + allowedValues: ['composer'], + default: null, + cli: false, + env: false, + }, + { + name: 'httpsCertificateAuthority', + description: 'The overriding trusted CA certificate.', + type: 'string', + stage: 'repository', + parents: ['hostRules'], + default: null, + cli: false, + env: false, + }, + { + name: 'httpsPrivateKey', + description: 'The private key in PEM format.', + type: 'string', + stage: 'repository', + parents: ['hostRules'], + default: null, + cli: false, + env: false, + }, + { + name: 'httpsCertificate', + description: 'The certificate chains in PEM format.', + type: 'string', + stage: 'repository', + parents: ['hostRules'], + default: null, + cli: false, + env: false, + }, + { + name: 'cacheHardTtlMinutes', + description: + 'Maximum duration in minutes to keep datasource cache entries.', + type: 'integer', + stage: 'repository', + default: 7 * 24 * 60, + globalOnly: true, + }, + { + name: 'cacheTtlOverride', + description: 'An object that contains cache namespace TTL override values.', + type: 'object', + stage: 'repository', + default: {}, + globalOnly: true, + experimental: true, + advancedUse: true, + }, + { + name: 'prBodyDefinitions', + description: 'Table column definitions to use in PR tables.', + type: 'object', + freeChoice: true, + mergeable: true, + default: { + Package: '{{{depNameLinked}}}', + Type: '{{{depType}}}', + Update: '{{{updateType}}}', + 'Current value': '{{{currentValue}}}', + 'New value': '{{{newValue}}}', + Change: '`{{{displayFrom}}}` -> `{{{displayTo}}}`', + Pending: '{{{displayPending}}}', + References: '{{{references}}}', + 'Package file': '{{{packageFile}}}', + Age: "{{#if newVersion}}[![age](https://developer.mend.io/api/mc/badges/age/{{datasource}}/{{replace '/' '%2f' depName}}/{{{newVersion}}}?slim=true)](https://docs.renovatebot.com/merge-confidence/){{/if}}", + Adoption: + "{{#if newVersion}}[![adoption](https://developer.mend.io/api/mc/badges/adoption/{{datasource}}/{{replace '/' '%2f' depName}}/{{{newVersion}}}?slim=true)](https://docs.renovatebot.com/merge-confidence/){{/if}}", + Passing: + "{{#if newVersion}}[![passing](https://developer.mend.io/api/mc/badges/compatibility/{{datasource}}/{{replace '/' '%2f' depName}}/{{{currentVersion}}}/{{{newVersion}}}?slim=true)](https://docs.renovatebot.com/merge-confidence/){{/if}}", + Confidence: + "{{#if newVersion}}[![confidence](https://developer.mend.io/api/mc/badges/confidence/{{datasource}}/{{replace '/' '%2f' depName}}/{{{currentVersion}}}/{{{newVersion}}}?slim=true)](https://docs.renovatebot.com/merge-confidence/){{/if}}", + }, + }, + { + name: 'prBodyColumns', + description: 'List of columns to use in PR bodies.', + type: 'array', + subType: 'string', + default: ['Package', 'Type', 'Update', 'Change', 'Pending'], + }, + { + name: 'prBodyNotes', + description: + 'List of extra notes or templates to include in the Pull Request body.', + type: 'array', + subType: 'string', + default: [], + allowString: true, + mergeable: true, + }, + { + name: 'suppressNotifications', + description: + 'Options to suppress various types of warnings and other notifications.', + type: 'array', + subType: 'string', + default: ['deprecationWarningIssues'], + allowedValues: [ + 'artifactErrors', + 'branchAutomergeFailure', + 'configErrorIssue', + 'dependencyLookupWarnings', + 'deprecationWarningIssues', + 'lockFileErrors', + 'missingCredentialsError', + 'onboardingClose', + 'prEditedNotification', + 'prIgnoreNotification', + ], + cli: false, + env: false, + mergeable: true, + }, + { + name: 'pruneStaleBranches', + description: 'Set to `false` to disable pruning stale branches.', + type: 'boolean', + default: true, + }, + { + name: 'unicodeEmoji', + description: 'Enable or disable Unicode emoji.', + type: 'boolean', + default: true, + globalOnly: true, + }, + { + name: 'gitLabIgnoreApprovals', + description: `Ignore approval rules for MRs created by Renovate, which is useful for automerge.`, + type: 'boolean', + default: false, + }, + { + name: 'customManagers', + description: 'Custom managers using regex matching.', + type: 'array', + subType: 'object', + default: [], + stage: 'package', + cli: true, + mergeable: true, + }, + { + name: 'customType', + description: + 'Custom manager to use. Valid only within a `customManagers` object.', + type: 'string', + allowedValues: ['regex'], + parents: ['customManagers'], + cli: false, + env: false, + }, + { + name: 'matchStrings', + description: + 'Regex capture rule to use. Valid only within a `customManagers` object.', + type: 'array', + subType: 'string', + format: 'regex', + parents: ['customManagers'], + cli: false, + env: false, + }, + { + name: 'matchStringsStrategy', + description: 'Strategy how to interpret matchStrings.', + type: 'string', + default: 'any', + allowedValues: ['any', 'recursive', 'combination'], + parents: ['customManagers'], + cli: false, + env: false, + }, + { + name: 'depNameTemplate', + description: + 'Optional depName for extracted dependencies. Valid only within a `customManagers` object.', + type: 'string', + parents: ['customManagers'], + cli: false, + env: false, + }, + { + name: 'packageNameTemplate', + description: + 'Optional packageName for extracted dependencies, else defaults to `depName` value. Valid only within a `customManagers` object.', + type: 'string', + parents: ['customManagers'], + cli: false, + env: false, + }, + { + name: 'datasourceTemplate', + description: + 'Optional datasource for extracted dependencies. Valid only within a `customManagers` object.', + type: 'string', + parents: ['customManagers'], + cli: false, + env: false, + }, + { + name: 'depTypeTemplate', + description: + 'Optional `depType` for extracted dependencies. Valid only within a `customManagers` object.', + type: 'string', + parents: ['customManagers'], + cli: false, + env: false, + }, + { + name: 'currentValueTemplate', + description: + 'Optional `currentValue` for extracted dependencies. Valid only within a `customManagers` object.', + type: 'string', + parents: ['customManagers'], + cli: false, + env: false, + }, + { + name: 'versioningTemplate', + description: + 'Optional versioning for extracted dependencies. Valid only within a `customManagers` object.', + type: 'string', + parents: ['customManagers'], + cli: false, + env: false, + }, + { + name: 'registryUrlTemplate', + description: + 'Optional registry URL for extracted dependencies. Valid only within a `customManagers` object.', + type: 'string', + parents: ['customManagers'], + cli: false, + env: false, + }, + { + name: 'extractVersionTemplate', + description: + 'Optional `extractVersion` for extracted dependencies. Valid only within a `customManagers` object.', + type: 'string', + parents: ['customManagers'], + cli: false, + env: false, + }, + { + name: 'autoReplaceStringTemplate', + description: + 'Optional `extractVersion` for extracted dependencies. Valid only within a `customManagers` object.', + type: 'string', + parents: ['customManagers'], + cli: false, + env: false, + }, + { + name: 'fetchChangeLogs', + description: 'Controls if and when changelogs/release notes are fetched.', + type: 'string', + allowedValues: ['off', 'branch', 'pr'], + default: 'pr', + cli: false, + env: false, + }, + { + name: 'cloneSubmodules', + description: + 'Set to `true` to initialize submodules during repository clone.', + type: 'boolean', + default: false, + }, + { + name: 'ignorePrAuthor', + description: + 'Set to `true` to fetch the entire list of PRs instead of only those authored by the Renovate user.', + type: 'boolean', + default: false, + }, + { + name: 'gitNoVerify', + description: + 'Which Git commands will be run with the `--no-verify` option.', + type: 'array', + subType: 'string', + allowString: true, + allowedValues: ['commit', 'push'], + default: ['commit', 'push'], + stage: 'global', + globalOnly: true, + }, + { + name: 'updatePinnedDependencies', + description: + 'Whether to update pinned (single version) dependencies or not.', + type: 'boolean', + default: true, + }, + { + name: 'gitUrl', + description: + 'Overrides the default resolution for Git remote, e.g. to switch GitLab from HTTPS to SSH-based.', + type: 'string', + supportedPlatforms: ['gitlab', 'bitbucket-server'], + allowedValues: ['default', 'ssh', 'endpoint'], + default: 'default', + stage: 'repository', + globalOnly: true, + }, + { + name: 'writeDiscoveredRepos', + description: 'Writes discovered repositories to a JSON file and then exit.', + type: 'string', + globalOnly: true, + env: false, + }, + { + name: 'platformAutomerge', + description: `Controls if platform-native auto-merge is used.`, + type: 'boolean', + default: true, + supportedPlatforms: ['azure', 'gitea', 'github', 'gitlab'], + }, + { + name: 'userStrings', + description: + 'User-facing strings for the Renovate comment when a PR is closed.', + type: 'object', + freeChoice: true, + default: { + ignoreTopic: 'Renovate Ignore Notification', + ignoreMajor: + 'Because you closed this PR without merging, Renovate will ignore this update. You will not get PRs for *any* future `{{{newMajor}}}.x` releases. But if you manually upgrade to `{{{newMajor}}}.x` then Renovate will re-enable `minor` and `patch` updates automatically.', + ignoreDigest: + 'Because you closed this PR without merging, Renovate will ignore this update. You will not get PRs for the `{{{depName}}}` `{{{newDigestShort}}}` update again.', + ignoreOther: + 'Because you closed this PR without merging, Renovate will ignore this update (`{{{newValue}}}`). You will get a PR once a newer version is released. To ignore this dependency forever, add it to the `ignoreDeps` array of your Renovate config.', + }, + }, + { + name: 'platformCommit', + description: `Use platform API to perform commits instead of using Git directly.`, + type: 'boolean', + default: false, + supportedPlatforms: ['github'], + }, + { + name: 'branchNameStrict', + description: `Whether to be strict about the use of special characters within the branch name.`, + type: 'boolean', + default: false, + }, + { + name: 'checkedBranches', + description: + 'A list of branch names to mark for creation or rebasing as if it was selected in the Dependency Dashboard issue.', + type: 'array', + subType: 'string', + experimental: true, + globalOnly: true, + default: [], + }, + { + name: 'maxRetryAfter', + description: + 'Maximum retry-after header value to wait for before retrying a failed request.', + type: 'integer', + default: 60, + stage: 'package', + parents: ['hostRules'], + cli: false, + env: false, + }, + { + name: 'logLevelRemap', + description: 'Remap log levels to different levels.', + type: 'array', + subType: 'object', + stage: 'repository', + cli: false, + env: false, + }, + { + name: 'matchMessage', + description: 'Regex/minimatch expression to match against log message.', + type: 'string', + parents: ['logLevelRemap'], + cli: false, + env: false, + }, + { + name: 'newLogLevel', + description: 'New log level to use if matchMessage matches.', + type: 'string', + allowedValues: ['trace', 'debug', 'info', 'warn', 'error', 'fatal'], + parents: ['logLevelRemap'], + cli: false, + env: false, + }, + { + name: 'milestone', + description: `The number of a milestone. If set, the milestone will be set when Renovate creates the PR.`, + type: 'integer', + default: null, + supportedPlatforms: ['github'], + }, + { + name: 'httpCacheTtlDays', + description: 'Maximum duration in days to keep HTTP cache entries.', + type: 'integer', + stage: 'repository', + default: 90, + globalOnly: true, + }, +]; + +export function getOptions(): RenovateOptions[] { + return options; +} + +function loadManagerOptions(): void { + const allManagers = new Map([...getManagers(), ...getCustomManagers()]); + for (const [name, config] of allManagers.entries()) { + if (config.defaultConfig) { + const managerConfig: RenovateOptions = { + name, + description: `Configuration object for the ${name} manager`, + stage: 'package', + type: 'object', + default: config.defaultConfig, + mergeable: true, + cli: false, + autogenerated: true, + }; + options.push(managerConfig); + } + } +} + +loadManagerOptions(); diff --git a/lib/config/presets/__snapshots__/index.spec.ts.snap b/lib/config/presets/__snapshots__/index.spec.ts.snap index b3fac71cdca566..433ee0a7f9861a 100644 --- a/lib/config/presets/__snapshots__/index.spec.ts.snap +++ b/lib/config/presets/__snapshots__/index.spec.ts.snap @@ -56,7 +56,7 @@ exports[`config/presets/index resolvePreset migrates automerge in presets 1`] = }, "packageRules": [ { - "matchPackagePatterns": [ + "matchPackageNames": [ "*", ], "semanticCommitType": "chore", @@ -83,7 +83,7 @@ exports[`config/presets/index resolvePreset migrates automerge in presets 1`] = "semanticCommitType": "fix", }, { - "matchPackagePatterns": [ + "matchPackageNames": [ "*", ], "rangeStrategy": "replace", @@ -120,13 +120,10 @@ exports[`config/presets/index resolvePreset resolves eslint 1`] = ` "@types/eslint", "babel-eslint", "@babel/eslint-parser", - ], - "matchPackagePrefixes": [ - "@eslint/", - "@stylistic/eslint-plugin", - "@types/eslint__", - "@typescript-eslint/", - "eslint", + "@eslint/**", + "@types/eslint__**", + "@typescript-eslint/**", + "eslint**", ], } `; @@ -137,30 +134,24 @@ exports[`config/presets/index resolvePreset resolves linters 1`] = ` "All lint-related packages.", ], "matchPackageNames": [ + "ember-template-lint**", "@types/eslint", "babel-eslint", "@babel/eslint-parser", + "@eslint/**", + "@types/eslint__**", + "@typescript-eslint/**", + "eslint**", "friendsofphp/php-cs-fixer", "squizlabs/php_codesniffer", "symplify/easy-coding-standard", - "@stylistic/stylelint-plugin", + "stylelint**", "codelyzer", + "/\\btslint\\b/", "prettier", "remark-lint", "standard", ], - "matchPackagePatterns": [ - "\\btslint\\b", - ], - "matchPackagePrefixes": [ - "ember-template-lint", - "@eslint/", - "@stylistic/eslint-plugin", - "@types/eslint__", - "@typescript-eslint/", - "eslint", - "stylelint", - ], } `; @@ -176,30 +167,24 @@ exports[`config/presets/index resolvePreset resolves nested groups 1`] = ` "All lint-related packages.", ], "matchPackageNames": [ + "ember-template-lint**", "@types/eslint", "babel-eslint", "@babel/eslint-parser", + "@eslint/**", + "@types/eslint__**", + "@typescript-eslint/**", + "eslint**", "friendsofphp/php-cs-fixer", "squizlabs/php_codesniffer", "symplify/easy-coding-standard", - "@stylistic/stylelint-plugin", + "stylelint**", "codelyzer", + "/\\btslint\\b/", "prettier", "remark-lint", "standard", ], - "matchPackagePatterns": [ - "\\btslint\\b", - ], - "matchPackagePrefixes": [ - "ember-template-lint", - "@eslint/", - "@stylistic/eslint-plugin", - "@types/eslint__", - "@typescript-eslint/", - "eslint", - "stylelint", - ], }, ], } diff --git a/lib/config/presets/index.spec.ts b/lib/config/presets/index.spec.ts index a55ae336459288..8443eea157fe4e 100644 --- a/lib/config/presets/index.spec.ts +++ b/lib/config/presets/index.spec.ts @@ -229,27 +229,6 @@ describe('config/presets/index', () => { expect(e!.validationMessage).toBeUndefined(); }); - it('combines two package alls', async () => { - config.extends = ['packages:eslint', 'packages:stylelint']; - const res = await presets.resolveConfigPresets(config); - expect(res).toEqual({ - matchPackageNames: [ - '@types/eslint', - 'babel-eslint', - '@babel/eslint-parser', - '@stylistic/stylelint-plugin', - ], - matchPackagePrefixes: [ - '@eslint/', - '@stylistic/eslint-plugin', - '@types/eslint__', - '@typescript-eslint/', - 'eslint', - 'stylelint', - ], - }); - }); - it('resolves packageRule', async () => { config.packageRules = [ { @@ -266,13 +245,10 @@ describe('config/presets/index', () => { '@types/eslint', 'babel-eslint', '@babel/eslint-parser', - ], - matchPackagePrefixes: [ - '@eslint/', - '@stylistic/eslint-plugin', - '@types/eslint__', - '@typescript-eslint/', - 'eslint', + '@eslint/**', + '@types/eslint__**', + '@typescript-eslint/**', + 'eslint**', ], }, ], @@ -283,16 +259,14 @@ describe('config/presets/index', () => { config.extends = ['packages:eslint']; const res = await presets.resolveConfigPresets(config); expect(res).toMatchSnapshot(); - expect(res.matchPackagePrefixes).toHaveLength(5); + expect(res.matchPackageNames).toHaveLength(7); }); it('resolves linters', async () => { config.extends = ['packages:linters']; const res = await presets.resolveConfigPresets(config); expect(res).toMatchSnapshot(); - expect(res.matchPackageNames).toHaveLength(11); - expect(res.matchPackagePatterns).toHaveLength(1); - expect(res.matchPackagePrefixes).toHaveLength(7); + expect(res.matchPackageNames).toHaveLength(17); }); it('resolves nested groups', async () => { @@ -301,9 +275,7 @@ describe('config/presets/index', () => { expect(res).toMatchSnapshot(); const rule = res.packageRules![0]; expect(rule.automerge).toBeTrue(); - expect(rule.matchPackageNames).toHaveLength(11); - expect(rule.matchPackagePatterns).toHaveLength(1); - expect(rule.matchPackagePrefixes).toHaveLength(7); + expect(rule.matchPackageNames).toHaveLength(17); }); it('migrates automerge in presets', async () => { diff --git a/lib/config/presets/index.ts b/lib/config/presets/index.ts index 93e8e1fc082399..9a96ed1f6f5aab 100644 --- a/lib/config/presets/index.ts +++ b/lib/config/presets/index.ts @@ -288,15 +288,7 @@ export async function getPreset( // preset is just a collection of other presets delete presetConfig.description; } - const packageListKeys = [ - 'description', - 'matchPackageNames', - 'excludePackageNames', - 'matchPackagePatterns', - 'excludePackagePatterns', - 'matchPackagePrefixes', - 'excludePackagePrefixes', - ]; + const packageListKeys = ['description', 'matchPackageNames']; if (presetKeys.every((key) => packageListKeys.includes(key))) { delete presetConfig.description; } diff --git a/lib/config/presets/internal/default.ts b/lib/config/presets/internal/default.ts index 29fe0081b4ce92..d06839b4b9d3dd 100644 --- a/lib/config/presets/internal/default.ts +++ b/lib/config/presets/internal/default.ts @@ -115,7 +115,7 @@ export const presets: Record = { packageRules: [ { automerge: true, - matchPackagePrefixes: ['@types/'], + matchPackageNames: ['@types/**'], }, ], }, @@ -375,7 +375,7 @@ export const presets: Record = { description: 'Pin all dependency versions except `peerDependencies`.', packageRules: [ { - matchPackagePatterns: ['*'], + matchPackageNames: ['*'], rangeStrategy: 'pin', }, { @@ -412,7 +412,7 @@ export const presets: Record = { 'Pin dependency versions for `devDependencies` and retain SemVer ranges for others.', packageRules: [ { - matchPackagePatterns: ['*'], + matchPackageNames: ['*'], rangeStrategy: 'replace', }, { @@ -451,7 +451,7 @@ export const presets: Record = { preserveSemverRanges: { description: 'Preserve (but continue to upgrade) any existing SemVer ranges.', - packageRules: [{ matchPackagePatterns: ['*'], rangeStrategy: 'replace' }], + packageRules: [{ matchPackageNames: ['*'], rangeStrategy: 'replace' }], }, prHourlyLimit1: { description: 'Rate limit PR creation to a maximum of one per hour.', @@ -542,7 +542,7 @@ export const presets: Record = { 'Use semantic commit type `fix` for dependencies and `chore` for all others if semantic commits are in use.', packageRules: [ { - matchPackagePatterns: ['*'], + matchPackageNames: ['*'], semanticCommitType: 'chore', }, { diff --git a/lib/config/presets/internal/group.ts b/lib/config/presets/internal/group.ts index f6cf6562cb9f4a..64c7aed8b0acda 100644 --- a/lib/config/presets/internal/group.ts +++ b/lib/config/presets/internal/group.ts @@ -17,7 +17,7 @@ const staticGroups = { { groupName: 'all dependencies', groupSlug: 'all', - matchPackagePatterns: ['*'], + matchPackageNames: ['*'], }, ], @@ -38,7 +38,7 @@ const staticGroups = { { groupName: 'all digest updates', groupSlug: 'all-digest', - matchPackagePatterns: ['*'], + matchPackageNames: ['*'], matchUpdateTypes: ['digest'], }, ], @@ -49,7 +49,7 @@ const staticGroups = { { groupName: 'all non-major dependencies', groupSlug: 'all-minor-patch', - matchPackagePatterns: ['*'], + matchPackageNames: ['*'], matchUpdateTypes: ['minor', 'patch'], }, ], @@ -59,7 +59,7 @@ const staticGroups = { packageRules: [ { groupName: 'CodeMirror', - matchPackagePrefixes: ['@codemirror/'], + matchPackageNames: ['@codemirror/**'], }, ], }, @@ -68,7 +68,7 @@ const staticGroups = { packageRules: [ { groupName: 'definitelyTyped', - matchPackagePrefixes: ['@types/'], + matchPackageNames: ['@types/**'], }, ], }, @@ -78,7 +78,7 @@ const staticGroups = { { groupName: '.NET Core Docker containers', matchDatasources: ['docker'], - matchPackagePrefixes: ['mcr.microsoft.com/dotnet/'], + matchPackageNames: ['mcr.microsoft.com/dotnet/**'], }, ], }, @@ -87,7 +87,7 @@ const staticGroups = { packageRules: [ { groupName: 'Font Awesome', - matchPackagePrefixes: ['@fortawesome/'], + matchPackageNames: ['@fortawesome/**'], }, ], }, @@ -98,8 +98,10 @@ const staticGroups = { 'fusion-core', 'fusion-test-utils', 'fusion-tokens', + 'fusion-plugin-**', + 'fusion-react**', + 'fusion-apollo**', ], - matchPackagePrefixes: ['fusion-plugin-', 'fusion-react', '^usion-apollo'], }, githubArtifactActions: { description: @@ -142,7 +144,7 @@ const staticGroups = { groupName: 'go-openapi packages', groupSlug: 'go-openapi', matchDatasources: ['go'], - matchPackagePrefixes: ['github.com/go-openapi/'], + matchPackageNames: ['github.com/go-openapi/**'], }, ], }, @@ -151,7 +153,7 @@ const staticGroups = { packageRules: [ { groupName: 'hibernate commons', - matchPackagePrefixes: ['org.hibernate.common:'], + matchPackageNames: ['org.hibernate.common:**'], }, ], }, @@ -160,7 +162,7 @@ const staticGroups = { packageRules: [ { groupName: 'hibernate core', - matchPackagePrefixes: ['org.hibernate:'], + matchPackageNames: ['org.hibernate:**'], }, ], }, @@ -169,7 +171,7 @@ const staticGroups = { packageRules: [ { groupName: 'hibernate ogm', - matchPackagePrefixes: ['org.hibernate.ogm:'], + matchPackageNames: ['org.hibernate.ogm:**'], }, ], }, @@ -178,7 +180,7 @@ const staticGroups = { packageRules: [ { groupName: 'hibernate validator', - matchPackagePrefixes: ['org.hibernate.validator:'], + matchPackageNames: ['org.hibernate.validator:**'], }, ], }, @@ -188,7 +190,7 @@ const staticGroups = { { groupName: 'illuminate packages', groupSlug: 'illuminate', - matchPackagePrefixes: ['illuminate/'], + matchPackageNames: ['illuminate/**'], }, ], }, @@ -197,9 +199,9 @@ const staticGroups = { packageRules: [ { groupName: 'jekyll ecosystem packages', - matchSourceUrlPrefixes: [ - 'https://github.com/jekyll/', - 'https://github.com/github/pages-gem', + matchSourceUrls: [ + 'https://github.com/jekyll/**', + 'https://github.com/github/pages-gem**', ], }, ], @@ -269,7 +271,7 @@ const staticGroups = { { groupName: 'JWT Framework packages', matchDatasources: ['packagist'], - matchPackagePrefixes: ['web-token/'], + matchPackageNames: ['web-token/**'], }, ], }, @@ -280,34 +282,34 @@ const staticGroups = { groupName: 'kubernetes packages', groupSlug: 'kubernetes-go', matchDatasources: ['go'], - matchPackagePrefixes: [ - 'k8s.io/api', - 'k8s.io/apiextensions-apiserver', - 'k8s.io/apimachinery', - 'k8s.io/apiserver', - 'k8s.io/cli-runtime', - 'k8s.io/client-go', - 'k8s.io/cloud-provider', - 'k8s.io/cluster-bootstrap', - 'k8s.io/code-generator', - 'k8s.io/component-base', - 'k8s.io/controller-manager', - 'k8s.io/cri-api', + matchPackageNames: [ + 'k8s.io/api**', + 'k8s.io/apiextensions-apiserver**', + 'k8s.io/apimachinery**', + 'k8s.io/apiserver**', + 'k8s.io/cli-runtime**', + 'k8s.io/client-go**', + 'k8s.io/cloud-provider**', + 'k8s.io/cluster-bootstrap**', + 'k8s.io/code-generator**', + 'k8s.io/component-base**', + 'k8s.io/controller-manager**', + 'k8s.io/cri-api**', // 'k8s.io/csi-api', has not go.mod set up and does not follow the versioning of other repos - 'k8s.io/csi-translation-lib', - 'k8s.io/kube-aggregator', - 'k8s.io/kube-controller-manager', - 'k8s.io/kube-proxy', - 'k8s.io/kube-scheduler', - 'k8s.io/kubectl', - 'k8s.io/kubelet', - 'k8s.io/legacy-cloud-providers', - 'k8s.io/metrics', - 'k8s.io/mount-utils', - 'k8s.io/pod-security-admission', - 'k8s.io/sample-apiserver', - 'k8s.io/sample-cli-plugin', - 'k8s.io/sample-controller', + 'k8s.io/csi-translation-lib**', + 'k8s.io/kube-aggregator**', + 'k8s.io/kube-controller-manager**', + 'k8s.io/kube-proxy**', + 'k8s.io/kube-scheduler**', + 'k8s.io/kubectl**', + 'k8s.io/kubelet**', + 'k8s.io/legacy-cloud-providers**', + 'k8s.io/metrics**', + 'k8s.io/mount-utils**', + 'k8s.io/pod-security-admission**', + 'k8s.io/sample-apiserver**', + 'k8s.io/sample-cli-plugin**', + 'k8s.io/sample-controller**', ], }, ], @@ -327,14 +329,14 @@ const staticGroups = { packageRules: [ { commitMessageTopic: 'Node.js', - excludePackageNames: [ - 'calico/node', - 'docker.io/calico/node', - 'kindest/node', - ], matchDatasources: ['docker'], matchDepNames: ['node'], - matchPackagePatterns: ['/node$'], + matchPackageNames: [ + '//node$/', // Ends with "node" + '!calico/node', + '!docker.io/calico/node', + '!kindest/node', + ], }, ], }, @@ -344,7 +346,7 @@ const staticGroups = { { groupName: 'PHPStan packages', matchDatasources: ['packagist'], - matchPackagePatterns: ['^phpstan/phpstan$', '/phpstan-', '/larastan'], + matchPackageNames: ['phpstan/phpstan', '//phpstan-/', '//larastan/'], }, ], }, @@ -353,7 +355,7 @@ const staticGroups = { packageRules: [ { groupName: 'polymer packages', - matchPackagePrefixes: ['@polymer/'], + matchPackageNames: ['@polymer/**'], }, ], }, @@ -374,35 +376,35 @@ const staticGroups = { groupName: 'Pulumi', groupSlug: 'pulumi-node', matchDatasources: ['npm'], - matchPackagePrefixes: ['@pulumi/'], + matchPackageNames: ['@pulumi/**'], }, { description: 'Group Pulumi Python packages together.', groupName: 'Pulumi', groupSlug: 'pulumi-python', matchDatasources: ['pypi'], - matchPackagePrefixes: ['pulumi-'], + matchPackageNames: ['pulumi-**'], }, { description: 'Group Pulumi Go packages together.', groupName: 'Pulumi', groupSlug: 'pulumi-go', matchDatasources: ['go'], - matchPackagePrefixes: ['github.com/pulumi/'], + matchPackageNames: ['github.com/pulumi/**'], }, { description: 'Group Pulumi Java packages together.', groupName: 'Pulumi', groupSlug: 'pulumi-java', matchDatasources: ['maven'], - matchPackagePrefixes: ['com.pulumi'], + matchPackageNames: ['com.pulumi**'], }, { description: 'Group Pulumi .NET packages together.', groupName: 'Pulumi', groupSlug: 'pulumi-dotnet', matchDatasources: ['nuget'], - matchPackagePrefixes: ['Pulumi'], + matchPackageNames: ['Pulumi**'], }, ], }, @@ -478,7 +480,7 @@ const staticGroups = { { groupName: 'remark', matchDatasources: ['npm'], - matchSourceUrlPrefixes: ['https://github.com/remarkjs/'], + matchSourceUrls: ['https://github.com/remarkjs/**'], }, ], }, @@ -487,7 +489,7 @@ const staticGroups = { packageRules: [ { groupName: 'resilience4j', - matchPackagePrefixes: ['io.github.resilience4j:'], + matchPackageNames: ['io.github.resilience4j:**'], }, ], }, @@ -497,7 +499,7 @@ const staticGroups = { { groupName: 'omniauth packages', matchDatasources: ['rubygems'], - matchPackagePrefixes: ['omniauth'], + matchPackageNames: ['omniauth**'], }, ], }, @@ -530,7 +532,7 @@ const staticGroups = { packageRules: [ { groupName: 'socket.io packages', - matchPackagePrefixes: ['socket.io'], + matchPackageNames: ['socket.io**'], }, ], }, @@ -539,7 +541,7 @@ const staticGroups = { packageRules: [ { groupName: 'spring amqp', - matchPackagePrefixes: ['org.springframework.amqp:'], + matchPackageNames: ['org.springframework.amqp:**'], }, ], }, @@ -548,7 +550,7 @@ const staticGroups = { packageRules: [ { groupName: 'spring android', - matchPackagePrefixes: ['org.springframework.android:'], + matchPackageNames: ['org.springframework.android:**'], }, ], }, @@ -557,7 +559,7 @@ const staticGroups = { packageRules: [ { groupName: 'spring batch', - matchPackagePrefixes: ['org.springframework.batch:'], + matchPackageNames: ['org.springframework.batch:**'], }, ], }, @@ -567,7 +569,7 @@ const staticGroups = { { groupName: 'spring boot', matchDepNames: ['org.springframework.boot'], - matchPackagePrefixes: ['org.springframework.boot:'], + matchPackageNames: ['org.springframework.boot:**'], }, ], }, @@ -576,7 +578,7 @@ const staticGroups = { packageRules: [ { groupName: 'spring cloud', - matchPackagePrefixes: ['org.springframework.cloud:'], + matchPackageNames: ['org.springframework.cloud:**'], }, ], }, @@ -585,7 +587,7 @@ const staticGroups = { packageRules: [ { groupName: 'spring core', - matchPackagePrefixes: ['org.springframework:'], + matchPackageNames: ['org.springframework:**'], }, ], }, @@ -594,7 +596,7 @@ const staticGroups = { packageRules: [ { groupName: 'spring data', - matchPackagePrefixes: ['org.springframework.data:'], + matchPackageNames: ['org.springframework.data:**'], }, ], }, @@ -603,7 +605,7 @@ const staticGroups = { packageRules: [ { groupName: 'spring hateoas', - matchPackagePrefixes: ['org.springframework.hateoas:'], + matchPackageNames: ['org.springframework.hateoas:**'], }, ], }, @@ -612,7 +614,7 @@ const staticGroups = { packageRules: [ { groupName: 'spring integration', - matchPackagePrefixes: ['org.springframework.integration:'], + matchPackageNames: ['org.springframework.integration:**'], }, ], }, @@ -621,7 +623,7 @@ const staticGroups = { packageRules: [ { groupName: 'spring kafka', - matchPackagePrefixes: ['org.springframework.kafka:'], + matchPackageNames: ['org.springframework.kafka:**'], }, ], }, @@ -630,7 +632,7 @@ const staticGroups = { packageRules: [ { groupName: 'spring ldap', - matchPackagePrefixes: ['org.springframework.ldap:'], + matchPackageNames: ['org.springframework.ldap:**'], }, ], }, @@ -639,7 +641,7 @@ const staticGroups = { packageRules: [ { groupName: 'spring mobile', - matchPackagePrefixes: ['org.springframework.mobile:'], + matchPackageNames: ['org.springframework.mobile:**'], }, ], }, @@ -648,7 +650,7 @@ const staticGroups = { packageRules: [ { groupName: 'spring osgi', - matchPackagePrefixes: ['org.springframework.osgi:'], + matchPackageNames: ['org.springframework.osgi:**'], }, ], }, @@ -657,7 +659,7 @@ const staticGroups = { packageRules: [ { groupName: 'spring restdocs', - matchPackagePrefixes: ['org.springframework.restdocs:'], + matchPackageNames: ['org.springframework.restdocs:**'], }, ], }, @@ -666,7 +668,7 @@ const staticGroups = { packageRules: [ { groupName: 'spring roo', - matchPackagePrefixes: ['org.springframework.roo:'], + matchPackageNames: ['org.springframework.roo:**'], }, ], }, @@ -675,7 +677,7 @@ const staticGroups = { packageRules: [ { groupName: 'spring scala', - matchPackagePrefixes: ['org.springframework.scala:'], + matchPackageNames: ['org.springframework.scala:**'], }, ], }, @@ -684,7 +686,7 @@ const staticGroups = { packageRules: [ { groupName: 'spring security', - matchPackagePrefixes: ['org.springframework.security:'], + matchPackageNames: ['org.springframework.security:**'], }, ], }, @@ -693,7 +695,7 @@ const staticGroups = { packageRules: [ { groupName: 'spring session', - matchPackagePrefixes: ['org.springframework.session:'], + matchPackageNames: ['org.springframework.session:**'], }, ], }, @@ -702,7 +704,7 @@ const staticGroups = { packageRules: [ { groupName: 'spring shell', - matchPackagePrefixes: ['org.springframework.shell:'], + matchPackageNames: ['org.springframework.shell:**'], }, ], }, @@ -711,7 +713,7 @@ const staticGroups = { packageRules: [ { groupName: 'spring social', - matchPackagePrefixes: ['org.springframework.social:'], + matchPackageNames: ['org.springframework.social:**'], }, ], }, @@ -720,7 +722,7 @@ const staticGroups = { packageRules: [ { groupName: 'spring statemachine', - matchPackagePrefixes: ['org.springframework.statemachine:'], + matchPackageNames: ['org.springframework.statemachine:**'], }, ], }, @@ -729,7 +731,7 @@ const staticGroups = { packageRules: [ { groupName: 'spring webflow', - matchPackagePrefixes: ['org.springframework.webflow:'], + matchPackageNames: ['org.springframework.webflow:**'], }, ], }, @@ -738,7 +740,7 @@ const staticGroups = { packageRules: [ { groupName: 'spring ws', - matchPackagePrefixes: ['org.springframework.ws:'], + matchPackageNames: ['org.springframework.ws:**'], }, ], }, @@ -748,7 +750,7 @@ const staticGroups = { { groupName: 'symfony packages', groupSlug: 'symfony', - matchPackagePrefixes: ['symfony/'], + matchPackageNames: ['symfony/**'], }, ], }, diff --git a/lib/config/presets/internal/monorepo.ts b/lib/config/presets/internal/monorepo.ts index 1ce02c452d62b8..1e3982ec8fe382 100644 --- a/lib/config/presets/internal/monorepo.ts +++ b/lib/config/presets/internal/monorepo.ts @@ -591,13 +591,13 @@ for (const [name, value] of Object.entries(repoGroups)) { for (const [name, value] of Object.entries(orgGroups)) { presets[name] = { description: `${name} monorepo`, - matchSourceUrlPrefixes: toArray(value), + matchSourceUrls: toArray(value).map((prefix) => `${prefix}**`), }; } for (const [name, value] of Object.entries(patternGroups)) { presets[name] = { description: `${name} monorepo`, - matchPackagePatterns: toArray(value), + matchPackageNames: toArray(value).map((pattern) => `/${pattern}/`), }; } diff --git a/lib/config/presets/internal/packages.ts b/lib/config/presets/internal/packages.ts index daac49f540fa31..1056e6349745ee 100644 --- a/lib/config/presets/internal/packages.ts +++ b/lib/config/presets/internal/packages.ts @@ -14,11 +14,11 @@ export const presets: Record = { }, apollographql: { description: 'All packages published by Apollo GraphQL.', - matchSourceUrlPrefixes: ['https://github.com/apollographql/'], + matchSourceUrls: ['https://github.com/apollographql/**'], }, emberTemplateLint: { description: 'All ember-template-lint packages.', - matchPackagePrefixes: ['ember-template-lint'], + matchPackageNames: ['ember-template-lint**'], }, eslint: { description: 'All ESLint packages.', @@ -26,13 +26,10 @@ export const presets: Record = { '@types/eslint', 'babel-eslint', '@babel/eslint-parser', - ], - matchPackagePrefixes: [ - '@eslint/', - '@stylistic/eslint-plugin', - '@types/eslint__', - '@typescript-eslint/', - 'eslint', + '@eslint/**', + '@types/eslint__**', + '@typescript-eslint/**', + 'eslint**', ], }, gatsby: { @@ -42,8 +39,7 @@ export const presets: Record = { googleapis: { description: 'All `googleapis` packages.', matchDatasources: ['npm'], - matchPackageNames: ['google-auth-library'], - matchPackagePrefixes: ['@google-cloud/'], + matchPackageNames: ['google-auth-library', '@google-cloud/**'], }, jsTest: { description: 'JavaScript test packages.', @@ -77,17 +73,15 @@ export const presets: Record = { 'ts-auto-mock', 'ts-jest', 'vitest', - ], - matchPackagePrefixes: [ - '@testing-library', - '@types/testing-library__', - '@vitest', - 'chai', - 'jest', - 'mocha', - 'qunit', - 'should', - 'sinon', + '@testing-library**', + '@types/testing-library__**', + '@vitest**', + 'chai**', + 'jest**', + 'mocha**', + 'qunit**', + 'should**', + 'sinon**', ], }, linters: { @@ -103,7 +97,7 @@ export const presets: Record = { }, mapbox: { description: 'All Mapbox-related packages.', - matchPackagePrefixes: ['leaflet', 'mapbox'], + matchPackageNames: ['leaflet**', 'mapbox**'], }, phpLinters: { description: 'All PHP lint-related packages.', @@ -124,23 +118,21 @@ export const presets: Record = { 'phpspec/prophecy-phpunit', 'phpspec/phpspec', 'phpunit/phpunit', + 'pestphp/**', + 'php-mock/**', ], - matchPackagePrefixes: ['pestphp/', 'php-mock/'], }, postcss: { description: 'All PostCSS packages.', - matchPackageNames: ['postcss'], - matchPackagePrefixes: ['postcss-'], + matchPackageNames: ['postcss', 'postcss-**'], }, react: { description: 'All React packages.', - matchPackageNames: ['@types/react'], - matchPackagePrefixes: ['react'], + matchPackageNames: ['@types/react', 'react**'], }, stylelint: { description: 'All Stylelint packages.', - matchPackageNames: ['@stylistic/stylelint-plugin'], - matchPackagePrefixes: ['stylelint'], + matchPackageNames: ['stylelint**'], }, test: { description: 'Test packages.', @@ -148,8 +140,7 @@ export const presets: Record = { }, tslint: { description: 'All TSLint packages.', - matchPackageNames: ['codelyzer'], - matchPackagePatterns: ['\\btslint\\b'], + matchPackageNames: ['codelyzer', '/\\btslint\\b/'], }, unitTest: { description: 'All unit test packages.', @@ -158,6 +149,6 @@ export const presets: Record = { vite: { description: 'All Vite related packages', matchDatasources: ['npm'], - matchPackagePatterns: ['^vite$', 'vite-plugin', '@vitejs'], + matchPackageNames: ['vite', '**vite-plugin**', '@vitejs/**'], }, }; diff --git a/lib/config/presets/internal/replacements.ts b/lib/config/presets/internal/replacements.ts index 74335ad3acd1bd..7e813c33802a45 100644 --- a/lib/config/presets/internal/replacements.ts +++ b/lib/config/presets/internal/replacements.ts @@ -128,10 +128,10 @@ export const presets: Record = { description: 'Replace `containerbase/(buildpack|base)` and `renovate/buildpack` with `ghcr.io/containerbase/base`.', matchDatasources: ['docker'], - matchPackagePatterns: [ - '^(?:docker\\.io/)?containerbase/(?:buildpack|base)$', - '^ghcr\\.io/containerbase/buildpack$', - '^(?:docker\\.io/)?renovate/buildpack$', + matchPackageNames: [ + '/^(?:docker\\.io/)?containerbase/(?:buildpack|base)$/', + '/^ghcr\\.io/containerbase/buildpack$/', + '/^(?:docker\\.io/)?renovate/buildpack$/', ], replacementName: 'ghcr.io/containerbase/base', }, @@ -139,8 +139,8 @@ export const presets: Record = { description: 'Replace `containerbase/node` and `renovate/node` with `ghcr.io/containerbase/node`.', matchDatasources: ['docker'], - matchPackagePatterns: [ - '^(?:docker\\.io/)?(?:containerbase|renovate)/node$', + matchPackageNames: [ + '/^(?:docker\\.io/)?(?:containerbase|renovate)/node$/', ], replacementName: 'ghcr.io/containerbase/node', }, @@ -148,8 +148,8 @@ export const presets: Record = { description: 'Replace `containerbase/sidecar` and `renovate/sidecar` with `ghcr.io/containerbase/sidecar`.', matchDatasources: ['docker'], - matchPackagePatterns: [ - '^(?:docker\\.io/)?(?:containerbase|renovate)/sidecar$', + matchPackageNames: [ + '/^(?:docker\\.io/)?(?:containerbase|renovate)/sidecar$/', ], replacementName: 'ghcr.io/containerbase/sidecar', }, @@ -164,8 +164,10 @@ export const presets: Record = { description: 'Replace `renovate` `slim` docker tag with `latest`.', matchCurrentValue: '/^slim$/', matchDatasources: ['docker'], - matchPackageNames: ['ghcr.io/renovatebot/renovate'], - matchPackagePatterns: ['^(?:docker\\.io/)?renovate/renovate$'], + matchPackageNames: [ + 'ghcr.io/renovatebot/renovate', + '/^(?:docker\\.io/)?renovate/renovate$/', + ], replacementVersion: 'latest', }, { @@ -173,8 +175,10 @@ export const presets: Record = { extractVersion: '^(?.+)-slim$', matchCurrentValue: '/-slim$/', matchDatasources: ['docker'], - matchPackageNames: ['ghcr.io/renovatebot/renovate'], - matchPackagePatterns: ['^(?:docker\\.io/)?renovate/renovate$'], + matchPackageNames: [ + 'ghcr.io/renovatebot/renovate', + '/^(?:docker\\.io/)?renovate/renovate$/s', + ], versioning: 'semver', }, ], @@ -675,7 +679,7 @@ export const presets: Record = { packageRules: [ { matchDatasources: ['docker'], - matchPackagePatterns: ['^k8s\\.gcr\\.io/.+$'], + matchPackageNames: ['/^k8s\\.gcr\\.io/.+$/'], replacementNameTemplate: "{{{replace 'k8s\\.gcr\\.io/' 'registry.k8s.io/' packageName}}}", }, diff --git a/lib/config/presets/internal/security.ts b/lib/config/presets/internal/security.ts index a5e72a45e21eec..00998d05ba8233 100644 --- a/lib/config/presets/internal/security.ts +++ b/lib/config/presets/internal/security.ts @@ -5,7 +5,7 @@ export const presets: Record = { description: 'Show OpenSSF badge on pull requests.', packageRules: [ { - matchSourceUrlPrefixes: ['https://github.com/'], + matchSourceUrls: ['https://github.com/**'], prBodyDefinitions: { OpenSSF: '[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/{{sourceRepo}}/badge)](https://securityscorecards.dev/viewer/?uri=github.com/{{sourceRepo}})', diff --git a/lib/config/presets/internal/workarounds.ts b/lib/config/presets/internal/workarounds.ts index 158515222e43b0..8a6652b152fba0 100644 --- a/lib/config/presets/internal/workarounds.ts +++ b/lib/config/presets/internal/workarounds.ts @@ -49,8 +49,8 @@ export const presets: Record = { description: 'Use node versioning for `(containerbase|renovate)/node` images', matchDatasources: ['docker'], - matchPackagePatterns: [ - '^(?:(?:docker|ghcr)\\.io/)?(?:containerbase|renovate)/node$', + matchPackageNames: [ + '/^(?:(?:docker|ghcr)\\.io/)?(?:containerbase|renovate)/node$/', ], versioning: 'node', }, @@ -100,7 +100,7 @@ export const presets: Record = { { allowedVersions: `!/^1\\.0-\\d+-[a-fA-F0-9]{7}$/`, matchManagers: ['sbt'], - matchPackagePrefixes: ['org.http4s:'], + matchPackageNames: ['org.http4s:**'], }, ], }, @@ -142,11 +142,9 @@ export const presets: Record = { 'java', 'java-jre', 'sapmachine', - ], - matchPackagePatterns: [ - '^azul/zulu-openjdk', - '^bellsoft/liberica-openj(dk|re)-', - '^cimg/openjdk', + '/^azul/zulu-openjdk/', + '/^bellsoft/liberica-openj(dk|re)-/', + '/^cimg/openjdk/', ], versioning: 'regex:^(?\\d+)?(\\.(?\\d+))?(\\.(?\\d+))?([\\._+](?(\\d\\.?)+)(LTS)?)?(-(?.*))?$', @@ -176,7 +174,7 @@ export const presets: Record = { { allowedVersions: '!/^200\\d{5}(\\.\\d+)?/', matchDatasources: ['maven', 'sbt-package'], - matchPackagePrefixes: ['commons-'], + matchPackageNames: ['commons-**'], }, ], }, @@ -213,18 +211,16 @@ export const presets: Record = { 'registry.access.redhat.com/rhel-atomic', 'registry.access.redhat.com/rhel-init', 'registry.access.redhat.com/rhel-minimal', - ], - matchPackagePrefixes: [ - 'registry.access.redhat.com/rhceph/', - 'registry.access.redhat.com/rhgs3/', - 'registry.access.redhat.com/rhel7', - 'registry.access.redhat.com/rhel8/', - 'registry.access.redhat.com/rhel9/', - 'registry.access.redhat.com/rhscl/', - 'registry.access.redhat.com/ubi7', - 'registry.access.redhat.com/ubi8', - 'registry.access.redhat.com/ubi9', - 'redhat/', + 'registry.access.redhat.com/rhceph/**', + 'registry.access.redhat.com/rhgs3/**', + 'registry.access.redhat.com/rhel7**', + 'registry.access.redhat.com/rhel8/**', + 'registry.access.redhat.com/rhel9/**', + 'registry.access.redhat.com/rhscl/**', + 'registry.access.redhat.com/ubi7**', + 'registry.access.redhat.com/ubi8**', + 'registry.access.redhat.com/ubi9**', + 'redhat/**', ], versioning: 'redhat', }, diff --git a/lib/config/types.ts b/lib/config/types.ts index 4c901b29149c12..f4ce8611feee4a 100644 --- a/lib/config/types.ts +++ b/lib/config/types.ts @@ -358,13 +358,6 @@ export interface PackageRule UpdateConfig, Record { description?: string | string[]; - excludeDepNames?: string[]; - excludeDepPatterns?: string[]; - excludeDepPrefixes?: string[]; - excludePackageNames?: string[]; - excludePackagePatterns?: string[]; - excludePackagePrefixes?: string[]; - excludeRepositories?: string[]; isVulnerabilityAlert?: boolean; matchBaseBranches?: string[]; matchCategories?: string[]; @@ -374,17 +367,12 @@ export interface PackageRule matchCurrentVersion?: string; matchDatasources?: string[]; matchDepNames?: string[]; - matchDepPatterns?: string[]; - matchDepPrefixes?: string[]; matchDepTypes?: string[]; matchFileNames?: string[]; matchManagers?: string[]; matchNewValue?: string; matchPackageNames?: string[]; - matchPackagePatterns?: string[]; - matchPackagePrefixes?: string[]; matchRepositories?: string[]; - matchSourceUrlPrefixes?: string[]; matchSourceUrls?: string[]; matchUpdateTypes?: UpdateType[]; registryUrls?: string[] | null; diff --git a/lib/config/validation.spec.ts b/lib/config/validation.spec.ts index 1e351402d2b0c1..a2848d6b77a9df 100644 --- a/lib/config/validation.spec.ts +++ b/lib/config/validation.spec.ts @@ -369,8 +369,11 @@ describe('config/validation', () => { timezone: 'Asia/Singapore', packageRules: [ { - matchPackagePatterns: ['*'], - excludePackagePatterns: ['abc ([a-z]+) ([a-z]+))'], + matchPackageNames: [ + '*', + '/abc ([a-z]+) ([a-z]+))/', + '!/abc ([a-z]+) ([a-z]+))/', + ], enabled: true, }, ], @@ -384,7 +387,7 @@ describe('config/validation', () => { config, ); expect(warnings).toHaveLength(0); - expect(errors).toHaveLength(3); + expect(errors).toHaveLength(4); expect(errors).toMatchSnapshot(); }); @@ -476,19 +479,13 @@ describe('config/validation', () => { lockFileMaintenance: false as any, extends: [':timezone(Europe/Brussel)'], packageRules: [ - { - excludePackageNames: ['foo'], - enabled: true, - }, { foo: 1, }, 'what?' as any, { - matchDepPatterns: 'abc ([a-z]+) ([a-z]+))', - matchPackagePatterns: 'abc ([a-z]+) ([a-z]+))', - excludeDepPatterns: ['abc ([a-z]+) ([a-z]+))'], - excludePackagePatterns: ['abc ([a-z]+) ([a-z]+))'], + matchPackageNames: '/abc ([a-z]+) ([a-z]+))/', + matchDepNames: ['abc ([a-z]+) ([a-z]+))'], enabled: false, }, ], @@ -500,7 +497,7 @@ describe('config/validation', () => { ); expect(warnings).toHaveLength(1); expect(errors).toMatchSnapshot(); - expect(errors).toHaveLength(15); + expect(errors).toHaveLength(12); }); it('selectors outside packageRules array trigger errors', async () => { @@ -1044,9 +1041,7 @@ describe('config/validation', () => { it('warns if only selectors in packageRules', async () => { const config = { - packageRules: [ - { matchDepTypes: ['foo'], excludePackageNames: ['bar'] }, - ], + packageRules: [{ matchDepTypes: ['foo'], matchPackageNames: ['bar'] }], }; const { warnings, errors } = await configValidation.validateConfig( 'repo', diff --git a/lib/config/validation.ts b/lib/config/validation.ts index 0b9f8889662f15..94e3d8781ff540 100644 --- a/lib/config/validation.ts +++ b/lib/config/validation.ts @@ -433,21 +433,9 @@ export async function validateConfig( 'matchDatasources', 'matchDepTypes', 'matchDepNames', - 'matchDepPatterns', - 'matchDepPrefixes', 'matchPackageNames', - 'matchPackagePatterns', - 'matchPackagePrefixes', - 'excludeDepNames', - 'excludeDepPatterns', - 'excludeDepPrefixes', - 'excludePackageNames', - 'excludePackagePatterns', - 'excludePackagePrefixes', - 'excludeRepositories', 'matchCurrentValue', 'matchCurrentVersion', - 'matchSourceUrlPrefixes', 'matchSourceUrls', 'matchUpdateTypes', 'matchConfidence', @@ -605,18 +593,14 @@ export async function validateConfig( } } } - if ( - [ - 'matchPackagePatterns', - 'excludePackagePatterns', - 'matchDepPatterns', - 'excludeDepPatterns', - ].includes(key) - ) { + if (['matchPackageNames', 'matchDepNames'].includes(key)) { + const startPattern = regEx(/!?\//); + const endPattern = regEx(/\/g?i?$/); for (const pattern of val as string[]) { - if (pattern !== '*') { + if (startPattern.test(pattern) && endPattern.test(pattern)) { try { - regEx(pattern); + // regEx isn't aware of our !/ prefix but can handle the suffix + regEx(pattern.replace(startPattern, '/')); } catch (e) { errors.push({ topic: 'Configuration Error', diff --git a/lib/modules/datasource/npm/npmrc.spec.ts b/lib/modules/datasource/npm/npmrc.spec.ts index 707270507eb05b..21cc3b35b61e66 100644 --- a/lib/modules/datasource/npm/npmrc.spec.ts +++ b/lib/modules/datasource/npm/npmrc.spec.ts @@ -136,8 +136,8 @@ describe('modules/datasource/npm/npmrc', () => { "matchDatasources": [ "npm", ], - "matchPackagePrefixes": [ - "@fontawesome/", + "matchPackageNames": [ + "@fontawesome/**", ], "registryUrls": [ "https://npm.fontawesome.com/", diff --git a/lib/modules/datasource/npm/npmrc.ts b/lib/modules/datasource/npm/npmrc.ts index 73b2e1eef52896..72291ad2e6bbc0 100644 --- a/lib/modules/datasource/npm/npmrc.ts +++ b/lib/modules/datasource/npm/npmrc.ts @@ -111,7 +111,7 @@ export function convertNpmrcToRules(npmrc: Record): NpmrcRules { if (isHttpUrl(value)) { rules.packageRules?.push({ matchDatasources, - matchPackagePrefixes: [scope + '/'], + matchPackageNames: [`${scope}/**`], registryUrls: [value], }); } else { @@ -168,10 +168,10 @@ export function setNpmrc(input?: string): void { export function resolveRegistryUrl(packageName: string): string { let registryUrl = defaultRegistryUrls[0]; for (const rule of packageRules) { - const { matchPackagePrefixes, registryUrls } = rule; + const { matchPackageNames, registryUrls } = rule; if ( - !matchPackagePrefixes || - packageName.startsWith(matchPackagePrefixes[0]) + !matchPackageNames || + packageName.startsWith(matchPackageNames[0].replace(regEx(/\*\*$/), '')) ) { // TODO: fix types #22198 registryUrl = registryUrls![0]; diff --git a/lib/modules/versioning/regex/readme.md b/lib/modules/versioning/regex/readme.md index 2fe779d5015cde..b8512e5c95ef55 100644 --- a/lib/modules/versioning/regex/readme.md +++ b/lib/modules/versioning/regex/readme.md @@ -45,7 +45,7 @@ Here is another example, this time for handling Bitnami Docker images, which use "packageRules": [ { "matchDatasources": ["docker"], - "matchPackagePrefixes": ["bitnami/", "docker.io/bitnami/"], + "matchPackageNamees": ["bitnami/**", "docker.io/bitnami/**"], "versioning": "regex:^(?\\d+)\\.(?\\d+)\\.(?\\d+)(?:-(?.+)(?\\d+)-r(?\\d+))?$" } ] diff --git a/lib/util/package-rules/base.ts b/lib/util/package-rules/base.ts index 981a11575335db..121a982a7fc40d 100644 --- a/lib/util/package-rules/base.ts +++ b/lib/util/package-rules/base.ts @@ -2,19 +2,6 @@ import type { PackageRule, PackageRuleInputConfig } from '../../config/types'; import type { MatcherApi } from './types'; export abstract class Matcher implements MatcherApi { - /** - * Test exclusion packageRule against inputConfig - * @return null if no rules are defined, true if exclusion should be applied and else false - * @param inputConfig - * @param packageRule - */ - excludes( - inputConfig: PackageRuleInputConfig, - packageRule: PackageRule, - ): boolean | null { - return null; - } - /** * Test match packageRule against inputConfig * @return null if no rules are defined, true if match should be applied and else false diff --git a/lib/util/package-rules/dep-names.spec.ts b/lib/util/package-rules/dep-names.spec.ts index eb0bea92f2584e..3a97c5696e40d3 100644 --- a/lib/util/package-rules/dep-names.spec.ts +++ b/lib/util/package-rules/dep-names.spec.ts @@ -16,18 +16,4 @@ describe('util/package-rules/dep-names', () => { expect(result).toBeFalse(); }); }); - - describe('exclude', () => { - it('should return false if packageFile is not defined', () => { - const result = depNameMatcher.excludes( - { - depName: undefined, - }, - { - excludeDepNames: ['@opentelemetry/http'], - }, - ); - expect(result).toBeFalse(); - }); - }); }); diff --git a/lib/util/package-rules/dep-names.ts b/lib/util/package-rules/dep-names.ts index f9278ba650aac7..0b808de7984fc0 100644 --- a/lib/util/package-rules/dep-names.ts +++ b/lib/util/package-rules/dep-names.ts @@ -16,17 +16,4 @@ export class DepNameMatcher extends Matcher { } return matchRegexOrGlobList(depName, matchDepNames); } - - override excludes( - { depName }: PackageRuleInputConfig, - { excludeDepNames }: PackageRule, - ): boolean | null { - if (is.undefined(excludeDepNames)) { - return null; - } - if (is.undefined(depName)) { - return false; - } - return matchRegexOrGlobList(depName, excludeDepNames); - } } diff --git a/lib/util/package-rules/dep-patterns.spec.ts b/lib/util/package-rules/dep-patterns.spec.ts deleted file mode 100644 index 103adcfb302a39..00000000000000 --- a/lib/util/package-rules/dep-patterns.spec.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { DepPatternsMatcher } from './dep-patterns'; - -describe('util/package-rules/dep-patterns', () => { - const depPatternsMatcher = new DepPatternsMatcher(); - - describe('match', () => { - it('should return false if depName is not defined', () => { - const result = depPatternsMatcher.matches( - { - depName: undefined, - }, - { - matchDepPatterns: ['@opentelemetry/http'], - }, - ); - expect(result).toBeFalse(); - }); - - it('should massage wildcards', () => { - const result = depPatternsMatcher.matches( - { - depName: 'http', - }, - { - matchDepPatterns: ['*'], - }, - ); - expect(result).toBeTrue(); - }); - - it('should convert to regex', () => { - const result = depPatternsMatcher.matches( - { - depName: 'http', - }, - { - matchDepPatterns: ['^h'], - }, - ); - expect(result).toBeTrue(); - }); - }); - - describe('exclude', () => { - it('should return false if depName is not defined', () => { - const result = depPatternsMatcher.excludes( - { - depName: undefined, - }, - { - excludeDepPatterns: ['@opentelemetry/http'], - }, - ); - expect(result).toBeFalse(); - }); - - it('should massage wildcards', () => { - const result = depPatternsMatcher.excludes( - { - depName: 'http', - }, - { - excludeDepPatterns: ['*'], - }, - ); - expect(result).toBeTrue(); - }); - - it('should convert to regex', () => { - const result = depPatternsMatcher.excludes( - { - depName: 'http', - }, - { - excludeDepPatterns: ['^h'], - }, - ); - expect(result).toBeTrue(); - }); - }); -}); diff --git a/lib/util/package-rules/dep-patterns.ts b/lib/util/package-rules/dep-patterns.ts deleted file mode 100644 index 21d533010041ac..00000000000000 --- a/lib/util/package-rules/dep-patterns.ts +++ /dev/null @@ -1,41 +0,0 @@ -import is from '@sindresorhus/is'; -import type { PackageRule, PackageRuleInputConfig } from '../../config/types'; -import { matchRegexOrGlobList } from '../string-match'; -import { Matcher } from './base'; - -export class DepPatternsMatcher extends Matcher { - override matches( - { depName }: PackageRuleInputConfig, - { matchDepPatterns }: PackageRule, - ): boolean | null { - if (is.undefined(matchDepPatterns)) { - return null; - } - - if (is.undefined(depName)) { - return false; - } - - const massagedPatterns = matchDepPatterns.map((pattern) => - pattern === '^*$' || pattern === '*' ? '*' : `/${pattern}/`, - ); - return matchRegexOrGlobList(depName, massagedPatterns); - } - - override excludes( - { depName }: PackageRuleInputConfig, - { excludeDepPatterns }: PackageRule, - ): boolean | null { - if (is.undefined(excludeDepPatterns)) { - return null; - } - if (is.undefined(depName)) { - return false; - } - - const massagedPatterns = excludeDepPatterns.map((pattern) => - pattern === '^*$' || pattern === '*' ? '*' : `/${pattern}/`, - ); - return matchRegexOrGlobList(depName, massagedPatterns); - } -} diff --git a/lib/util/package-rules/dep-prefixes.spec.ts b/lib/util/package-rules/dep-prefixes.spec.ts deleted file mode 100644 index d5b35da075989d..00000000000000 --- a/lib/util/package-rules/dep-prefixes.spec.ts +++ /dev/null @@ -1,105 +0,0 @@ -import { DepPrefixesMatcher } from './dep-prefixes'; - -describe('util/package-rules/dep-prefixes', () => { - const depPrefixesMatcher = new DepPrefixesMatcher(); - - describe('match', () => { - it('should return null if matchDepPrefixes is not defined', () => { - const result = depPrefixesMatcher.matches( - { - depName: 'abc1', - }, - { - matchDepPrefixes: undefined, - }, - ); - expect(result).toBeNull(); - }); - - it('should return false if depName is not defined', () => { - const result = depPrefixesMatcher.matches( - { - depName: undefined, - }, - { - matchDepPrefixes: ['@opentelemetry'], - }, - ); - expect(result).toBeFalse(); - }); - - it('should return true if depName matched', () => { - const result = depPrefixesMatcher.matches( - { - depName: 'abc1', - }, - { - matchDepPrefixes: ['abc'], - }, - ); - expect(result).toBeTrue(); - }); - - it('should return false if depName does not match', () => { - const result = depPrefixesMatcher.matches( - { - depName: 'abc1', - }, - { - matchDepPrefixes: ['def'], - }, - ); - expect(result).toBeFalse(); - }); - }); - - describe('exclude', () => { - it('should return null if excludeDepPrefixes is not defined', () => { - const result = depPrefixesMatcher.excludes( - { - depName: 'abc1', - }, - { - excludeDepPrefixes: undefined, - }, - ); - expect(result).toBeNull(); - }); - - it('should return false if depName is not defined', () => { - const result = depPrefixesMatcher.excludes( - { - depName: undefined, - }, - { - excludeDepPrefixes: ['@opentelemetry'], - }, - ); - expect(result).toBeFalse(); - }); - - it('should return true if depName matched', () => { - const result = depPrefixesMatcher.excludes( - { - depName: 'abc1', - }, - { - excludeDepPrefixes: ['abc'], - }, - ); - expect(result).toBeTrue(); - }); - - it('should return false if depName does not match', () => { - const result = depPrefixesMatcher.excludes( - { - depName: 'abc1', - }, - { - excludeDepPrefixes: ['def'], - }, - ); - expect(result).toBeFalse(); - }); - }); -}); diff --git a/lib/util/package-rules/dep-prefixes.ts b/lib/util/package-rules/dep-prefixes.ts deleted file mode 100644 index 351df41f8605e5..00000000000000 --- a/lib/util/package-rules/dep-prefixes.ts +++ /dev/null @@ -1,35 +0,0 @@ -import is from '@sindresorhus/is'; -import type { PackageRule, PackageRuleInputConfig } from '../../config/types'; -import { Matcher } from './base'; - -export class DepPrefixesMatcher extends Matcher { - override matches( - { depName }: PackageRuleInputConfig, - { matchDepPrefixes }: PackageRule, - ): boolean | null { - if (is.undefined(matchDepPrefixes)) { - return null; - } - - if (is.undefined(depName)) { - return false; - } - - return matchDepPrefixes.some((prefix) => depName.startsWith(prefix)); - } - - override excludes( - { depName }: PackageRuleInputConfig, - { excludeDepPrefixes }: PackageRule, - ): boolean | null { - if (is.undefined(excludeDepPrefixes)) { - return null; - } - - if (is.undefined(depName)) { - return false; - } - - return excludeDepPrefixes.some((prefix) => depName.startsWith(prefix)); - } -} diff --git a/lib/util/package-rules/index.spec.ts b/lib/util/package-rules/index.spec.ts index 9f911c3541fd9e..a2b9a293152f95 100644 --- a/lib/util/package-rules/index.spec.ts +++ b/lib/util/package-rules/index.spec.ts @@ -19,20 +19,15 @@ describe('util/package-rules/index', () => { packageRules: [ { - matchPackageNames: ['a', 'b'], - matchPackagePrefixes: ['xyz/'], - excludePackagePrefixes: ['xyz/foo'], + matchPackageNames: ['a', 'b', 'xyz/**', '!xyz/foo**'], x: 2, }, { - matchPackagePatterns: ['a', 'b'], - excludePackageNames: ['aa'], - excludePackagePatterns: ['d'], + matchPackageNames: ['/a/', '/b/', '!aa', '!/d/'], y: 2, }, { - matchPackagePrefixes: ['xyz/'], - excludePackageNames: ['xyz/foo'], + matchPackageNames: ['xyz/**', '!xyz/foo'], groupName: 'xyz', }, ], @@ -46,23 +41,19 @@ describe('util/package-rules/index', () => { currentValue: '1.0.0', packageRules: [ { - matchPackagePatterns: ['*'], + matchPackageNames: ['*'], matchCurrentVersion: '<= 2.0.0', }, { matchPackageNames: ['b'], matchCurrentVersion: '<= 2.0.0', }, - { - excludePackagePatterns: ['*'], - }, { matchUpdateTypes: ['bump'], labels: ['bump'], }, { - excludePackageNames: ['a'], - matchPackageNames: ['b'], + matchPackageNames: ['b', '!a'], }, { matchCurrentVersion: '<= 2.0.0', @@ -105,17 +96,7 @@ describe('util/package-rules/index', () => { expect(res.groupName).toBeUndefined(); }); - it('applies matchPackagePrefixes', () => { - const dep = { - packageName: 'xyz/abc', - }; - const res = applyPackageRules({ ...config1, ...dep }); - expect(res.x).toBe(2); - expect(res.y).toBe(2); - expect(res.groupName).toBe('xyz'); - }); - - it('applies excludePackageNames', () => { + it('applies matchPackageNames', () => { const dep = { packageName: 'xyz/foo', }; @@ -123,15 +104,6 @@ describe('util/package-rules/index', () => { expect(res.groupName).toBeUndefined(); }); - it('applies excludePackagePrefixes', () => { - const dep = { - packageName: 'xyz/foo-a', - }; - const res = applyPackageRules({ ...config1, ...dep }); - expect(res.x).toBeUndefined(); - expect(res.groupName).toBe('xyz'); - }); - it('applies the second second rule', () => { const dep = { packageName: 'bc', @@ -165,33 +137,14 @@ describe('util/package-rules/index', () => { updateType: 'lockFileMaintenance' as UpdateType, packageRules: [ { - excludePackagePatterns: ['^foo'], - automerge: false, - }, - ], - }; - const res = applyPackageRules(dep); - expect(res.automerge).toBeFalse(); - const res2 = applyPackageRules({ ...dep, packageName: 'foo' }); - expect(res2.automerge).toBeTrue(); - }); - - it('do not apply rule with empty matchPackagePattern', () => { - const dep = { - automerge: true, - updateType: 'lockFileMaintenance' as UpdateType, - packageRules: [ - { - matchPackagePatterns: [], - excludePackagePatterns: ['^foo'], + matchPackageNames: ['!/^foo/'], automerge: false, }, ], }; + // This should not match const res = applyPackageRules(dep); expect(res.automerge).toBeTrue(); - const res2 = applyPackageRules({ ...dep, packageName: 'foo' }); - expect(res2.automerge).toBeTrue(); }); it('do apply rule with matchPackageName', () => { @@ -211,39 +164,11 @@ describe('util/package-rules/index', () => { expect(res2.automerge).toBeFalse(); }); - it('sets skipReason=package-rules if enabled=false', () => { - const dep: any = { - depName: 'foo', - packageRules: [ - { - enabled: false, - }, - ], - }; - const res = applyPackageRules(dep); - expect(res.enabled).toBeFalse(); - expect(res.skipReason).toBe('package-rules'); - }); - - it('skips skipReason=package-rules if enabled=true', () => { - const dep: any = { - enabled: false, - depName: 'foo', - packageRules: [ - { - enabled: false, - }, - ], - }; - const res = applyPackageRules(dep); - expect(res.skipReason).toBeUndefined(); - }); - it('matches anything if missing inclusive rules', () => { const config: TestConfig = { packageRules: [ { - excludePackageNames: ['foo'], + matchPackageNames: ['!foo'], x: 1, }, ], @@ -264,8 +189,7 @@ describe('util/package-rules/index', () => { const config: TestConfig = { packageRules: [ { - matchPackageNames: ['neutrino'], - matchPackagePatterns: ['^@neutrino\\/'], + matchPackageNames: ['neutrino', '/^@neutrino\\//'], x: 1, }, ], @@ -564,13 +488,13 @@ describe('util/package-rules/index', () => { expect(res.y).toBeUndefined(); }); - it('matches matchSourceUrlPrefixes', () => { + it('matches matchSourceUrls with glob', () => { const config: TestConfig = { packageRules: [ { - matchSourceUrlPrefixes: [ - 'https://github.com/foo/bar', - 'https://github.com/renovatebot/', + matchSourceUrls: [ + 'https://github.com/foo/bar**', + 'https://github.com/renovatebot/**', ], x: 1, }, @@ -586,13 +510,13 @@ describe('util/package-rules/index', () => { expect(res.x).toBe(1); }); - it('non-matches matchSourceUrlPrefixes', () => { + it('non-matches matchSourceUrls with globs', () => { const config: TestConfig = { packageRules: [ { - matchSourceUrlPrefixes: [ - 'https://github.com/foo/bar', - 'https://github.com/renovatebot/', + matchSourceUrls: [ + 'https://github.com/foo/bar**', + 'https://github.com/renovatebot/**', ], x: 1, }, @@ -608,13 +532,13 @@ describe('util/package-rules/index', () => { expect(res.x).toBeUndefined(); }); - it('handles matchSourceUrlPrefixes when missing sourceUrl', () => { + it('handles matchSourceUrls when missing sourceUrl', () => { const config: TestConfig = { packageRules: [ { - matchSourceUrlPrefixes: [ - 'https://github.com/foo/bar', - 'https://github.com/renovatebot/', + matchSourceUrls: [ + 'https://github.com/foo/bar**', + 'https://github.com/renovatebot/**', ], x: 1, }, @@ -673,27 +597,6 @@ describe('util/package-rules/index', () => { expect(res.x).toBeUndefined(); }); - it('handles matchSourceUrls when missing sourceUrl', () => { - const config: TestConfig = { - packageRules: [ - { - matchSourceUrls: [ - 'https://github.com/foo/bar', - 'https://github.com/renovatebot/', - ], - x: 1, - }, - ], - }; - const dep = { - depType: 'dependencies', - packageName: 'a', - updateType: 'patch' as UpdateType, - }; - const res = applyPackageRules({ ...config, ...dep }); - expect(res.x).toBeUndefined(); - }); - describe('matchConfidence', () => { const hostRule: HostRule = { hostType: 'merge-confidence', @@ -1072,12 +975,12 @@ describe('util/package-rules/index', () => { packageName: 'foo', packageRules: [ { - matchPackagePatterns: ['*'], + matchPackageNames: ['*'], groupName: 'A', groupSlug: 'a', }, { - matchPackagePatterns: ['*'], + matchPackageNames: ['*'], groupName: 'B', }, ], @@ -1086,13 +989,13 @@ describe('util/package-rules/index', () => { expect(res.groupSlug).toBe('b'); }); - it('matches matchSourceUrlPrefixes(case-insensitive)', () => { + it('matches matchSourceUrls with patterns (case-insensitive)', () => { const config: TestConfig = { packageRules: [ { - matchSourceUrlPrefixes: [ - 'https://github.com/foo/bar', - 'https://github.com/Renovatebot/', + matchSourceUrls: [ + 'https://github.com/foo/bar**', + 'https://github.com/Renovatebot/**', ], x: 1, }, @@ -1205,123 +1108,20 @@ describe('util/package-rules/index', () => { expect(res2.x).toBeUndefined(); }); - it('matches excludeDepNames(depName)', () => { + it('matches if there are no matchers', () => { const config: TestConfig = { packageRules: [ { - excludeDepNames: ['test1'], x: 1, }, ], }; - const res1 = applyPackageRules({ - ...config, - depName: 'test1', - }); - const res2 = applyPackageRules({ + const res = applyPackageRules({ ...config, depName: 'test2', }); - applyPackageRules(config); // coverage - expect(res1.x).toBeUndefined(); - expect(res2.x).toBe(1); - }); - - it('matches matchDepPatterns(depName)', () => { - const config: TestConfig = { - packageRules: [ - { - matchDepPatterns: ['^test$'], - x: 1, - }, - ], - }; - - const res1 = applyPackageRules({ - ...config, - depName: 'test', - }); - const res2 = applyPackageRules({ - ...config, - depName: 'test1', - }); - applyPackageRules(config); // coverage - - expect(res1.x).toBe(1); - expect(res2.x).toBeUndefined(); - }); - - it('matches excludeDepPatterns(depName)', () => { - const config: TestConfig = { - packageRules: [ - { - excludeDepPatterns: ['^test$'], - x: 1, - }, - ], - }; - - const res1 = applyPackageRules({ - ...config, - depName: 'test', - }); - const res2 = applyPackageRules({ - ...config, - depName: 'test1', - }); - applyPackageRules(config); // coverage - - expect(res1.x).toBeUndefined(); - expect(res2.x).toBe(1); - }); - - it('matches matchDepPrefixes(depName)', () => { - const config: TestConfig = { - packageRules: [ - { - matchDepPrefixes: ['abc'], - x: 1, - }, - ], - }; - - const res1 = applyPackageRules({ - ...config, - depName: 'abc1', - }); - const res2 = applyPackageRules({ - ...config, - depName: 'def1', - }); - applyPackageRules(config); // coverage - - expect(res1.x).toBe(1); - expect(res2.x).toBeUndefined(); - }); - - it('matches excludeDepPrefixes(depName)', () => { - const config: TestConfig = { - packageRules: [ - { - excludeDepPrefixes: ['abc'], - x: 1, - }, - ], - }; - - const res1 = applyPackageRules({ - ...config, - depName: 'abc1', - }); - const res2 = applyPackageRules({ - ...config, - depName: 'def1', - }); - applyPackageRules(config); // coverage - - expect(res1.x).toBeUndefined(); - expect(res2.x).toBe(1); + expect(res.x).toBe(1); }); }); diff --git a/lib/util/package-rules/index.ts b/lib/util/package-rules/index.ts index f625ea5b24462f..dd6c54ba9194cf 100644 --- a/lib/util/package-rules/index.ts +++ b/lib/util/package-rules/index.ts @@ -4,60 +4,25 @@ import { mergeChildConfig } from '../../config'; import type { PackageRule, PackageRuleInputConfig } from '../../config/types'; import { logger } from '../../logger'; import matchers from './matchers'; -import { matcherOR } from './utils'; function matchesRule( inputConfig: PackageRuleInputConfig, packageRule: PackageRule, ): boolean { - let positiveMatch = true; - let matchApplied = false; - // matches - for (const groupMatchers of matchers) { - const isMatch = matcherOR( - 'matches', - groupMatchers, - inputConfig, - packageRule, - ); + for (const matcher of matchers) { + const isMatch = matcher.matches(inputConfig, packageRule); // no rules are defined if (is.nullOrUndefined(isMatch)) { continue; } - matchApplied = true; - if (!is.truthy(isMatch)) { return false; } } - // not a single match rule is defined --> assume to match everything - if (!matchApplied) { - positiveMatch = true; - } - - // excludes - for (const groupExcludes of matchers) { - const isExclude = matcherOR( - 'excludes', - groupExcludes, - inputConfig, - packageRule, - ); - - // no rules are defined - if (is.nullOrUndefined(isExclude)) { - continue; - } - - if (isExclude) { - return false; - } - } - - return positiveMatch; + return true; } export function applyPackageRules( diff --git a/lib/util/package-rules/matchers.ts b/lib/util/package-rules/matchers.ts index 61f68973c9ae54..9ad89afe0a92aa 100644 --- a/lib/util/package-rules/matchers.ts +++ b/lib/util/package-rules/matchers.ts @@ -5,23 +5,18 @@ import { CurrentValueMatcher } from './current-value'; import { CurrentVersionMatcher } from './current-version'; import { DatasourcesMatcher } from './datasources'; import { DepNameMatcher } from './dep-names'; -import { DepPatternsMatcher } from './dep-patterns'; -import { DepPrefixesMatcher } from './dep-prefixes'; import { DepTypesMatcher } from './dep-types'; import { FileNamesMatcher } from './files'; import { ManagersMatcher } from './managers'; import { MergeConfidenceMatcher } from './merge-confidence'; import { NewValueMatcher } from './new-value'; import { PackageNameMatcher } from './package-names'; -import { PackagePatternsMatcher } from './package-patterns'; -import { PackagePrefixesMatcher } from './package-prefixes'; import { RepositoriesMatcher } from './repositories'; -import { SourceUrlPrefixesMatcher } from './sourceurl-prefixes'; import { SourceUrlsMatcher } from './sourceurls'; import type { MatcherApi } from './types'; import { UpdateTypesMatcher } from './update-types'; -const matchers: MatcherApi[][] = []; +const matchers: MatcherApi[] = []; export default matchers; // Each matcher under the same index will use a logical OR, if multiple matchers are applied AND will be used @@ -29,25 +24,19 @@ export default matchers; // applyPackageRules evaluates matchers in the order of insertion and returns early on failure. // Therefore, when multiple matchers are set in a single packageRule, some may not be checked. // Since matchConfidence matcher can abort the run due to unauthenticated use, it should be evaluated first. -matchers.push([new MergeConfidenceMatcher()]); -matchers.push([new RepositoriesMatcher()]); -matchers.push([new BaseBranchesMatcher()]); -matchers.push([new CategoriesMatcher()]); -matchers.push([new ManagersMatcher()]); -matchers.push([new FileNamesMatcher()]); -matchers.push([new DatasourcesMatcher()]); -matchers.push([ - new DepNameMatcher(), - new DepPatternsMatcher(), - new DepPrefixesMatcher(), - new PackageNameMatcher(), - new PackagePatternsMatcher(), - new PackagePrefixesMatcher(), -]); -matchers.push([new DepTypesMatcher()]); -matchers.push([new CurrentValueMatcher()]); -matchers.push([new CurrentVersionMatcher()]); -matchers.push([new UpdateTypesMatcher()]); -matchers.push([new SourceUrlsMatcher(), new SourceUrlPrefixesMatcher()]); -matchers.push([new NewValueMatcher()]); -matchers.push([new CurrentAgeMatcher()]); +matchers.push(new MergeConfidenceMatcher()); +matchers.push(new RepositoriesMatcher()); +matchers.push(new BaseBranchesMatcher()); +matchers.push(new CategoriesMatcher()); +matchers.push(new ManagersMatcher()); +matchers.push(new FileNamesMatcher()); +matchers.push(new DatasourcesMatcher()); +matchers.push(new PackageNameMatcher()); +matchers.push(new DepNameMatcher()); +matchers.push(new DepTypesMatcher()); +matchers.push(new CurrentValueMatcher()); +matchers.push(new CurrentVersionMatcher()); +matchers.push(new UpdateTypesMatcher()); +matchers.push(new SourceUrlsMatcher()); +matchers.push(new NewValueMatcher()); +matchers.push(new CurrentAgeMatcher()); diff --git a/lib/util/package-rules/matchers.ts.orig b/lib/util/package-rules/matchers.ts.orig new file mode 100644 index 00000000000000..cab1058e1d2b14 --- /dev/null +++ b/lib/util/package-rules/matchers.ts.orig @@ -0,0 +1,67 @@ +import { BaseBranchesMatcher } from './base-branches'; +import { CategoriesMatcher } from './categories'; +import { CurrentAgeMatcher } from './current-age'; +import { CurrentValueMatcher } from './current-value'; +import { CurrentVersionMatcher } from './current-version'; +import { DatasourcesMatcher } from './datasources'; +import { DepNameMatcher } from './dep-names'; +import { DepTypesMatcher } from './dep-types'; +import { FileNamesMatcher } from './files'; +import { ManagersMatcher } from './managers'; +import { MergeConfidenceMatcher } from './merge-confidence'; +import { NewValueMatcher } from './new-value'; +import { PackageNameMatcher } from './package-names'; +import { RepositoriesMatcher } from './repositories'; +import { SourceUrlsMatcher } from './sourceurls'; +import type { MatcherApi } from './types'; +import { UpdateTypesMatcher } from './update-types'; + +const matchers: MatcherApi[] = []; +export default matchers; + +// Each matcher under the same index will use a logical OR, if multiple matchers are applied AND will be used + +// applyPackageRules evaluates matchers in the order of insertion and returns early on failure. +// Therefore, when multiple matchers are set in a single packageRule, some may not be checked. +// Since matchConfidence matcher can abort the run due to unauthenticated use, it should be evaluated first. +<<<<<<< HEAD +matchers.push([new MergeConfidenceMatcher()]); +matchers.push([new RepositoriesMatcher()]); +matchers.push([new BaseBranchesMatcher()]); +matchers.push([new CategoriesMatcher()]); +matchers.push([new ManagersMatcher()]); +matchers.push([new FileNamesMatcher()]); +matchers.push([new DatasourcesMatcher()]); +matchers.push([ + new DepNameMatcher(), + new DepPatternsMatcher(), + new DepPrefixesMatcher(), + new PackageNameMatcher(), + new PackagePatternsMatcher(), + new PackagePrefixesMatcher(), +]); +matchers.push([new DepTypesMatcher()]); +matchers.push([new CurrentValueMatcher()]); +matchers.push([new CurrentVersionMatcher()]); +matchers.push([new UpdateTypesMatcher()]); +matchers.push([new SourceUrlsMatcher(), new SourceUrlPrefixesMatcher()]); +matchers.push([new NewValueMatcher()]); +matchers.push([new CurrentAgeMatcher()]); +======= +matchers.push(new MergeConfidenceMatcher()); +matchers.push(new DepNameMatcher()); +matchers.push(new PackageNameMatcher()); +matchers.push(new FileNamesMatcher()); +matchers.push(new DepTypesMatcher()); +matchers.push(new BaseBranchesMatcher()); +matchers.push(new ManagersMatcher()); +matchers.push(new DatasourcesMatcher()); +matchers.push(new UpdateTypesMatcher()); +matchers.push(new SourceUrlsMatcher()); +matchers.push(new CurrentValueMatcher()); +matchers.push(new NewValueMatcher()); +matchers.push(new CurrentVersionMatcher()); +matchers.push(new RepositoriesMatcher()); +matchers.push(new CategoriesMatcher()); +matchers.push(new CurrentAgeMatcher()); +>>>>>>> b66597a89 (feat(packageRules): migrate matchers and excludes (#28602)) diff --git a/lib/util/package-rules/package-names.spec.ts b/lib/util/package-rules/package-names.spec.ts index aa6d8035b79820..47fd4fcdfa20fb 100644 --- a/lib/util/package-rules/package-names.spec.ts +++ b/lib/util/package-rules/package-names.spec.ts @@ -40,28 +40,14 @@ describe('util/package-rules/package-names', () => { ); expect(result).toBeTrue(); }); - }); - describe('exclude', () => { - it('should return false if packageName is not defined', () => { - const result = packageNameMatcher.excludes( - { - packageName: undefined, - }, - { - excludePackageNames: ['@opentelemetry/http'], - }, - ); - expect(result).toBeFalse(); - }); - - it('should excludePackageName', () => { - const result = packageNameMatcher.excludes( + it('should match pattern', () => { + const result = packageNameMatcher.matches( { - packageName: 'def', + packageName: 'b', }, { - excludePackageNames: ['def'], + matchPackageNames: ['/b/'], }, ); expect(result).toBeTrue(); diff --git a/lib/util/package-rules/package-names.ts b/lib/util/package-rules/package-names.ts index fe21b0b8b84165..9586fb5caa5fbe 100644 --- a/lib/util/package-rules/package-names.ts +++ b/lib/util/package-rules/package-names.ts @@ -17,18 +17,4 @@ export class PackageNameMatcher extends Matcher { } return matchRegexOrGlobList(packageName, matchPackageNames); } - - override excludes( - { packageName }: PackageRuleInputConfig, - packageRule: PackageRule, - ): boolean | null { - const { excludePackageNames } = packageRule; - if (is.undefined(excludePackageNames)) { - return null; - } - if (!packageName) { - return false; - } - return matchRegexOrGlobList(packageName, excludePackageNames); - } } diff --git a/lib/util/package-rules/package-patterns.spec.ts b/lib/util/package-rules/package-patterns.spec.ts deleted file mode 100644 index 684d2bfd6b8009..00000000000000 --- a/lib/util/package-rules/package-patterns.spec.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { PackagePatternsMatcher } from './package-patterns'; - -describe('util/package-rules/package-patterns', () => { - const packagePatternsMatcher = new PackagePatternsMatcher(); - - describe('match', () => { - it('should return false if packageName is not defined', () => { - const result = packagePatternsMatcher.matches( - { - packageName: undefined, - }, - { - matchPackagePatterns: ['@opentelemetry/http'], - }, - ); - expect(result).toBeFalse(); - }); - - it('should match packageName', () => { - const result = packagePatternsMatcher.matches( - { - packageName: 'def', - }, - { - matchPackagePatterns: ['def'], - }, - ); - expect(result).toBeTrue(); - }); - - it('should not fall back to matching depName', () => { - const result = packagePatternsMatcher.matches( - { - depName: 'abc', - packageName: 'def', - }, - { - matchPackagePatterns: ['abc'], - }, - ); - expect(result).toBeFalse(); - }); - }); - - describe('exclude', () => { - it('should exclude packageName', () => { - const result = packagePatternsMatcher.excludes( - { - packageName: 'def', - }, - { - excludePackagePatterns: ['def'], - }, - ); - expect(result).toBeTrue(); - }); - }); -}); diff --git a/lib/util/package-rules/package-patterns.ts b/lib/util/package-rules/package-patterns.ts deleted file mode 100644 index 8ca7ebdfab611c..00000000000000 --- a/lib/util/package-rules/package-patterns.ts +++ /dev/null @@ -1,44 +0,0 @@ -import is from '@sindresorhus/is'; -import type { PackageRule, PackageRuleInputConfig } from '../../config/types'; -import { matchRegexOrGlobList } from '../string-match'; -import { Matcher } from './base'; - -export class PackagePatternsMatcher extends Matcher { - override matches( - { packageName }: PackageRuleInputConfig, - packageRule: PackageRule, - ): boolean | null { - const { matchPackagePatterns } = packageRule; - if (is.undefined(matchPackagePatterns)) { - return null; - } - - if (!packageName) { - return false; - } - - const massagedPatterns = matchPackagePatterns.map((pattern) => - pattern === '^*$' || pattern === '*' ? '*' : `/${pattern}/`, - ); - return matchRegexOrGlobList(packageName, massagedPatterns); - } - - override excludes( - { packageName }: PackageRuleInputConfig, - packageRule: PackageRule, - ): boolean | null { - const { excludePackagePatterns } = packageRule; - // ignore lockFileMaintenance for backwards compatibility - if (is.undefined(excludePackagePatterns)) { - return null; - } - if (!packageName) { - return false; - } - - const massagedPatterns = excludePackagePatterns.map((pattern) => - pattern === '^*$' || pattern === '*' ? '*' : `/${pattern}/`, - ); - return matchRegexOrGlobList(packageName, massagedPatterns); - } -} diff --git a/lib/util/package-rules/package-prefixes.spec.ts b/lib/util/package-rules/package-prefixes.spec.ts deleted file mode 100644 index 3fc7c6edc4bf54..00000000000000 --- a/lib/util/package-rules/package-prefixes.spec.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { PackagePrefixesMatcher } from './package-prefixes'; - -describe('util/package-rules/package-prefixes', () => { - const packagePrefixesMatcher = new PackagePrefixesMatcher(); - - describe('match', () => { - it('should return false if packageName is not defined', () => { - const result = packagePrefixesMatcher.matches( - { - packageName: undefined, - }, - { - matchPackagePrefixes: ['@opentelemetry'], - }, - ); - expect(result).toBeFalse(); - }); - - it('should return true if packageName matched', () => { - const result = packagePrefixesMatcher.matches( - { - packageName: 'def1', - }, - { - matchPackagePrefixes: ['def'], - }, - ); - expect(result).toBeTrue(); - }); - }); - - describe('exclude', () => { - it('should return false if packageName is not defined', () => { - const result = packagePrefixesMatcher.excludes( - { - packageName: undefined, - }, - { - excludePackagePrefixes: ['@opentelemetry'], - }, - ); - expect(result).toBeFalse(); - }); - - it('should return true if packageName matched', () => { - const result = packagePrefixesMatcher.excludes( - { - packageName: 'def1', - }, - { - excludePackagePrefixes: ['def'], - }, - ); - expect(result).toBeTrue(); - }); - }); -}); diff --git a/lib/util/package-rules/package-prefixes.ts b/lib/util/package-rules/package-prefixes.ts deleted file mode 100644 index ff83d94059ba97..00000000000000 --- a/lib/util/package-rules/package-prefixes.ts +++ /dev/null @@ -1,42 +0,0 @@ -import is from '@sindresorhus/is'; -import type { PackageRule, PackageRuleInputConfig } from '../../config/types'; -import { matchRegexOrGlobList } from '../string-match'; -import { Matcher } from './base'; - -export class PackagePrefixesMatcher extends Matcher { - override matches( - { packageName }: PackageRuleInputConfig, - { matchPackagePrefixes }: PackageRule, - ): boolean | null { - if (is.undefined(matchPackagePrefixes)) { - return null; - } - - if (!packageName) { - return false; - } - - const massagedPatterns = matchPackagePrefixes.map( - (pattern) => `${pattern}**`, - ); - return matchRegexOrGlobList(packageName, massagedPatterns); - } - - override excludes( - { packageName }: PackageRuleInputConfig, - packageRule: PackageRule, - ): boolean | null { - const { excludePackagePrefixes } = packageRule; - if (is.undefined(excludePackagePrefixes)) { - return null; - } - if (!packageName) { - return false; - } - - const massagedPatterns = excludePackagePrefixes.map( - (pattern) => `${pattern}**`, - ); - return matchRegexOrGlobList(packageName, massagedPatterns); - } -} diff --git a/lib/util/package-rules/repositories.spec.ts b/lib/util/package-rules/repositories.spec.ts index 369927de30b157..73b93cf06e1bbb 100644 --- a/lib/util/package-rules/repositories.spec.ts +++ b/lib/util/package-rules/repositories.spec.ts @@ -102,100 +102,88 @@ describe('util/package-rules/repositories', () => { }); describe('excludes', () => { - it('should return null if exclude repositories is not defined', () => { - const result = repositoryMatcher.excludes( - { - repository: 'org/repo', - }, - { - excludeRepositories: undefined, - }, - ); - expect(result).toBeNull(); - }); - it('should return false if exclude repository is not defined', () => { - const result = repositoryMatcher.excludes( + const result = repositoryMatcher.matches( { repository: undefined, }, { - excludeRepositories: ['org/repo'], + matchRepositories: ['!org/repo'], }, ); expect(result).toBeFalse(); }); - it('should return true if exclude repository matches regex pattern', () => { - const result = repositoryMatcher.excludes( + it('should return false if exclude repository matches regex pattern', () => { + const result = repositoryMatcher.matches( { repository: 'org/repo', }, { - excludeRepositories: ['/^org/repo$/'], + matchRepositories: ['!/^org/repo$/'], }, ); - expect(result).toBeTrue(); + expect(result).toBeFalse(); }); - it('should return false if exclude repository has invalid regex pattern', () => { - const result = repositoryMatcher.excludes( + it('should return true if exclude repository has invalid regex pattern', () => { + const result = repositoryMatcher.matches( { repository: 'org/repo', }, { - excludeRepositories: ['/[/'], + matchRepositories: ['!/[/'], }, ); - expect(result).toBeFalse(); + expect(result).toBeTrue(); }); - it('should return false if exclude repository does not match regex pattern', () => { - const result = repositoryMatcher.excludes( + it('should return true if exclude repository does not match regex pattern', () => { + const result = repositoryMatcher.matches( { repository: 'org/repo', }, { - excludeRepositories: ['/^org/other-repo$/'], + matchRepositories: ['!/^org/other-repo$/'], }, ); - expect(result).toBeFalse(); + expect(result).toBeTrue(); }); - it('should return true if exclude repository matches minimatch pattern', () => { - const result = repositoryMatcher.excludes( + it('should return false if exclude repository matches minimatch pattern', () => { + const result = repositoryMatcher.matches( { repository: 'org/repo', }, { - excludeRepositories: ['org/**'], + matchRepositories: ['!org/**'], }, ); - expect(result).toBeTrue(); + expect(result).toBeFalse(); }); - it('should return false if exclude repository does not match minimatch pattern', () => { - const result = repositoryMatcher.excludes( + it('should return true if exclude repository does not match minimatch pattern', () => { + const result = repositoryMatcher.matches( { repository: 'org/repo', }, { - excludeRepositories: ['other-org/**'], + matchRepositories: ['!other-org/**'], }, ); - expect(result).toBeFalse(); + expect(result).toBeTrue(); }); - it('should return true if exclude repository matches at least one pattern', () => { - const result = repositoryMatcher.excludes( + it('should return false if exclude repository matches at least one pattern', () => { + const result = repositoryMatcher.matches( { repository: 'org/repo-archived', }, { - excludeRepositories: ['/^org/repo$/', '**/*-archived'], + matchRepositories: ['!/^org/repo$/', '!**/*-archived'], }, ); - expect(result).toBeTrue(); + expect(result).toBeFalse(); }); }); }); diff --git a/lib/util/package-rules/repositories.ts b/lib/util/package-rules/repositories.ts index bc3c45ac8fb43c..9e47c0c475f95d 100644 --- a/lib/util/package-rules/repositories.ts +++ b/lib/util/package-rules/repositories.ts @@ -18,19 +18,4 @@ export class RepositoriesMatcher extends Matcher { return matchRegexOrGlobList(repository, matchRepositories); } - - override excludes( - { repository }: PackageRuleInputConfig, - { excludeRepositories }: PackageRule, - ): boolean | null { - if (is.undefined(excludeRepositories)) { - return null; - } - - if (is.undefined(repository)) { - return false; - } - - return matchRegexOrGlobList(repository, excludeRepositories); - } } diff --git a/lib/util/package-rules/sourceurl-prefixes.ts b/lib/util/package-rules/sourceurl-prefixes.ts deleted file mode 100644 index 13d6d4801cb9d7..00000000000000 --- a/lib/util/package-rules/sourceurl-prefixes.ts +++ /dev/null @@ -1,22 +0,0 @@ -import is from '@sindresorhus/is'; -import type { PackageRule, PackageRuleInputConfig } from '../../config/types'; -import { Matcher } from './base'; - -export class SourceUrlPrefixesMatcher extends Matcher { - override matches( - { sourceUrl }: PackageRuleInputConfig, - { matchSourceUrlPrefixes }: PackageRule, - ): boolean | null { - if (is.undefined(matchSourceUrlPrefixes)) { - return null; - } - if (is.undefined(sourceUrl)) { - return false; - } - const upperCaseSourceUrl = sourceUrl?.toUpperCase(); - - return matchSourceUrlPrefixes.some((prefix) => - upperCaseSourceUrl?.startsWith(prefix.toUpperCase()), - ); - } -} diff --git a/lib/util/package-rules/types.ts b/lib/util/package-rules/types.ts index 0307f2e82d6b36..938232b86aa6d4 100644 --- a/lib/util/package-rules/types.ts +++ b/lib/util/package-rules/types.ts @@ -7,8 +7,4 @@ export interface MatcherApi { inputConfig: PackageRuleInputConfig, packageRule: PackageRule, ): boolean | null; - excludes( - inputConfig: PackageRuleInputConfig, - packageRule: PackageRule, - ): boolean | null; } diff --git a/lib/util/package-rules/utils.ts b/lib/util/package-rules/utils.ts deleted file mode 100644 index 2fd138eb1a046e..00000000000000 --- a/lib/util/package-rules/utils.ts +++ /dev/null @@ -1,35 +0,0 @@ -import is from '@sindresorhus/is'; -import type { PackageRule, PackageRuleInputConfig } from '../../config/types'; -import type { MatchType, MatcherApi } from './types'; - -export function matcherOR( - matchType: MatchType, - groupMatchers: MatcherApi[], - inputConfig: PackageRuleInputConfig, - packageRule: PackageRule, -): boolean | null { - let matchApplied = false; - for (const matcher of groupMatchers) { - let isMatch; - switch (matchType) { - case 'excludes': - isMatch = matcher.excludes(inputConfig, packageRule); - break; - case 'matches': - isMatch = matcher.matches(inputConfig, packageRule); - break; - } - - // no rules are defined - if (is.nullOrUndefined(isMatch)) { - continue; - } - - matchApplied = true; - - if (is.truthy(isMatch)) { - return true; - } - } - return matchApplied ? false : null; -} diff --git a/lib/workers/repository/process/lookup/index.spec.ts b/lib/workers/repository/process/lookup/index.spec.ts index a2aacf36f70911..3c67849975f522 100644 --- a/lib/workers/repository/process/lookup/index.spec.ts +++ b/lib/workers/repository/process/lookup/index.spec.ts @@ -4071,7 +4071,7 @@ describe('workers/repository/process/lookup/index', () => { config.datasource = NpmDatasource.id; config.packageRules = [ { - matchSourceUrlPrefixes: ['https://github.com/kriskowal/q'], + matchSourceUrls: ['https://github.com/kriskowal/**'], allowedVersions: '< 1.4.0', }, ];