From 682829f33a1a5cc28a0f62e8b92c853098c85080 Mon Sep 17 00:00:00 2001
From: Tim Knight <tim.knight1@engineering.digital.dwp.gov.uk>
Date: Sat, 10 Dec 2022 07:09:11 +0000
Subject: [PATCH] docs: improve regexManager documentation (#19278)

Co-authored-by: Rhys Arkins <rhys@arkins.net>
Co-authored-by: HonkingGoose <34918129+HonkingGoose@users.noreply.github.com>
Resolves https://github.com/renovatebot/renovate/issues/19265
---
 lib/modules/manager/regex/readme.md           | 45 +++++++++++++++++++
 lib/util/string.spec.ts                       | 27 +++++++++++
 .../update/branch/auto-replace.spec.ts        | 36 +++++++++++++++
 3 files changed, 108 insertions(+)
 create mode 100644 lib/util/string.spec.ts

diff --git a/lib/modules/manager/regex/readme.md b/lib/modules/manager/regex/readme.md
index de89ae27b5..3d267bb9e7 100644
--- a/lib/modules/manager/regex/readme.md
+++ b/lib/modules/manager/regex/readme.md
@@ -130,3 +130,48 @@ The `Dockerfile` is documented better as well.
 
 The syntax in the example is arbitrary and you can set your own syntax.
 If you do, update your `matchStrings` regex!
+
+### Using regexManager to update the dependency name in addition to version
+
+#### Updating `gitlab-ci include` dep names
+
+You can use the regex manager to update the `depName` and the version.
+This can be handy when the location of files referenced in gitlab-ci `includes:` fields has changed.
+
+You may need to set a second `matchString` for the new name to ensure the regex manager can detect the new value.
+For example:
+
+```json
+{
+  "regexManagers": [
+    {
+      "fileMatch": [".*y[a]?ml$"],
+      "matchStringsStrategy": "combination",
+      "matchStrings": [
+        "['\"]?(?<depName>/pipeline-fragments\\/fragment-version-check)['\"]?\\s*ref:\\s['\"]?(?<currentValue>[\\d-]*)['\"]?",
+        "['\"]?(?<depName>pipeline-solutions\\/gitlab\\/fragments\\/fragment-version-check)['\"]?\\s*ref:\\s['\"]?(?<currentValue>[\\d-]*)['\"]?"
+      ],
+      "depNameTemplate": "pipeline-solutions/gitlab/fragments/fragment-version-check",
+      "autoReplaceStringTemplate": "'{{{depName}}}'\n    ref: {{{newValue}}}",
+      "datasourceTemplate": "gitlab-tags",
+      "versioningTemplate": "gitlab-tags"
+    }
+  ]
+}
+```
+
+The config above will migrate:
+
+```yaml
+- project: 'pipeline-fragments/docker-lint'
+  ref: 2-4-0
+  file: 'ci-include-docker-lint-base.yml'
+```
+
+To this:
+
+```yaml
+- project: 'pipeline-solutions/gitlab/fragments/docker-lint'
+  ref: 2-4-1
+  file: 'ci-include-docker-lint-base.yml'
+```
diff --git a/lib/util/string.spec.ts b/lib/util/string.spec.ts
new file mode 100644
index 0000000000..4751abec63
--- /dev/null
+++ b/lib/util/string.spec.ts
@@ -0,0 +1,27 @@
+import { replaceAt } from './string';
+
+describe('util/string', () => {
+  describe('replaceAt', () => {
+    test('replaceAt inserts newString which is one char longer than oldString', () => {
+      const content = 'I am a dog';
+      const index = 2;
+      const newString = 'are';
+      const oldString = 'am';
+
+      const newContent = replaceAt(content, index, oldString, newString);
+
+      expect(newContent).toBe('I are a dog');
+    });
+
+    test('replaceAt inserts newString which is significantly longer than oldString', () => {
+      const content = 'I am a dog';
+      const index = 2;
+      const newString = 'want to have a new pet maybe';
+      const oldString = 'am';
+
+      const newContent = replaceAt(content, index, oldString, newString);
+
+      expect(newContent).toBe('I want to have a new pet maybe a dog');
+    });
+  });
+});
diff --git a/lib/workers/repository/update/branch/auto-replace.spec.ts b/lib/workers/repository/update/branch/auto-replace.spec.ts
index b24ab21504..65c998815b 100644
--- a/lib/workers/repository/update/branch/auto-replace.spec.ts
+++ b/lib/workers/repository/update/branch/auto-replace.spec.ts
@@ -163,6 +163,42 @@ describe('workers/repository/update/branch/auto-replace', () => {
       );
     });
 
+    it('succeeds when using autoReplaceStringTemplate to update depName when using regex', async () => {
+      const yml =
+        "- project: 'pipeline-fragments/docker-test'\n" +
+        'ref: 3-0-0\n' +
+        "file: 'ci-include-docker-test-base.yml'\n" +
+        "- project: 'pipeline-fragments/docker-lint'\n" +
+        'ref: 2-4-0\n' +
+        "file: 'ci-include-docker-lint-base.yml'";
+      upgrade.manager = 'regex';
+      upgrade.depName = 'pipeline-solutions/gitlab/fragments/docker-lint';
+      upgrade.currentValue = '2-4-0';
+      upgrade.newValue = '2-4-1';
+      upgrade.depIndex = 0;
+      upgrade.replaceString = "'pipeline-fragments/docker-lint'\nref: 2-4-0";
+      upgrade.packageFile = '.gitlab-ci.yml';
+      upgrade.autoReplaceStringTemplate =
+        "'{{{depName}}}'\nref: {{{newValue}}}";
+      upgrade.matchStringsStrategy = 'combination';
+
+      // If the new "name" is not added to the matchStrings, the regex matcher fails to extract from `newContent` as
+      // there's nothing defined in there anymore that it can match
+      upgrade.matchStrings = [
+        '[\'"]?(?<depName>pipeline-fragments\\/docker-lint)[\'"]?\\s*ref:\\s[\'"]?(?<currentValue>[\\d-]*)[\'"]?',
+        '[\'"]?(?<depName>pipeline-solutions\\/gitlab\\/fragments\\/docker-lint)[\'"]?\\s*ref:\\s[\'"]?(?<currentValue>[\\d-]*)[\'"]?',
+      ];
+      const res = await doAutoReplace(upgrade, yml, reuseExistingBranch);
+      expect(res).toBe(
+        "- project: 'pipeline-fragments/docker-test'\n" +
+          'ref: 3-0-0\n' +
+          "file: 'ci-include-docker-test-base.yml'\n" +
+          "- project: 'pipeline-solutions/gitlab/fragments/docker-lint'\n" +
+          'ref: 2-4-1\n' +
+          "file: 'ci-include-docker-lint-base.yml'"
+      );
+    });
+
     it('fails with oldversion in depname', async () => {
       const yml =
         'image: "1111111111.dkr.ecr.us-east-1.amazonaws.com/my-repository:1"\n\n';
-- 
GitLab