diff --git a/lib/modules/datasource/common.ts b/lib/modules/datasource/common.ts
index 6c7a05f47d570d1e8776116277a6bf20efe12316..f4a4b9d4e4902c8520ad6a141743abc259854e1e 100644
--- a/lib/modules/datasource/common.ts
+++ b/lib/modules/datasource/common.ts
@@ -1,6 +1,37 @@
 import is from '@sindresorhus/is';
-import type { HttpResponse } from '../../util/http/types';
-import type { GetPkgReleasesConfig } from './types';
+import { logger } from '../../logger';
+import { filterMap } from '../../util/filter-map';
+import { regEx } from '../../util/regex';
+import { defaultVersioning } from '../versioning';
+import * as allVersioning from '../versioning';
+import datasources from './api';
+import { CustomDatasource } from './custom';
+import type {
+  DatasourceApi,
+  GetPkgReleasesConfig,
+  ReleaseResult,
+} from './types';
+
+export function getDatasourceFor(datasource: string): DatasourceApi | null {
+  if (datasource?.startsWith('custom.')) {
+    return getDatasourceFor(CustomDatasource.id);
+  }
+  return datasources.get(datasource) ?? null;
+}
+
+export function getDefaultVersioning(
+  datasourceName: string | undefined
+): string {
+  if (!datasourceName) {
+    return defaultVersioning.id;
+  }
+  const datasource = getDatasourceFor(datasourceName);
+  // istanbul ignore if: wrong regex manager config?
+  if (!datasource) {
+    logger.warn({ datasourceName }, 'Missing datasource!');
+  }
+  return datasource?.defaultVersioning ?? defaultVersioning.id;
+}
 
 export function isGetPkgReleasesConfig(
   input: unknown
@@ -15,10 +46,136 @@ export function isGetPkgReleasesConfig(
   );
 }
 
-const JFROG_ARTIFACTORY_RES_HEADER = 'x-jfrog-version';
+export function applyExtractVersion<
+  Config extends Pick<GetPkgReleasesConfig, 'extractVersion'>
+>(config: Config, releaseResult: ReleaseResult): ReleaseResult {
+  if (!config.extractVersion) {
+    return releaseResult;
+  }
+
+  const extractVersionRegEx = regEx(config.extractVersion);
+  releaseResult.releases = filterMap(releaseResult.releases, (release) => {
+    const version = extractVersionRegEx.exec(release.version)?.groups?.version;
+    if (!version) {
+      return null;
+    }
+
+    release.version = version;
+    return release;
+  });
+
+  return releaseResult;
+}
+
+export function filterValidVersions<
+  Config extends Pick<GetPkgReleasesConfig, 'versioning' | 'datasource'>
+>(config: Config, releaseResult: ReleaseResult): ReleaseResult {
+  const versioningName =
+    config.versioning ?? getDefaultVersioning(config.datasource);
+  const versioning = allVersioning.get(versioningName);
+
+  releaseResult.releases = filterMap(releaseResult.releases, (release) =>
+    versioning.isVersion(release.version) ? release : null
+  );
+
+  return releaseResult;
+}
+
+export function sortAndRemoveDuplicates<
+  Config extends Pick<GetPkgReleasesConfig, 'versioning' | 'datasource'>
+>(config: Config, releaseResult: ReleaseResult): ReleaseResult {
+  const versioningName =
+    config.versioning ?? getDefaultVersioning(config.datasource);
+  const versioning = allVersioning.get(versioningName);
+
+  releaseResult.releases = releaseResult.releases.sort((a, b) =>
+    versioning.sortVersions(a.version, b.version)
+  );
+
+  // Once releases are sorted, deduplication is straightforward and efficient
+  let previousVersion: string | null = null;
+  releaseResult.releases = filterMap(releaseResult.releases, (release) => {
+    if (previousVersion === release.version) {
+      return null;
+    }
+    previousVersion = release.version;
+    return release;
+  });
+
+  return releaseResult;
+}
+
+export function applyConstraintsFiltering<
+  Config extends Pick<
+    GetPkgReleasesConfig,
+    | 'constraintsFiltering'
+    | 'versioning'
+    | 'datasource'
+    | 'constraints'
+    | 'packageName'
+  >
+>(config: Config, releaseResult: ReleaseResult): ReleaseResult {
+  if (config?.constraintsFiltering !== 'strict') {
+    for (const release of releaseResult.releases) {
+      delete release.constraints;
+    }
+
+    return releaseResult;
+  }
+
+  const versioningName =
+    config.versioning ?? getDefaultVersioning(config.datasource);
+  const versioning = allVersioning.get(versioningName);
+
+  const configConstraints = config.constraints;
+  const filteredReleases: string[] = [];
+  releaseResult.releases = filterMap(releaseResult.releases, (release) => {
+    const releaseConstraints = release.constraints;
+    delete release.constraints;
+
+    // istanbul ignore if
+    if (!configConstraints || !releaseConstraints) {
+      return release;
+    }
+
+    for (const [name, configConstraint] of Object.entries(configConstraints)) {
+      // istanbul ignore if
+      if (!versioning.isValid(configConstraint)) {
+        continue;
+      }
+
+      const constraint = releaseConstraints[name];
+      if (!is.nonEmptyArray(constraint)) {
+        // A release with no constraints is OK
+        continue;
+      }
+
+      const satisfiesConstraints = constraint.some(
+        // If the constraint value is a subset of any release's constraints, then it's OK
+        // fallback to release's constraint match if subset is not supported by versioning
+        (releaseConstraint) =>
+          !releaseConstraint ||
+          (versioning.subset?.(configConstraint, releaseConstraint) ??
+            versioning.matches(configConstraint, releaseConstraint))
+      );
+
+      if (!satisfiesConstraints) {
+        filteredReleases.push(release.version);
+        return null;
+      }
+    }
+
+    return release;
+  });
+
+  if (filteredReleases.length) {
+    const count = filteredReleases.length;
+    const packageName = config.packageName;
+    const releases = filteredReleases.join(', ');
+    logger.debug(
+      `Filtered ${count} releases for ${packageName} due to constraintsFiltering=strict: ${releases}`
+    );
+  }
 
-export function isArtifactoryServer<T = unknown>(
-  res: HttpResponse<T> | undefined
-): boolean {
-  return is.string(res?.headers[JFROG_ARTIFACTORY_RES_HEADER]);
+  return releaseResult;
 }
diff --git a/lib/modules/datasource/conan/index.ts b/lib/modules/datasource/conan/index.ts
index 9e4f3b05db83b6c16c8596cfb83299fe20f97a3a..44493c1b00bb29d09667ae030a122819b7f6fcfe 100644
--- a/lib/modules/datasource/conan/index.ts
+++ b/lib/modules/datasource/conan/index.ts
@@ -5,7 +5,6 @@ import { cache } from '../../../util/cache/package/decorator';
 import { GithubHttp } from '../../../util/http/github';
 import { ensureTrailingSlash, joinUrlParts } from '../../../util/url';
 import * as allVersioning from '../../versioning';
-import { isArtifactoryServer } from '../common';
 import { Datasource } from '../datasource';
 import type {
   DigestConfig,
@@ -13,6 +12,7 @@ import type {
   Release,
   ReleaseResult,
 } from '../types';
+import { isArtifactoryServer } from '../util';
 import {
   conanDatasourceRegex,
   datasource,
diff --git a/lib/modules/datasource/docker/index.ts b/lib/modules/datasource/docker/index.ts
index 6bcd11ddaf53b018c14764efe211f50a97395be7..f5082fd06e1a73997957b57ab2f5e8a105e9d580 100644
--- a/lib/modules/datasource/docker/index.ts
+++ b/lib/modules/datasource/docker/index.ts
@@ -14,9 +14,9 @@ import {
   parseLinkHeader,
 } from '../../../util/url';
 import { id as dockerVersioningId } from '../../versioning/docker';
-import { isArtifactoryServer } from '../common';
 import { Datasource } from '../datasource';
 import type { DigestConfig, GetReleasesConfig, ReleaseResult } from '../types';
+import { isArtifactoryServer } from '../util';
 import {
   DOCKER_HUB,
   dockerDatasourceId,
diff --git a/lib/modules/datasource/index.spec.ts b/lib/modules/datasource/index.spec.ts
index e5c91e2c88e8a23c154915abd32fd21bcdf47f55..a37361384a1a1dd43e06bea8589cfdd72af3a4d9 100644
--- a/lib/modules/datasource/index.spec.ts
+++ b/lib/modules/datasource/index.spec.ts
@@ -7,6 +7,7 @@ import {
 import { ExternalHostError } from '../../types/errors/external-host-error';
 import { loadModules } from '../../util/modules';
 import datasources from './api';
+import { getDefaultVersioning } from './common';
 import { Datasource } from './datasource';
 import type {
   DatasourceApi,
@@ -17,7 +18,6 @@ import type {
 import {
   getDatasourceList,
   getDatasources,
-  getDefaultVersioning,
   getDigest,
   getPkgReleases,
   supportsDigests,
diff --git a/lib/modules/datasource/index.ts b/lib/modules/datasource/index.ts
index ee92733dba4de0ae1cc173e2b2c0fd08d87c4c98..20cbcd9da98dd982305f7444eed428118183e52f 100644
--- a/lib/modules/datasource/index.ts
+++ b/lib/modules/datasource/index.ts
@@ -6,13 +6,15 @@ import { ExternalHostError } from '../../types/errors/external-host-error';
 import * as memCache from '../../util/cache/memory';
 import * as packageCache from '../../util/cache/package';
 import { clone } from '../../util/clone';
-import { filterMap } from '../../util/filter-map';
-import { regEx } from '../../util/regex';
 import { trimTrailingSlash } from '../../util/url';
-import { defaultVersioning } from '../versioning';
-import * as allVersioning from '../versioning';
 import datasources from './api';
-import { CustomDatasource } from './custom';
+import {
+  applyConstraintsFiltering,
+  applyExtractVersion,
+  filterValidVersions,
+  getDatasourceFor,
+  sortAndRemoveDuplicates,
+} from './common';
 import { addMetaData } from './metadata';
 import { setNpmrc } from './npm';
 import { resolveRegistryUrl } from './npm/npmrc';
@@ -33,13 +35,6 @@ export const getDatasourceList = (): string[] => Array.from(datasources.keys());
 
 const cacheNamespace = 'datasource-releases';
 
-export function getDatasourceFor(datasource: string): DatasourceApi | null {
-  if (datasource?.startsWith('custom.')) {
-    return getDatasourceFor(CustomDatasource.id);
-  }
-  return datasources.get(datasource) ?? null;
-}
-
 type GetReleasesInternalConfig = GetReleasesConfig & GetPkgReleasesConfig;
 
 // TODO: fix error Type
@@ -241,20 +236,6 @@ function resolveRegistryUrls(
   return massageRegistryUrls(resolvedUrls);
 }
 
-export function getDefaultVersioning(
-  datasourceName: string | undefined
-): string {
-  if (!datasourceName) {
-    return defaultVersioning.id;
-  }
-  const datasource = getDatasourceFor(datasourceName);
-  // istanbul ignore if: wrong regex manager config?
-  if (!datasource) {
-    logger.warn({ datasourceName }, 'Missing datasource!');
-  }
-  return datasource?.defaultVersioning ?? defaultVersioning.id;
-}
-
 function applyReplacements(
   config: GetReleasesInternalConfig
 ): Pick<ReleaseResult, 'replacementName' | 'replacementVersion'> | undefined {
@@ -346,131 +327,6 @@ function getRawReleases(
   return promisedRes;
 }
 
-function applyExtractVersion<
-  Config extends Pick<GetPkgReleasesConfig, 'extractVersion'>
->(config: Config, releaseResult: ReleaseResult): void {
-  if (!config.extractVersion) {
-    return;
-  }
-
-  const extractVersionRegEx = regEx(config.extractVersion);
-  releaseResult.releases = filterMap(releaseResult.releases, (release) => {
-    const version = extractVersionRegEx.exec(release.version)?.groups?.version;
-    if (!version) {
-      return null;
-    }
-
-    release.version = version;
-    return release;
-  });
-}
-
-function filterValidVersions<
-  Config extends Pick<GetPkgReleasesConfig, 'versioning' | 'datasource'>
->(config: Config, releaseResult: ReleaseResult): void {
-  const versioningName =
-    config.versioning ?? getDefaultVersioning(config.datasource);
-  const versioning = allVersioning.get(versioningName);
-
-  releaseResult.releases = filterMap(releaseResult.releases, (release) =>
-    versioning.isVersion(release.version) ? release : null
-  );
-}
-
-function sortAndRemoveDuplicates<
-  Config extends Pick<GetPkgReleasesConfig, 'versioning' | 'datasource'>
->(config: Config, releaseResult: ReleaseResult): void {
-  const versioningName =
-    config.versioning ?? getDefaultVersioning(config.datasource);
-  const versioning = allVersioning.get(versioningName);
-
-  releaseResult.releases = releaseResult.releases.sort((a, b) =>
-    versioning.sortVersions(a.version, b.version)
-  );
-
-  // Once releases are sorted, deduplication is straightforward and efficient
-  let previousVersion: string | null = null;
-  releaseResult.releases = filterMap(releaseResult.releases, (release) => {
-    if (previousVersion === release.version) {
-      return null;
-    }
-    previousVersion = release.version;
-    return release;
-  });
-}
-
-function applyConstraintsFiltering<
-  Config extends Pick<
-    GetPkgReleasesConfig,
-    | 'constraintsFiltering'
-    | 'versioning'
-    | 'datasource'
-    | 'constraints'
-    | 'packageName'
-  >
->(config: Config, releaseResult: ReleaseResult): void {
-  if (config?.constraintsFiltering !== 'strict') {
-    for (const release of releaseResult.releases) {
-      delete release.constraints;
-    }
-    return;
-  }
-
-  const versioningName =
-    config.versioning ?? getDefaultVersioning(config.datasource);
-  const versioning = allVersioning.get(versioningName);
-
-  const configConstraints = config.constraints;
-  const filteredReleases: string[] = [];
-  releaseResult.releases = filterMap(releaseResult.releases, (release) => {
-    const releaseConstraints = release.constraints;
-    delete release.constraints;
-
-    // istanbul ignore if
-    if (!configConstraints || !releaseConstraints) {
-      return release;
-    }
-
-    for (const [name, configConstraint] of Object.entries(configConstraints)) {
-      // istanbul ignore if
-      if (!versioning.isValid(configConstraint)) {
-        continue;
-      }
-
-      const constraint = releaseConstraints[name];
-      if (!is.nonEmptyArray(constraint)) {
-        // A release with no constraints is OK
-        continue;
-      }
-
-      const satisfiesConstraints = constraint.some(
-        // If the constraint value is a subset of any release's constraints, then it's OK
-        // fallback to release's constraint match if subset is not supported by versioning
-        (releaseConstraint) =>
-          !releaseConstraint ||
-          (versioning.subset?.(configConstraint, releaseConstraint) ??
-            versioning.matches(configConstraint, releaseConstraint))
-      );
-
-      if (!satisfiesConstraints) {
-        filteredReleases.push(release.version);
-        return null;
-      }
-    }
-
-    return release;
-  });
-
-  if (filteredReleases.length) {
-    const count = filteredReleases.length;
-    const packageName = config.packageName;
-    const releases = filteredReleases.join(', ');
-    logger.debug(
-      `Filtered ${count} releases for ${packageName} due to constraintsFiltering=strict: ${releases}`
-    );
-  }
-}
-
 export async function getPkgReleases(
   config: GetPkgReleasesConfig
 ): Promise<ReleaseResult | null> {
diff --git a/lib/modules/datasource/util.ts b/lib/modules/datasource/util.ts
new file mode 100644
index 0000000000000000000000000000000000000000..7293769a2b33e1a1165fe2f49070d8df70dfd4be
--- /dev/null
+++ b/lib/modules/datasource/util.ts
@@ -0,0 +1,10 @@
+import is from '@sindresorhus/is';
+import type { HttpResponse } from '../../util/http/types';
+
+const JFROG_ARTIFACTORY_RES_HEADER = 'x-jfrog-version';
+
+export function isArtifactoryServer<T = unknown>(
+  res: HttpResponse<T> | undefined
+): boolean {
+  return is.string(res?.headers[JFROG_ARTIFACTORY_RES_HEADER]);
+}
diff --git a/lib/modules/datasource/common.spec.ts b/lib/modules/datasource/utils.spec.ts
similarity index 85%
rename from lib/modules/datasource/common.spec.ts
rename to lib/modules/datasource/utils.spec.ts
index c68448381d058fcfe8a653485c1453826b2c10b4..20d8161e84c5310683685ac4ffaf2120050697f7 100644
--- a/lib/modules/datasource/common.spec.ts
+++ b/lib/modules/datasource/utils.spec.ts
@@ -1,7 +1,7 @@
 import type { HttpResponse } from '../../util/http/types';
-import { isArtifactoryServer } from './common';
+import { isArtifactoryServer } from './util';
 
-describe('modules/datasource/common', () => {
+describe('modules/datasource/utils', () => {
   it('is artifactory server invalid', () => {
     const response: HttpResponse<string> = {
       statusCode: 200,
diff --git a/lib/workers/repository/process/fetch.ts b/lib/workers/repository/process/fetch.ts
index e8208445af4d361500a6b15d1f0beff882da93c8..4d11ec848fa45b8923dc15537bfcfd498ae0ae23 100644
--- a/lib/workers/repository/process/fetch.ts
+++ b/lib/workers/repository/process/fetch.ts
@@ -3,10 +3,8 @@ import is from '@sindresorhus/is';
 import { getManagerConfig, mergeChildConfig } from '../../../config';
 import type { RenovateConfig } from '../../../config/types';
 import { logger } from '../../../logger';
-import {
-  getDefaultConfig,
-  getDefaultVersioning,
-} from '../../../modules/datasource';
+import { getDefaultConfig } from '../../../modules/datasource';
+import { getDefaultVersioning } from '../../../modules/datasource/common';
 import type {
   PackageDependency,
   PackageFile,
diff --git a/lib/workers/repository/process/lookup/index.ts b/lib/workers/repository/process/lookup/index.ts
index be900de83d1543251194d68072bb00751889a5cd..b3c8298bd232745d0a1e3cc64571f995b427dc68 100644
--- a/lib/workers/repository/process/lookup/index.ts
+++ b/lib/workers/repository/process/lookup/index.ts
@@ -6,13 +6,15 @@ import { logger } from '../../../../logger';
 import {
   Release,
   ReleaseResult,
-  getDatasourceFor,
-  getDefaultVersioning,
   getDigest,
   getPkgReleases,
   isGetPkgReleasesConfig,
   supportsDigests,
 } from '../../../../modules/datasource';
+import {
+  getDatasourceFor,
+  getDefaultVersioning,
+} from '../../../../modules/datasource/common';
 import { getRangeStrategy } from '../../../../modules/manager';
 import * as allVersioning from '../../../../modules/versioning';
 import { ExternalHostError } from '../../../../types/errors/external-host-error';
diff --git a/lib/workers/repository/process/vulnerabilities.ts b/lib/workers/repository/process/vulnerabilities.ts
index 9ff98a803dfb6af82a1f43341896bdabadf0cf14..15991b863f60bba452e765d0c4c6f83e739bb989 100644
--- a/lib/workers/repository/process/vulnerabilities.ts
+++ b/lib/workers/repository/process/vulnerabilities.ts
@@ -6,7 +6,7 @@ import { parseCvssVector } from 'vuln-vects';
 import { getManagerConfig, mergeChildConfig } from '../../../config';
 import type { PackageRule, RenovateConfig } from '../../../config/types';
 import { logger } from '../../../logger';
-import { getDefaultVersioning } from '../../../modules/datasource';
+import { getDefaultVersioning } from '../../../modules/datasource/common';
 import type {
   PackageDependency,
   PackageFile,