diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index e2b714c7aeb12ec65aa30e46289eeea9cadc8800..276e52ae1eefdcce73bd5468c33dd5a3ff2295ef 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -404,7 +404,7 @@ jobs:
       - name: Check coverage threshold
         run: |
           pnpm nyc check-coverage -t ./coverage/nyc \
-            --branches 99.61 \
+            --branches 100 \
             --functions 100 \
             --lines 100 \
             --statements 100
diff --git a/lib/modules/manager/maven/extract.ts b/lib/modules/manager/maven/extract.ts
index 1c9c3a6ee3ba03f119bfc8b1a0ccebb9a2f9071c..5ab8652717bca5a025231dca01cead49fc5ebf25 100644
--- a/lib/modules/manager/maven/extract.ts
+++ b/lib/modules/manager/maven/extract.ts
@@ -39,7 +39,7 @@ function containsPlaceholder(str: string | null | undefined): boolean {
 
 function depFromNode(
   node: XmlElement,
-  underBuildSettingsElement = false
+  underBuildSettingsElement: boolean
 ): PackageDependency | null {
   if (!('valueWithPath' in node)) {
     return null;
@@ -198,7 +198,10 @@ function applyPropsInternal(
           groupName = propKey;
         }
         fileReplacePosition = propValue.fileReplacePosition;
-        propSource = propValue.packageFile ?? undefined;
+        propSource =
+          propValue.packageFile ??
+          // istanbul ignore next
+          undefined;
         anyChange = true;
         if (previouslySeenProps.has(propKey)) {
           fatal = true;
diff --git a/lib/modules/manager/npm/extract/locked-versions.spec.ts b/lib/modules/manager/npm/extract/locked-versions.spec.ts
index 8d4e8ce57ce8b0d09804caf09299d4440e268b0a..04f6c692865a35070e3ae1e95e607f8c943c1f0f 100644
--- a/lib/modules/manager/npm/extract/locked-versions.spec.ts
+++ b/lib/modules/manager/npm/extract/locked-versions.spec.ts
@@ -295,6 +295,34 @@ describe('modules/manager/npm/extract/locked-versions', () => {
       ]);
     });
 
+    it('does nothing if managerData is not present', async () => {
+      npm.getNpmLock.mockResolvedValue({
+        lockedVersions: { a: '1.0.0', b: '2.0.0', c: '3.0.0' },
+        lockfileVersion: 1,
+      });
+      const packageFiles = [
+        {
+          extractedConstraints: {},
+          deps: [
+            { depName: 'a', currentValue: '1.0.0' },
+            { depName: 'b', currentValue: '2.0.0' },
+          ],
+          packageFile: 'some-file',
+        },
+      ];
+      await getLockedVersions(packageFiles);
+      expect(packageFiles).toEqual([
+        {
+          extractedConstraints: {},
+          deps: [
+            { currentValue: '1.0.0', depName: 'a' },
+            { currentValue: '2.0.0', depName: 'b' },
+          ],
+          packageFile: 'some-file',
+        },
+      ]);
+    });
+
     it('uses package-lock.json with npm v7.0.0', async () => {
       npm.getNpmLock.mockResolvedValue({
         lockedVersions: { a: '1.0.0', b: '2.0.0', c: '3.0.0' },
diff --git a/lib/modules/manager/npm/extract/monorepo.spec.ts b/lib/modules/manager/npm/extract/monorepo.spec.ts
index ce5c9e3e461ae12885b3475758a97b8059f75e8c..f7e46f2ab69ee7b2986cb33be749b66ef2b1cabb 100644
--- a/lib/modules/manager/npm/extract/monorepo.spec.ts
+++ b/lib/modules/manager/npm/extract/monorepo.spec.ts
@@ -165,6 +165,10 @@ describe('modules/manager/npm/extract/monorepo', () => {
           packageFile: 'packages/b/package.json',
           managerData: { packageJsonName: '@org/b' },
         },
+        // for coverage
+        {
+          packageFile: 'packages/c/package.json',
+        },
       ];
       await detectMonorepos(packageFiles);
       expect(packageFiles[1].managerData?.lernaJsonFile).toBe('lerna.json');
diff --git a/lib/modules/manager/npm/post-update/index.spec.ts b/lib/modules/manager/npm/post-update/index.spec.ts
index e6fd13d8496eab49f805f94e014d44d0169b4499..c6eaaacc1497d1358a1cbf98f1e3b7a7607d58e2 100644
--- a/lib/modules/manager/npm/post-update/index.spec.ts
+++ b/lib/modules/manager/npm/post-update/index.spec.ts
@@ -454,7 +454,7 @@ describe('modules/manager/npm/post-update/index', () => {
       ]);
     });
 
-    it('detects if lock file contents are unchanged', async () => {
+    it('detects if lock file contents are unchanged(reuseExistingBranch=true)', async () => {
       spyNpm.mockResolvedValueOnce({ error: false, lockFile: '{}' });
       fs.readLocalFile.mockImplementation((f): Promise<any> => {
         if (f === 'package-lock.json') {
@@ -482,6 +482,36 @@ describe('modules/manager/npm/post-update/index', () => {
       ).toBeUndefined();
     });
 
+    // for coverage run once when not reusing the branch
+    it('detects if lock file contents are unchanged(reuseExistingBranch=false)', async () => {
+      spyNpm.mockResolvedValueOnce({ error: false, lockFile: '{}' });
+      fs.readLocalFile.mockImplementation((f): Promise<any> => {
+        if (f === 'package-lock.json') {
+          return Promise.resolve('{}');
+        }
+        return Promise.resolve(null);
+      });
+      git.getFile.mockImplementation((f) => {
+        if (f === 'package-lock.json') {
+          return Promise.resolve('{}');
+        }
+        return Promise.resolve(null);
+      });
+      expect(
+        (
+          await getAdditionalFiles(
+            {
+              ...updateConfig,
+              updateLockFiles: true,
+              reuseExistingBranch: false,
+              baseBranch: 'base',
+            },
+            additionalFiles
+          )
+        ).updatedArtifacts.find((a) => a.path === 'package-lock.json')
+      ).toBeUndefined();
+    });
+
     it('works for yarn', async () => {
       spyYarn.mockResolvedValueOnce({ error: false, lockFile: '{}' });
       expect(
diff --git a/lib/modules/manager/npm/post-update/npm.ts b/lib/modules/manager/npm/post-update/npm.ts
index e6ff36f57d5df8cb30bdd8bc616f84fb6fdc079b..f81921d8eb75f1d737ee3b069db8f75ed3cd3f82 100644
--- a/lib/modules/manager/npm/post-update/npm.ts
+++ b/lib/modules/manager/npm/post-update/npm.ts
@@ -251,7 +251,7 @@ export function divideWorkspaceAndRootDeps(
         // compare workspaceDir to workspace patterns
         // stop when the first match is found and
         // add workspaceDir to workspaces set and upgrade object
-        for (const workspacePattern of workspacePatterns ?? []) {
+        for (const workspacePattern of workspacePatterns) {
           if (minimatch(workspacePattern).match(workspaceDir)) {
             workspaceName = workspaceDir;
             break;
diff --git a/lib/modules/manager/npm/update/dependency/index.spec.ts b/lib/modules/manager/npm/update/dependency/index.spec.ts
index 01b3b91f04f5bf02278dd23499cd56f0881be52a..e243622063f19739af9c90322eb1e3ec6d2dc254 100644
--- a/lib/modules/manager/npm/update/dependency/index.spec.ts
+++ b/lib/modules/manager/npm/update/dependency/index.spec.ts
@@ -347,5 +347,33 @@ describe('modules/manager/npm/update/dependency/index', () => {
       });
       expect(testContent).toEqual(expected);
     });
+
+    it('handles override dependency object where lastParent === depName', () => {
+      const upgrade = {
+        depType: 'overrides',
+        depName: 'typescript',
+        newValue: '0.60.0',
+        managerData: { parents: ['typescript'] },
+      };
+      const overrideDependencies = `{
+        "overrides": {
+          "typescript": {
+           ".": "3.0.0"
+         }
+        }
+      }`;
+      const expected = `{
+        "overrides": {
+          "typescript": {
+           ".": "0.60.0"
+         }
+        }
+      }`;
+      const testContent = npmUpdater.updateDependency({
+        fileContent: overrideDependencies,
+        upgrade,
+      });
+      expect(testContent).toEqual(expected);
+    });
   });
 });
diff --git a/lib/modules/platform/bitbucket-server/index.spec.ts b/lib/modules/platform/bitbucket-server/index.spec.ts
index 9084bb165cdc4399aa409ae36f63a5ad0336ae21..72c6c9c094280e31f8458322d1c35f2692a3fa30 100644
--- a/lib/modules/platform/bitbucket-server/index.spec.ts
+++ b/lib/modules/platform/bitbucket-server/index.spec.ts
@@ -1244,9 +1244,23 @@ describe('modules/platform/bitbucket-server/index', () => {
             });
 
           expect(
-            await bitbucket.findPr({
-              branchName: 'userName1/pullRequest1',
-            })
+            await bitbucket.getBranchPr('userName1/pullRequest1')
+          ).toBeNull();
+        });
+
+        it('has no existing pr', async () => {
+          const scope = await initRepo();
+          scope
+            .get(
+              `${urlPath}/rest/api/1.0/projects/SOME/repos/repo/pull-requests?state=ALL&role.1=AUTHOR&username.1=abc&limit=100`
+            )
+            .reply(200, {
+              isLastPage: true,
+              values: [],
+            });
+
+          expect(
+            await bitbucket.getBranchPr('userName1/pullRequest1')
           ).toBeNull();
         });
       });
diff --git a/lib/modules/platform/bitbucket/index.ts b/lib/modules/platform/bitbucket/index.ts
index b0343723d6edc38f781e47ff546db7d77a9411d6..96a23aa49c3484ac9fe35bfed0118892fe51c9e6 100644
--- a/lib/modules/platform/bitbucket/index.ts
+++ b/lib/modules/platform/bitbucket/index.ts
@@ -366,7 +366,7 @@ export async function getPr(prNo: number): Promise<Pr | null> {
 }
 
 const escapeHash = (input: string): string =>
-  input ? input.replace(regEx(/#/g), '%23') : input;
+  input?.replace(regEx(/#/g), '%23');
 
 // Return the commit SHA for a branch
 async function getBranchCommit(
diff --git a/lib/modules/platform/codecommit/index.spec.ts b/lib/modules/platform/codecommit/index.spec.ts
index e82ff378cfda9d0550ef796e55710fe8552f255a..f8fd754ccf15f0d2dabbf46dacfd69bcc21c30d3 100644
--- a/lib/modules/platform/codecommit/index.spec.ts
+++ b/lib/modules/platform/codecommit/index.spec.ts
@@ -15,6 +15,7 @@ import {
   UpdatePullRequestTitleCommand,
 } from '@aws-sdk/client-codecommit';
 import { mockClient } from 'aws-sdk-client-mock';
+import * as aws4 from 'aws4';
 import { logger } from '../../../../test/util';
 import {
   PLATFORM_BAD_CREDENTIALS,
@@ -48,6 +49,7 @@ describe('modules/platform/codecommit/index', () => {
     codeCommitClient.reset();
     config.prList = undefined;
     config.repository = undefined;
+    jest.useRealTimers();
   });
 
   it('validates massageMarkdown functionality', () => {
@@ -84,13 +86,19 @@ describe('modules/platform/codecommit/index', () => {
       });
     });
 
-    it('should ', async () => {
+    it('should', async () => {
       await expect(
         codeCommit.initPlatform({ endpoint: 'non://parsable.url' })
       ).resolves.toEqual({
         endpoint: 'non://parsable.url',
       });
     });
+
+    it('should as well', async () => {
+      await expect(codeCommit.initPlatform({})).resolves.toEqual({
+        endpoint: 'https://git-codecommit.us-east-1.amazonaws.com/',
+      });
+    });
   });
 
   describe('initRepos()', () => {
@@ -190,6 +198,33 @@ describe('modules/platform/codecommit/index', () => {
         )
       ).toBe('https://git-codecommit.eu-central-1.amazonaws.com/v1/repos/name');
     });
+
+    it('gets url with username and token', () => {
+      jest.useFakeTimers().setSystemTime(new Date('2020-01-01'));
+      process.env.AWS_ACCESS_KEY_ID = 'access-key-id';
+      process.env.AWS_SECRET_ACCESS_KEY = 'secret-access-key';
+      process.env.AWS_REGION = 'eu-central-1';
+      process.env.AWS_SESSION_TOKEN = '';
+      const signer = new aws4.RequestSigner({
+        service: 'codecommit',
+        host: 'git-codecommit.eu-central-1.amazonaws.com',
+        method: 'GIT',
+        path: 'v1/repos/name',
+      });
+      const dateTime = signer.getDateTime();
+      const token = `${dateTime}Z${signer.signature()}`;
+      expect(
+        getCodeCommitUrl(
+          {
+            defaultBranch: 'main',
+            repositoryId: 'id',
+          },
+          'name'
+        )
+      ).toBe(
+        `https://access-key-id:${token}@git-codecommit.eu-central-1.amazonaws.com/v1/repos/name`
+      );
+    });
   });
 
   describe('getRepos()', () => {
diff --git a/lib/modules/platform/github/index.spec.ts b/lib/modules/platform/github/index.spec.ts
index 0a5cdbc72d35daa4918e67c4464de6092681f6b3..7f456f21ad8c80b1d2d00d266d6baaf4ac93fa54 100644
--- a/lib/modules/platform/github/index.spec.ts
+++ b/lib/modules/platform/github/index.spec.ts
@@ -1406,6 +1406,23 @@ describe('modules/platform/github/index', () => {
       const res = await github.getBranchStatusCheck('somebranch', 'context-4');
       expect(res).toBeNull();
     });
+
+    it('returns yellow if state not present in context object', async () => {
+      const scope = httpMock.scope(githubApiHost);
+      initRepoMock(scope, 'some/repo');
+      scope
+        .get(
+          '/repos/some/repo/commits/0d9c7726c3d628b7e28af234595cfd20febdbf8e/statuses'
+        )
+        .reply(200, [
+          {
+            context: 'context-1',
+          },
+        ]);
+      await github.initRepo({ repository: 'some/repo' });
+      const res = await github.getBranchStatusCheck('somebranch', 'context-1');
+      expect(res).toBe('yellow');
+    });
   });
 
   describe('setBranchStatus', () => {
diff --git a/lib/modules/platform/github/index.ts b/lib/modules/platform/github/index.ts
index 773fe122f942ddf25706706ff4862bb4794d89e7..c6a14a41da28a4e89d71421850c66cde665cfec2 100644
--- a/lib/modules/platform/github/index.ts
+++ b/lib/modules/platform/github/index.ts
@@ -24,6 +24,7 @@ import { logger } from '../../../logger';
 import type { BranchStatus, VulnerabilityAlert } from '../../../types';
 import { ExternalHostError } from '../../../types/errors/external-host-error';
 import { isGithubFineGrainedPersonalAccessToken } from '../../../util/check-token';
+import { coerceToNull } from '../../../util/coerce';
 import * as git from '../../../util/git';
 import { listCommitTree, pushCommitToRenovateRef } from '../../../util/git';
 import type {
@@ -35,9 +36,10 @@ import * as hostRules from '../../../util/host-rules';
 import * as githubHttp from '../../../util/http/github';
 import type { GithubHttpOptions } from '../../../util/http/github';
 import type { HttpResponse } from '../../../util/http/types';
+import { coerceObject } from '../../../util/object';
 import { regEx } from '../../../util/regex';
 import { sanitize } from '../../../util/sanitize';
-import { fromBase64, looseEquals } from '../../../util/string';
+import { coerceString, fromBase64, looseEquals } from '../../../util/string';
 import { ensureTrailingSlash } from '../../../util/url';
 import type {
   AggregatedVulnerabilities,
@@ -112,7 +114,7 @@ export async function detectGhe(token: string): Promise<void> {
   if (platformConfig.isGhe) {
     const gheHeaderKey = 'x-github-enterprise-version';
     const gheQueryRes = await githubApi.headJson('/', { token });
-    const gheHeaders = gheQueryRes?.headers || {};
+    const gheHeaders = coerceObject(gheQueryRes?.headers);
     const [, gheVersion] =
       Object.entries(gheHeaders).find(
         ([k]) => k.toLowerCase() === gheHeaderKey
@@ -580,7 +582,7 @@ export async function initRepo({
             sha,
             force: true,
           },
-          token: forkToken ?? opts.token,
+          token: coerceString(forkToken, opts.token),
         });
       } catch (err) /* istanbul ignore next */ {
         logger.warn(
@@ -603,7 +605,7 @@ export async function initRepo({
   // istanbul ignore else
   if (forkToken) {
     logger.debug('Using forkToken for git init');
-    parsedEndpoint.auth = config.forkToken ?? null;
+    parsedEndpoint.auth = coerceToNull(config.forkToken);
   } else {
     const tokenType = opts.token?.startsWith('x-access-token:')
       ? 'app'
@@ -736,7 +738,7 @@ export async function getPrList(): Promise<GhPr[]> {
     // TODO: check null `repo` (#22198)
     const prCache = await getPrCache(githubApi, repo!, username);
     config.prList = Object.values(prCache).sort(
-      ({ number: a }, { number: b }) => (a > b ? -1 : 1)
+      ({ number: a }, { number: b }) => b - a
     );
   }
 
@@ -1826,7 +1828,7 @@ export async function getVulnerabilityAlerts(): Promise<VulnerabilityAlert[]> {
           const key = `${ecosystem.toLowerCase()}/${name}`;
           const range = vulnerableVersionRange;
           const elem = shortAlerts[key] || {};
-          elem[range] = patch ?? null;
+          elem[range] = coerceToNull(patch);
           shortAlerts[key] = elem;
         }
         logger.debug({ alerts: shortAlerts }, 'GitHub vulnerability details');
diff --git a/lib/modules/versioning/conan/common.ts b/lib/modules/versioning/conan/common.ts
index cf7cc094abf4ff9aa7fdc02ba63599f55b3024d7..864a90f07b5999123d3d3d8a946d03bebd2b9b38 100644
--- a/lib/modules/versioning/conan/common.ts
+++ b/lib/modules/versioning/conan/common.ts
@@ -1,5 +1,6 @@
 import * as semver from 'semver';
 import { regEx } from '../../../util/regex';
+import { coerceString } from '../../../util/string';
 
 export function makeVersion(
   version: string,
@@ -66,7 +67,7 @@ export function matchesWithOptions(
     options.includePrerelease
   ) {
     const coercedVersion = semver.coerce(cleanedVersion)?.raw;
-    cleanedVersion = coercedVersion ? coercedVersion : '';
+    cleanedVersion = coerceString(coercedVersion);
   }
   return semver.satisfies(cleanedVersion, cleanRange, options);
 }
diff --git a/lib/modules/versioning/conan/range.ts b/lib/modules/versioning/conan/range.ts
index f559c17936d8b447633b2ca4604040f194dc6b8c..efda646033903382f6de898d00ea308952c4ae83 100644
--- a/lib/modules/versioning/conan/range.ts
+++ b/lib/modules/versioning/conan/range.ts
@@ -1,6 +1,7 @@
 import * as semver from 'semver';
 import { SemVer, parseRange } from 'semver-utils';
 import { logger } from '../../../logger';
+import { coerceString } from '../../../util/string';
 import type { NewValueConfig } from '../types';
 import {
   cleanVersion,
@@ -89,7 +90,7 @@ export function fixParsedRange(range: string): any {
         major,
       };
 
-      let full = `${operator ?? ''}${major}`;
+      let full = `${coerceString(operator)}${major}`;
       if (minor) {
         NewSemVer.minor = minor;
         full = `${full}.${minor}`;
diff --git a/lib/modules/versioning/gradle/index.spec.ts b/lib/modules/versioning/gradle/index.spec.ts
index a4a727a4e47c6a0a5f75b9367388282b01cc276e..9141d62826adbc401245b7168364f139da064d31 100644
--- a/lib/modules/versioning/gradle/index.spec.ts
+++ b/lib/modules/versioning/gradle/index.spec.ts
@@ -76,6 +76,7 @@ describe('modules/versioning/gradle/index', () => {
     ${'Hoxton.SR1'}              | ${'Hoxton.RELEASE'}          | ${1}
     ${'1.0-sp-1'}                | ${'1.0-release'}             | ${1}
     ${'1.0-sp-2'}                | ${'1.0-sp-1'}                | ${1}
+    ${''}                        | ${''}                        | ${0}
   `('compare("$a", "$b") === $expected', ({ a, b, expected }) => {
     expect(compare(a, b)).toEqual(expected);
   });
diff --git a/lib/modules/versioning/maven/compare.spec.ts b/lib/modules/versioning/maven/compare.spec.ts
index 5de6a0185de6bab03bec4da8dcec6e1afc1908bc..1fe6a033292c3320468dee4ec9402dbfc0808ebf 100644
--- a/lib/modules/versioning/maven/compare.spec.ts
+++ b/lib/modules/versioning/maven/compare.spec.ts
@@ -1,8 +1,10 @@
 import {
   autoExtendMavenRange,
   compare,
+  isSubversion,
   parseRange,
   rangeToStr,
+  tokenize,
 } from './compare';
 
 describe('modules/versioning/maven/compare', () => {
@@ -220,6 +222,196 @@ describe('modules/versioning/maven/compare', () => {
     });
   });
 
+  describe('isSubversion', () => {
+    it.each`
+      majorVersion         | minorVersion    | expected
+      ${'1.2.3'}           | ${'1.2.3'}      | ${true}
+      ${'1.2.3'}           | ${'1.0.0'}      | ${false}
+      ${'2.0.0'}           | ${'2.0.1'}      | ${true}
+      ${'3.1.0'}           | ${'3.01.00'}    | ${true}
+      ${'4.0.0'}           | ${''}           | ${false}
+      ${'5.0.0'}           | ${'4.5.2'}      | ${false}
+      ${'6.0.0'}           | ${'6.0.0-beta'} | ${true}
+      ${'invalid.version'} | ${''}           | ${false}
+      ${''}                | ${'1.2.3'}      | ${false}
+      ${'v1.2.3'}          | ${'1.2.3'}      | ${true}
+      ${'v1.2.3'}          | ${'v1.2.3'}     | ${true}
+    `(
+      'isSubversion("$majorVersion", "$minorVersion") === $expected',
+      ({ majorVersion, minorVersion, expected }) => {
+        expect(isSubversion(majorVersion, minorVersion)).toBe(expected);
+      }
+    );
+  });
+
+  describe('tokenize', () => {
+    const zeroToken = {
+      prefix: 'PREFIX_HYPHEN',
+      type: 'TYPE_NUMBER',
+      val: 0,
+      isTransition: false,
+    };
+    const testObj = [
+      {
+        input: '1.2.3',
+        expected: [
+          {
+            isTransition: false,
+            prefix: 'PREFIX_HYPHEN',
+            type: 'TYPE_NUMBER',
+            val: 1,
+          },
+          {
+            isTransition: false,
+            prefix: 'PREFIX_DOT',
+            type: 'TYPE_NUMBER',
+            val: 2,
+          },
+          {
+            isTransition: false,
+            prefix: 'PREFIX_DOT',
+            type: 'TYPE_NUMBER',
+            val: 3,
+          },
+        ],
+      },
+      {
+        input: 'alpha.beta.rc',
+        expected: [
+          {
+            isTransition: false,
+            prefix: 'PREFIX_HYPHEN',
+            type: 'TYPE_QUALIFIER',
+            val: 'alpha',
+          },
+          {
+            isTransition: false,
+            prefix: 'PREFIX_DOT',
+            type: 'TYPE_QUALIFIER',
+            val: 'beta',
+          },
+          {
+            isTransition: false,
+            prefix: 'PREFIX_DOT',
+            type: 'TYPE_QUALIFIER',
+            val: 'rc',
+          },
+        ],
+      },
+      {
+        input: '1.2.3-alpha.beta',
+        expected: [
+          {
+            isTransition: false,
+            prefix: 'PREFIX_HYPHEN',
+            type: 'TYPE_NUMBER',
+            val: 1,
+          },
+          {
+            isTransition: false,
+            prefix: 'PREFIX_DOT',
+            type: 'TYPE_NUMBER',
+            val: 2,
+          },
+          {
+            isTransition: false,
+            prefix: 'PREFIX_DOT',
+            type: 'TYPE_NUMBER',
+            val: 3,
+          },
+          {
+            isTransition: false,
+            prefix: 'PREFIX_HYPHEN',
+            type: 'TYPE_QUALIFIER',
+            val: 'alpha',
+          },
+          {
+            isTransition: false,
+            prefix: 'PREFIX_DOT',
+            type: 'TYPE_QUALIFIER',
+            val: 'beta',
+          },
+        ],
+      },
+      {
+        input: '1.2.x-3',
+        expected: [
+          {
+            isTransition: false,
+            prefix: 'PREFIX_HYPHEN',
+            type: 'TYPE_NUMBER',
+            val: 1,
+          },
+          {
+            isTransition: false,
+            prefix: 'PREFIX_DOT',
+            type: 'TYPE_NUMBER',
+            val: 2,
+          },
+          {
+            isTransition: false,
+            prefix: 'PREFIX_DOT',
+            type: 'TYPE_QUALIFIER',
+            val: 'x',
+          },
+          {
+            isTransition: false,
+            prefix: 'PREFIX_HYPHEN',
+            type: 'TYPE_NUMBER',
+            val: 3,
+          },
+        ],
+      },
+      {
+        input: '00.02.003',
+        expected: [
+          {
+            isTransition: false,
+            prefix: 'PREFIX_HYPHEN',
+            type: 'TYPE_NUMBER',
+            val: 0,
+          },
+          {
+            isTransition: false,
+            prefix: 'PREFIX_DOT',
+            type: 'TYPE_NUMBER',
+            val: 2,
+          },
+          {
+            isTransition: false,
+            prefix: 'PREFIX_DOT',
+            type: 'TYPE_NUMBER',
+            val: 3,
+          },
+        ],
+      },
+      {
+        input: 'invalid.version',
+        expected: [
+          {
+            isTransition: false,
+            prefix: 'PREFIX_HYPHEN',
+            type: 'TYPE_QUALIFIER',
+            val: 'invalid',
+          },
+          {
+            isTransition: false,
+            prefix: 'PREFIX_DOT',
+            type: 'TYPE_QUALIFIER',
+            val: 'version',
+          },
+        ],
+      },
+      { input: '', expected: [zeroToken] },
+    ];
+
+    it('should tokenize', () => {
+      for (const { input, expected } of testObj) {
+        expect(tokenize(input)).toEqual(expected);
+      }
+    });
+  });
+
   describe('Non-standard behavior', () => {
     describe('equality', () => {
       it.each`
diff --git a/lib/modules/versioning/maven/compare.ts b/lib/modules/versioning/maven/compare.ts
index 9ede3007e1c40951a7573a2d82eadbb1b2f801cb..f70d7965e70afe528fe9e6a9a8f9e165ff358e93 100644
--- a/lib/modules/versioning/maven/compare.ts
+++ b/lib/modules/versioning/maven/compare.ts
@@ -111,13 +111,6 @@ function isNull(token: Token): boolean {
   );
 }
 
-const zeroToken: NumberToken = {
-  prefix: PREFIX_HYPHEN,
-  type: TYPE_NUMBER,
-  val: 0,
-  isTransition: false,
-};
-
 function tokenize(versionStr: string, preserveMinorZeroes = false): Token[] {
   let buf: Token[] = [];
   let result: Token[] = [];
@@ -136,7 +129,7 @@ function tokenize(versionStr: string, preserveMinorZeroes = false): Token[] {
       buf = [];
     }
   });
-  return result.length ? result : [zeroToken];
+  return result;
 }
 
 function nullFor(token: Token): Token {
diff --git a/lib/modules/versioning/maven/index.ts b/lib/modules/versioning/maven/index.ts
index 1ce3e218d1fdc3a15b74002786050614ab39762e..67521565f70e405cc25cae5181dda1f0295adcb1 100644
--- a/lib/modules/versioning/maven/index.ts
+++ b/lib/modules/versioning/maven/index.ts
@@ -1,4 +1,5 @@
 import type { RangeStrategy } from '../../../types/versioning';
+import { coerceString } from '../../../util/string';
 import type { NewValueConfig, VersioningApi } from '../types';
 import {
   EXCLUDING_POINT,
@@ -152,7 +153,10 @@ function getNewValue({
   if (isVersion(currentValue) || rangeStrategy === 'pin') {
     return newVersion;
   }
-  return autoExtendMavenRange(currentValue, newVersion) ?? currentValue;
+  return coerceString(
+    autoExtendMavenRange(currentValue, newVersion),
+    currentValue
+  );
 }
 
 export { isValid };
diff --git a/lib/util/coerce.spec.ts b/lib/util/coerce.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..bc0d14b291d1ce3a19a96cc16bb7fa3099da073f
--- /dev/null
+++ b/lib/util/coerce.spec.ts
@@ -0,0 +1,29 @@
+import { coerceToNull, coerceToUndefined } from './coerce';
+
+describe('util/coerce', () => {
+  describe('coerceToNull', () => {
+    it('should return null', () => {
+      expect(coerceToNull(undefined)).toBeNull();
+      expect(coerceToNull(null)).toBeNull();
+    });
+
+    it('should return original value', () => {
+      expect(coerceToNull({})).toEqual({});
+      expect(coerceToNull('str')).toBe('str');
+      expect(coerceToNull(false)).toBe(false);
+    });
+  });
+
+  describe('coerceToUndefined', () => {
+    it('should return undefined', () => {
+      expect(coerceToUndefined(undefined)).toBeUndefined();
+      expect(coerceToUndefined(null)).toBeUndefined();
+    });
+
+    it('should return original value', () => {
+      expect(coerceToUndefined({})).toEqual({});
+      expect(coerceToUndefined('str')).toBe('str');
+      expect(coerceToUndefined(false)).toBe(false);
+    });
+  });
+});
diff --git a/lib/util/coerce.ts b/lib/util/coerce.ts
new file mode 100644
index 0000000000000000000000000000000000000000..bad74fefe0caf8166fc7c1c4e5b61f16ac3b0f06
--- /dev/null
+++ b/lib/util/coerce.ts
@@ -0,0 +1,9 @@
+export function coerceToNull<T>(input: T | null | undefined): T | null {
+  return input ?? null;
+}
+
+export function coerceToUndefined<T>(
+  input: T | null | undefined
+): T | undefined {
+  return input ?? undefined;
+}
diff --git a/lib/util/object.spec.ts b/lib/util/object.spec.ts
index 3abbe23f097617f34b89b522ad57a699df8188ce..046c7c0f47292431a550927eabf081562bee533f 100644
--- a/lib/util/object.spec.ts
+++ b/lib/util/object.spec.ts
@@ -1,4 +1,4 @@
-import { hasKey } from './object';
+import { coerceObject, hasKey } from './object';
 
 describe('util/object', () => {
   beforeEach(() => {
@@ -16,4 +16,19 @@ describe('util/object', () => {
   it('returns false for wrong instance type', () => {
     expect(hasKey('foo', 'i-am-not-an-object')).toBeFalse();
   });
+
+  describe('coerceObject', () => {
+    it('should return empty object', () => {
+      expect(coerceObject(undefined)).toEqual({});
+      expect(coerceObject(null)).toEqual({});
+    });
+
+    it('should return input object', () => {
+      expect(coerceObject({})).toEqual({});
+      expect(coerceObject({ name: 'name' })).toEqual({ name: 'name' });
+      expect(coerceObject(undefined, { name: 'name' })).toEqual({
+        name: 'name',
+      });
+    });
+  });
 });
diff --git a/lib/util/object.ts b/lib/util/object.ts
index 560b3f4ff93003ac73b958ce9b0b0b86af648989..a9c22dc9c093e81441996278f2cd45926bb33969 100644
--- a/lib/util/object.ts
+++ b/lib/util/object.ts
@@ -11,3 +11,12 @@ export function hasKey<K extends string, T>(
 ): o is T & Record<K, unknown> {
   return o && typeof o === 'object' && k in o;
 }
+
+/**
+ * Coerce a value to a object with optional default value.
+ * @param val value to coerce
+ * @returns the coerced value.
+ */
+export function coerceObject<T>(val: T | null | undefined, def?: T): T {
+  return val ?? def ?? ({} as T);
+}
diff --git a/lib/workers/repository/errors-warnings.spec.ts b/lib/workers/repository/errors-warnings.spec.ts
index 2123c920003a3bb3ff4e3b688bf362533943a2e9..0c508c1d21c766cabf08d809ebd220ffca268fa9 100644
--- a/lib/workers/repository/errors-warnings.spec.ts
+++ b/lib/workers/repository/errors-warnings.spec.ts
@@ -275,6 +275,7 @@ describe('workers/repository/errors-warnings', () => {
               {},
             ],
           },
+          partial<PackageFile>(), // for coverage
           {
             packageFile: 'backend/package.json',
             deps: [
@@ -293,6 +294,10 @@ describe('workers/repository/errors-warnings', () => {
               },
             ],
           },
+          // coverage
+          partial<PackageFile>({
+            packageFile: 'Dockerfile',
+          }),
         ],
       };
       const res = getDepWarningsOnboardingPR(packageFiles, config);
@@ -313,6 +318,17 @@ describe('workers/repository/errors-warnings', () => {
       `);
     });
 
+    it('handle empty package files', () => {
+      const config: RenovateConfig = {};
+      const packageFiles: Record<string, PackageFile[]> = {
+        npm: undefined as never,
+      };
+      let res = getDepWarningsOnboardingPR(packageFiles, config);
+      expect(res).toBe('');
+      res = getDepWarningsOnboardingPR(undefined as never, config);
+      expect(res).toBe('');
+    });
+
     it('suppress notifications contains dependencyLookupWarnings flag then return empty string', () => {
       const config: RenovateConfig = {
         suppressNotifications: ['dependencyLookupWarnings'],
diff --git a/lib/workers/repository/init/merge.spec.ts b/lib/workers/repository/init/merge.spec.ts
index 5a191d4e205bc4c247318c187647e924c5122454..b7a4b5d91cd29c31cd8b6fc8cbfbdac4a7ababba 100644
--- a/lib/workers/repository/init/merge.spec.ts
+++ b/lib/workers/repository/init/merge.spec.ts
@@ -363,5 +363,23 @@ describe('workers/repository/init/merge', () => {
       config.extends = [':automergeDisabled'];
       expect(await mergeRenovateConfig(config)).toBeDefined();
     });
+
+    it('continues if no errors-2', async () => {
+      scm.getFileList.mockResolvedValue(['package.json', '.renovaterc.json']);
+      fs.readLocalFile.mockResolvedValue('{}');
+      migrateAndValidate.migrateAndValidate.mockResolvedValue({
+        warnings: [],
+        errors: [],
+      });
+      expect(
+        await mergeRenovateConfig({
+          ...config,
+          requireConfig: 'ignored',
+          configFileParsed: undefined,
+          warnings: undefined,
+          secrets: undefined,
+        })
+      ).toBeDefined();
+    });
   });
 });
diff --git a/lib/workers/repository/onboarding/branch/index.spec.ts b/lib/workers/repository/onboarding/branch/index.spec.ts
index aaecdb04bd56a892fa51e77aaae105feaa57207d..bc6e748928daa819b92b770a4d97d23409418194 100644
--- a/lib/workers/repository/onboarding/branch/index.spec.ts
+++ b/lib/workers/repository/onboarding/branch/index.spec.ts
@@ -387,7 +387,7 @@ describe('workers/repository/onboarding/branch/index', () => {
       });
 
       it('detects missing rebase checkbox', async () => {
-        const pr = { bodyStruct: { rebaseRequested: undefined } };
+        const pr = { bodyStruct: undefined };
         platform.getBranchPr.mockResolvedValueOnce(mock<Pr>(pr));
 
         await checkOnboardingBranch(config);
diff --git a/lib/workers/repository/process/lookup/filter-checks.ts b/lib/workers/repository/process/lookup/filter-checks.ts
index 74c02cc24ea0b226a9514df87bf0e5cf7796de55..3959e36f77e509d1945492ec656b6a81c758f21e 100644
--- a/lib/workers/repository/process/lookup/filter-checks.ts
+++ b/lib/workers/repository/process/lookup/filter-checks.ts
@@ -9,6 +9,7 @@ import {
   isActiveConfidenceLevel,
   satisfiesConfidenceLevel,
 } from '../../../../util/merge-confidence';
+import { coerceNumber } from '../../../../util/number';
 import { applyPackageRules } from '../../../../util/package-rules';
 import { toMs } from '../../../../util/pretty-time';
 import type { LookupUpdateConfig, UpdateResult } from './types';
@@ -61,7 +62,10 @@ export async function filterInternalChecks(
         updateType,
       } = releaseConfig;
       if (is.nonEmptyString(minimumReleaseAge) && releaseTimestamp) {
-        if (getElapsedMs(releaseTimestamp) < (toMs(minimumReleaseAge) ?? 0)) {
+        if (
+          getElapsedMs(releaseTimestamp) <
+          coerceNumber(toMs(minimumReleaseAge), 0)
+        ) {
           // Skip it if it doesn't pass checks
           logger.trace(
             { depName, check: 'minimumReleaseAge' },
diff --git a/lib/workers/repository/process/lookup/filter.spec.ts b/lib/workers/repository/process/lookup/filter.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..2ba090b5b49cd9b4db807b4a48c30ad86b4ee5e7
--- /dev/null
+++ b/lib/workers/repository/process/lookup/filter.spec.ts
@@ -0,0 +1,61 @@
+import { partial } from '../../../../../test/util';
+import * as allVersioning from '../../../../modules/versioning';
+import { filterVersions } from './filter';
+import type { FilterConfig } from './types';
+
+const versioning = allVersioning.get('semver');
+
+const releases = [
+  {
+    version: '1.0.1',
+    releaseTimestamp: '2021-01-01T00:00:01.000Z',
+  },
+  {
+    version: '1.2.0',
+    releaseTimestamp: '2021-01-03T00:00:00.000Z',
+  },
+  {
+    version: '2.0.0',
+    releaseTimestamp: '2021-01-05T00:00:00.000Z',
+  },
+  {
+    version: '2.1.0',
+    releaseTimestamp: '2021-01-07T00:00:00.000Z',
+  },
+  // for coverage
+  {
+    version: 'invalid.version',
+    releaseTimestamp: '2021-01-07T00:00:00.000Z',
+  },
+];
+
+describe('workers/repository/process/lookup/filter', () => {
+  describe('.filterVersions()', () => {
+    it('should filter versions allowed by semver syntax when allowedVersions is not valid version, range or pypi syntax', () => {
+      const config = partial<FilterConfig>({
+        ignoreUnstable: false,
+        ignoreDeprecated: false,
+        respectLatest: false,
+        allowedVersions: '>1',
+      });
+      const currentVersion = '1.0.0';
+      const latestVersion = '2.0.0';
+
+      jest.spyOn(versioning, 'isVersion').mockReturnValue(true);
+      jest.spyOn(versioning, 'isGreaterThan').mockReturnValue(true);
+
+      const filteredVersions = filterVersions(
+        config,
+        currentVersion,
+        latestVersion,
+        releases,
+        versioning
+      );
+
+      expect(filteredVersions).toEqual([
+        { version: '2.0.0', releaseTimestamp: '2021-01-05T00:00:00.000Z' },
+        { version: '2.1.0', releaseTimestamp: '2021-01-07T00:00:00.000Z' },
+      ]);
+    });
+  });
+});
diff --git a/lib/workers/repository/process/sort.spec.ts b/lib/workers/repository/process/sort.spec.ts
index 07ff392ecbf0bfeee85cd848a830b5a825aa4523..64e6993b01cbce4cb3ffb165efbb36ea25cf619a 100644
--- a/lib/workers/repository/process/sort.spec.ts
+++ b/lib/workers/repository/process/sort.spec.ts
@@ -13,17 +13,22 @@ describe('workers/repository/process/sort', () => {
           updateType: 'pin' as UpdateType,
           prTitle: 'some pin',
         },
+        {
+          updateType: 'minor' as UpdateType,
+          prTitle: 'a minor update',
+        },
         {
           updateType: 'pin' as UpdateType,
-          prTitle: 'some other pin',
+          prTitle: 'some other other pin',
         },
         {
-          updateType: 'minor' as UpdateType,
-          prTitle: 'a minor update',
+          updateType: 'pin' as UpdateType,
+          prTitle: 'some other pin',
         },
       ];
       sortBranches(branches);
       expect(branches).toEqual([
+        { prTitle: 'some other other pin', updateType: 'pin' },
         { prTitle: 'some other pin', updateType: 'pin' },
         { prTitle: 'some pin', updateType: 'pin' },
         { prTitle: 'a minor update', updateType: 'minor' },
diff --git a/lib/workers/repository/update/branch/auto-replace.spec.ts b/lib/workers/repository/update/branch/auto-replace.spec.ts
index 3a6a1f6cf5780cc9f4d3a747d3b4e9847e77a06c..04f7a440c15bb327789de9aaa86eefb1de56911f 100644
--- a/lib/workers/repository/update/branch/auto-replace.spec.ts
+++ b/lib/workers/repository/update/branch/auto-replace.spec.ts
@@ -52,6 +52,29 @@ describe('workers/repository/update/branch/auto-replace', () => {
       expect(res).toBeNull();
     });
 
+    // for coverage
+    it('uses depName or packageName', async () => {
+      upgrade.baseDeps = [
+        {
+          datasource: 'cdnjs',
+          packageName: 'react-router/react-router-test.min.js',
+          currentValue: '4.2.1',
+          replaceString:
+            '<script src=" https://cdnjs.cloudflare.com/ajax/libs/react-router/4.3.1/react-router.min.js">',
+        },
+        {
+          datasource: 'cdnjs',
+          depName: 'react-router-test',
+          currentValue: '4.1.1',
+          replaceString:
+            '<script src=" https://cdnjs.cloudflare.com/ajax/libs/react-router/4.3.1/react-router.min.js">',
+        },
+      ];
+      reuseExistingBranch = true;
+      const res = await doAutoReplace(upgrade, sampleHtml, reuseExistingBranch);
+      expect(res).toBeNull();
+    });
+
     it('updates version only', async () => {
       const script =
         '<script src="https://cdnjs.cloudflare.com/ajax/libs/reactstrap/7.1.0/reactstrap.min.js">';
diff --git a/lib/workers/repository/update/branch/execute-post-upgrade-commands.spec.ts b/lib/workers/repository/update/branch/execute-post-upgrade-commands.spec.ts
index ec5e6fac3a302349cf03abdd436b4311e9831584..82d48d621c6ca41d300e28c15fd948ead37a1a95 100644
--- a/lib/workers/repository/update/branch/execute-post-upgrade-commands.spec.ts
+++ b/lib/workers/repository/update/branch/execute-post-upgrade-commands.spec.ts
@@ -66,5 +66,53 @@ describe('workers/repository/update/branch/execute-post-upgrade-commands', () =>
       expect(res.updatedArtifacts).toHaveLength(3);
       expect(fs.writeLocalFile).toHaveBeenCalledTimes(1);
     });
+
+    it('executes commands on update package files', async () => {
+      const commands = partial<BranchUpgradeConfig>([
+        {
+          manager: 'some-manager',
+          branchName: 'main',
+          postUpgradeTasks: {
+            executionMode: 'update',
+            commands: ['disallowed_command'],
+          },
+        },
+      ]);
+      const config: BranchConfig = {
+        manager: 'some-manager',
+        updatedPackageFiles: [
+          { type: 'addition', path: 'some-existing-dir', contents: '' },
+          { type: 'addition', path: 'artifact', contents: '' },
+        ],
+        upgrades: [],
+        branchName: 'main',
+        baseBranch: 'base',
+      };
+      git.getRepoStatus.mockResolvedValueOnce(
+        partial<StatusResult>({
+          modified: [],
+          not_added: [],
+          deleted: [],
+        })
+      );
+      GlobalConfig.set({
+        localDir: __dirname,
+        allowedPostUpgradeCommands: ['some-command'],
+      });
+      fs.localPathIsFile
+        .mockResolvedValueOnce(true)
+        .mockResolvedValueOnce(false);
+      fs.localPathExists
+        .mockResolvedValueOnce(true)
+        .mockResolvedValueOnce(true);
+
+      const res = await postUpgradeCommands.postUpgradeCommandsExecutor(
+        commands,
+        config
+      );
+
+      expect(res.updatedArtifacts).toHaveLength(0);
+      expect(fs.writeLocalFile).toHaveBeenCalledTimes(1);
+    });
   });
 });
diff --git a/lib/workers/repository/update/branch/execute-post-upgrade-commands.ts b/lib/workers/repository/update/branch/execute-post-upgrade-commands.ts
index 2dce9840bb69884f9c2f92807ba69f2b0939775f..bfbf825f80e8801f4303627c3a8c01b690478bf2 100644
--- a/lib/workers/repository/update/branch/execute-post-upgrade-commands.ts
+++ b/lib/workers/repository/update/branch/execute-post-upgrade-commands.ts
@@ -4,6 +4,7 @@ import { mergeChildConfig } from '../../../../config';
 import { GlobalConfig } from '../../../../config/global';
 import { addMeta, logger } from '../../../../logger';
 import type { ArtifactError } from '../../../../modules/manager/types';
+import { coerceArray } from '../../../../util/array';
 import { exec } from '../../../../util/exec';
 import {
   localPathIsFile,
@@ -45,7 +46,7 @@ export async function postUpgradeCommandsExecutor(
       },
       `Checking for post-upgrade tasks`
     );
-    const commands = upgrade.postUpgradeTasks?.commands ?? [];
+    const commands = upgrade.postUpgradeTasks?.commands;
     const fileFilters = upgrade.postUpgradeTasks?.fileFilters ?? ['**/*'];
     if (is.nonEmptyArray(commands)) {
       // Persist updated files in file system so any executed commands can see them
@@ -136,7 +137,7 @@ export async function postUpgradeCommandsExecutor(
         }
       }
 
-      for (const relativePath of status.deleted || []) {
+      for (const relativePath of coerceArray(status.deleted)) {
         for (const pattern of fileFilters) {
           if (minimatch(pattern, { dot: true }).match(relativePath)) {
             logger.debug(
diff --git a/lib/workers/repository/update/branch/get-updated.ts b/lib/workers/repository/update/branch/get-updated.ts
index 676c7dfff2bb4b73ef16b0f6853b01d2f59fd613..94b329e93b184c61531674c4920d0076690ebdd8 100644
--- a/lib/workers/repository/update/branch/get-updated.ts
+++ b/lib/workers/repository/update/branch/get-updated.ts
@@ -9,6 +9,7 @@ import type {
 } from '../../../../modules/manager/types';
 import { getFile } from '../../../../util/git';
 import type { FileAddition, FileChange } from '../../../../util/git/types';
+import { coerceString } from '../../../../util/string';
 import type { BranchConfig } from '../../../types';
 import { doAutoReplace } from './auto-replace';
 
@@ -248,7 +249,9 @@ export async function getUpdatedPackageFiles(
             reuseExistingBranch: false,
           });
         }
-        logger.debug(`Updating ${depName} in ${packageFile || lockFile}`);
+        logger.debug(
+          `Updating ${depName} in ${coerceString(packageFile, lockFile)}`
+        );
         updatedFileContents[packageFile] = newContent;
         delete nonUpdatedFileContents[packageFile];
       }
@@ -334,10 +337,7 @@ export async function getUpdatedPackageFiles(
       if (updateArtifacts) {
         const packageFileContents =
           updatedFileContents[packageFile] ||
-          (await getFile(
-            packageFile,
-            reuseExistingBranch ? config.branchName : config.baseBranch
-          ));
+          (await getFile(packageFile, config.baseBranch));
         const results = await updateArtifacts({
           packageFileName: packageFile,
           updatedDeps: [],
diff --git a/lib/workers/repository/update/branch/index.spec.ts b/lib/workers/repository/update/branch/index.spec.ts
index 3a07c835ff92c8508542feaf631f8bb59efb9cc1..df1b53166e4b9f48dea96fa3ca0ba689e1e5ccc3 100644
--- a/lib/workers/repository/update/branch/index.spec.ts
+++ b/lib/workers/repository/update/branch/index.spec.ts
@@ -1392,7 +1392,7 @@ describe('workers/repository/update/branch/index', () => {
       );
       npmPostExtract.getAdditionalFiles.mockResolvedValueOnce({
         artifactErrors: [],
-        updatedArtifacts: [partial<FileChange>()],
+        updatedArtifacts: [{ type: 'deletion', path: 'dummy' }],
       });
       scm.branchExists.mockResolvedValue(true);
       platform.getBranchPr.mockResolvedValueOnce(
diff --git a/lib/workers/repository/update/branch/index.ts b/lib/workers/repository/update/branch/index.ts
index 54abd336fc9d51af60913e5f33bdbe29a9d7e8b3..a78d2f1fcae6f3c41fb8a158a37596fa36d25dbc 100644
--- a/lib/workers/repository/update/branch/index.ts
+++ b/lib/workers/repository/update/branch/index.ts
@@ -30,6 +30,7 @@ import {
   isActiveConfidenceLevel,
   satisfiesConfidenceLevel,
 } from '../../../../util/merge-confidence';
+import { coerceNumber } from '../../../../util/number';
 import { toMs } from '../../../../util/pretty-time';
 import * as template from '../../../../util/template';
 import { isLimitReached } from '../../../global/limits';
@@ -346,7 +347,7 @@ export async function processBranch(
           upgrade.releaseTimestamp
         ) {
           const timeElapsed = getElapsedMs(upgrade.releaseTimestamp);
-          if (timeElapsed < (toMs(upgrade.minimumReleaseAge) ?? 0)) {
+          if (timeElapsed < coerceNumber(toMs(upgrade.minimumReleaseAge))) {
             logger.debug(
               {
                 depName: upgrade.depName,
@@ -852,7 +853,7 @@ export async function processBranch(
       } else if (config.automerge) {
         logger.debug('PR is configured for automerge');
         // skip automerge if there is a new commit since status checks aren't done yet
-        if (!commitSha || config.ignoreTests) {
+        if (config.ignoreTests === true || !commitSha) {
           logger.debug('checking auto-merge');
           const prAutomergeResult = await checkAutoMerge(pr, config);
           if (prAutomergeResult?.automerged) {
diff --git a/lib/workers/repository/update/pr/body/updates-table.ts b/lib/workers/repository/update/pr/body/updates-table.ts
index f6718c3099f30959566e4830cce186f9b9862ec2..568e3c2f28a641d3cb036d745e87d49e091f145c 100644
--- a/lib/workers/repository/update/pr/body/updates-table.ts
+++ b/lib/workers/repository/update/pr/body/updates-table.ts
@@ -48,10 +48,7 @@ export function getPrUpdatesTable(config: BranchConfig): string {
     .filter((upgrade) => upgrade !== undefined)
     .map((upgrade) => {
       const res: Record<string, string> = {};
-      const rowDefinition = getRowDefinition(
-        config.prBodyColumns ?? [],
-        upgrade
-      );
+      const rowDefinition = getRowDefinition(config.prBodyColumns!, upgrade);
       for (const column of rowDefinition) {
         const { header, value } = column;
         try {
diff --git a/lib/workers/repository/update/pr/index.ts b/lib/workers/repository/update/pr/index.ts
index 705f6b0951545ba89d4cd4aae655f1fd11971943..8aefec5074c093b0a450c25057fcb7ef5f97205c 100644
--- a/lib/workers/repository/update/pr/index.ts
+++ b/lib/workers/repository/update/pr/index.ts
@@ -99,7 +99,7 @@ function hasNotIgnoredReviewers(pr: Pr, config: BranchConfig): boolean {
       0
     );
   }
-  return pr.reviewers ? pr.reviewers.length > 0 : false;
+  return is.nonEmptyArray(pr.reviewers);
 }
 
 // Ensures that PR exists with matching title/body
diff --git a/lib/workers/repository/update/pr/participants.spec.ts b/lib/workers/repository/update/pr/participants.spec.ts
index 699da1190fe2b1f2ecb54bb1f92e360e0fca893a..04e3f148cca646de6dbdc5c6c59c047afc49190a 100644
--- a/lib/workers/repository/update/pr/participants.spec.ts
+++ b/lib/workers/repository/update/pr/participants.spec.ts
@@ -28,6 +28,11 @@ describe('workers/repository/update/pr/participants', () => {
   });
 
   describe('assignees', () => {
+    it('does not assignees when there are none', async () => {
+      await addParticipants({ ...config, assignees: undefined }, pr);
+      expect(platform.addAssignees).not.toHaveBeenCalled();
+    });
+
     it('adds assignees', async () => {
       await addParticipants(config, pr);
       expect(platform.addAssignees).toHaveBeenCalledWith(123, ['a', 'b', 'c']);
@@ -73,6 +78,11 @@ describe('workers/repository/update/pr/participants', () => {
   });
 
   describe('reviewers', () => {
+    it('does not assignees when there are none', async () => {
+      await addParticipants({ ...config, reviewers: undefined }, pr);
+      expect(platform.addReviewers).not.toHaveBeenCalled();
+    });
+
     it('adds reviewers', async () => {
       await addParticipants(config, pr);
       expect(platform.addReviewers).toHaveBeenCalledWith(123, ['x', 'y', 'z']);
diff --git a/lib/workers/repository/update/pr/pr-cache.spec.ts b/lib/workers/repository/update/pr/pr-cache.spec.ts
index 65f704241d1817373f96811a06caff6458b05a20..51455f04190227210dbd67614aab57008dc093ff 100644
--- a/lib/workers/repository/update/pr/pr-cache.spec.ts
+++ b/lib/workers/repository/update/pr/pr-cache.spec.ts
@@ -57,7 +57,7 @@ describe('workers/repository/update/pr/pr-cache', () => {
       );
     });
 
-    it('set prCache', () => {
+    it('updates cache', () => {
       cache.getCache.mockReturnValue(dummyCache);
       jest.useFakeTimers().setSystemTime(new Date('2020-01-01'));
       setPrCache('branch_name', 'fingerprint_hash', true);
@@ -73,5 +73,33 @@ describe('workers/repository/update/pr/pr-cache', () => {
         ],
       });
     });
+
+    it('does not update details if pr not modified', () => {
+      const dummyCache2 = {
+        branches: [
+          {
+            ...branchCache,
+            prCache: {
+              bodyFingerprint: 'fingerprint_hash',
+              lastEdited: new Date('2020-01-01').toISOString(),
+            },
+          },
+        ],
+      };
+      cache.getCache.mockReturnValue(dummyCache);
+      jest.useFakeTimers().setSystemTime(new Date('2020-01-02'));
+      setPrCache('branch_name', 'fingerprint_hash', false);
+      expect(dummyCache2).toStrictEqual({
+        branches: [
+          {
+            ...branchCache,
+            prCache: {
+              bodyFingerprint: 'fingerprint_hash',
+              lastEdited: new Date('2020-01-01').toISOString(),
+            },
+          },
+        ],
+      });
+    });
   });
 });