diff --git a/lib/config/decrypt.ts b/lib/config/decrypt.ts
index 3d06a171f28a8a63e1432dbdf7721e89f895fb20..c79e7ba9280d25de0864dd814572a9ea1f9e86ef 100644
--- a/lib/config/decrypt.ts
+++ b/lib/config/decrypt.ts
@@ -174,7 +174,7 @@ export async function decryptConfig(
           }
           logger.debug(`Decrypted ${eKey}`);
           if (eKey === 'npmToken') {
-            const token = decryptedStr.replace(regEx(/\n$/), ''); // TODO #12071
+            const token = decryptedStr.replace(regEx(/\n$/), '');
             add(token);
             logger.debug(
               { decryptedToken: maskToken(token) },
@@ -191,7 +191,7 @@ export async function decryptConfig(
               } else {
                 logger.debug('Appending _authToken= to end of existing npmrc');
                 decryptedConfig.npmrc = decryptedConfig.npmrc.replace(
-                  regEx(/\n?$/), // TODO #12071
+                  regEx(/\n?$/),
                   `\n_authToken=${token}\n`
                 );
               }
diff --git a/lib/config/migration.ts b/lib/config/migration.ts
index c2c4015e065799e04ca733498e4784feefc2c87c..89fc7a49b9c2c71caa4a4aa36f33015d0b857371 100644
--- a/lib/config/migration.ts
+++ b/lib/config/migration.ts
@@ -17,9 +17,11 @@ import type {
 import { mergeChildConfig } from './utils';
 
 const options = getOptions();
+export function fixShortHours(input: string): string {
+  return input.replace(regEx(/( \d?\d)((a|p)m)/g), '$1:00$2');
+}
 
 let optionTypes: Record<string, RenovateOptions['type']>;
-
 // Returns a migrated config
 export function migrateConfig(
   config: RenovateConfig,
@@ -157,12 +159,12 @@ export function migrateConfig(
         }
       } else if (is.string(val) && val.includes('{{baseDir}}')) {
         migratedConfig[key] = val.replace(
-          regEx(/{{baseDir}}/g), // TODO #12071
+          regEx(/{{baseDir}}/g),
           '{{packageFileDir}}'
         );
       } else if (is.string(val) && val.includes('{{depNameShort}}')) {
         migratedConfig[key] = val.replace(
-          regEx(/{{depNameShort}}/g), // TODO #12071
+          regEx(/{{depNameShort}}/g),
           '{{depName}}'
         );
       } else if (key === 'gitFs') {
@@ -340,6 +342,9 @@ export function migrateConfig(
         const schedules = is.string(val) ? [val] : [...(val as string[])];
         // split 'and'
         const schedulesLength = schedules.length;
+        const afterBeforeRe = regEx(
+          /^(.*?)(after|before) (.*?) and (after|before) (.*?)( |$)(.*)/
+        );
         for (let i = 0; i < schedulesLength; i += 1) {
           if (
             schedules[i].includes(' and ') &&
@@ -348,28 +353,16 @@ export function migrateConfig(
           ) {
             const parsedSchedule = later.parse.text(
               // We need to massage short hours first before we can parse it
-              schedules[i].replace(regEx(/( \d?\d)((a|p)m)/g), '$1:00$2') // TODO #12071
+              fixShortHours(schedules[i])
             ).schedules[0];
             // Only migrate if the after time is greater than before, e.g. "after 10pm and before 5am"
             if (parsedSchedule?.t_a?.[0] > parsedSchedule?.t_b?.[0]) {
               const toSplit = schedules[i];
               schedules[i] = toSplit
-                .replace(
-                  regEx(
-                    /^(.*?)(after|before) (.*?) and (after|before) (.*?)( |$)(.*)/
-                  ), // TODO #12071
-                  '$1$2 $3 $7'
-                )
+                .replace(afterBeforeRe, '$1$2 $3 $7')
                 .trim();
               schedules.push(
-                toSplit
-                  .replace(
-                    regEx(
-                      /^(.*?)(after|before) (.*?) and (after|before) (.*?)( |$)(.*)/
-                    ), // TODO #12071
-                    '$1$4 $5 $7'
-                  )
-                  .trim()
+                toSplit.replace(afterBeforeRe, '$1$4 $5 $7').trim()
               );
             }
           }
@@ -393,10 +386,10 @@ export function migrateConfig(
           if (
             regEx(/every (mon|tues|wednes|thurs|fri|satur|sun)day$/).test(
               schedules[i]
-            ) // TODO #12071
+            )
           ) {
             schedules[i] = schedules[i].replace(
-              regEx(/every ([a-z]*day)$/), // TODO #12071
+              regEx(/every ([a-z]*day)$/),
               'on $1'
             );
           }
@@ -514,7 +507,7 @@ export function migrateConfig(
       if (is.string(migratedConfig[key])) {
         for (const [from, to] of Object.entries(migratedTemplates)) {
           migratedConfig[key] = (migratedConfig[key] as string).replace(
-            regEx(from, 'g'), // TODO #12071
+            regEx(from, 'g'),
             to
           );
         }
diff --git a/lib/config/validation.ts b/lib/config/validation.ts
index a33a909d49dfca373189e6dcb4a5c598ac317622..98d7750cefd7dfdc32d2d4977af78089587a6a34 100644
--- a/lib/config/validation.ts
+++ b/lib/config/validation.ts
@@ -37,7 +37,8 @@ const ignoredNodes = [
   'prBody', // deprecated
   'minimumConfidence', // undocumented feature flag
 ];
-
+const tzRe = regEx(/^:timezone\((.+)\)$/);
+const rulesRe = regEx(/p.*Rules\[\d+\]$/);
 function isManagerPath(parentPath: string): boolean {
   return (
     regEx(/^regexManagers\[[0-9]+]$/).test(parentPath) ||
@@ -253,7 +254,6 @@ export async function validateConfig(
               }
             }
             if (key === 'extends') {
-              const tzRe = regEx(/^:timezone\((.+)\)$/); // TODO #12071
               for (const subval of val) {
                 if (is.string(subval)) {
                   if (
@@ -488,7 +488,7 @@ export async function validateConfig(
             }
             if (
               (selectors.includes(key) || key === 'matchCurrentVersion') &&
-              !regEx(/p.*Rules\[\d+\]$/).test(parentPath) && // Inside a packageRule  // TODO #12071
+              !rulesRe.test(parentPath) && // Inside a packageRule
               (parentPath || !isPreset) // top level in a preset
             ) {
               errors.push({
diff --git a/lib/datasource/artifactory/index.ts b/lib/datasource/artifactory/index.ts
index 95744dcb28d466d998075845e9c17c6e356883ed..1b1047aa069db6a438a4e3db8e764cf429905525 100644
--- a/lib/datasource/artifactory/index.ts
+++ b/lib/datasource/artifactory/index.ts
@@ -109,6 +109,6 @@ export class ArtifactoryDatasource extends Datasource {
   }
 
   private static parseReleaseTimestamp(rawText: string): string {
-    return rawText.trim().replace(regEx(/ ?-$/), '') + 'Z'; // TODO #12071
+    return rawText.trim().replace(regEx(/ ?-$/), '') + 'Z';
   }
 }
diff --git a/lib/datasource/github-releases/digest.ts b/lib/datasource/github-releases/digest.ts
index 21b669998904eafd12fa368d3bb2ed0be10a84f3..3401f8507c420c355ed13445234384360eb6bbc4 100644
--- a/lib/datasource/github-releases/digest.ts
+++ b/lib/datasource/github-releases/digest.ts
@@ -14,7 +14,7 @@ async function findDigestFile(
   for (const asset of smallAssets) {
     const res = await http.get(asset.browser_download_url);
     for (const line of res.body.split('\n')) {
-      const [lineDigest, lineFn] = line.split(regEx(/\s+/), 2); // TODO #12071
+      const [lineDigest, lineFn] = line.split(regEx(/\s+/), 2);
       if (lineDigest === digest) {
         return {
           assetName: asset.name,
diff --git a/lib/datasource/maven/index.ts b/lib/datasource/maven/index.ts
index 468ee1b1574373a5adb1a81865b20897926c7721..7ad19360fc2e787d473ff54dc7a3ded74c44a9f3 100644
--- a/lib/datasource/maven/index.ts
+++ b/lib/datasource/maven/index.ts
@@ -5,6 +5,7 @@ import { XmlDocument } from 'xmldoc';
 import { logger } from '../../logger';
 import * as packageCache from '../../util/cache/package';
 import { regEx } from '../../util/regex';
+import { ensureTrailingSlash } from '../../util/url';
 import mavenVersion from '../../versioning/maven';
 import * as mavenVersioning from '../../versioning/maven';
 import { compare } from '../../versioning/maven/compare';
@@ -306,7 +307,7 @@ export async function getReleases({
   registryUrl,
 }: GetReleasesConfig): Promise<ReleaseResult | null> {
   const dependency = getDependencyParts(lookupName);
-  const repoUrl = registryUrl.replace(/\/?$/, '/'); // TODO #12071
+  const repoUrl = ensureTrailingSlash(registryUrl);
 
   logger.debug(`Looking up ${dependency.display} in repository ${repoUrl}`);
 
diff --git a/lib/datasource/pod/index.ts b/lib/datasource/pod/index.ts
index 32a3d5ef46fd37a9be0c5c330bce53222811115e..55ea2b369a7714c1eadb753eaa20a87c63dc03d2 100644
--- a/lib/datasource/pod/index.ts
+++ b/lib/datasource/pod/index.ts
@@ -183,7 +183,6 @@ async function getReleasesFromCDN(
       const line = lines[idx];
       const [name, ...versions] = line.split('/');
       if (name === lookupName.replace(regEx(/\/.*$/), '')) {
-        // TODO #12071
         const releases = versions.map((version) => ({ version }));
         return { releases };
       }
diff --git a/lib/datasource/pypi/index.ts b/lib/datasource/pypi/index.ts
index e2705686601c9487d59f4d7dffdac1c41e4b570d..c587e460c6ca3c4d6ab67ef95af4673160b7446d 100644
--- a/lib/datasource/pypi/index.ts
+++ b/lib/datasource/pypi/index.ts
@@ -176,7 +176,7 @@ export class PypiDatasource extends Datasource {
     const srcPrefix = `${packageName}-`;
     const srcSuffix = '.tar.gz';
     if (srcText.startsWith(srcPrefix) && srcText.endsWith(srcSuffix)) {
-      return srcText.replace(srcPrefix, '').replace(regEx(/\.tar\.gz$/), ''); // TODO #12071
+      return srcText.replace(srcPrefix, '').replace(regEx(/\.tar\.gz$/), '');
     }
 
     // pep-0427 wheel packages
diff --git a/lib/datasource/sbt-package/index.ts b/lib/datasource/sbt-package/index.ts
index bd34c2d1d94cc71c4b491aebab3954b3cea83c6f..5c889fa487528166113248de1659f797158e2eea 100644
--- a/lib/datasource/sbt-package/index.ts
+++ b/lib/datasource/sbt-package/index.ts
@@ -123,10 +123,10 @@ export async function getUrls(
         const sourceUrl = pomXml.valueWithPath('scm.url');
         if (sourceUrl) {
           result.sourceUrl = sourceUrl
-            .replace(regEx(/^scm:/), '') // TODO #12071
-            .replace(regEx(/^git:/), '') // TODO #12071
-            .replace(regEx(/^git@github.com:/), 'https://github.com/') // TODO #12071
-            .replace(regEx(/\.git$/), ''); // TODO #12071
+            .replace(regEx(/^scm:/), '')
+            .replace(regEx(/^git:/), '')
+            .replace(regEx(/^git@github.com:/), 'https://github.com/')
+            .replace(regEx(/\.git$/), '');
         }
 
         return result;
diff --git a/lib/datasource/sbt-plugin/index.ts b/lib/datasource/sbt-plugin/index.ts
index c069dd07d1ce3ad79dbe4cad0dea862accbbc41f..807e33c87f5d8381c6158a29e75243ee88293101 100644
--- a/lib/datasource/sbt-plugin/index.ts
+++ b/lib/datasource/sbt-plugin/index.ts
@@ -1,5 +1,6 @@
 import { logger } from '../../logger';
 import { regEx } from '../../util/regex';
+import { ensureTrailingSlash } from '../../util/url';
 import * as ivyVersioning from '../../versioning/ivy';
 import { compare } from '../../versioning/maven/compare';
 import { downloadHttpProtocol } from '../maven/util';
@@ -18,8 +19,6 @@ export const defaultRegistryUrls = [SBT_PLUGINS_REPO];
 export const defaultVersioning = ivyVersioning.id;
 export const registryStrategy = 'hunt';
 
-const ensureTrailingSlash = (str: string): string => str.replace(/\/?$/, '/'); // TODO #12071
-
 async function resolvePluginReleases(
   rootUrl: string,
   artifact: string,
diff --git a/lib/manager/ansible-galaxy/extract.ts b/lib/manager/ansible-galaxy/extract.ts
index bd010432a587c743f2d909ce31043814ebe58066..b1ac37cc44f73c33d19ab00eb06fcb467f3ff449 100644
--- a/lib/manager/ansible-galaxy/extract.ts
+++ b/lib/manager/ansible-galaxy/extract.ts
@@ -46,11 +46,9 @@ export default function extractPackageFile(
       // find role and collection block
       lines.forEach((line, index) => {
         if (regEx(/^collections:/).exec(line)) {
-          // TODO #12071
           positions.collections = index;
         }
         if (regEx(/^roles:/).exec(line)) {
-          // TODO #12071
           positions.roles = index;
         }
       });
diff --git a/lib/manager/buildkite/extract.ts b/lib/manager/buildkite/extract.ts
index 6e008b5dbe1cca63eb1a982dc6b4c9a63f236178..ee60c0828c4c23409687b9bad07c04060bb84ff9 100644
--- a/lib/manager/buildkite/extract.ts
+++ b/lib/manager/buildkite/extract.ts
@@ -16,7 +16,7 @@ export function extractPackageFile(content: string): PackageFile | null {
       const line = lines[lineIdx];
       const pluginsSection = regEx(
         /^(?<pluginsIndent>\s*)(-?\s*)plugins:/
-      ).exec(line); // TODO #12071
+      ).exec(line);
       if (pluginsSection) {
         logger.trace(`Matched plugins on line ${lineNumber}`);
         isPluginsSection = true;
@@ -25,10 +25,10 @@ export function extractPackageFile(content: string): PackageFile | null {
         logger.debug(`serviceImageLine: "${line}"`);
         const { currentIndent } = regEx(/^(?<currentIndent>\s*)/).exec(
           line
-        ).groups; // TODO #12071
+        ).groups;
         const depLineMatch = regEx(
           /^\s+(?:-\s+)?(?<depName>[^#]+)#(?<currentValue>[^:]+)/
-        ).exec(line); // TODO #12071
+        ).exec(line);
         if (currentIndent.length <= pluginsIndent.length) {
           isPluginsSection = false;
           pluginsIndent = '';
diff --git a/lib/manager/bundler/extract.ts b/lib/manager/bundler/extract.ts
index 2d8ccd655cc3176e200321f300bae5a734db8ae0..22a676d6b76f19b547af2f1d26e9b47a233d3b20 100644
--- a/lib/manager/bundler/extract.ts
+++ b/lib/manager/bundler/extract.ts
@@ -5,6 +5,10 @@ import { regEx } from '../../util/regex';
 import type { PackageDependency, PackageFile } from '../types';
 import { extractLockFileEntries } from './locked-version';
 
+function formatContent(input: string): string {
+  return input.replace(regEx(/^ {2}/), '') + '\n'; //remove leading witespace and add a new line at the end
+}
+
 export async function extractPackageFile(
   content: string,
   fileName?: string
@@ -22,7 +26,6 @@ export async function extractPackageFile(
       sourceMatch =
         sourceMatch ||
         regEx(`^source ${delimiter}([^${delimiter}]+)${delimiter}\\s*$`).exec(
-          // TODO #12071
           line
         );
     }
@@ -33,14 +36,14 @@ export async function extractPackageFile(
     for (const delimiter of delimiters) {
       rubyMatch =
         rubyMatch ||
-        regEx(`^ruby ${delimiter}([^${delimiter}]+)${delimiter}`).exec(line); // TODO #12071
+        regEx(`^ruby ${delimiter}([^${delimiter}]+)${delimiter}`).exec(line);
     }
     if (rubyMatch) {
       res.constraints = { ruby: rubyMatch[1] };
     }
     const gemMatchRegex = regEx(
       `^\\s*gem\\s+(['"])(?<depName>[^'"]+)(['"])(\\s*,\\s*(?<currentValue>(['"])[^'"]+['"](\\s*,\\s*['"][^'"]+['"])?))?`
-    ); // TODO #12071
+    );
     const gemMatch = gemMatchRegex.exec(line);
     if (gemMatch) {
       const dep: PackageDependency = {
@@ -49,19 +52,19 @@ export async function extractPackageFile(
       };
       if (gemMatch.groups.currentValue) {
         const currentValue = gemMatch.groups.currentValue;
-        dep.currentValue = regEx(/\s*,\s*/).test(currentValue) // TODO #12071
+        dep.currentValue = regEx(/\s*,\s*/).test(currentValue)
           ? currentValue
           : currentValue.slice(1, -1);
       }
       dep.datasource = RubyGemsDatasource.id;
       res.deps.push(dep);
     }
-    const groupMatch = regEx(/^group\s+(.*?)\s+do/).exec(line); // TODO #12071
+    const groupMatch = regEx(/^group\s+(.*?)\s+do/).exec(line);
     if (groupMatch) {
       const depTypes = groupMatch[1]
         .split(',')
         .map((group) => group.trim())
-        .map((group) => group.replace(regEx(/^:/), '')); // TODO #12071
+        .map((group) => group.replace(regEx(/^:/), ''));
       const groupLineNumber = lineNumber;
       let groupContent = '';
       let groupLine = '';
@@ -69,7 +72,7 @@ export async function extractPackageFile(
         lineNumber += 1;
         groupLine = lines[lineNumber];
         if (groupLine !== 'end') {
-          groupContent += (groupLine || '').replace(regEx(/^ {2}/), '') + '\n'; // TODO #12071
+          groupContent += formatContent(groupLine || '');
         }
       }
       const groupRes = await extractPackageFile(groupContent);
@@ -88,7 +91,7 @@ export async function extractPackageFile(
     }
     for (const delimiter of delimiters) {
       const sourceBlockMatch = regEx(
-        `^source\\s+${delimiter}(.*?)${delimiter}\\s+do` // TODO #12071
+        `^source\\s+${delimiter}(.*?)${delimiter}\\s+do`
       ).exec(line);
       if (sourceBlockMatch) {
         const repositoryUrl = sourceBlockMatch[1];
@@ -104,7 +107,7 @@ export async function extractPackageFile(
             sourceLine = 'end';
           }
           if (sourceLine !== 'end') {
-            sourceContent += sourceLine.replace(regEx(/^ {2}/), '') + '\n'; // TODO #12071
+            sourceContent += formatContent(sourceLine);
           }
         }
         const sourceRes = await extractPackageFile(sourceContent);
@@ -122,7 +125,7 @@ export async function extractPackageFile(
         }
       }
     }
-    const platformsMatch = regEx(/^platforms\s+(.*?)\s+do/).test(line); // TODO #12071
+    const platformsMatch = regEx(/^platforms\s+(.*?)\s+do/).test(line);
     if (platformsMatch) {
       const platformsLineNumber = lineNumber;
       let platformsContent = '';
@@ -131,7 +134,7 @@ export async function extractPackageFile(
         lineNumber += 1;
         platformsLine = lines[lineNumber];
         if (platformsLine !== 'end') {
-          platformsContent += platformsLine.replace(regEx(/^ {2}/), '') + '\n'; // TODO #12071
+          platformsContent += formatContent(platformsLine);
         }
       }
       const platformsRes = await extractPackageFile(platformsContent);
@@ -147,7 +150,7 @@ export async function extractPackageFile(
         );
       }
     }
-    const ifMatch = regEx(/^if\s+(.*?)/).test(line); // TODO #12071
+    const ifMatch = regEx(/^if\s+(.*?)/).test(line);
     if (ifMatch) {
       const ifLineNumber = lineNumber;
       let ifContent = '';
@@ -156,7 +159,7 @@ export async function extractPackageFile(
         lineNumber += 1;
         ifLine = lines[lineNumber];
         if (ifLine !== 'end') {
-          ifContent += ifLine.replace(regEx(/^ {2}/), '') + '\n'; // TODO #12071
+          ifContent += formatContent(ifLine);
         }
       }
       const ifRes = await extractPackageFile(ifContent);
diff --git a/lib/manager/circleci/extract.ts b/lib/manager/circleci/extract.ts
index 800c1eafdbebbefd1e0e2bcc59dd3c69940fc4ee..8f44a985015221a826d613bca591f6bcab5439dd 100644
--- a/lib/manager/circleci/extract.ts
+++ b/lib/manager/circleci/extract.ts
@@ -11,7 +11,7 @@ export function extractPackageFile(content: string): PackageFile | null {
     const lines = content.split('\n');
     for (let lineNumber = 0; lineNumber < lines.length; lineNumber += 1) {
       const line = lines[lineNumber];
-      const orbs = regEx(/^\s*orbs:\s*$/).exec(line); // TODO #12071
+      const orbs = regEx(/^\s*orbs:\s*$/).exec(line);
       if (orbs) {
         logger.trace(`Matched orbs on line ${lineNumber}`);
         let foundOrbOrNoop: boolean;
@@ -19,14 +19,14 @@ export function extractPackageFile(content: string): PackageFile | null {
           foundOrbOrNoop = false;
           const orbLine = lines[lineNumber + 1];
           logger.trace(`orbLine: "${orbLine}"`);
-          const yamlNoop = regEx(/^\s*(#|$)/).exec(orbLine); // TODO #12071
+          const yamlNoop = regEx(/^\s*(#|$)/).exec(orbLine);
           if (yamlNoop) {
             logger.debug('orbNoop');
             foundOrbOrNoop = true;
             lineNumber += 1;
             continue;
           }
-          const orbMatch = regEx(/^\s+([^:]+):\s(.+)$/).exec(orbLine); // TODO #12071
+          const orbMatch = regEx(/^\s+([^:]+):\s(.+)$/).exec(orbLine);
           if (orbMatch) {
             logger.trace('orbMatch');
             foundOrbOrNoop = true;
@@ -47,7 +47,7 @@ export function extractPackageFile(content: string): PackageFile | null {
           }
         } while (foundOrbOrNoop);
       }
-      const match = regEx(/^\s*-? image:\s*'?"?([^\s'"]+)'?"?\s*$/).exec(line); // TODO #12071
+      const match = regEx(/^\s*-? image:\s*'?"?([^\s'"]+)'?"?\s*$/).exec(line);
       if (match) {
         const currentFrom = match[1];
         const dep = getDep(currentFrom);
diff --git a/lib/manager/cocoapods/extract.ts b/lib/manager/cocoapods/extract.ts
index 84306227bda2a42956d85ee8b0864a13bcece022..7bea8620ed22d0b31c9fc3ea213bd2329d5c68b8 100644
--- a/lib/manager/cocoapods/extract.ts
+++ b/lib/manager/cocoapods/extract.ts
@@ -26,7 +26,7 @@ export function parseLine(line: string): ParsedLine {
     return result;
   }
   for (const regex of Object.values(regexMappings)) {
-    const match = regex.exec(line.replace(regEx(/#.*$/), '')); // TODO #12071
+    const match = regex.exec(line.replace(regEx(/#.*$/), ''));
     if (match?.groups) {
       result = { ...result, ...match.groups };
     }
@@ -105,7 +105,7 @@ export async function extractPackageFile(
     }: ParsedLine = parsedLine;
 
     if (source) {
-      registryUrls.push(source.replace(regEx(/\/*$/), '')); // TODO #12071
+      registryUrls.push(source.replace(regEx(/\/*$/), ''));
     }
 
     if (depName) {
diff --git a/lib/manager/composer/extract.ts b/lib/manager/composer/extract.ts
index 8eb3c6a4e78d637c0e2c9ff79d11e4cf6df87475..e1982f88770a7c5c6796fbc2b73fc5ea25718e6a 100644
--- a/lib/manager/composer/extract.ts
+++ b/lib/manager/composer/extract.ts
@@ -22,7 +22,7 @@ import type {
  * See https://github.com/composer/composer/blob/750a92b4b7aecda0e5b2f9b963f1cb1421900675/src/Composer/Repository/ComposerRepository.php#L815
  */
 function transformRegUrl(url: string): string {
-  return url.replace(regEx(/(\/packages\.json)$/), ''); // TODO #12071
+  return url.replace(regEx(/(\/packages\.json)$/), '');
 }
 
 /**
@@ -159,7 +159,7 @@ export async function extractPackageFile(
               (item) => item.name === dep.depName
             );
             if (lockedDep && semverComposer.isVersion(lockedDep.version)) {
-              dep.lockedVersion = lockedDep.version.replace(regEx(/^v/i), ''); // TODO #12071
+              dep.lockedVersion = lockedDep.version.replace(regEx(/^v/i), '');
             }
           }
           deps.push(dep);
diff --git a/lib/manager/droneci/extract.ts b/lib/manager/droneci/extract.ts
index b02dffd55ca5db7a5145703883fb96e8b2c9e7d1..6dc15f47d47db6c81f4a2896d9394000c5272475 100644
--- a/lib/manager/droneci/extract.ts
+++ b/lib/manager/droneci/extract.ts
@@ -9,7 +9,7 @@ export function extractPackageFile(content: string): PackageFile | null {
     const lines = content.split('\n');
     for (let lineNumber = 0; lineNumber < lines.length; lineNumber += 1) {
       const line = lines[lineNumber];
-      const match = regEx(/^\s* image:\s*'?"?([^\s'"]+)'?"?\s*$/).exec(line); // TODO #12071
+      const match = regEx(/^\s* image:\s*'?"?([^\s'"]+)'?"?\s*$/).exec(line);
       if (match) {
         const currentFrom = match[1];
         const dep = getDep(currentFrom);
diff --git a/lib/manager/git-submodules/extract.ts b/lib/manager/git-submodules/extract.ts
index f67c0b46a7def9dd3e80fe75e736806cf24c2518..201682508779289f54cf9d9625f397b9992cddaa 100644
--- a/lib/manager/git-submodules/extract.ts
+++ b/lib/manager/git-submodules/extract.ts
@@ -76,7 +76,7 @@ async function getModules(
       .filter((s) => !!s);
 
     for (const line of modules) {
-      const [, name, path] = line.split(regEx(/submodule\.(.+?)\.path\s(.+)/)); // TODO #12071
+      const [, name, path] = line.split(regEx(/submodule\.(.+?)\.path\s(.+)/));
       res.push({ name, path });
     }
   } catch (err) /* istanbul ignore next */ {
@@ -105,8 +105,8 @@ export default async function extractPackageFile(
     try {
       const [currentDigest] = (await git.subModule(['status', path]))
         .trim()
-        .replace(regEx(/^[-+]/), '') // TODO #12071
-        .split(regEx(/\s/)); // TODO #12071
+        .replace(regEx(/^[-+]/), '')
+        .split(regEx(/\s/));
       const subModuleUrl = await getUrl(git, gitModulesPath, name);
       // hostRules only understands HTTP URLs
       // Find HTTP URL, then apply token
diff --git a/lib/manager/gitlabci-include/extract.ts b/lib/manager/gitlabci-include/extract.ts
index cd5c5a73927f2e1e806c4d34711e4248efe7762f..7e0c8306a90c2c18b320532d7d7de2a329ddc4c3 100644
--- a/lib/manager/gitlabci-include/extract.ts
+++ b/lib/manager/gitlabci-include/extract.ts
@@ -48,7 +48,7 @@ export function extractPackageFile(
         if (config.endpoint) {
           dep.registryUrls = [
             config.endpoint.replace(regEx(/\/api\/v4\/?/), ''),
-          ]; // TODO #12071
+          ];
         }
         deps.push(dep);
       }
diff --git a/lib/manager/gitlabci/extract.ts b/lib/manager/gitlabci/extract.ts
index 14a478b453af2b0e2e929862c4ca0dc1e5010428..7fe6b85617dfe31c4a524d8c9e79b3172c75e704 100644
--- a/lib/manager/gitlabci/extract.ts
+++ b/lib/manager/gitlabci/extract.ts
@@ -65,7 +65,7 @@ export function extractPackageFile(content: string): PackageFile | null {
           }
         }
       }
-      const services = regEx(/^\s*services:\s*$/).test(line); // TODO #12071
+      const services = regEx(/^\s*services:\s*$/).test(line);
       if (services) {
         logger.trace(`Matched services on line ${lineNumber}`);
         let foundImage: boolean;
diff --git a/lib/manager/gomod/extract.ts b/lib/manager/gomod/extract.ts
index 8627020e8dd232d2bb4c4e9a7eb91ed63cd6c12e..d266cf2d7b395f920f58cd0906df638e17f09f06 100644
--- a/lib/manager/gomod/extract.ts
+++ b/lib/manager/gomod/extract.ts
@@ -51,12 +51,12 @@ export function extractPackageFile(content: string): PackageFile | null {
       }
       const replaceMatch = regEx(
         /^replace\s+[^\s]+[\s]+[=][>]\s+([^\s]+)\s+([^\s]+)/
-      ).exec(line); // TODO #12071
+      ).exec(line);
       if (replaceMatch) {
         const dep = getDep(lineNumber, replaceMatch, 'replace');
         deps.push(dep);
       }
-      const requireMatch = regEx(/^require\s+([^\s]+)\s+([^\s]+)/).exec(line); // TODO #12071
+      const requireMatch = regEx(/^require\s+([^\s]+)\s+([^\s]+)/).exec(line);
       if (requireMatch && !line.endsWith('// indirect')) {
         logger.trace({ lineNumber }, `require line: "${line}"`);
         const dep = getDep(lineNumber, requireMatch, 'require');
@@ -67,7 +67,7 @@ export function extractPackageFile(content: string): PackageFile | null {
         do {
           lineNumber += 1;
           line = lines[lineNumber];
-          const multiMatch = regEx(/^\s+([^\s]+)\s+([^\s]+)/).exec(line); // TODO #12071
+          const multiMatch = regEx(/^\s+([^\s]+)\s+([^\s]+)/).exec(line);
           logger.trace(`reqLine: "${line}"`);
           if (multiMatch && !line.endsWith('// indirect')) {
             logger.trace({ lineNumber }, `require line: "${line}"`);
diff --git a/lib/manager/gradle/deep/gradle-updates-report.ts b/lib/manager/gradle/deep/gradle-updates-report.ts
index d3a64069e193f6c361427fcd058dd7fbe6423265..c8567eee451182e0dfa5d4168da3c5116f18042b 100644
--- a/lib/manager/gradle/deep/gradle-updates-report.ts
+++ b/lib/manager/gradle/deep/gradle-updates-report.ts
@@ -145,12 +145,11 @@ export async function extractDependenciesFromUpdatesReport(
       if (depName.endsWith('_%%')) {
         return {
           ...dep,
-          depName: depName.replace(regEx(/_%%/), ''), // TODO #12071
+          depName: depName.replace(regEx(/_%%/), ''),
           datasource: datasourceSbtPackage.id,
         };
       }
       if (regEx(/^%.*%$/).test(currentValue)) {
-        // TODO #12071
         return { ...dep, skipReason: 'version-placeholder' };
       }
       return dep;
diff --git a/lib/manager/kubernetes/extract.ts b/lib/manager/kubernetes/extract.ts
index 1eb9b20c27b0ed3b3fda0269acefef6186f98509..f537f5dadea5f7f8af654df3e075a616356c4b51 100644
--- a/lib/manager/kubernetes/extract.ts
+++ b/lib/manager/kubernetes/extract.ts
@@ -15,7 +15,7 @@ export function extractPackageFile(content: string): PackageFile | null {
   }
 
   for (const line of content.split('\n')) {
-    const match = regEx(/^\s*-?\s*image:\s*'?"?([^\s'"]+)'?"?\s*$/).exec(line); // TODO #12071
+    const match = regEx(/^\s*-?\s*image:\s*'?"?([^\s'"]+)'?"?\s*$/).exec(line);
     if (match) {
       const currentFrom = match[1];
       const dep = getDep(currentFrom);
diff --git a/lib/manager/meteor/extract.ts b/lib/manager/meteor/extract.ts
index 943842d904cb34b034b9663724673166693df0ad..d5dde17014c566f9c6a5da98a824a24c95ed535c 100644
--- a/lib/manager/meteor/extract.ts
+++ b/lib/manager/meteor/extract.ts
@@ -15,7 +15,7 @@ export function extractPackageFile(content: string): PackageFile | null {
       .split(',')
       .map((dep) => dep.trim())
       .filter((dep) => dep.length)
-      .map((dep) => dep.split(regEx(/:(.*)/))) // TODO #12071
+      .map((dep) => dep.split(regEx(/:(.*)/)))
       .map((arr) => {
         const [depName, currentValue] = arr;
         // istanbul ignore if
diff --git a/lib/manager/npm/extract/index.ts b/lib/manager/npm/extract/index.ts
index 6504c3e49f9aa420bfac4e24341de40d36c8daa8..6a7d85acb73e579cd7bc51daa56c92971250b475 100644
--- a/lib/manager/npm/extract/index.ts
+++ b/lib/manager/npm/extract/index.ts
@@ -108,7 +108,9 @@ export async function extractPackageFile(
     } else {
       npmrc = config.npmrc || '';
       if (npmrc.length) {
-        npmrc = npmrc.replace(/\n?$/, '\n'); // TODO #12875 add \n to front when used with re2
+        if (!npmrc.endsWith('\n')) {
+          npmrc += '\n';
+        }
       }
       if (repoNpmrc?.includes('package-lock')) {
         logger.debug('Stripping package-lock setting from .npmrc');
diff --git a/lib/manager/npm/post-update/index.ts b/lib/manager/npm/post-update/index.ts
index 0af01617d009a9ddd74cf4eae0488d9c466d9f6d..260b0c19207431365a3a96e72459f978b7af46bc 100644
--- a/lib/manager/npm/post-update/index.ts
+++ b/lib/manager/npm/post-update/index.ts
@@ -25,6 +25,7 @@ import {
 import { branchExists, getFile, getRepoStatus } from '../../../util/git';
 import * as hostRules from '../../../util/host-rules';
 import { regEx } from '../../../util/regex';
+import { ensureTrailingSlash } from '../../../util/url';
 import type { PackageFile, PostUpdateConfig, Upgrade } from '../../types';
 import { getZeroInstallPaths } from '../extract/yarn';
 import * as lerna from './lerna';
@@ -376,10 +377,9 @@ async function updateYarnOffline(
         .split('\n')
         .find((line) => line.startsWith('yarn-offline-mirror '));
       if (mirrorLine) {
-        const mirrorPath = mirrorLine
-          .split(' ')[1]
-          .replace(regEx(/"/g), '')
-          .replace(regEx(/\/?$/), '/');
+        const mirrorPath = ensureTrailingSlash(
+          mirrorLine.split(' ')[1].replace(regEx(/"/g), '')
+        );
         resolvedPaths.push(upath.join(lockFileDir, mirrorPath));
       }
     }
diff --git a/lib/manager/npm/post-update/rules.ts b/lib/manager/npm/post-update/rules.ts
index 0b7cc70bd18e08e1f235aa75fa9351751ad50fed..c3b8daddd98eb1cd6ccd10c76b8c598c58d4a547 100644
--- a/lib/manager/npm/post-update/rules.ts
+++ b/lib/manager/npm/post-update/rules.ts
@@ -19,7 +19,7 @@ export function processHostRules(): HostRulesResult {
   for (const hostRule of npmHostRules) {
     if (hostRule.resolvedHost) {
       let uri = hostRule.matchHost;
-      uri = validateUrl(uri) ? uri.replace(regEx(/^https?:/), '') : `//${uri}/`; // TODO #12071
+      uri = validateUrl(uri) ? uri.replace(regEx(/^https?:/), '') : `//${uri}/`;
       if (hostRule.token) {
         const key = hostRule.authType === 'Basic' ? '_auth' : '_authToken';
         additionalNpmrcContent.push(`${uri}:${key}=${hostRule.token}`);
diff --git a/lib/manager/nuget/util.ts b/lib/manager/nuget/util.ts
index 51fbb26d817755ccdb76773b323ffd98c6e1d278..1f7365b8ecbd3f372a61fb7e50eef15c1cabe82e 100644
--- a/lib/manager/nuget/util.ts
+++ b/lib/manager/nuget/util.ts
@@ -69,7 +69,7 @@ export async function getConfiguredRegistries(
         logger.debug(`clearing registry URLs`);
         registries.length = 0;
       } else if (child.name === 'add') {
-        const isHttpUrl = regEx(/^https?:\/\//i).test(child.attr.value); // TODO #12071
+        const isHttpUrl = regEx(/^https?:\/\//i).test(child.attr.value);
         if (isHttpUrl) {
           let registryUrl = child.attr.value;
           if (child.attr.protocolVersion) {
diff --git a/lib/manager/pip_requirements/extract.ts b/lib/manager/pip_requirements/extract.ts
index ca34d85b90e343d20481b1cc27002914371b3e92..5ca09fe420d97fd05d8d069340384be1e21ff462 100644
--- a/lib/manager/pip_requirements/extract.ts
+++ b/lib/manager/pip_requirements/extract.ts
@@ -90,18 +90,18 @@ export function extractPackageFile(
   if (registryUrls.length > 0) {
     res.registryUrls = registryUrls.map((url) => {
       // handle the optional quotes in eg. `--extra-index-url "https://foo.bar"`
-      const cleaned = url.replace(regEx(/^"/), '').replace(regEx(/"$/), ''); // TODO #12071
+      const cleaned = url.replace(regEx(/^"/), '').replace(regEx(/"$/), '');
       if (!GlobalConfig.get('exposeAllEnv')) {
         return cleaned;
       }
       // interpolate any environment variables
       return cleaned.replace(
-        regEx(/(\$[A-Za-z\d_]+)|(\${[A-Za-z\d_]+})/g), // TODO #12071
+        regEx(/(\$[A-Za-z\d_]+)|(\${[A-Za-z\d_]+})/g),
         (match) => {
           const envvar = match
             .substring(1)
             .replace(regEx(/^{/), '')
-            .replace(regEx(/}$/), ''); // TODO #12071
+            .replace(regEx(/}$/), '');
           const sub = process.env[envvar];
           return sub || match;
         }
diff --git a/lib/manager/sbt/extract.ts b/lib/manager/sbt/extract.ts
index 65dd05a6ec526c479c82b7ff79d3d90d635a6d80..7c5e176721f1f0d566face49ad97d674988dccb9 100644
--- a/lib/manager/sbt/extract.ts
+++ b/lib/manager/sbt/extract.ts
@@ -142,7 +142,7 @@ function parseDepExpr(
   const tokens = expr
     .trim()
     .split(regEx(/("[^"]*")/g))
-    .map((x) => (regEx(/"[^"]*"/).test(x) ? x : x.replace(regEx(/[()]+/g), ''))) // TODO #12071
+    .map((x) => (regEx(/"[^"]*"/).test(x) ? x : x.replace(regEx(/[()]+/g), '')))
     .join('')
     .split(regEx(/\s*(%%?)\s*|\s*classifier\s*/));
 
diff --git a/lib/manager/setup-cfg/extract.ts b/lib/manager/setup-cfg/extract.ts
index 7ab666964a029c9edb16977528a3196c27f71e4c..d4eec82780fe0522317c2eead85c37e13320e5b9 100644
--- a/lib/manager/setup-cfg/extract.ts
+++ b/lib/manager/setup-cfg/extract.ts
@@ -4,12 +4,12 @@ import pep440 from '../../versioning/pep440';
 import type { PackageDependency, PackageFile, Result } from '../types';
 
 function getSectionName(str: string): string {
-  const [, sectionName] = regEx(/^\[\s*([^\s]+)\s*]\s*$/).exec(str) || []; // TODO #12071
+  const [, sectionName] = regEx(/^\[\s*([^\s]+)\s*]\s*$/).exec(str) || [];
   return sectionName;
 }
 
 function getSectionRecord(str: string): string {
-  const [, sectionRecord] = regEx(/^([^\s]+)\s+=/).exec(str) || []; // TODO #12071
+  const [, sectionRecord] = regEx(/^([^\s]+)\s+=/).exec(str) || [];
   return sectionRecord;
 }
 
@@ -65,7 +65,7 @@ export function extractPackageFile(
   const deps: PackageDependency[] = [];
   content
     .split('\n')
-    .map((line) => line.replace(regEx(/[;#].*$/), '').trimRight()) // TODO #12071
+    .map((line) => line.replace(regEx(/[;#].*$/), '').trimRight())
     .forEach((rawLine) => {
       let line = rawLine;
       const newSectionName = getSectionName(line);
@@ -75,7 +75,7 @@ export function extractPackageFile(
       } else {
         if (newSectionRecord) {
           sectionRecord = newSectionRecord;
-          line = rawLine.replace(regEx(/^[^=]*=\s*/), '\t'); // TODO #12071
+          line = rawLine.replace(regEx(/^[^=]*=\s*/), '\t');
         }
         const dep = parseDep(line, sectionName, sectionRecord);
         if (dep) {
diff --git a/lib/manager/terraform/lockfile/hash.ts b/lib/manager/terraform/lockfile/hash.ts
index 1918148a9c351f5196a20705ab2d787a3ee89269..f6b0b33d5f41ca8ed50f1eb3de7f2fc813038211 100644
--- a/lib/manager/terraform/lockfile/hash.ts
+++ b/lib/manager/terraform/lockfile/hash.ts
@@ -32,7 +32,7 @@ export class TerraformProviderHash {
 
       // add double space, the filename and a new line char
       rootHash.update('  ');
-      const fileName = file.replace(regEx(/^.*[\\/]/), ''); // TODO #12071
+      const fileName = file.replace(regEx(/^.*[\\/]/), '');
       rootHash.update(fileName);
       rootHash.update('\n');
     }
diff --git a/lib/manager/terraform/providers.ts b/lib/manager/terraform/providers.ts
index e742b8837cbe3546635afab3e35cc4eff852b7ab..50ee59488c06972d9a62c8684d4419a7abf70b1c 100644
--- a/lib/manager/terraform/providers.ts
+++ b/lib/manager/terraform/providers.ts
@@ -42,8 +42,8 @@ export function extractTerraformProvider(
     // istanbul ignore else
     if (is.string(line)) {
       // `{` will be counted wit +1 and `}` with -1. Therefore if we reach braceCounter == 0. We have found the end of the terraform block
-      const openBrackets = (line.match(regEx(/\{/g)) || []).length; // TODO #12071
-      const closedBrackets = (line.match(regEx(/\}/g)) || []).length; // TODO #12071
+      const openBrackets = (line.match(regEx(/\{/g)) || []).length;
+      const closedBrackets = (line.match(regEx(/\}/g)) || []).length;
       braceCounter = braceCounter + openBrackets - closedBrackets;
 
       // only update fields inside the root block
diff --git a/lib/platform/github/index.ts b/lib/platform/github/index.ts
index c038c9d557d851996c45a4a64c1a4e37d80b36d4..9168f725ef3d96c4b43f21c1966ab092d9dd14c3 100644
--- a/lib/platform/github/index.ts
+++ b/lib/platform/github/index.ts
@@ -1244,7 +1244,7 @@ export async function addReviewers(
   const userReviewers = reviewers.filter((e) => !e.startsWith('team:'));
   const teamReviewers = reviewers
     .filter((e) => e.startsWith('team:'))
-    .map((e) => e.replace(regEx(/^team:/), '')); // TODO #12071
+    .map((e) => e.replace(regEx(/^team:/), ''));
   try {
     await githubApi.postJson(
       `repos/${
diff --git a/lib/util/git/index.ts b/lib/util/git/index.ts
index 010beaadb6cb0c98ac000512b32f034b19755ae4..b6dd617c6b63acf20a74353ba1c56b8fde8e0527 100644
--- a/lib/util/git/index.ts
+++ b/lib/util/git/index.ts
@@ -108,7 +108,7 @@ function checkForPlatformFailure(err: Error): void {
 }
 
 function localName(branchName: string): string {
-  return branchName.replace(regEx(/^origin\//), ''); // TODO #12071
+  return branchName.replace(regEx(/^origin\//), '');
 }
 
 async function isDirectory(dir: string): Promise<boolean> {
@@ -196,7 +196,7 @@ async function fetchBranchCommits(): Promise<void> {
     (await git.raw(opts))
       .split('\n')
       .filter(Boolean)
-      .map((line) => line.trim().split(regEx(/\s+/))) // TODO #12071
+      .map((line) => line.trim().split(regEx(/\s+/)))
       .forEach(([sha, ref]) => {
         config.branchCommits[ref.replace('refs/heads/', '')] = sha;
       });
@@ -488,7 +488,7 @@ export async function getFileList(): Promise<string[]> {
     .split('\n')
     .filter(Boolean)
     .filter((line) => line.startsWith('100'))
-    .map((line) => line.split(regEx(/\t/)).pop()) // TODO #12071
+    .map((line) => line.split(regEx(/\t/)).pop())
     .filter((file: string) =>
       submodules.every((submodule: string) => !file.startsWith(submodule))
     );
diff --git a/lib/util/git/url.ts b/lib/util/git/url.ts
index e7a6ef0d3093fa1c4095a72f57ed2c6535591394..9dff260a519083a272c336249f9ee659d1e54215 100644
--- a/lib/util/git/url.ts
+++ b/lib/util/git/url.ts
@@ -8,7 +8,7 @@ export function getHttpUrl(url: string, token?: string): string {
 
   parsedUrl.token = token;
 
-  const protocol = regEx(/^https?$/).exec(parsedUrl.protocol) // TODO #12071
+  const protocol = regEx(/^https?$/).exec(parsedUrl.protocol)
     ? parsedUrl.protocol
     : 'https';
   return parsedUrl.toString(protocol);
diff --git a/lib/util/markdown.ts b/lib/util/markdown.ts
index 962f0cf11848b1479a5b0a72d2cff178dd6594f1..8f869c1afe3481cc4d51c08314acc640119bd888 100644
--- a/lib/util/markdown.ts
+++ b/lib/util/markdown.ts
@@ -6,18 +6,18 @@ import { regEx } from './regex';
 export function sanitizeMarkdown(markdown: string): string {
   let res = markdown;
   // Put a zero width space after every # followed by a digit
-  res = res.replace(regEx(/#(\d)/gi), '#&#8203;$1'); // TODO #12071
+  res = res.replace(regEx(/#(\d)/gi), '#&#8203;$1');
   // Put a zero width space after every @ symbol to prevent unintended hyperlinking
-  res = res.replace(regEx(/@/g), '@&#8203;'); // TODO #12071
-  res = res.replace(regEx(/(`\[?@)&#8203;/g), '$1'); // TODO #12071
-  res = res.replace(regEx(/([a-z]@)&#8203;/gi), '$1'); // TODO #12071
-  res = res.replace(regEx(/\/compare\/@&#8203;/g), '/compare/@'); // TODO #12071
-  res = res.replace(regEx(/(\(https:\/\/[^)]*?)\.\.\.@&#8203;/g), '$1...@'); // TODO #12071
-  res = res.replace(regEx(/([\s(])#(\d+)([)\s]?)/g), '$1#&#8203;$2$3'); // TODO #12071
+  res = res.replace(regEx(/@/g), '@&#8203;');
+  res = res.replace(regEx(/(`\[?@)&#8203;/g), '$1');
+  res = res.replace(regEx(/([a-z]@)&#8203;/gi), '$1');
+  res = res.replace(regEx(/\/compare\/@&#8203;/g), '/compare/@');
+  res = res.replace(regEx(/(\(https:\/\/[^)]*?)\.\.\.@&#8203;/g), '$1...@');
+  res = res.replace(regEx(/([\s(])#(\d+)([)\s]?)/g), '$1#&#8203;$2$3');
   // convert escaped backticks back to `
-  const backTickRe = regEx(/&#x60;([^/]*?)&#x60;/g); // TODO #12071
+  const backTickRe = regEx(/&#x60;([^/]*?)&#x60;/g);
   res = res.replace(backTickRe, '`$1`');
-  res = res.replace(regEx(/`#&#8203;(\d+)`/g), '`#$1`'); // TODO #12071
+  res = res.replace(regEx(/`#&#8203;(\d+)`/g), '`#$1`');
   return res;
 }
 
diff --git a/lib/util/package-rules.ts b/lib/util/package-rules.ts
index 487738be03a722e064cc1272ba005ee9b7b941c2..92228a94fc9557feb390696ccf495958dcbf485d 100644
--- a/lib/util/package-rules.ts
+++ b/lib/util/package-rules.ts
@@ -143,7 +143,7 @@ function matchesRule(
           packagePattern === '^*$' || packagePattern === '*'
             ? '.*'
             : packagePattern
-        ); // TODO #12071
+        );
         if (packageRegex.test(depName)) {
           logger.trace(`${depName} matches against ${String(packageRegex)}`);
           isMatch = true;
@@ -173,7 +173,7 @@ function matchesRule(
     for (const pattern of excludePackagePatterns) {
       const packageRegex = regEx(
         pattern === '^*$' || pattern === '*' ? '.*' : pattern
-      ); // TODO #12071
+      );
       if (packageRegex.test(depName)) {
         logger.trace(`${depName} matches against ${String(packageRegex)}`);
         isMatch = true;
diff --git a/lib/util/regex.ts b/lib/util/regex.ts
index 612a4a1aee16421957e8d97485e702ced8076f37..d1da43bea11d1c7cbc51b4181061eef34c6a5f16 100644
--- a/lib/util/regex.ts
+++ b/lib/util/regex.ts
@@ -46,7 +46,7 @@ export function regEx(
 }
 
 export function escapeRegExp(input: string): string {
-  return input.replace(regEx(/[.*+\-?^${}()|[\]\\]/g), '\\$&'); // $& means the whole matched string // TODO #12071
+  return input.replace(regEx(/[.*+\-?^${}()|[\]\\]/g), '\\$&'); // $& means the whole matched string
 }
 
 const configValStart = regEx(/^!?\//);
diff --git a/lib/versioning/hashicorp/index.ts b/lib/versioning/hashicorp/index.ts
index 62c1e99f476ffb2da6eb6988b772c76e5d150676..d71645853183827f6d3669198a469c3af326cbc5 100644
--- a/lib/versioning/hashicorp/index.ts
+++ b/lib/versioning/hashicorp/index.ts
@@ -49,14 +49,14 @@ function getNewValue({
         replaceValue = `$<prefix>${npm.getMinor(newVersion)}$<suffix>`;
       }
       return currentValue.replace(
-        regEx(`(?<prefix>~>\\s*0\\.)\\d+(?<suffix>.*)$`), // TODO #12071
+        regEx(`(?<prefix>~>\\s*0\\.)\\d+(?<suffix>.*)$`),
         replaceValue
       );
     }
     // handle special ~> 1.2 case
     if (regEx(/(~>\s*)\d+\.\d+$/).test(currentValue)) {
       return currentValue.replace(
-        regEx(`(?<prefix>~>\\s*)\\d+\\.\\d+$`), // TODO #12071
+        regEx(`(?<prefix>~>\\s*)\\d+\\.\\d+$`),
         `$<prefix>${npm.getMajor(newVersion)}.0`
       );
     }
diff --git a/lib/versioning/hex/index.ts b/lib/versioning/hex/index.ts
index 828837720ba36e60f58005af92dc2dfe03aa547c..161c276bf365ab2c697353d4756591e836ca0548 100644
--- a/lib/versioning/hex/index.ts
+++ b/lib/versioning/hex/index.ts
@@ -10,11 +10,11 @@ export const supportedRangeStrategies = ['bump', 'extend', 'pin', 'replace'];
 
 function hex2npm(input: string): string {
   return input
-    .replace(regEx(/~>\s*(\d+\.\d+)$/), '^$1') // TODO #12071
-    .replace(regEx(/~>\s*(\d+\.\d+\.\d+)/), '~$1') // TODO #12071
-    .replace(regEx(/==|and/), '') // TODO #12071
+    .replace(regEx(/~>\s*(\d+\.\d+)$/), '^$1')
+    .replace(regEx(/~>\s*(\d+\.\d+\.\d+)/), '~$1')
+    .replace(regEx(/==|and/), '')
     .replace('or', '||')
-    .replace(regEx(/!=\s*(\d+\.\d+(\.\d+.*)?)/), '>$1 <$1') // TODO #12071
+    .replace(regEx(/!=\s*(\d+\.\d+(\.\d+.*)?)/), '>$1 <$1')
     .trim();
 }
 
diff --git a/lib/versioning/pep440/range.ts b/lib/versioning/pep440/range.ts
index e2c840ba784b89334ce56928bf848b8ba18c9f73..80d5846613c0cd56fdfaf049d54febc5aaf82c08 100644
--- a/lib/versioning/pep440/range.ts
+++ b/lib/versioning/pep440/range.ts
@@ -167,8 +167,8 @@ export function isLessThanRange(input: string, range: string): boolean {
       .split(',')
       .map((x) =>
         x
-          .replace(regEx(/\s*/g), '') // TODO #12071
-          .split(regEx(/(~=|==|!=|<=|>=|<|>|===)/)) // TODO #12071
+          .replace(regEx(/\s*/g), '')
+          .split(regEx(/(~=|==|!=|<=|>=|<|>|===)/))
           .slice(1)
       )
       .map(([op, version]) => {
diff --git a/lib/versioning/rez/transform.ts b/lib/versioning/rez/transform.ts
index 9b1cb5556da5fbc370581880d5b345e161903cee..10c2a3155a5c8e7c2204518bf4147be7ac7e211e 100644
--- a/lib/versioning/rez/transform.ts
+++ b/lib/versioning/rez/transform.ts
@@ -105,7 +105,7 @@ export function rez2pep440(input: string): string {
 export function pep4402rezInclusiveBound(input: string): string {
   return input
     .split(',')
-    .map((v) => v.trim().replace(regEx(/[<>=]/g), '')) // TODO #12071
+    .map((v) => v.trim().replace(regEx(/[<>=]/g), ''))
     .join('..');
 }
 
diff --git a/lib/versioning/ruby/index.ts b/lib/versioning/ruby/index.ts
index ce03799f00d6f49abc473a541e4885aa849f2a85..e0566af075273e209b0076a375a3ae9449d3c834 100644
--- a/lib/versioning/ruby/index.ts
+++ b/lib/versioning/ruby/index.ts
@@ -127,16 +127,15 @@ const getNewValue = ({
     const delimiter = currentValue[0];
     return newValue
       .split(',')
-      .map(
-        (element) =>
-          element.replace(
-            regEx(`^(?<whitespace>\\s*)`),
-            `$<whitespace>${delimiter}`
-          ) // TODO #12071
+      .map((element) =>
+        element.replace(
+          regEx(`^(?<whitespace>\\s*)`),
+          `$<whitespace>${delimiter}`
+        )
       )
       .map(
         (element) =>
-          element.replace(/(?<whitespace>\s*)$/, `${delimiter}$<whitespace>`) // TODO #12071 #12875 adds ' at front when re2 is used
+          element.replace(/(?<whitespace>\s*)$/, `${delimiter}$<whitespace>`) // TODO #12875 adds ' at front when re2 is used
       )
       .join(',');
   }
diff --git a/lib/workers/branch/schedule.ts b/lib/workers/branch/schedule.ts
index 71696d72ff125560e987e99a0ba03e30a5d4215a..a84d7ed839ae551d1b618f9d55a3532bb2e3ee8b 100644
--- a/lib/workers/branch/schedule.ts
+++ b/lib/workers/branch/schedule.ts
@@ -1,19 +1,15 @@
 import later from '@breejs/later';
 import is from '@sindresorhus/is';
 import { DateTime } from 'luxon';
+import { fixShortHours } from '../../config/migration';
 import type { RenovateConfig } from '../../config/types';
 import { logger } from '../../logger';
-import { regEx } from '../../util/regex';
 
 const scheduleMappings: Record<string, string> = {
   'every month': 'before 3am on the first day of the month',
   monthly: 'before 3am on the first day of the month',
 };
 
-function fixShortHours(input: string): string {
-  return input.replace(regEx(/( \d?\d)((a|p)m)/g), '$1:00$2');
-}
-
 export function hasValidTimezone(
   timezone: string
 ): [boolean] | [boolean, string] {
diff --git a/lib/workers/pr/body/index.ts b/lib/workers/pr/body/index.ts
index 0a3f509fc9271140b37b9b0e5148c4c82ef097af..b67ec88964ffac2ea123729563526512db386745 100644
--- a/lib/workers/pr/body/index.ts
+++ b/lib/workers/pr/body/index.ts
@@ -1,6 +1,7 @@
 import { platform } from '../../../platform';
 import { regEx } from '../../../util/regex';
 import * as template from '../../../util/template';
+import { ensureTrailingSlash } from '../../../util/url';
 import type { BranchConfig } from '../../types';
 import { getChangelogs } from './changelogs';
 import { getPrConfigDescription } from './config-description';
@@ -43,7 +44,7 @@ function massageUpdateMetadata(config: BranchConfig): void {
       let fullUrl = sourceUrl;
       if (sourceDirectory) {
         fullUrl =
-          sourceUrl.replace(regEx(/\/?$/), '/') +
+          ensureTrailingSlash(sourceUrl) +
           'tree/HEAD/' +
           sourceDirectory.replace('^/?/', '');
       }
diff --git a/lib/workers/pr/body/updates-table.ts b/lib/workers/pr/body/updates-table.ts
index 173fe873c94748061fe3bc0ebc6d87e52ba9a5de..bb4aebe8d8c9f5b5f988ba746031768247c44a59 100644
--- a/lib/workers/pr/body/updates-table.ts
+++ b/lib/workers/pr/body/updates-table.ts
@@ -46,7 +46,7 @@ export function getPrUpdatesTable(config: BranchConfig): string {
         if (value) {
           res[header] = template
             .compile(value, upgrade)
-            .replace(regEx(/^``$/), ''); // TODO #12071
+            .replace(regEx(/^``$/), '');
         } else {
           res[header] = '';
         }
@@ -67,7 +67,7 @@ export function getPrUpdatesTable(config: BranchConfig): string {
       const content = row[column]
         ? row[column]
             .replace(regEx(/^@/), '@&#8203;')
-            .replace(regEx(/\|/g), '\\|') // TODO #12071
+            .replace(regEx(/\|/g), '\\|')
         : '';
       val += ` ${content} |`;
     }
diff --git a/lib/workers/pr/changelog/release-notes.ts b/lib/workers/pr/changelog/release-notes.ts
index ac3395296a44520284a0fa4b28ce199c3989ae90..192785bb20fcb4b05026575d28e050ae54dfd6bd 100644
--- a/lib/workers/pr/changelog/release-notes.ts
+++ b/lib/workers/pr/changelog/release-notes.ts
@@ -68,9 +68,9 @@ export function massageBody(
 ): string {
   let body = input || '';
   // Convert line returns
-  body = body.replace(regEx(/\r\n/g), '\n'); // TODO #12071
+  body = body.replace(regEx(/\r\n/g), '\n');
   // semantic-release cleanup
-  body = body.replace(regEx(/^<a name="[^"]*"><\/a>\n/), ''); // TODO #12071
+  body = body.replace(regEx(/^<a name="[^"]*"><\/a>\n/), '');
   body = body.replace(
     regEx(
       `^##? \\[[^\\]]*\\]\\(${baseUrl}[^/]*\\/[^/]*\\/compare\\/.*?\\n`,
@@ -78,17 +78,17 @@ export function massageBody(
       false
     ),
     ''
-  ); // TODO #12071
+  );
   // Clean-up unnecessary commits link
   body = `\n${body}\n`.replace(
     regEx(`\\n${baseUrl}[^/]+\\/[^/]+\\/compare\\/[^\\n]+(\\n|$)`),
     '\n'
-  ); // TODO #12071
+  );
   // Reduce headings size
   body = body
-    .replace(regEx(/\n\s*####? /g), '\n##### ') // TODO #12071
-    .replace(regEx(/\n\s*## /g), '\n#### ') // TODO #12071
-    .replace(regEx(/\n\s*# /g), '\n### '); // TODO #12071
+    .replace(regEx(/\n\s*####? /g), '\n##### ')
+    .replace(regEx(/\n\s*## /g), '\n#### ')
+    .replace(regEx(/\n\s*# /g), '\n### ');
   // Trim whitespace
   return body.trim();
 }
@@ -253,13 +253,13 @@ export async function getReleaseNotesMd(
           const deParenthesizedSection = section.replace(
             regEx(/[[\]()]/g),
             ' '
-          ); // TODO #12071
+          );
           const [heading] = deParenthesizedSection.split('\n');
           const title = heading
-            .replace(regEx(/^\s*#*\s*/), '') // TODO #12071
+            .replace(regEx(/^\s*#*\s*/), '')
             .split(' ')
             .filter(Boolean);
-          let body = section.replace(regEx(/.*?\n(-{3,}\n)?/), '').trim(); // TODO #12071
+          let body = section.replace(regEx(/.*?\n(-{3,}\n)?/), '').trim();
           for (const word of title) {
             if (word.includes(version) && !isUrl(word)) {
               logger.trace({ body }, 'Found release notes for v' + version);
@@ -268,7 +268,7 @@ export async function getReleaseNotesMd(
               const url =
                 notesSourceUrl +
                 '#' +
-                title.join('-').replace(regEx(/[^A-Za-z0-9-]/g), ''); // TODO #12071
+                title.join('-').replace(regEx(/[^A-Za-z0-9-]/g), '');
               body = massageBody(body, baseUrl);
               if (body?.length) {
                 try {
diff --git a/lib/workers/pr/code-owners.ts b/lib/workers/pr/code-owners.ts
index 22f7681adb6a0a9afc5e4aaa114494814a481500..8fcdbfe7094885f41ef71d0c7c5f8184e41d1d47 100644
--- a/lib/workers/pr/code-owners.ts
+++ b/lib/workers/pr/code-owners.ts
@@ -27,7 +27,7 @@ export async function codeOwnersForPr(pr: Pr): Promise<string[]> {
       .map((line) => line.trim())
       .filter((line) => line && !line.startsWith('#'))
       .map((line) => {
-        const [pattern, ...usernames] = line.split(regEx(/\s+/)); // TODO #12071
+        const [pattern, ...usernames] = line.split(regEx(/\s+/));
         return {
           usernames,
           match: (path: string) => {
diff --git a/lib/workers/repository/init/vulnerability.ts b/lib/workers/repository/init/vulnerability.ts
index 321ddf5bbb5cc90a754599c60a5acdf41d3d7ce8..eb259a32ac170c2b7cbe5b3ceee8a36414a278ee 100644
--- a/lib/workers/repository/init/vulnerability.ts
+++ b/lib/workers/repository/init/vulnerability.ts
@@ -114,7 +114,7 @@ export async function detectVulnerabilityAlerts(
         vulnerableRequirements = vulnerableRequirements.replace(
           regEx(/^= /),
           '== '
-        ); // TODO #12071
+        );
       }
       combinedAlerts[fileName] ||= {};
       combinedAlerts[fileName][datasource] ||= {};
diff --git a/lib/workers/repository/onboarding/pr/pr-list.ts b/lib/workers/repository/onboarding/pr/pr-list.ts
index b381c9f485966a77faf3ab0d99f6cddf0de6eb6d..519b4f7ec5c6a081c6cf441ddc78da07b0017d6c 100644
--- a/lib/workers/repository/onboarding/pr/pr-list.ts
+++ b/lib/workers/repository/onboarding/pr/pr-list.ts
@@ -18,7 +18,7 @@ export function getPrList(
   prDesc += branches.length > 1 ? `s:\n\n` : `:\n\n`;
 
   for (const branch of branches) {
-    const prTitleRe = regEx(/@([a-z]+\/[a-z]+)/); // TODO #12071
+    const prTitleRe = regEx(/@([a-z]+\/[a-z]+)/);
     prDesc += `<details>\n<summary>${branch.prTitle.replace(
       prTitleRe,
       '@&#8203;$1'
diff --git a/lib/workers/repository/updates/flatten.ts b/lib/workers/repository/updates/flatten.ts
index 5f3bf1e64df39d4c666422fdd3abc5fce34669f6..36cd1411407ae62b1ffc29c6a1c96fc49578106f 100644
--- a/lib/workers/repository/updates/flatten.ts
+++ b/lib/workers/repository/updates/flatten.ts
@@ -19,8 +19,8 @@ function sanitizeDepName(depName: string): string {
   return depName
     .replace('@types/', '')
     .replace('@', '')
-    .replace(regEx(/\//g), '-') // TODO #12071
-    .replace(regEx(/\s+/g), '-') // TODO #12071
+    .replace(regEx(/\//g), '-')
+    .replace(regEx(/\s+/g), '-')
     .replace(regEx(/-+/), '-')
     .toLowerCase();
 }
@@ -39,8 +39,8 @@ export function applyUpdateConfig(input: BranchUpgradeConfig): any {
     const parsedSourceUrl = parseUrl(updateConfig.sourceUrl);
     if (parsedSourceUrl?.pathname) {
       updateConfig.sourceRepoSlug = parsedSourceUrl.pathname
-        .replace(regEx(/^\//), '') // remove leading slash  // TODO #12071
-        .replace(regEx(/\//g), '-') // change slashes to hyphens   // TODO #12071
+        .replace(regEx(/^\//), '') // remove leading slash
+        .replace(regEx(/\//g), '-') // change slashes to hyphens
         .replace(regEx(/-+/g), '-'); // remove multiple hyphens
     }
   }
diff --git a/lib/workers/repository/updates/generate.ts b/lib/workers/repository/updates/generate.ts
index 49c9570f2577f3eb319c7df0f2e26d7baca7a6ef..56d86aff208c558672b08a7314db1b5e88838ae5 100644
--- a/lib/workers/repository/updates/generate.ts
+++ b/lib/workers/repository/updates/generate.ts
@@ -160,7 +160,7 @@ export function generateBranchConfig(
       }
       upgrade.commitMessagePrefix = CommitMessage.formatPrefix(semanticPrefix);
       upgrade.toLowerCase =
-        regEx(/[A-Z]/).exec(upgrade.semanticCommitType) === null && // TODO #12071
+        regEx(/[A-Z]/).exec(upgrade.semanticCommitType) === null &&
         !upgrade.semanticCommitType.startsWith(':');
     }
     // Compile a few times in case there are nested templates
@@ -179,9 +179,9 @@ export function generateBranchConfig(
       throw new Error(CONFIG_SECRETS_EXPOSED);
     }
     upgrade.commitMessage = upgrade.commitMessage.trim(); // Trim exterior whitespace
-    upgrade.commitMessage = upgrade.commitMessage.replace(regEx(/\s+/g), ' '); // Trim extra whitespace inside string // TODO #12071
+    upgrade.commitMessage = upgrade.commitMessage.replace(regEx(/\s+/g), ' '); // Trim extra whitespace inside string
     upgrade.commitMessage = upgrade.commitMessage.replace(
-      regEx(/to vv(\d)/), // TODO #12071
+      regEx(/to vv(\d)/),
       'to v$1'
     );
     if (upgrade.toLowerCase) {
@@ -203,7 +203,7 @@ export function generateBranchConfig(
       upgrade.prTitle = template
         .compile(upgrade.prTitle, upgrade)
         .trim()
-        .replace(regEx(/\s+/g), ' '); // TODO #12071
+        .replace(regEx(/\s+/g), ' ');
       // istanbul ignore if
       if (upgrade.prTitle !== sanitize(upgrade.prTitle)) {
         logger.debug(
diff --git a/test/exec-util.ts b/test/exec-util.ts
index d6cecc504632d6a4ba9f34747e4cac7c51dd819d..2f00637e76d918e5ad6ae84978773448682a6c3c 100644
--- a/test/exec-util.ts
+++ b/test/exec-util.ts
@@ -31,7 +31,7 @@ export function execSnapshot(cmd: string, options?: CallOptions): ExecSnapshot {
     if (is.string(v)) {
       const val = v
         .replace(regEx(/\\(\w)/g), '/$1')
-        .replace(cwd, '/root/project'); // TODO #12071
+        .replace(cwd, '/root/project');
       this.update(val);
     }
   });
diff --git a/tools/generate-imports.mjs b/tools/generate-imports.mjs
index e9508e15874902ff4b718e1836c62cb0a0c2bafc..4633a0d09e64408b5b9086c282a887b1637475bd 100644
--- a/tools/generate-imports.mjs
+++ b/tools/generate-imports.mjs
@@ -73,7 +73,7 @@ async function generateData() {
   /** @type {string[]} */
   const contentMapAssignments = [];
   for (const file of files) {
-    const key = file.replace(/\\/g, '/'); // TODO #12071
+    const key = file.replace(/\\/g, '/');
 
     const rawFileContent = await fs.readFile(file, 'utf8');
     const value = JSON.stringify(rawFileContent);