From 41999b1ff7193660c678e7558441e0f40412d5cb Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 7 Apr 2026 06:31:12 +0000 Subject: [PATCH 01/13] build(deps): update dependency re2 to v1.24.0 (main) (#42410) build(deps): update dependency re2 to v1.24.0 | datasource | package | from | to | | ---------- | ------- | ------ | ------ | | npm | re2 | 1.23.3 | 1.24.0 | Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 26bb4cc7c1a..ff84cb14cb5 100644 --- a/package.json +++ b/package.json @@ -275,7 +275,7 @@ "optionalDependencies": { "better-sqlite3": "12.8.0", "openpgp": "6.3.0", - "re2": "1.23.3" + "re2": "1.24.0" }, "devDependencies": { "@biomejs/biome": "2.4.6", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6e2e7071cee..b1cc07e06c6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -620,8 +620,8 @@ importers: specifier: 6.3.0 version: 6.3.0 re2: - specifier: 1.23.3 - version: 1.23.3 + specifier: 1.24.0 + version: 1.24.0 packages: @@ -5368,8 +5368,8 @@ packages: resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} hasBin: true - re2@1.23.3: - resolution: {integrity: sha512-5jh686rmj/8dYpBo72XYgwzgG8Y9HNDATYZ1x01gqZ6FvXVUP33VZ0+6GLCeavaNywz3OkXBU8iNX7LjiuisPg==} + re2@1.24.0: + resolution: {integrity: sha512-pBm6cMaOb0Yb0kg0Sfw/k4LwDMkPScb/NVd7GrEllDwfsPZstsZIo93A6Nn0wZuWJw3h57GdzkrOk81EofKY/g==} react-is@18.3.1: resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} @@ -11946,7 +11946,7 @@ snapshots: minimist: 1.2.8 strip-json-comments: 2.0.1 - re2@1.23.3: + re2@1.24.0: dependencies: install-artifact-from-github: 1.4.0 nan: 2.26.2 From 4d04f66a2bf34d1d4ac85056068821dd4e38ca71 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 7 Apr 2026 07:02:59 +0000 Subject: [PATCH 02/13] build(deps): update dependency jsonc-weaver to v0.2.4 (main) (#42411) build(deps): update dependency jsonc-weaver to v0.2.4 | datasource | package | from | to | | ---------- | ------------ | ----- | ----- | | npm | jsonc-weaver | 0.2.2 | 0.2.4 | Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index ff84cb14cb5..031e8742b91 100644 --- a/package.json +++ b/package.json @@ -232,7 +232,7 @@ "json-stringify-pretty-compact": "4.0.0", "json5": "2.2.3", "jsonata": "2.1.0", - "jsonc-weaver": "0.2.2", + "jsonc-weaver": "0.2.4", "klona": "2.0.6", "luxon": "3.7.2", "markdown-it": "14.1.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b1cc07e06c6..f21b254d72f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -246,8 +246,8 @@ importers: specifier: 2.1.0 version: 2.1.0 jsonc-weaver: - specifier: 0.2.2 - version: 0.2.2 + specifier: 0.2.4 + version: 0.2.4 klona: specifier: 2.0.6 version: 2.0.6 @@ -4308,14 +4308,14 @@ packages: resolution: {integrity: sha512-OCzaRMK8HobtX8fp37uIVmL8CY1IGc/a6gLsDqz3quExFR09/U78HUzWYr7T31UEB6+Eu0/8dkVD5fFDOl9a8w==} engines: {node: '>= 8'} - jsonc-morph@0.3.2: - resolution: {integrity: sha512-FmHfnQ3OMs/+HosrGV8RHwerWXjTaco0hvBhn8+hP0gux06Jylynct4H0P+sjsK3QXRvN5zlq+SJxvXgfu8JfQ==} + jsonc-morph@0.3.3: + resolution: {integrity: sha512-YljoHRXfZacx4utaktqGlz8p9xJJaV12WxciEpf4+g+8jVk0QNmxpxStkXVwjTnJZr9EAK4TT5TzdCO5M2i7rw==} jsonc-parser@3.3.1: resolution: {integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==} - jsonc-weaver@0.2.2: - resolution: {integrity: sha512-fDO1+8cpEFGlw42kvEqh/HAnXd47Lv19mWQaR30p2k6wOwfL4Dx/B2f8reaQepBc1aupBIOTwWmhThFUgv9zLQ==} + jsonc-weaver@0.2.4: + resolution: {integrity: sha512-aIKK8SOg+TdBdeML4MB++phUEdS7KWZxuaPPjxUSat8Kc/2A+2AoxmAGhvbVajNjqsgSX4dhjfCJq3QlE/NSCg==} jsonfile@6.2.0: resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==} @@ -10701,13 +10701,13 @@ snapshots: jsonata@2.1.0: {} - jsonc-morph@0.3.2: {} + jsonc-morph@0.3.3: {} jsonc-parser@3.3.1: {} - jsonc-weaver@0.2.2: + jsonc-weaver@0.2.4: dependencies: - jsonc-morph: 0.3.2 + jsonc-morph: 0.3.3 jsonfile@6.2.0: dependencies: From 83a55c2c2b1ad0629552ab392df28643c750acc8 Mon Sep 17 00:00:00 2001 From: mikaello <2505178+mikaello@users.noreply.github.com> Date: Tue, 7 Apr 2026 09:57:32 +0200 Subject: [PATCH 03/13] fix(presets): add java-jdk to LTS workaround (#42407) fix(java): add java-jdk to LTS workaround --- lib/config/presets/internal/workarounds.preset.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/config/presets/internal/workarounds.preset.ts b/lib/config/presets/internal/workarounds.preset.ts index 12afee3ce43..95c3dd565fb 100644 --- a/lib/config/presets/internal/workarounds.preset.ts +++ b/lib/config/presets/internal/workarounds.preset.ts @@ -165,6 +165,7 @@ export const presets: Record = { 'adoptopenjdk', 'openjdk', 'java', + 'java-jdk', 'java-jre', 'sapmachine', '/^azul/zulu-openjdk/', From 7303b248caaeb810850c3d4b670851461d4f388c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 7 Apr 2026 08:06:46 +0000 Subject: [PATCH 04/13] chore(deps): update ghcr.io/containerbase/devcontainer docker tag to v14.6.15 (main) (#42412) chore(deps): update ghcr.io/containerbase/devcontainer docker tag to v14.6.15 | datasource | package | from | to | | ---------- | ---------------------------------- | ------- | ------- | | docker | ghcr.io/containerbase/devcontainer | 14.6.14 | 14.6.15 | Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .devcontainer/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index ac932fb1fe1..c745db122b9 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1 +1 @@ -FROM ghcr.io/containerbase/devcontainer:14.6.14 +FROM ghcr.io/containerbase/devcontainer:14.6.15 From 1a05f1a39c2fe617a7d5a6fa2992f5c69044786f Mon Sep 17 00:00:00 2001 From: Sergei Zharinov Date: Tue, 7 Apr 2026 05:09:57 -0300 Subject: [PATCH 05/13] refactor(lint): extract custom oxlint rules into separate files (#42388) Split `tools/lint/rules.js` into one file per rule under `tools/lint/rules/`. Also simplify `test-root-describe` with early-exit guard clauses. --- package.json | 1 + pnpm-lock.yaml | 3 + tools/lint/rules.js | 77 ++------------------------ tools/lint/rules/no-tools-import.js | 48 ++++++++++++++++ tools/lint/rules/test-root-describe.js | 53 ++++++++++++++++++ 5 files changed, 109 insertions(+), 73 deletions(-) create mode 100644 tools/lint/rules/no-tools-import.js create mode 100644 tools/lint/rules/test-root-describe.js diff --git a/package.json b/package.json index 031e8742b91..0dfc4aeedb4 100644 --- a/package.json +++ b/package.json @@ -298,6 +298,7 @@ "@types/clean-git-ref": "2.0.2", "@types/common-tags": "1.8.4", "@types/eslint-config-prettier": "6.11.3", + "@types/estree": "1.0.8", "@types/fs-extra": "11.0.4", "@types/github-url-from-git": "1.5.3", "@types/global-agent": "3.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f21b254d72f..8ed69c580de 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -423,6 +423,9 @@ importers: '@types/eslint-config-prettier': specifier: 6.11.3 version: 6.11.3 + '@types/estree': + specifier: 1.0.8 + version: 1.0.8 '@types/fs-extra': specifier: 11.0.4 version: 11.0.4 diff --git a/tools/lint/rules.js b/tools/lint/rules.js index ec95499e029..ae1cf1763e0 100644 --- a/tools/lint/rules.js +++ b/tools/lint/rules.js @@ -1,5 +1,5 @@ -const CWD = process.cwd(); -const TOOLS_IMPORT_PATTERN = /(?:^|\/|\.\.\/)tools\//; +import noToolsImport from './rules/no-tools-import.js'; +import testRootDescribe from './rules/test-root-describe.js'; /** @type {import('eslint').ESLint.Plugin} */ export default { @@ -7,76 +7,7 @@ export default { name: 'renovate', }, rules: { - 'no-tools-import': { - meta: { - type: 'problem', - messages: { - noToolsImport: 'Importing from tools/ is not allowed in lib/', - }, - }, - create(context) { - const filename = context.filename ?? context.physicalFilename ?? ''; - if (!filename.includes('/lib/')) { - return {}; - } - return { - ImportDeclaration(node) { - if (TOOLS_IMPORT_PATTERN.test(node.source.value)) { - context.report({ node: node.source, messageId: 'noToolsImport' }); - } - }, - }; - }, - }, - 'test-root-describe': { - meta: { - fixable: 'code', - }, - create(context) { - const absoluteFileName = context.filename; - if (!absoluteFileName.endsWith('.spec.ts')) { - return {}; - } - const relativeFileName = absoluteFileName - .replace(CWD, '') - .replace(/\\/g, '/') - .replace(/^(?:\/(?:lib|src|test))?\//, ''); - const testName = relativeFileName.replace(/\.spec\.ts$/, ''); - return { - CallExpression(node) { - const { callee } = node; - if ( - callee.type === 'Identifier' && - callee.name === 'describe' && - node.parent.parent.type === 'Program' - ) { - const [descr] = node.arguments; - - if (!descr) { - context.report({ - node, - message: 'Test root describe must have arguments', - }); - return; - } - - const isOkay = - descr.type === 'Literal' && - typeof descr.value === 'string' && - testName === descr.value; - if (!isOkay) { - context.report({ - node: descr, - message: `Test must be described by this string: '${testName}'`, - fix(fixer) { - return fixer.replaceText(descr, `'${testName}'`); - }, - }); - } - } - }, - }; - }, - }, + 'no-tools-import': noToolsImport, + 'test-root-describe': testRootDescribe, }, }; diff --git a/tools/lint/rules/no-tools-import.js b/tools/lint/rules/no-tools-import.js new file mode 100644 index 00000000000..e6d523f1d39 --- /dev/null +++ b/tools/lint/rules/no-tools-import.js @@ -0,0 +1,48 @@ +const TOOLS_IMPORT_PATTERN = /(?:^|\/|\.\.\/)tools\//; + +/** + * @param {import('eslint').Rule.RuleContext} context + * @param {import('estree').Literal} source + */ +function check(context, source) { + if ( + typeof source.value === 'string' && + TOOLS_IMPORT_PATTERN.test(source.value) + ) { + context.report({ node: source, messageId: 'noToolsImport' }); + } +} + +/** @type {import('eslint').Rule.RuleModule} */ +export default { + meta: { + type: 'problem', + messages: { + noToolsImport: 'Importing from tools/ is not allowed in lib/', + }, + }, + create(context) { + const filename = context.filename ?? context.physicalFilename ?? ''; + if (!filename.includes('/lib/')) { + return {}; + } + return { + ImportDeclaration(node) { + check(context, node.source); + }, + ExportNamedDeclaration(node) { + if (node.source) { + check(context, node.source); + } + }, + ExportAllDeclaration(node) { + check(context, node.source); + }, + ImportExpression(node) { + if (node.source.type === 'Literal') { + check(context, node.source); + } + }, + }; + }, +}; diff --git a/tools/lint/rules/test-root-describe.js b/tools/lint/rules/test-root-describe.js new file mode 100644 index 00000000000..3d2f19f9da9 --- /dev/null +++ b/tools/lint/rules/test-root-describe.js @@ -0,0 +1,53 @@ +/** @type {import('eslint').Rule.RuleModule} */ +export default { + meta: { + fixable: 'code', + }, + create(context) { + const absoluteFileName = context.filename; + if (!absoluteFileName.endsWith('.spec.ts')) { + return {}; + } + const relativeFileName = absoluteFileName + .replace(context.cwd, '') + .replace(/\\/g, '/') + .replace(/^(?:\/(?:lib|src|test))?\//, ''); + const testName = relativeFileName.replace(/\.spec\.ts$/, ''); + return { + CallExpression(node) { + const { callee } = node; + if (callee.type !== 'Identifier' || callee.name !== 'describe') { + return; + } + if (node.parent?.parent?.type !== 'Program') { + return; + } + + const [descr] = node.arguments; + if (!descr) { + context.report({ + node, + message: 'Test root describe must have arguments', + }); + return; + } + + if ( + descr.type === 'Literal' && + typeof descr.value === 'string' && + testName === descr.value + ) { + return; + } + + context.report({ + node: descr, + message: `Test must be described by this string: '${testName}'`, + fix(fixer) { + return fixer.replaceText(descr, `'${testName}'`); + }, + }); + }, + }; + }, +}; From 373f42e6a1a5ea11c72584f215d4d5b331f611be Mon Sep 17 00:00:00 2001 From: RahulGautamSingh Date: Tue, 7 Apr 2026 14:51:55 +0545 Subject: [PATCH 06/13] feat(manager): add Apache Ant manager with basic inline version extraction (#42173) * feat(manager): add Apache Ant manager with basic inline version extraction Add new ant package manager that extracts Maven dependencies from Ant build.xml files using the maven-resolver-ant-tasks library. Supports inline version attributes on dependency elements. * fix test * reuse fn * fix lint * fix coverage * apply suggestions * simplify tests * use extractPackageFile and extractPackageFiles * coverage fix * apply sugestions --- lib/modules/manager/ant/extract.spec.ts | 157 ++++++++++++++++++++++++ lib/modules/manager/ant/extract.ts | 125 +++++++++++++++++++ lib/modules/manager/ant/index.ts | 14 +++ lib/modules/manager/ant/readme.md | 2 + lib/modules/manager/api.ts | 2 + 5 files changed, 300 insertions(+) create mode 100644 lib/modules/manager/ant/extract.spec.ts create mode 100644 lib/modules/manager/ant/extract.ts create mode 100644 lib/modules/manager/ant/index.ts create mode 100644 lib/modules/manager/ant/readme.md diff --git a/lib/modules/manager/ant/extract.spec.ts b/lib/modules/manager/ant/extract.spec.ts new file mode 100644 index 00000000000..8ccc5b34e3f --- /dev/null +++ b/lib/modules/manager/ant/extract.spec.ts @@ -0,0 +1,157 @@ +import { codeBlock } from 'common-tags'; +import { fs } from '~test/util.ts'; +import { extractAllPackageFiles, extractPackageFile } from './extract.ts'; + +vi.mock('../../../util/fs/index.ts'); + +describe('modules/manager/ant/extract', () => { + it('extracts inline version dependencies from build.xml', () => { + expect( + extractPackageFile( + codeBlock` + + + + + + `, + 'build.xml', + ), + ).toEqual({ + deps: [ + expect.objectContaining({ + datasource: 'maven', + depName: 'junit:junit', + currentValue: '4.13.2', + depType: 'test', + registryUrls: [], + }), + ], + }); + }); + + it('extracts multiple dependencies', () => { + expect( + extractPackageFile( + codeBlock` + + + + + + + + `, + 'build.xml', + ), + ).toMatchObject({ + deps: [ + expect.objectContaining({ + depName: 'junit:junit', + currentValue: '4.13.2', + depType: 'test', + }), + expect.objectContaining({ + depName: 'org.slf4j:slf4j-api', + currentValue: '1.7.36', + depType: 'compile', + }), + expect.objectContaining({ + depName: 'org.apache.commons:commons-lang3', + currentValue: '3.12.0', + depType: 'runtime', + }), + ], + }); + }); + + it('defaults depType to compile when no scope is set', () => { + expect( + extractPackageFile( + codeBlock` + + + + + + `, + 'build.xml', + ), + ).toEqual({ + deps: [ + expect.objectContaining({ + depName: 'junit:junit', + depType: 'compile', + }), + ], + }); + }); + + it('returns null for invalid XML', () => { + expect(extractPackageFile('<<< not xml >>>', 'build.xml')).toBeNull(); + }); + + it('returns null for build.xml with no dependencies', async () => { + fs.readLocalFile.mockResolvedValue( + '', + ); + + await expect(extractAllPackageFiles({}, ['build.xml'])).resolves.toBeNull(); + }); + + it('ignores dependency nodes without version', () => { + expect( + extractPackageFile( + codeBlock` + + + + + + `, + 'build.xml', + ), + ).toBeNull(); + }); + + it('extracts dependencies with single-quoted attributes', () => { + expect( + extractPackageFile( + "", + 'build.xml', + ), + ).toEqual({ + deps: [ + expect.objectContaining({ + depName: 'junit:junit', + currentValue: '4.13.2', + }), + ], + }); + }); + + it('returns null for unreadable build.xml', async () => { + fs.readLocalFile.mockResolvedValue(null); + + await expect(extractAllPackageFiles({}, ['build.xml'])).resolves.toBeNull(); + }); + + it('does not revisit the same file', async () => { + let readCount = 0; + fs.readLocalFile.mockImplementation(() => { + readCount++; + return Promise.resolve(codeBlock` + + + + + + `); + }); + + const result = await extractAllPackageFiles({}, ['build.xml', 'build.xml']); + + expect(result).toHaveLength(1); + expect(readCount).toBe(1); + }); +}); diff --git a/lib/modules/manager/ant/extract.ts b/lib/modules/manager/ant/extract.ts new file mode 100644 index 00000000000..5c314621a0b --- /dev/null +++ b/lib/modules/manager/ant/extract.ts @@ -0,0 +1,125 @@ +import type { XmlElement } from 'xmldoc'; +import { XmlDocument } from 'xmldoc'; +import { logger } from '../../../logger/index.ts'; +import { readLocalFile } from '../../../util/fs/index.ts'; +import { MavenDatasource } from '../../datasource/maven/index.ts'; +import { isXmlElement } from '../nuget/util.ts'; +import type { + ExtractConfig, + PackageDependency, + PackageFile, + PackageFileContent, +} from '../types.ts'; + +const scopeNames = new Set([ + 'compile', + 'runtime', + 'test', + 'provided', + 'system', +]); + +function getDependencyType(scope: string | undefined): string { + if (scope && scopeNames.has(scope)) { + return scope; + } + return 'compile'; +} + +function collectDependency(node: XmlElement): PackageDependency | null { + const { groupId, artifactId, version, scope } = node.attr; + + if (!version || !groupId || !artifactId) { + return null; + } + + return { + datasource: MavenDatasource.id, + depName: `${groupId}:${artifactId}`, + currentValue: version, + depType: getDependencyType(scope), + registryUrls: [], + }; +} + +function walkNode( + node: XmlElement | XmlDocument, + deps: PackageDependency[], +): void { + for (const child of node.children) { + if (!isXmlElement(child)) { + continue; + } + + if (child.name === 'dependency') { + const dep = collectDependency(child); + if (dep) { + deps.push(dep); + } + } else { + walkNode(child, deps); + } + } +} + +export function extractPackageFile( + content: string, + packageFile: string, +): PackageFileContent | null { + let doc: XmlDocument; + try { + doc = new XmlDocument(content); + } catch { + logger.debug(`ant manager: could not parse XML ${packageFile}`); + return null; + } + + const deps: PackageDependency[] = []; + walkNode(doc, deps); + + if (deps.length === 0) { + return null; + } + + return { deps }; +} + +async function walkXmlFile( + packageFile: string, + visitedFiles: Set, +): Promise { + if (visitedFiles.has(packageFile)) { + return null; + } + visitedFiles.add(packageFile); + + const content = await readLocalFile(packageFile, 'utf8'); + if (!content) { + logger.debug(`ant manager: could not read ${packageFile}`); + return null; + } + + const result = extractPackageFile(content, packageFile); + if (!result) { + return null; + } + + return { packageFile, ...result }; +} + +export async function extractAllPackageFiles( + _config: ExtractConfig, + packageFiles: string[], +): Promise { + const results: PackageFile[] = []; + const visitedFiles = new Set(); + + for (const packageFile of packageFiles) { + const result = await walkXmlFile(packageFile, visitedFiles); + if (result) { + results.push(result); + } + } + + return results.length > 0 ? results : null; +} diff --git a/lib/modules/manager/ant/index.ts b/lib/modules/manager/ant/index.ts new file mode 100644 index 00000000000..697f7efeb17 --- /dev/null +++ b/lib/modules/manager/ant/index.ts @@ -0,0 +1,14 @@ +import type { Category } from '../../../constants/index.ts'; +import { MavenDatasource } from '../../datasource/maven/index.ts'; + +export { extractAllPackageFiles, extractPackageFile } from './extract.ts'; + +export const displayName = 'Apache Ant'; +export const url = 'https://ant.apache.org'; +export const categories: Category[] = ['java']; + +export const defaultConfig = { + managerFilePatterns: ['**/build.xml'], +}; + +export const supportedDatasources = [MavenDatasource.id]; diff --git a/lib/modules/manager/ant/readme.md b/lib/modules/manager/ant/readme.md new file mode 100644 index 00000000000..09fbd672b58 --- /dev/null +++ b/lib/modules/manager/ant/readme.md @@ -0,0 +1,2 @@ +Extracts Apache Ant dependencies from `build.xml` files that use the `maven-resolver-ant-tasks` library. +Dependencies are looked up using the Maven datasource. diff --git a/lib/modules/manager/api.ts b/lib/modules/manager/api.ts index 1343715d32a..78c74496853 100644 --- a/lib/modules/manager/api.ts +++ b/lib/modules/manager/api.ts @@ -1,5 +1,6 @@ import * as ansible from './ansible/index.ts'; import * as ansibleGalaxy from './ansible-galaxy/index.ts'; +import * as ant from './ant/index.ts'; import * as argoCD from './argocd/index.ts'; import * as asdf from './asdf/index.ts'; import * as azurePipelines from './azure-pipelines/index.ts'; @@ -113,6 +114,7 @@ import * as woodpecker from './woodpecker/index.ts'; const api = new Map(); export default api; +api.set('ant', ant); api.set('ansible', ansible); api.set('ansible-galaxy', ansibleGalaxy); api.set('argocd', argoCD); From 6ec2825e7a88984ed7ae2cc23c884df905d17ac8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 7 Apr 2026 09:19:48 +0000 Subject: [PATCH 07/13] fix(deps): update ghcr.io/renovatebot/base-image docker tag to v13.33.10 (main) (#42414) fix(deps): update ghcr.io/renovatebot/base-image docker tag to v13.33.10 | datasource | package | from | to | | ---------- | ------------------------------ | ------- | -------- | | docker | ghcr.io/renovatebot/base-image | 13.33.9 | 13.33.10 | Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- lib/config/options/index.ts | 2 +- tools/docker/Dockerfile | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/config/options/index.ts b/lib/config/options/index.ts index a87705184a1..43e95964b80 100644 --- a/lib/config/options/index.ts +++ b/lib/config/options/index.ts @@ -659,7 +659,7 @@ const options: Readonly[] = [ description: 'Change this value to override the default Renovate sidecar image.', type: 'string', - default: 'ghcr.io/renovatebot/base-image:13.33.9', + default: 'ghcr.io/renovatebot/base-image:13.33.10', globalOnly: true, deprecationMsg: 'The usage of `binarySource=docker` is deprecated, and will be removed in the future', diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile index ea24ac0fdf0..b03a82c833a 100644 --- a/tools/docker/Dockerfile +++ b/tools/docker/Dockerfile @@ -5,19 +5,19 @@ ARG BASE_IMAGE_TYPE=slim # -------------------------------------- # slim image # -------------------------------------- -FROM ghcr.io/renovatebot/base-image:13.33.9@sha256:e828902e2a063fa426fec36266df3258a9074015e0626b65acf5aeac917fb365 AS slim-base +FROM ghcr.io/renovatebot/base-image:13.33.10@sha256:e18520da3439e7b4ed56e9f591b356ebf0b3beef0d62ea200f97696191df7f57 AS slim-base # -------------------------------------- # full image # -------------------------------------- -FROM ghcr.io/renovatebot/base-image:13.33.9-full@sha256:66d3ad6a34dc8cd19d58d5cee1e229f8b312469ff325dc0fa8af6bad1c219f8e AS full-base +FROM ghcr.io/renovatebot/base-image:13.33.10-full@sha256:ee12f2e5e560d181f142c62c36a5adb4138917a8aada60e24cc659b233838b0c AS full-base ENV RENOVATE_BINARY_SOURCE=global # -------------------------------------- # build image # -------------------------------------- -FROM --platform=$BUILDPLATFORM ghcr.io/renovatebot/base-image:13.33.9@sha256:e828902e2a063fa426fec36266df3258a9074015e0626b65acf5aeac917fb365 AS build +FROM --platform=$BUILDPLATFORM ghcr.io/renovatebot/base-image:13.33.10@sha256:e18520da3439e7b4ed56e9f591b356ebf0b3beef0d62ea200f97696191df7f57 AS build # We want a specific node version here # renovate: datasource=github-releases packageName=containerbase/node-prebuild versioning=node From 624d95d1c0977cec53a204a35842028e1057efd8 Mon Sep 17 00:00:00 2001 From: ldt-fweichert <147594401+ldt-fweichert@users.noreply.github.com> Date: Tue, 7 Apr 2026 11:34:35 +0200 Subject: [PATCH 08/13] feat(gradle): add `!!`-notation support for strictly and prefer constraints (#42135) * gradle: add strictly / prefer support * fix tests * improve code coverage * apply suggestions from @Churro * Update lib/modules/versioning/gradle/compare.ts Co-authored-by: RahulGautamSingh * Update lib/modules/versioning/gradle/index.ts Co-authored-by: RahulGautamSingh * fixed pin strategy * ignore pin strategy --------- Co-authored-by: RahulGautamSingh --- lib/modules/manager/gradle/parser.spec.ts | 25 ++++--- lib/modules/manager/gradle/utils.ts | 2 +- lib/modules/versioning/gradle/compare.ts | 82 +++++++++++---------- lib/modules/versioning/gradle/index.spec.ts | 78 ++++++++++---------- lib/modules/versioning/gradle/index.ts | 29 ++++++++ 5 files changed, 124 insertions(+), 92 deletions(-) diff --git a/lib/modules/manager/gradle/parser.spec.ts b/lib/modules/manager/gradle/parser.spec.ts index ee6f67612ea..10010b44fd5 100644 --- a/lib/modules/manager/gradle/parser.spec.ts +++ b/lib/modules/manager/gradle/parser.spec.ts @@ -382,17 +382,20 @@ describe('modules/manager/gradle/parser', () => { describe('dependencies', () => { describe('simple dependency strings', () => { it.each` - input | output - ${'"foo:bar:1.2.3"'} | ${{ depName: 'foo:bar', currentValue: '1.2.3' }} - ${'"foo:bar:1.2+"'} | ${{ depName: 'foo:bar', currentValue: '1.2+' }} - ${'"foo:bar:1.2.3@zip"'} | ${{ depName: 'foo:bar', currentValue: '1.2.3', dataType: 'zip' }} - ${'"foo:bar:1.2.3:docs@jar"'} | ${{ depName: 'foo:bar', currentValue: '1.2.3', dataType: 'jar' }} - ${'"foo:bar1:1"'} | ${{ depName: 'foo:bar1', currentValue: '1', managerData: { fileReplacePosition: 10 } }} - ${'"foo:bar:[1.2.3, )"'} | ${{ depName: 'foo:bar', currentValue: '[1.2.3, )', managerData: { fileReplacePosition: 9 } }} - ${'"foo:bar:[1.2.3, 1.2.4)"'} | ${{ depName: 'foo:bar', currentValue: '[1.2.3, 1.2.4)', managerData: { fileReplacePosition: 9 } }} - ${'"foo:bar:[,1.2.4)"'} | ${{ depName: 'foo:bar', currentValue: '[,1.2.4)', managerData: { fileReplacePosition: 9 } }} - ${'"foo:bar:x86@x86"'} | ${{ depName: 'foo:bar', currentValue: 'x86', managerData: { fileReplacePosition: 9 } }} - ${'foo.bar = "foo:bar:1.2.3"'} | ${{ depName: 'foo:bar', currentValue: '1.2.3' }} + input | output + ${'"foo:bar:1.2.3"'} | ${{ depName: 'foo:bar', currentValue: '1.2.3' }} + ${'"foo:bar:1.2+"'} | ${{ depName: 'foo:bar', currentValue: '1.2+' }} + ${'"foo:bar:1.2.3@zip"'} | ${{ depName: 'foo:bar', currentValue: '1.2.3', dataType: 'zip' }} + ${'"foo:bar:1.2.3:docs@jar"'} | ${{ depName: 'foo:bar', currentValue: '1.2.3', dataType: 'jar' }} + ${'"foo:bar1:1"'} | ${{ depName: 'foo:bar1', currentValue: '1', managerData: { fileReplacePosition: 10 } }} + ${'"foo:bar:[1.2.3, )"'} | ${{ depName: 'foo:bar', currentValue: '[1.2.3, )', managerData: { fileReplacePosition: 9 } }} + ${'"foo:bar:[1.2.3, 1.2.4)"'} | ${{ depName: 'foo:bar', currentValue: '[1.2.3, 1.2.4)', managerData: { fileReplacePosition: 9 } }} + ${'"foo:bar:[,1.2.4)"'} | ${{ depName: 'foo:bar', currentValue: '[,1.2.4)', managerData: { fileReplacePosition: 9 } }} + ${'"foo:bar:[1.2.3, )!!1.2.3"'} | ${{ depName: 'foo:bar', currentValue: '[1.2.3, )!!1.2.3', managerData: { fileReplacePosition: 9 } }} + ${'"foo:bar:[1.2.3, 1.2.4)!!1.2.3"'} | ${{ depName: 'foo:bar', currentValue: '[1.2.3, 1.2.4)!!1.2.3', managerData: { fileReplacePosition: 9 } }} + ${'"foo:bar:[,1.2.4)!!1.2.4"'} | ${{ depName: 'foo:bar', currentValue: '[,1.2.4)!!1.2.4', managerData: { fileReplacePosition: 9 } }} + ${'"foo:bar:x86@x86"'} | ${{ depName: 'foo:bar', currentValue: 'x86', managerData: { fileReplacePosition: 9 } }} + ${'foo.bar = "foo:bar:1.2.3"'} | ${{ depName: 'foo:bar', currentValue: '1.2.3' }} `('$input', ({ input, output }) => { const { deps } = parseGradle(input); expect(deps).toMatchObject([output]); diff --git a/lib/modules/manager/gradle/utils.ts b/lib/modules/manager/gradle/utils.ts index 4309a16b876..de06bdcd439 100644 --- a/lib/modules/manager/gradle/utils.ts +++ b/lib/modules/manager/gradle/utils.ts @@ -12,7 +12,7 @@ const artifactRegex = regEx( '^[a-zA-Z][-_a-zA-Z0-9]*(?:\\.[a-zA-Z0-9][-_a-zA-Z0-9]*?)*$', ); -const versionLikeRegex = regEx('^(?[-_.\\[\\](),a-zA-Z0-9+ ]+)'); +const versionLikeRegex = regEx('^(?[-_.\\[\\](),a-zA-Z0-9+! ]+)'); // Extracts version-like and range-like strings from the beginning of input export function versionLikeSubstring( diff --git a/lib/modules/versioning/gradle/compare.ts b/lib/modules/versioning/gradle/compare.ts index 8b67d04774f..08c408fd5e4 100644 --- a/lib/modules/versioning/gradle/compare.ts +++ b/lib/modules/versioning/gradle/compare.ts @@ -232,6 +232,9 @@ interface MavenBasedRange { rightBound: RangeBound; rightBoundStr: string; rightVal: string | null; + // The existence of preferredVal implies the "strictly" keyword "!!" + // leading up to preferredVal: "!![preferred version]" + preferredVal: string | null; } export function parsePrefixRange(input: string): PrefixRange | null { @@ -256,7 +259,7 @@ export function parsePrefixRange(input: string): PrefixRange | null { } const mavenBasedRangeRegex = regEx( - /^(?[[\](]\s*)(?[-._+a-zA-Z0-9]*?)(?\s*,\s*)(?[-._+a-zA-Z0-9]*?)(?\s*[[\])])$/, + /^(?[[\](]\s*)(?[-._+a-zA-Z0-9]*?)(?\s*,\s*)(?[-._+a-zA-Z0-9]*?)(?\s*[[\])])(?:!!(?[-._+a-zA-Z0-9]+))?$/, ); export function parseMavenBasedRange(input: string): MavenBasedRange | null { @@ -265,47 +268,46 @@ export function parseMavenBasedRange(input: string): MavenBasedRange | null { } const matchGroups = mavenBasedRangeRegex.exec(input)?.groups; - if (matchGroups) { - const { leftBoundStr, separator, rightBoundStr } = matchGroups; - let leftVal: string | null = matchGroups.leftVal; - let rightVal: string | null = matchGroups.rightVal; - if (!leftVal) { - leftVal = null; - } - if (!rightVal) { - rightVal = null; - } - const isVersionLeft = isString(leftVal) && isVersion(leftVal); - const isVersionRight = isString(rightVal) && isVersion(rightVal); - if ( - (leftVal === null || isVersionLeft) && - (rightVal === null || isVersionRight) - ) { - if ( - isVersionLeft && - isVersionRight && - leftVal && - rightVal && - compare(leftVal, rightVal) === 1 - ) { - return null; - } - const leftBound = leftBoundStr.trim() === '[' ? 'inclusive' : 'exclusive'; - const rightBound = - rightBoundStr.trim() === ']' ? 'inclusive' : 'exclusive'; - return { - leftBound, - leftBoundStr, - leftVal, - separator, - rightBound, - rightBoundStr, - rightVal, - }; - } + if (!matchGroups) { + return null; } - return null; + const { leftBoundStr, separator, rightBoundStr } = matchGroups; + const leftVal = matchGroups.leftVal || null; + const rightVal = matchGroups.rightVal || null; + const preferredVal = matchGroups.preferredVal || null; + const isVersionLeft = isString(leftVal) && isVersion(leftVal); + const isVersionRight = isString(rightVal) && isVersion(rightVal); + if ( + (leftVal !== null && !isVersionLeft) || + (rightVal !== null && !isVersionRight) + ) { + return null; + } + + if ( + isVersionLeft && + isVersionRight && + leftVal && + rightVal && + compare(leftVal, rightVal) === 1 + ) { + return null; + } + + const leftBound = leftBoundStr.trim() === '[' ? 'inclusive' : 'exclusive'; + const rightBound = rightBoundStr.trim() === ']' ? 'inclusive' : 'exclusive'; + + return { + leftBound, + leftBoundStr, + leftVal, + separator, + rightBound, + rightBoundStr, + rightVal, + preferredVal, + }; } interface SingleVersionRange { diff --git a/lib/modules/versioning/gradle/index.spec.ts b/lib/modules/versioning/gradle/index.spec.ts index 39726d3e03e..27686e2a1bf 100644 --- a/lib/modules/versioning/gradle/index.spec.ts +++ b/lib/modules/versioning/gradle/index.spec.ts @@ -116,6 +116,7 @@ describe('modules/versioning/gradle/index', () => { ${'[1.2,,1.3]'} ${'[1,[2,3],4]'} ${'[1.3,1.2]'} + ${'[1..3,1.2]'} `('parseMavenBasedRange("$rangeStr") is null', ({ rangeStr }) => { const range = parseMavenBasedRange(rangeStr); expect(range).toBeNull(); @@ -301,46 +302,43 @@ describe('modules/versioning/gradle/index', () => { describe('getNewValue', () => { it.each` - currentValue | rangeStrategy | currentVersion | newVersion | expected - ${'1'} | ${null} | ${null} | ${'1.1'} | ${'1.1'} - ${'[1.2.3,]'} | ${null} | ${null} | ${'1.2.4'} | ${'[1.2.3,]'} - ${'[1.2.3,2)'} | ${null} | ${null} | ${'2.0.0'} | ${'[1.2.3,3)'} - ${'[1.3,1.4)'} | ${null} | ${null} | ${'2.0.0'} | ${'[2.0,3.0)'} - ${'[1.3,1.4)'} | ${null} | ${null} | ${'1.5.1'} | ${'[1.5,1.6)'} - ${'[1,1.4)'} | ${null} | ${null} | ${'1.5.1'} | ${'[1,1.6)'} - ${'[1.3,2)'} | ${null} | ${null} | ${'1.4.0'} | ${'[1.3,2)'} - ${'1.?'} | ${null} | ${null} | ${'2'} | ${'1.?'} - ${'1..'} | ${null} | ${null} | ${'2'} | ${'1..'} - ${'1--'} | ${null} | ${null} | ${'2'} | ${'1--'} - ${'+'} | ${null} | ${null} | ${'1.2.4'} | ${null} - ${'1.+'} | ${null} | ${null} | ${'1.2.4'} | ${'1.+'} - ${'1.+'} | ${null} | ${null} | ${'2.1.2'} | ${'2.+'} - ${'1.+'} | ${null} | ${null} | ${'2'} | ${'2.+'} - ${'1.3.+'} | ${null} | ${null} | ${'1.3.4'} | ${'1.3.+'} - ${'1.3.+'} | ${null} | ${null} | ${'1.5.2'} | ${'1.5.+'} - ${'1.3.+'} | ${null} | ${null} | ${'2'} | ${'2'} - ${'[1.2.3]'} | ${'pin'} | ${'1.2.3'} | ${'1.2.4'} | ${'1.2.4'} - ${'[1.0.0,1.2.3]'} | ${'pin'} | ${'1.0.0'} | ${'1.2.4'} | ${'1.2.4'} - ${'[1.0.0,1.2.23]'} | ${'pin'} | ${'1.0.0'} | ${'1.2.23'} | ${'1.2.23'} - ${'(,1.0]'} | ${'pin'} | ${'0.0.1'} | ${'2.0'} | ${'2.0'} - ${'],1.0]'} | ${'pin'} | ${'0.0.1'} | ${'2.0'} | ${'2.0'} - ${'(,1.0)'} | ${'pin'} | ${'0.1'} | ${'2.0'} | ${'2.0'} - ${'],1.0['} | ${'pin'} | ${'2.0'} | ${'],2.0['} | ${'],2.0['} - ${'[1.0,1.2],[1.3,1.5)'} | ${'pin'} | ${'1.0'} | ${'1.2.4'} | ${'1.2.4'} - ${'[1.0,1.2],[1.3,1.5['} | ${'pin'} | ${'1.0'} | ${'1.2.4'} | ${'1.2.4'} - ${'[1.2.3,)'} | ${'pin'} | ${'1.2.3'} | ${'1.2.4'} | ${'1.2.4'} - ${'[1.2.3,['} | ${'pin'} | ${'1.2.3'} | ${'1.2.4'} | ${'1.2.4'} - ${'[1.2.3]'} | ${'bump'} | ${'1.2.3'} | ${'1.2.4'} | ${'[1.2.4]'} - ${'[1.0.0,1.2.3]'} | ${'bump'} | ${'1.0.0'} | ${'1.2.4'} | ${'[1.0.0,1.2.4]'} - ${'[1.0.0,1.2.23]'} | ${'bump'} | ${'1.0.0'} | ${'1.2.23'} | ${'[1.0.0,1.2.23]'} - ${'(,1.0]'} | ${'bump'} | ${'0.0.1'} | ${'2.0'} | ${'(,2.0]'} - ${'],1.0]'} | ${'bump'} | ${'0.0.1'} | ${'2.0'} | ${'],2.0]'} - ${'(,1.0)'} | ${'bump'} | ${'0.1'} | ${'2.0'} | ${'(,3.0)'} - ${'],1.0['} | ${'bump'} | ${'2.0'} | ${'],2.0['} | ${'],1.0['} - ${'[1.0,1.2],[1.3,1.5)'} | ${'bump'} | ${'1.0'} | ${'1.2.4'} | ${'[1.0,1.2],[1.3,1.5)'} - ${'[1.0,1.2],[1.3,1.5['} | ${'bump'} | ${'1.0'} | ${'1.2.4'} | ${'[1.0,1.2],[1.3,1.5['} - ${'[1.2.3,)'} | ${'bump'} | ${'1.2.3'} | ${'1.2.4'} | ${'[1.2.4,)'} - ${'[1.2.3,['} | ${'bump'} | ${'1.2.3'} | ${'1.2.4'} | ${'[1.2.4,['} + currentValue | rangeStrategy | currentVersion | newVersion | expected + ${'1'} | ${null} | ${null} | ${'1.1'} | ${'1.1'} + ${'[1.2.3,]'} | ${null} | ${null} | ${'1.2.4'} | ${'[1.2.3,]'} + ${'[1.2.3,2)'} | ${null} | ${null} | ${'2.0.0'} | ${'[1.2.3,3)'} + ${'[1.3,1.4)'} | ${null} | ${null} | ${'2.0.0'} | ${'[2.0,3.0)'} + ${'[1.3,1.4)'} | ${null} | ${null} | ${'1.5.1'} | ${'[1.5,1.6)'} + ${'[1,1.4)'} | ${null} | ${null} | ${'1.5.1'} | ${'[1,1.6)'} + ${'[1.3,2)'} | ${null} | ${null} | ${'1.4.0'} | ${'[1.3,2)'} + ${'1.?'} | ${null} | ${null} | ${'2'} | ${'1.?'} + ${'1..'} | ${null} | ${null} | ${'2'} | ${'1..'} + ${'1--'} | ${null} | ${null} | ${'2'} | ${'1--'} + ${'+'} | ${null} | ${null} | ${'1.2.4'} | ${null} + ${'1.+'} | ${null} | ${null} | ${'1.2.4'} | ${'1.+'} + ${'1.+'} | ${null} | ${null} | ${'2.1.2'} | ${'2.+'} + ${'1.+'} | ${null} | ${null} | ${'2'} | ${'2.+'} + ${'1.3.+'} | ${null} | ${null} | ${'1.3.4'} | ${'1.3.+'} + ${'1.3.+'} | ${null} | ${null} | ${'1.5.2'} | ${'1.5.+'} + ${'1.3.+'} | ${null} | ${null} | ${'2'} | ${'2'} + ${'[1.2.3]'} | ${'bump'} | ${'1.2.3'} | ${'1.2.4'} | ${'[1.2.4]'} + ${'[1.0.0,1.2.3]'} | ${'bump'} | ${'1.0.0'} | ${'1.2.4'} | ${'[1.0.0,1.2.4]'} + ${'[1.0.0,1.2.23]'} | ${'bump'} | ${'1.0.0'} | ${'1.2.23'} | ${'[1.0.0,1.2.23]'} + ${'(,1.0]'} | ${'bump'} | ${'0.0.1'} | ${'2.0'} | ${'(,2.0]'} + ${'],1.0]'} | ${'bump'} | ${'0.0.1'} | ${'2.0'} | ${'],2.0]'} + ${'(,1.0)'} | ${'bump'} | ${'0.1'} | ${'2.0'} | ${'(,3.0)'} + ${'],1.0['} | ${'bump'} | ${'2.0'} | ${'],2.0['} | ${'],1.0['} + ${'[1.0,1.2],[1.3,1.5)'} | ${'bump'} | ${'1.0'} | ${'1.2.4'} | ${'[1.0,1.2],[1.3,1.5)'} + ${'[1.0,1.2],[1.3,1.5['} | ${'bump'} | ${'1.0'} | ${'1.2.4'} | ${'[1.0,1.2],[1.3,1.5['} + ${'[1.2.3,)'} | ${'bump'} | ${'1.2.3'} | ${'1.2.4'} | ${'[1.2.4,)'} + ${'[1.2.3,['} | ${'bump'} | ${'1.2.3'} | ${'1.2.4'} | ${'[1.2.4,['} + ${'(,1.0]!!1.0'} | ${'bump'} | ${'0.0.1'} | ${'2.0'} | ${'(,2.0]!!2.0'} + ${'],1.0]!!1.0'} | ${'bump'} | ${'0.0.1'} | ${'2.0'} | ${'],2.0]!!2.0'} + ${'(,1.0)!!1.0'} | ${'bump'} | ${'0.1'} | ${'2.0'} | ${'(,3.0)!!2.0'} + ${'],1.0[!!1.0'} | ${'bump'} | ${'2.0'} | ${'],2.0['} | ${'],1.0[!!1.0'} + ${'[1.0,1.2],[1.3,1.5)!!1.0'} | ${'bump'} | ${'1.0'} | ${'1.2.4'} | ${'[1.0,1.2],[1.3,1.5)!!1.0'} + ${'[1.0,1.2],[1.3,1.5[!!1.0'} | ${'bump'} | ${'1.0'} | ${'1.2.4'} | ${'[1.0,1.2],[1.3,1.5[!!1.0'} + ${'[1.2.3,)!!1.2.3'} | ${'bump'} | ${'1.2.3'} | ${'1.2.4'} | ${'[1.2.4,)!!1.2.4'} + ${'[1.2.3,[!!1.2.3'} | ${'bump'} | ${'1.2.3'} | ${'1.2.4'} | ${'[1.2.4,[!!1.2.4'} `( 'getNewValue($currentValue, $rangeStrategy, $currentVersion, $newVersion, $expected) === $expected', ({ diff --git a/lib/modules/versioning/gradle/index.ts b/lib/modules/versioning/gradle/index.ts index 6de3aa5a6b2..3c01e7b455b 100644 --- a/lib/modules/versioning/gradle/index.ts +++ b/lib/modules/versioning/gradle/index.ts @@ -220,6 +220,35 @@ function getNewValue({ } } + const mavenRange = parseMavenBasedRange(currentValue); + if (mavenRange?.preferredVal) { + const { leftVal, rightVal, preferredVal } = mavenRange; + const baseRange = currentValue.slice( + 0, + currentValue.lastIndexOf(`!!${preferredVal}`), + ); + const newBaseRange = mavenVersion.getNewValue({ + currentValue: baseRange, + rangeStrategy, + newVersion, + }); + // v8 ignore if: the implementation has a non-null return type + if (newBaseRange === null) { + return null; + } + + const preferredIsBoundary = + preferredVal === leftVal || preferredVal === rightVal; + const newParsed = parseMavenBasedRange(newBaseRange); + const preferredStillPresent = + newParsed?.leftVal === preferredVal || + newParsed?.rightVal === preferredVal; + const newPreferredVal = + preferredIsBoundary && !preferredStillPresent ? newVersion : preferredVal; + + return `${newBaseRange}!!${newPreferredVal}`; + } + return mavenVersion.getNewValue({ currentValue, rangeStrategy, newVersion }); } From 434606bfb414c776e8000bdd743694e4bdee1af0 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Tue, 7 Apr 2026 11:29:52 +0100 Subject: [PATCH 09/13] feat(onboarding): make `Add your custom config to ...` more prominent (#42332) * feat(onboarding): make `Add your custom config to ...` more prominent As part of work to improve the Onboarding flow as part of larger repos, we noticed that the `Add your custom config to ...` comment may be missed. We can make this more prominent by moving it up to the top of the PR. * fixup! feat(onboarding): make `Add your custom config to ...` more prominent --- .../config-description.spec.ts.snap | 49 ------------------- .../pr/__snapshots__/index.spec.ts.snap | 12 +++++ .../onboarding/pr/config-description.spec.ts | 29 ----------- .../onboarding/pr/config-description.ts | 15 +----- .../repository/onboarding/pr/index.spec.ts | 33 ++++++++++++- lib/workers/repository/onboarding/pr/index.ts | 11 +++++ 6 files changed, 55 insertions(+), 94 deletions(-) diff --git a/lib/workers/repository/onboarding/pr/__snapshots__/config-description.spec.ts.snap b/lib/workers/repository/onboarding/pr/__snapshots__/config-description.spec.ts.snap index 1cab8241f10..c0e9ad29da8 100644 --- a/lib/workers/repository/onboarding/pr/__snapshots__/config-description.spec.ts.snap +++ b/lib/workers/repository/onboarding/pr/__snapshots__/config-description.spec.ts.snap @@ -1,50 +1,5 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`workers/repository/onboarding/pr/config-description > getConfigDesc() > contains the onboardingConfigFileName if set 1`] = ` -" -### Configuration Summary - -Based on the default config's presets, Renovate will: - - - Start dependency updates only once this onboarding PR is merged - - Run Renovate on following schedule: before 5am - -🔡 Do you want to change how Renovate upgrades your dependencies? Add your custom config to \`.github/renovate.json\` in this branch. Renovate will update the Pull Request description the next time it runs. - ---- -" -`; - -exports[`workers/repository/onboarding/pr/config-description > getConfigDesc() > falls back to "renovate.json" if onboardingConfigFileName is not set 1`] = ` -" -### Configuration Summary - -Based on the default config's presets, Renovate will: - - - Start dependency updates only once this onboarding PR is merged - - Run Renovate on following schedule: before 5am - -🔡 Do you want to change how Renovate upgrades your dependencies? Add your custom config to \`renovate.json\` in this branch. Renovate will update the Pull Request description the next time it runs. - ---- -" -`; - -exports[`workers/repository/onboarding/pr/config-description > getConfigDesc() > falls back to "renovate.json" if onboardingConfigFileName is not valid 1`] = ` -" -### Configuration Summary - -Based on the default config's presets, Renovate will: - - - Start dependency updates only once this onboarding PR is merged - - Run Renovate on following schedule: before 5am - -🔡 Do you want to change how Renovate upgrades your dependencies? Add your custom config to \`renovate.json\` in this branch. Renovate will update the Pull Request description the next time it runs. - ---- -" -`; - exports[`workers/repository/onboarding/pr/config-description > getConfigDesc() > include retry/refresh checkbox message only if onboardingRebaseCheckbox is true 1`] = ` " ### Configuration Summary @@ -54,8 +9,6 @@ Based on the default config's presets, Renovate will: - Start dependency updates only once this onboarding PR is merged - Run Renovate on following schedule: before 5am -🔡 Do you want to change how Renovate upgrades your dependencies? Add your custom config to \`.github/renovate.json\` in this branch and select the Retry/Rebase checkbox below. Renovate will update the Pull Request description the next time it runs. - --- " `; @@ -72,8 +25,6 @@ Based on the default config's presets, Renovate will: - something else - this is Docker-only -🔡 Do you want to change how Renovate upgrades your dependencies? Add your custom config to \`renovate.json\` in this branch. Renovate will update the Pull Request description the next time it runs. - --- " `; diff --git a/lib/workers/repository/onboarding/pr/__snapshots__/index.spec.ts.snap b/lib/workers/repository/onboarding/pr/__snapshots__/index.spec.ts.snap index 2df66344f20..520e798c10d 100644 --- a/lib/workers/repository/onboarding/pr/__snapshots__/index.spec.ts.snap +++ b/lib/workers/repository/onboarding/pr/__snapshots__/index.spec.ts.snap @@ -7,6 +7,8 @@ Welcome to [Renovate](https://github.com/renovatebot/renovate)! This is an onboa 🚦 To activate Renovate, merge this Pull Request. To disable Renovate, simply close this Pull Request unmerged. +🔡 Do you want to change how Renovate upgrades your dependencies? Add your custom config to \`renovate.json\` in this branch. Renovate will update the Pull Request description the next time it runs. + --- @@ -39,6 +41,8 @@ Welcome to [Renovate](https://github.com/renovatebot/renovate)! This is an onboa 🚦 To activate Renovate, merge this Pull Request. To disable Renovate, simply close this Pull Request unmerged. +🔡 Do you want to change how Renovate upgrades your dependencies? Add your custom config to \`renovate.json\` in this branch and select the Retry/Rebase checkbox below. Renovate will update the Pull Request description the next time it runs. + --- @@ -76,6 +80,8 @@ Welcome to [Renovate](https://github.com/renovatebot/renovate)! This is an onboa 🚦 To activate Renovate, merge this Pull Request. To disable Renovate, simply close this Pull Request unmerged. +🔡 Do you want to change how Renovate upgrades your dependencies? Add your custom config to \`renovate.json\` in this branch. Renovate will update the Pull Request description the next time it runs. + --- @@ -108,6 +114,8 @@ Welcome to [Renovate](https://github.com/renovatebot/renovate)! This is an onboa 🚦 To activate Renovate, merge this Pull Request. To disable Renovate, simply close this Pull Request unmerged. +🔡 Do you want to change how Renovate upgrades your dependencies? Add your custom config to \`renovate.json\` in this branch and select the Retry/Rebase checkbox below. Renovate will update the Pull Request description the next time it runs. + --- @@ -147,6 +155,8 @@ Welcome to [Renovate](https://github.com/renovatebot/renovate)! This is an onboa 🚦 To activate Renovate, merge this Pull Request. To disable Renovate, simply close this Pull Request unmerged. +🔡 Do you want to change how Renovate upgrades your dependencies? Add your custom config to \`renovate.json\` in this branch. Renovate will update the Pull Request description the next time it runs. + --- @@ -184,6 +194,8 @@ Welcome to [Renovate](https://github.com/renovatebot/renovate)! This is an onboa 🚦 To activate Renovate, merge this Pull Request. To disable Renovate, simply close this Pull Request unmerged. +🔡 Do you want to change how Renovate upgrades your dependencies? Add your custom config to \`renovate.json\` in this branch and select the Retry/Rebase checkbox below. Renovate will update the Pull Request description the next time it runs. + --- diff --git a/lib/workers/repository/onboarding/pr/config-description.spec.ts b/lib/workers/repository/onboarding/pr/config-description.spec.ts index e152622882f..56c312cfd56 100644 --- a/lib/workers/repository/onboarding/pr/config-description.spec.ts +++ b/lib/workers/repository/onboarding/pr/config-description.spec.ts @@ -50,40 +50,11 @@ describe('workers/repository/onboarding/pr/config-description', () => { - Start dependency updates only once this onboarding PR is merged - Run Renovate on following schedule: before 5am - 🔡 Do you want to change how Renovate upgrades your dependencies? Add your custom config to \`renovate.json\` in this branch. Renovate will update the Pull Request description the next time it runs. - --- " `); }); - it('contains the onboardingConfigFileName if set', () => { - delete config.description; - config.schedule = ['before 5am']; - GlobalConfig.set({ onboardingConfigFileName: '.github/renovate.json' }); - const res = getConfigDesc(config); - expect(res).toMatchSnapshot(); - expect(res.indexOf('`.github/renovate.json`')).not.toBe(-1); - expect(res.indexOf('`renovate.json`')).toBe(-1); - }); - - it('falls back to "renovate.json" if onboardingConfigFileName is not set', () => { - delete config.description; - config.schedule = ['before 5am']; - const res = getConfigDesc(config); - expect(res).toMatchSnapshot(); - expect(res.indexOf('`renovate.json`')).not.toBe(-1); - }); - - it('falls back to "renovate.json" if onboardingConfigFileName is not valid', () => { - delete config.description; - config.schedule = ['before 5am']; - GlobalConfig.set({ onboardingConfigFileName: 'foo.bar' }); - const res = getConfigDesc(config); - expect(res).toMatchSnapshot(); - expect(res.indexOf('`renovate.json`')).not.toBe(-1); - }); - it('include retry/refresh checkbox message only if onboardingRebaseCheckbox is true', () => { delete config.description; config.schedule = ['before 5am']; diff --git a/lib/workers/repository/onboarding/pr/config-description.ts b/lib/workers/repository/onboarding/pr/config-description.ts index 65f5e756f18..5774045f0b6 100644 --- a/lib/workers/repository/onboarding/pr/config-description.ts +++ b/lib/workers/repository/onboarding/pr/config-description.ts @@ -2,8 +2,6 @@ import { isArray, isString } from '@sindresorhus/is'; import type { RenovateConfig } from '../../../../config/types.ts'; import { logger } from '../../../../logger/index.ts'; import type { PackageFile } from '../../../../modules/manager/types.ts'; -import { emojify } from '../../../../util/emoji.ts'; -import { getDefaultConfigFileName } from '../common.ts'; export function getScheduleDesc(config: RenovateConfig): string[] { logger.debug('getScheduleDesc()'); @@ -32,8 +30,6 @@ export function getConfigDesc( // TODO: remove unused parameter _packageFiles?: Record, ): string { - // TODO: type (#22198) - const configFile = getDefaultConfigFileName(); logger.debug('getConfigDesc()'); logger.trace({ config }); const descriptionArr = getDescriptionArray(config); @@ -47,15 +43,6 @@ export function getConfigDesc( descriptionArr.forEach((d) => { desc += ` - ${d}\n`; }); - desc += '\n'; - desc += emojify( - `:abcd: Do you want to change how Renovate upgrades your dependencies?`, - ); - desc += ` Add your custom config to \`${configFile}\` in this branch${ - config.onboardingRebaseCheckbox - ? ' and select the Retry/Rebase checkbox below' - : '' - }. Renovate will update the Pull Request description the next time it runs.`; - desc += '\n\n---\n'; + desc += '\n---\n'; return desc; } diff --git a/lib/workers/repository/onboarding/pr/index.spec.ts b/lib/workers/repository/onboarding/pr/index.spec.ts index 52d6a440f1e..62070d6b00a 100644 --- a/lib/workers/repository/onboarding/pr/index.spec.ts +++ b/lib/workers/repository/onboarding/pr/index.spec.ts @@ -21,7 +21,7 @@ describe('workers/repository/onboarding/pr/index', () => { let branches: BranchConfig[]; const bodyStruct = { - hash: '6aa71f8cb7b1503b883485c8f5bd564b31923b9c7fa765abe2a7338af40e03b1', + hash: '137701e91134550a73cea4f6e6f2269897d4802122126657a2ff890459f07c72', }; beforeEach(() => { @@ -213,7 +213,7 @@ describe('workers/repository/onboarding/pr/index', () => { '(onboardingRebaseCheckbox="$onboardingRebaseCheckbox")', async ({ onboardingRebaseCheckbox }) => { const hash = - '30029ee05ed80b34d2f743afda6e78fe20247a1eedaa9ce6a8070045c229ebfa'; // no rebase checkbox PR hash + '4b0e83aaa5acee225d5b8af756a1f55eb1d3fe70aa5759d03cf708187ebec4df'; // no rebase checkbox PR hash config.onboardingRebaseCheckbox = onboardingRebaseCheckbox; OnboardingState.prUpdateRequested = true; // case 'false' is tested in "breaks early when onboarding" platform.getBranchPr.mockResolvedValue( @@ -475,6 +475,35 @@ describe('workers/repository/onboarding/pr/index', () => { expect(platform.createPr).toHaveBeenCalledTimes(1); }); + describe('the created PR references onboardingConfigFileName', () => { + it('when set', async () => { + GlobalConfig.set({ onboardingConfigFileName: '.github/renovate.json' }); + await ensureOnboardingPr(config, packageFiles, branches); + expect(platform.createPr.mock.calls[0][0].prBody).toContain( + `Add your custom config to \`.github/renovate.json\` in this branch`, + ); + expect(platform.createPr.mock.calls[0][0].prBody).not.toContain( + '`renovate.json`', + ); + }); + + it('when not set, falls back to "renovate.json"', async () => { + GlobalConfig.set({ onboardingConfigFileName: undefined }); + await ensureOnboardingPr(config, packageFiles, branches); + expect(platform.createPr.mock.calls[0][0].prBody).toContain( + `Add your custom config to \`renovate.json\` in this branch`, + ); + }); + + it('when set, but not a valid filename, falls back to "renovate.json"', async () => { + GlobalConfig.set({ onboardingConfigFileName: 'foo.bar' }); + await ensureOnboardingPr(config, packageFiles, branches); + expect(platform.createPr.mock.calls[0][0].prBody).toContain( + `Add your custom config to \`renovate.json\` in this branch`, + ); + }); + }); + it('dryrun of creates PR', async () => { GlobalConfig.set({ dryRun: 'full', diff --git a/lib/workers/repository/onboarding/pr/index.ts b/lib/workers/repository/onboarding/pr/index.ts index f3cfbccd293..78910517fde 100644 --- a/lib/workers/repository/onboarding/pr/index.ts +++ b/lib/workers/repository/onboarding/pr/index.ts @@ -148,6 +148,17 @@ export async function ensureOnboardingPr( : emojify( `:vertical_traffic_light: Renovate will begin keeping your dependencies up-to-date only once you merge or close this Pull Request.\n\n`, ); + + const configFile = getDefaultConfigFileName(); + prTemplate += emojify( + `:abcd: Do you want to change how Renovate upgrades your dependencies?`, + ); + prTemplate += ` Add your custom config to \`${configFile}\` in this branch${ + config.onboardingRebaseCheckbox + ? ' and select the Retry/Rebase checkbox below' + : '' + }. Renovate will update the Pull Request description the next time it runs.`; + prTemplate += '\n\n'; // TODO #22198 prTemplate += emojify( ` From 674ac6639e320798524f776dd19ea8e18c307249 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Tue, 7 Apr 2026 11:33:56 +0100 Subject: [PATCH 10/13] docs(reading-list): add a link to `config:recommended` (#42417) --- docs/usage/reading-list.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/usage/reading-list.md b/docs/usage/reading-list.md index 0290f497e04..db319887ba7 100644 --- a/docs/usage/reading-list.md +++ b/docs/usage/reading-list.md @@ -22,8 +22,8 @@ If you're self-hosting or need to update private packages, complete the relevant If you're new to Renovate, you should: - Use the Mend Renovate App, or let someone else host Renovate for you -- Stick with the `config:recommended` preset -- Use the Dependency Dashboard (`config:recommended` enables it automatically) +- Stick with the [`config:recommended`](./presets-config.md#configrecommended) preset +- Use the Dependency Dashboard ([`config:recommended`](./presets-config.md#configrecommended) enables it automatically) - Read the pages in the "Beginners" list - Only create custom Renovate configuration when really needed From ff6b16a468ff4b2e2f855560adec6ded6c6bdd7a Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Tue, 7 Apr 2026 11:47:35 +0100 Subject: [PATCH 11/13] feat(github-actions): extract Zizmor version automagically (#42415) --- .../manager/github-actions/community.ts | 26 ++++++++++ .../manager/github-actions/extract.spec.ts | 50 +++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/lib/modules/manager/github-actions/community.ts b/lib/modules/manager/github-actions/community.ts index 48162e5c1b2..ec06346f067 100644 --- a/lib/modules/manager/github-actions/community.ts +++ b/lib/modules/manager/github-actions/community.ts @@ -265,6 +265,31 @@ const SetupGolangciLint = z }; }); +const ZizmorcoreZizmorAction = z + .object({ + uses: matchAction('zizmorcore/zizmor-action'), + with: z.object({ version: z.string().optional() }), + }) + .transform(({ with: val }): PackageDependency => { + let skipStage: StageName | undefined; + let skipReason: SkipReason | undefined; + + if (!val.version) { + skipStage = 'extract'; + skipReason = 'unspecified-version'; + } + + return { + datasource: PypiDatasource.id, + depName: 'zizmor', + packageName: 'zizmor', + ...(skipStage && { skipStage }), + ...(skipReason && { skipReason }), + currentValue: val.version, + depType: 'uses-with', + }; + }); + /** * schema here should match the whole step, * there may be some actions use env as arguments version. @@ -282,4 +307,5 @@ export const CommunityActions = z.union([ SetupRuby, SetupHatch, SetupGolangciLint, + ZizmorcoreZizmorAction, ]); diff --git a/lib/modules/manager/github-actions/extract.spec.ts b/lib/modules/manager/github-actions/extract.spec.ts index 6514936154a..48dac7b2acf 100644 --- a/lib/modules/manager/github-actions/extract.spec.ts +++ b/lib/modules/manager/github-actions/extract.spec.ts @@ -1324,6 +1324,56 @@ describe('modules/manager/github-actions/extract', () => { }, ], }, + { + step: { + uses: 'zizmorcore/zizmor-action@v0.5.2', + with: {}, + }, + expected: [ + { + skipStage: 'extract', + skipReason: 'unspecified-version', + datasource: 'pypi', + depName: 'zizmor', + depType: 'uses-with', + packageName: 'zizmor', + }, + ], + }, + { + step: { + uses: 'zizmorcore/zizmor-action@v0.5.2', + with: { + version: 'v1.23.1', + }, + }, + expected: [ + { + currentValue: 'v1.23.1', + datasource: 'pypi', + depName: 'zizmor', + depType: 'uses-with', + packageName: 'zizmor', + }, + ], + }, + { + step: { + uses: 'zizmorcore/zizmor-action@v0.5.2', + with: { + version: '1.23.1', + }, + }, + expected: [ + { + currentValue: '1.23.1', + datasource: 'pypi', + depName: 'zizmor', + depType: 'uses-with', + packageName: 'zizmor', + }, + ], + }, ])('extract from $step.uses', ({ step, expected }) => { const yamlContent = yaml.dump({ jobs: { build: { steps: [step] } } }); From 5f02aa860dc68a96329646490db6edd610231d60 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Tue, 7 Apr 2026 11:57:01 +0100 Subject: [PATCH 12/13] chore(onboarding): add "reading list" link from onboarding PR (#42418) As a potentially actionable suggestion for newly onboarding users. --- .../onboarding/pr/__snapshots__/index.spec.ts.snap | 12 ++++++++++++ lib/workers/repository/onboarding/pr/index.spec.ts | 4 ++-- lib/workers/repository/onboarding/pr/index.ts | 4 ++++ 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/lib/workers/repository/onboarding/pr/__snapshots__/index.spec.ts.snap b/lib/workers/repository/onboarding/pr/__snapshots__/index.spec.ts.snap index 520e798c10d..48d56d36cb5 100644 --- a/lib/workers/repository/onboarding/pr/__snapshots__/index.spec.ts.snap +++ b/lib/workers/repository/onboarding/pr/__snapshots__/index.spec.ts.snap @@ -7,6 +7,8 @@ Welcome to [Renovate](https://github.com/renovatebot/renovate)! This is an onboa 🚦 To activate Renovate, merge this Pull Request. To disable Renovate, simply close this Pull Request unmerged. +📚 See our [Reading List](https://docs.renovatebot.com/reading-list/) for relevant documentation you may be interested in reading. + 🔡 Do you want to change how Renovate upgrades your dependencies? Add your custom config to \`renovate.json\` in this branch. Renovate will update the Pull Request description the next time it runs. @@ -41,6 +43,8 @@ Welcome to [Renovate](https://github.com/renovatebot/renovate)! This is an onboa 🚦 To activate Renovate, merge this Pull Request. To disable Renovate, simply close this Pull Request unmerged. +📚 See our [Reading List](https://docs.renovatebot.com/reading-list/) for relevant documentation you may be interested in reading. + 🔡 Do you want to change how Renovate upgrades your dependencies? Add your custom config to \`renovate.json\` in this branch and select the Retry/Rebase checkbox below. Renovate will update the Pull Request description the next time it runs. @@ -80,6 +84,8 @@ Welcome to [Renovate](https://github.com/renovatebot/renovate)! This is an onboa 🚦 To activate Renovate, merge this Pull Request. To disable Renovate, simply close this Pull Request unmerged. +📚 See our [Reading List](https://docs.renovatebot.com/reading-list/) for relevant documentation you may be interested in reading. + 🔡 Do you want to change how Renovate upgrades your dependencies? Add your custom config to \`renovate.json\` in this branch. Renovate will update the Pull Request description the next time it runs. @@ -114,6 +120,8 @@ Welcome to [Renovate](https://github.com/renovatebot/renovate)! This is an onboa 🚦 To activate Renovate, merge this Pull Request. To disable Renovate, simply close this Pull Request unmerged. +📚 See our [Reading List](https://docs.renovatebot.com/reading-list/) for relevant documentation you may be interested in reading. + 🔡 Do you want to change how Renovate upgrades your dependencies? Add your custom config to \`renovate.json\` in this branch and select the Retry/Rebase checkbox below. Renovate will update the Pull Request description the next time it runs. @@ -155,6 +163,8 @@ Welcome to [Renovate](https://github.com/renovatebot/renovate)! This is an onboa 🚦 To activate Renovate, merge this Pull Request. To disable Renovate, simply close this Pull Request unmerged. +📚 See our [Reading List](https://docs.renovatebot.com/reading-list/) for relevant documentation you may be interested in reading. + 🔡 Do you want to change how Renovate upgrades your dependencies? Add your custom config to \`renovate.json\` in this branch. Renovate will update the Pull Request description the next time it runs. @@ -194,6 +204,8 @@ Welcome to [Renovate](https://github.com/renovatebot/renovate)! This is an onboa 🚦 To activate Renovate, merge this Pull Request. To disable Renovate, simply close this Pull Request unmerged. +📚 See our [Reading List](https://docs.renovatebot.com/reading-list/) for relevant documentation you may be interested in reading. + 🔡 Do you want to change how Renovate upgrades your dependencies? Add your custom config to \`renovate.json\` in this branch and select the Retry/Rebase checkbox below. Renovate will update the Pull Request description the next time it runs. diff --git a/lib/workers/repository/onboarding/pr/index.spec.ts b/lib/workers/repository/onboarding/pr/index.spec.ts index 62070d6b00a..b34323091ac 100644 --- a/lib/workers/repository/onboarding/pr/index.spec.ts +++ b/lib/workers/repository/onboarding/pr/index.spec.ts @@ -21,7 +21,7 @@ describe('workers/repository/onboarding/pr/index', () => { let branches: BranchConfig[]; const bodyStruct = { - hash: '137701e91134550a73cea4f6e6f2269897d4802122126657a2ff890459f07c72', + hash: 'ca7d8b2b5477b8db83231a2584c4e0a1748e4c19e26089507ee1447b8eeb6894', }; beforeEach(() => { @@ -213,7 +213,7 @@ describe('workers/repository/onboarding/pr/index', () => { '(onboardingRebaseCheckbox="$onboardingRebaseCheckbox")', async ({ onboardingRebaseCheckbox }) => { const hash = - '4b0e83aaa5acee225d5b8af756a1f55eb1d3fe70aa5759d03cf708187ebec4df'; // no rebase checkbox PR hash + '16d923d407af84b1d00c4336c5dd88fc3cd0e6695b7e4e13debd02c7b8c4b60d'; // no rebase checkbox PR hash config.onboardingRebaseCheckbox = onboardingRebaseCheckbox; OnboardingState.prUpdateRequested = true; // case 'false' is tested in "breaks early when onboarding" platform.getBranchPr.mockResolvedValue( diff --git a/lib/workers/repository/onboarding/pr/index.ts b/lib/workers/repository/onboarding/pr/index.ts index 78910517fde..de654b56902 100644 --- a/lib/workers/repository/onboarding/pr/index.ts +++ b/lib/workers/repository/onboarding/pr/index.ts @@ -149,6 +149,10 @@ export async function ensureOnboardingPr( `:vertical_traffic_light: Renovate will begin keeping your dependencies up-to-date only once you merge or close this Pull Request.\n\n`, ); + prTemplate += emojify( + `:books: See our [Reading List](https://docs.renovatebot.com/reading-list/) for relevant documentation you may be interested in reading.\n\n`, + ); + const configFile = getDefaultConfigFileName(); prTemplate += emojify( `:abcd: Do you want to change how Renovate upgrades your dependencies?`, From eff00fb695e15643be45ed886f682672139b9d13 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Tue, 7 Apr 2026 12:16:16 +0100 Subject: [PATCH 13/13] ci: add Zizmor for GitHub Actions linting (#42346) Although we're generally in a positive place with our Actions, we also do currently have some findings from Zizmor. We should integrate it into our CI for better visibility. We can pin to a specific version of Zizmor to ensure that we get updates through `minimumReleaseAge` compliant means, rather than always pulling `latest`. This feeds findings into GitHub Advanced Security's Security tab by default. --- .github/workflows/build.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6b8a131527c..beffc5b7086 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -366,6 +366,8 @@ jobs: - setup-build runs-on: ubuntu-latest timeout-minutes: 7 + permissions: + security-events: write steps: - name: Checkout code @@ -379,6 +381,11 @@ jobs: with: args: -color -ignore "invalid activity type \"destroyed\" for \"merge_group\" Webhook event. available types are \"checks_requested\"" + - name: Run zizmor + uses: zizmorcore/zizmor-action@71321a20a9ded102f6e9ce5718a2fcec2c4f70d8 # v0.5.2 + with: + version: v1.23.1 + test: needs: [setup, prefetch]