diff --git a/lib/modules/manager/regex/index.spec.ts b/lib/modules/manager/regex/index.spec.ts index 1146c533f20d22151fe6e7a28822ceb17077b900..e5374ea51129b309c4ab2e431f539147f3871a51 100644 --- a/lib/modules/manager/regex/index.spec.ts +++ b/lib/modules/manager/regex/index.spec.ts @@ -214,6 +214,58 @@ describe('modules/manager/regex/index', () => { expect(res?.deps).toHaveLength(1); }); + it('extracts indentation: maintains indentation value if whitespace or empty', async () => { + const config = { + matchStrings: [ + '(?<indentation>\\s*)image:\\s+(?<depName>[^\\s]+):(?<currentValue>[^\\s]+)', + ], + autoReplaceStringTemplate: + 'image:\n{{{indentation}}} name: {{{depName}}}:{{{newValue}}}', + datasourceTemplate: 'docker', + }; + const res = await extractPackageFile( + ' image: eclipse-temurin:17.0.0-alpine', + 'bitbucket-pipelines.yml', + config + ); + expect(res).toMatchObject({ + deps: [ + { + depName: 'eclipse-temurin', + currentValue: '17.0.0-alpine', + datasource: 'docker', + indentation: ' ', + }, + ], + }); + }); + + it('extracts indentation: discards non-whitespace content', async () => { + const config = { + matchStrings: [ + '(?<indentation>.*)image:\\s+(?<depName>[^\\s]+):(?<currentValue>[^\\s]+)', + ], + autoReplaceStringTemplate: + 'image:\n{{{indentation}}} name: {{{depName}}}:{{{newValue}}}', + datasourceTemplate: 'docker', + }; + const res = await extractPackageFile( + 'name: image: eclipse-temurin:17.0.0-alpine', + 'bitbucket-pipelines.yml', + config + ); + expect(res).toMatchObject({ + deps: [ + { + depName: 'eclipse-temurin', + currentValue: '17.0.0-alpine', + datasource: 'docker', + indentation: '', + }, + ], + }); + }); + it('extracts with combination strategy', async () => { const config: CustomExtractConfig = { matchStrings: [ diff --git a/lib/modules/manager/regex/readme.md b/lib/modules/manager/regex/readme.md index e2a7efe66fe3803a2617d83ec5c96fe81bbf6d54..e2c0fe27f1b9506e2b9bf503d1ded616c890d19d 100644 --- a/lib/modules/manager/regex/readme.md +++ b/lib/modules/manager/regex/readme.md @@ -34,6 +34,8 @@ Configuration-wise, it works like this: - You can optionally have a `currentDigest` capture group. - You can optionally have a `registryUrl` capture group or a `registryUrlTemplate` config field - If it's a valid URL, it will be converted to the `registryUrls` field as a single-length array. +- You can optionally have an `indentation` capture group. + - If it's not empty or whitespace, it will be reset to an empty string. ### Regular Expression Capture Groups diff --git a/lib/modules/manager/regex/utils.ts b/lib/modules/manager/regex/utils.ts index 1d909a6e800cda0a87abc25f4bfb6778d7f1fc27..8f9a2743fcd2190059989a9e8015410bad1b8338 100644 --- a/lib/modules/manager/regex/utils.ts +++ b/lib/modules/manager/regex/utils.ts @@ -17,6 +17,7 @@ export const validMatchFields = [ 'extractVersion', 'registryUrl', 'depType', + 'indentation', ] as const; type ValidMatchFields = (typeof validMatchFields)[number]; @@ -39,6 +40,9 @@ function updateDependency( case 'datasource': dependency.datasource = migrateDatasource(value); break; + case 'indentation': + dependency.indentation = is.emptyStringOrWhitespace(value) ? value : ''; + break; default: dependency[field] = value; break; diff --git a/lib/modules/manager/types.ts b/lib/modules/manager/types.ts index 80f84fe48094df71f447509eb23b555e132ba338..abd361b4b15006e0074bc021754b311d5b0ca470 100644 --- a/lib/modules/manager/types.ts +++ b/lib/modules/manager/types.ts @@ -150,6 +150,7 @@ export interface PackageDependency<T = Record<string, any>> extractVersion?: string; isInternal?: boolean; variableName?: string; + indentation?: string; } export interface Upgrade<T = Record<string, any>> extends PackageDependency<T> { diff --git a/lib/util/template/index.ts b/lib/util/template/index.ts index 6034e2ce38024c334254f07af0b494feadd7aee5..c1b72dc9b80ad132bf383205d5a35d4f76f3fdd8 100644 --- a/lib/util/template/index.ts +++ b/lib/util/template/index.ts @@ -87,6 +87,7 @@ export const allowedFields = { displayPending: 'Latest pending update, if internalChecksFilter is in use', displayTo: 'The to value, formatted for display', hasReleaseNotes: 'true if the upgrade has release notes', + indentation: 'The indentation of the dependency being updated', isLockfileUpdate: 'true if the branch is a lock file update', isMajor: 'true if the upgrade is major', isPatch: 'true if the upgrade is a patch upgrade',