diff --git a/lib/constants/platform.spec.ts b/lib/constants/platform.spec.ts
index 24bd14b7ae6562ccbe74de4c2f4b7fdb0d0f5337..321b991aabaaf3873a9b56ea6e9e96144bf3b03c 100644
--- a/lib/constants/platform.spec.ts
+++ b/lib/constants/platform.spec.ts
@@ -1,6 +1,6 @@
 import { BitBucketTagsDatasource } from '../datasource/bitbucket-tags';
-import { id as GH_RELEASES_DS } from '../datasource/github-releases';
-import { id as GH_TAGS_DS } from '../datasource/github-tags';
+import { GithubReleasesDatasource } from '../datasource/github-releases';
+import { GithubTagsDatasource } from '../datasource/github-tags';
 import { GitlabPackagesDatasource } from '../datasource/gitlab-packages';
 import { GitlabReleasesDatasource } from '../datasource/gitlab-releases';
 import { GitlabTagsDatasource } from '../datasource/gitlab-tags';
@@ -36,8 +36,12 @@ describe('constants/platform', () => {
   });
 
   it('should be part of the GITHUB_API_USING_HOST_TYPES ', () => {
-    expect(GITHUB_API_USING_HOST_TYPES.includes(GH_TAGS_DS)).toBeTrue();
-    expect(GITHUB_API_USING_HOST_TYPES.includes(GH_RELEASES_DS)).toBeTrue();
+    expect(
+      GITHUB_API_USING_HOST_TYPES.includes(GithubTagsDatasource.id)
+    ).toBeTrue();
+    expect(
+      GITHUB_API_USING_HOST_TYPES.includes(GithubReleasesDatasource.id)
+    ).toBeTrue();
     expect(GITHUB_API_USING_HOST_TYPES.includes(PodDatasource.id)).toBeTrue();
     expect(
       GITHUB_API_USING_HOST_TYPES.includes(GITHUB_CHANGELOG_ID)
diff --git a/lib/datasource/api.ts b/lib/datasource/api.ts
index 11d8aaae45e7988ba441085b71237d052c754c03..0d23685404fcab1513cfa49ed5328d8c9de710f4 100644
--- a/lib/datasource/api.ts
+++ b/lib/datasource/api.ts
@@ -12,8 +12,8 @@ import { GalaxyDatasource } from './galaxy';
 import { GalaxyCollectionDatasource } from './galaxy-collection';
 import { GitRefsDatasource } from './git-refs';
 import { GitTagsDatasource } from './git-tags';
-import * as githubReleases from './github-releases';
-import * as githubTags from './github-tags';
+import { GithubReleasesDatasource } from './github-releases';
+import { GithubTagsDatasource } from './github-tags';
 import { GitlabPackagesDatasource } from './gitlab-packages';
 import { GitlabReleasesDatasource } from './gitlab-releases';
 import { GitlabTagsDatasource } from './gitlab-tags';
@@ -57,8 +57,8 @@ api.set(GalaxyDatasource.id, new GalaxyDatasource());
 api.set(GalaxyCollectionDatasource.id, new GalaxyCollectionDatasource());
 api.set(GitRefsDatasource.id, new GitRefsDatasource());
 api.set(GitTagsDatasource.id, new GitTagsDatasource());
-api.set('github-releases', githubReleases);
-api.set('github-tags', githubTags);
+api.set(GithubReleasesDatasource.id, new GithubReleasesDatasource());
+api.set(GithubTagsDatasource.id, new GithubTagsDatasource());
 api.set(GitlabPackagesDatasource.id, new GitlabPackagesDatasource());
 api.set(GitlabReleasesDatasource.id, new GitlabReleasesDatasource());
 api.set(GitlabTagsDatasource.id, new GitlabTagsDatasource());
diff --git a/lib/datasource/github-releases/common.spec.ts b/lib/datasource/github-releases/common.spec.ts
index 352dc80df7a07862c6579cdd17390dd6b5af733f..bdf3b4443a13facab9b889d82e8800bb4c933f9c 100644
--- a/lib/datasource/github-releases/common.spec.ts
+++ b/lib/datasource/github-releases/common.spec.ts
@@ -1,5 +1,4 @@
-import { GitHubReleaseMocker } from './test';
-import { getApiBaseUrl, getGithubRelease, getSourceUrlBase } from '.';
+import { getApiBaseUrl, getSourceUrlBase } from './common';
 
 describe('datasource/github-releases/common', () => {
   describe('getSourceUrlBase', () => {
@@ -24,18 +23,4 @@ describe('datasource/github-releases/common', () => {
       expect(apiUrl).toBe('https://gh.my-company.com/api/v3/');
     });
   });
-
-  describe('getGithubRelease', () => {
-    const apiUrl = 'https://github.com/';
-    const lookupName = 'someDep';
-    const releaseMock = new GitHubReleaseMocker(apiUrl, lookupName);
-
-    it('returns release', async () => {
-      const version = 'v1.0.0';
-      releaseMock.release(version);
-
-      const release = await getGithubRelease(apiUrl, lookupName, version);
-      expect(release.tag_name).toBe(version);
-    });
-  });
 });
diff --git a/lib/datasource/github-releases/common.ts b/lib/datasource/github-releases/common.ts
new file mode 100644
index 0000000000000000000000000000000000000000..0ec694dd97be6e5082fbe9429f372c052b0e8a17
--- /dev/null
+++ b/lib/datasource/github-releases/common.ts
@@ -0,0 +1,20 @@
+import { ensureTrailingSlash } from '../../util/url';
+
+const defaultSourceUrlBase = 'https://github.com/';
+
+export function getSourceUrlBase(registryUrl: string): string {
+  // default to GitHub.com if no GHE host is specified.
+  return ensureTrailingSlash(registryUrl ?? defaultSourceUrlBase);
+}
+
+export function getApiBaseUrl(registryUrl: string): string {
+  const sourceUrlBase = getSourceUrlBase(registryUrl);
+  return sourceUrlBase === defaultSourceUrlBase
+    ? `https://api.github.com/`
+    : `${sourceUrlBase}api/v3/`;
+}
+
+export function getSourceUrl(lookupName: string, registryUrl?: string): string {
+  const sourceUrlBase = getSourceUrlBase(registryUrl);
+  return `${sourceUrlBase}${lookupName}`;
+}
diff --git a/lib/datasource/github-releases/digest.spec.ts b/lib/datasource/github-releases/digest.spec.ts
index 56f4f27ebbd8b9ca678e756a3942feeca0f65cb3..7ffd8ade6d8fd2c04ec8f11c021437e43273fe5d 100644
--- a/lib/datasource/github-releases/digest.spec.ts
+++ b/lib/datasource/github-releases/digest.spec.ts
@@ -2,7 +2,8 @@ import hasha from 'hasha';
 import * as httpMock from '../../../test/http-mock';
 import { GitHubReleaseMocker } from './test';
 import type { DigestAsset } from './types';
-import { findDigestAsset, mapDigestAssetToRelease } from '.';
+
+import { GithubReleasesDatasource } from '.';
 
 describe('datasource/github-releases/digest', () => {
   const lookupName = 'some/dep';
@@ -10,6 +11,7 @@ describe('datasource/github-releases/digest', () => {
     'https://api.github.com',
     lookupName
   );
+  const githubReleases = new GithubReleasesDatasource();
 
   describe('findDigestAsset', () => {
     it('finds SHASUMS.txt file containing digest', async () => {
@@ -19,7 +21,10 @@ describe('datasource/github-releases/digest', () => {
         'another-digest linux-arm64.tar.gz'
       );
 
-      const digestAsset = await findDigestAsset(release, 'test-digest');
+      const digestAsset = await githubReleases.findDigestAsset(
+        release,
+        'test-digest'
+      );
       expect(digestAsset.assetName).toBe('SHASUMS.txt');
       expect(digestAsset.digestedFileName).toBe('linux-amd64.tar.gz');
     });
@@ -35,7 +40,10 @@ describe('datasource/github-releases/digest', () => {
         .get(`/repos/${lookupName}/releases/download/v1.0.0/SHASUMS.txt`)
         .reply(200, '');
 
-      const digestAsset = await findDigestAsset(release, 'test-digest');
+      const digestAsset = await githubReleases.findDigestAsset(
+        release,
+        'test-digest'
+      );
       expect(digestAsset).toBeNull();
     });
 
@@ -49,14 +57,20 @@ describe('datasource/github-releases/digest', () => {
       });
       const contentDigest = await hasha.async(content, { algorithm: 'sha256' });
 
-      const digestAsset = await findDigestAsset(release, contentDigest);
+      const digestAsset = await githubReleases.findDigestAsset(
+        release,
+        contentDigest
+      );
       expect(digestAsset.assetName).toBe('asset.zip');
       expect(digestAsset.digestedFileName).toBeUndefined();
     });
 
     it('returns null when no assets available', async () => {
       const release = releaseMock.release('v1.0.0');
-      const digestAsset = await findDigestAsset(release, 'test-digest');
+      const digestAsset = await githubReleases.findDigestAsset(
+        release,
+        'test-digest'
+      );
       expect(digestAsset).toBeNull();
     });
   });
@@ -75,7 +89,10 @@ describe('datasource/github-releases/digest', () => {
           'v1.0.1',
           'updated-digest  asset.zip'
         );
-        const digest = await mapDigestAssetToRelease(digestAsset, release);
+        const digest = await githubReleases.mapDigestAssetToRelease(
+          digestAsset,
+          release
+        );
         expect(digest).toBe('updated-digest');
       });
 
@@ -89,7 +106,7 @@ describe('datasource/github-releases/digest', () => {
           'v1.0.1',
           'updated-digest  asset-1.0.1.zip'
         );
-        const digest = await mapDigestAssetToRelease(
+        const digest = await githubReleases.mapDigestAssetToRelease(
           digestAssetWithVersion,
           release
         );
@@ -101,13 +118,19 @@ describe('datasource/github-releases/digest', () => {
           'v1.0.1',
           'moot-digest asset.tar.gz'
         );
-        const digest = await mapDigestAssetToRelease(digestAsset, release);
+        const digest = await githubReleases.mapDigestAssetToRelease(
+          digestAsset,
+          release
+        );
         expect(digest).toBeNull();
       });
 
       it('returns null when digest file not found', async () => {
         const release = releaseMock.release('v1.0.1');
-        const digest = await mapDigestAssetToRelease(digestAsset, release);
+        const digest = await githubReleases.mapDigestAssetToRelease(
+          digestAsset,
+          release
+        );
         expect(digest).toBeNull();
       });
     });
@@ -128,13 +151,19 @@ describe('datasource/github-releases/digest', () => {
           algorithm: 'sha256',
         });
 
-        const digest = await mapDigestAssetToRelease(digestAsset, release);
+        const digest = await githubReleases.mapDigestAssetToRelease(
+          digestAsset,
+          release
+        );
         expect(digest).toEqual(contentDigest);
       });
 
       it('returns null when not found', async () => {
         const release = releaseMock.release('v1.0.1');
-        const digest = await mapDigestAssetToRelease(digestAsset, release);
+        const digest = await githubReleases.mapDigestAssetToRelease(
+          digestAsset,
+          release
+        );
         expect(digest).toBeNull();
       });
     });
diff --git a/lib/datasource/github-releases/index.spec.ts b/lib/datasource/github-releases/index.spec.ts
index 786b08b51005cc5791177c427a40e39a0096b657..4e74c0fbe97f27d7d618833d6281ea43e3a7a8d4 100644
--- a/lib/datasource/github-releases/index.spec.ts
+++ b/lib/datasource/github-releases/index.spec.ts
@@ -2,8 +2,7 @@ import { getDigest, getPkgReleases } from '..';
 import * as httpMock from '../../../test/http-mock';
 import * as _hostRules from '../../util/host-rules';
 import { GitHubReleaseMocker } from './test';
-import { id as datasource } from '.';
-import * as github from '.';
+import { GithubReleasesDatasource } from '.';
 
 jest.mock('../../util/host-rules');
 const hostRules: any = _hostRules;
@@ -25,6 +24,8 @@ const responseBody = [
 ];
 
 describe('datasource/github-releases/index', () => {
+  const githubReleases = new GithubReleasesDatasource();
+
   beforeEach(() => {
     hostRules.hosts.mockReturnValue([]);
     hostRules.find.mockReturnValue({
@@ -40,7 +41,7 @@ describe('datasource/github-releases/index', () => {
         .reply(200, responseBody);
 
       const res = await getPkgReleases({
-        datasource,
+        datasource: GithubReleasesDatasource.id,
         depName: 'some/dep',
       });
       expect(res).toMatchSnapshot();
@@ -62,7 +63,7 @@ describe('datasource/github-releases/index', () => {
         .scope(githubEnterpriseApiHost)
         .get(`/api/v3/repos/${lookupName}/releases?per_page=100`)
         .reply(200, responseBody);
-      const res = await github.getReleases({
+      const res = await githubReleases.getReleases({
         registryUrl: 'https://git.enterprise.com',
         lookupName,
       });
@@ -80,14 +81,17 @@ describe('datasource/github-releases/index', () => {
     const releaseMock = new GitHubReleaseMocker(githubApiHost, depName);
 
     it('requires currentDigest', async () => {
-      const digest = await getDigest({ datasource, depName }, currentValue);
+      const digest = await getDigest(
+        { datasource: GithubReleasesDatasource.id, depName },
+        currentValue
+      );
       expect(digest).toBeNull();
     });
 
     it('defaults to currentDigest when currentVersion is missing', async () => {
       const digest = await getDigest(
         {
-          datasource,
+          datasource: GithubReleasesDatasource.id,
           depName,
           currentDigest,
         },
@@ -106,7 +110,7 @@ describe('datasource/github-releases/index', () => {
       releaseMock.withDigestFileAsset(nextValue, `${nextDigest} asset.zip`);
       const digest = await getDigest(
         {
-          datasource,
+          datasource: GithubReleasesDatasource.id,
           depName,
           currentValue,
           currentDigest,
@@ -122,7 +126,7 @@ describe('datasource/github-releases/index', () => {
       releaseMock.release(currentValue);
       const digest = await getDigest(
         {
-          datasource,
+          datasource: GithubReleasesDatasource.id,
           depName,
           currentValue,
           currentDigest,
diff --git a/lib/datasource/github-releases/index.ts b/lib/datasource/github-releases/index.ts
index 4b7f95c2bdc2c08bae082144a9890e22483504cb..3d2088156c0c7be246fa1184ce262d4d81df147a 100644
--- a/lib/datasource/github-releases/index.ts
+++ b/lib/datasource/github-releases/index.ts
@@ -1,45 +1,14 @@
 import hasha from 'hasha';
 import { logger } from '../../logger';
-import * as packageCache from '../../util/cache/package';
+import { cache } from '../../util/cache/package/decorator';
 import { GithubHttp } from '../../util/http/github';
 import { newlineRegex, regEx } from '../../util/regex';
-import { ensureTrailingSlash } from '../../util/url';
+import { Datasource } from '../datasource';
 import type { DigestConfig, GetReleasesConfig, ReleaseResult } from '../types';
+import { getApiBaseUrl, getSourceUrl } from './common';
 import type { DigestAsset, GithubRelease, GithubReleaseAsset } from './types';
 
-export const customRegistrySupport = true;
-export const defaultRegistryUrls = ['https://github.com'];
-export const registryStrategy = 'first';
-
-const defaultSourceUrlBase = 'https://github.com/';
-export const id = 'github-releases';
-
 export const cacheNamespace = 'datasource-github-releases';
-export const http = new GithubHttp(id);
-
-async function findDigestFile(
-  release: GithubRelease,
-  digest: string
-): Promise<DigestAsset | null> {
-  const smallAssets = release.assets.filter(
-    (a: GithubReleaseAsset) => a.size < 5 * 1024
-  );
-  for (const asset of smallAssets) {
-    const res = await http.get(asset.browser_download_url);
-    for (const line of res.body.split(newlineRegex)) {
-      const [lineDigest, lineFn] = line.split(regEx(/\s+/), 2);
-      if (lineDigest === digest) {
-        return {
-          assetName: asset.name,
-          digestedFileName: lineFn,
-          currentVersion: release.tag_name,
-          currentDigest: lineDigest,
-        };
-      }
-    }
-  }
-  return null;
-}
 
 function inferHashAlg(digest: string): string {
   switch (digest.length) {
@@ -51,243 +20,240 @@ function inferHashAlg(digest: string): string {
   }
 }
 
-function getAssetDigestCacheKey(
-  downloadUrl: string,
-  algorithm: string
-): string {
-  const type = 'assetDigest';
-  return `${downloadUrl}:${algorithm}:${type}`;
-}
+export class GithubReleasesDatasource extends Datasource {
+  static id = 'github-releases';
 
-async function downloadAndDigest(
-  asset: GithubReleaseAsset,
-  algorithm: string
-): Promise<string> {
-  const downloadUrl = asset.browser_download_url;
-  const cacheKey = getAssetDigestCacheKey(downloadUrl, algorithm);
-  const cachedResult = await packageCache.get<string>(cacheNamespace, cacheKey);
-  // istanbul ignore if
-  if (cachedResult) {
-    return cachedResult;
-  }
+  override readonly defaultRegistryUrls = ['https://github.com'];
 
-  const res = http.stream(downloadUrl);
-  const digest = await hasha.fromStream(res, { algorithm });
+  override http: GithubHttp;
 
-  const cacheMinutes = 1440;
-  await packageCache.set(cacheNamespace, cacheKey, digest, cacheMinutes);
-  return digest;
-}
+  constructor(id = GithubReleasesDatasource.id) {
+    super(id);
+    this.http = new GithubHttp(id);
+  }
 
-async function findAssetWithDigest(
-  release: GithubRelease,
-  digest: string
-): Promise<DigestAsset | null> {
-  const algorithm = inferHashAlg(digest);
-  const assetsBySize = release.assets.sort(
-    (a: GithubReleaseAsset, b: GithubReleaseAsset) => {
-      if (a.size < b.size) {
-        return -1;
-      }
-      if (a.size > b.size) {
-        return 1;
+  async findDigestFile(
+    release: GithubRelease,
+    digest: string
+  ): Promise<DigestAsset | null> {
+    const smallAssets = release.assets.filter(
+      (a: GithubReleaseAsset) => a.size < 5 * 1024
+    );
+    for (const asset of smallAssets) {
+      const res = await this.http.get(asset.browser_download_url);
+      for (const line of res.body.split(newlineRegex)) {
+        const [lineDigest, lineFn] = line.split(regEx(/\s+/), 2);
+        if (lineDigest === digest) {
+          return {
+            assetName: asset.name,
+            digestedFileName: lineFn,
+            currentVersion: release.tag_name,
+            currentDigest: lineDigest,
+          };
+        }
       }
-      return 0;
-    }
-  );
-
-  for (const asset of assetsBySize) {
-    const assetDigest = await downloadAndDigest(asset, algorithm);
-    if (assetDigest === digest) {
-      return {
-        assetName: asset.name,
-        currentVersion: release.tag_name,
-        currentDigest: assetDigest,
-      };
     }
+    return null;
   }
-  return null;
-}
 
-/** Identify the asset associated with a known digest. */
-export async function findDigestAsset(
-  release: GithubRelease,
-  digest: string
-): Promise<DigestAsset> {
-  const digestFile = await findDigestFile(release, digest);
-  if (digestFile) {
-    return digestFile;
+  @cache({
+    ttlMinutes: 1440,
+    namespace: 'datasource-github-releases',
+    key: (asset: GithubReleaseAsset, algorithm: string) =>
+      `${asset.browser_download_url}:${algorithm}:assetDigest`,
+  })
+  async downloadAndDigest(
+    asset: GithubReleaseAsset,
+    algorithm: string
+  ): Promise<string> {
+    const res = this.http.stream(asset.browser_download_url);
+    const digest = await hasha.fromStream(res, { algorithm });
+    return digest;
   }
 
-  const asset = await findAssetWithDigest(release, digest);
-  return asset;
-}
+  async findAssetWithDigest(
+    release: GithubRelease,
+    digest: string
+  ): Promise<DigestAsset | null> {
+    const algorithm = inferHashAlg(digest);
+    const assetsBySize = release.assets.sort(
+      (a: GithubReleaseAsset, b: GithubReleaseAsset) => {
+        if (a.size < b.size) {
+          return -1;
+        }
+        if (a.size > b.size) {
+          return 1;
+        }
+        return 0;
+      }
+    );
 
-/** Given a digest asset, find the equivalent digest in a different release. */
-export async function mapDigestAssetToRelease(
-  digestAsset: DigestAsset,
-  release: GithubRelease
-): Promise<string | null> {
-  const current = digestAsset.currentVersion.replace(regEx(/^v/), '');
-  const next = release.tag_name.replace(regEx(/^v/), '');
-  const releaseChecksumAssetName = digestAsset.assetName.replace(current, next);
-  const releaseAsset = release.assets.find(
-    (a: GithubReleaseAsset) => a.name === releaseChecksumAssetName
-  );
-  if (!releaseAsset) {
-    return null;
-  }
-  if (digestAsset.digestedFileName) {
-    const releaseFilename = digestAsset.digestedFileName.replace(current, next);
-    const res = await http.get(releaseAsset.browser_download_url);
-    for (const line of res.body.split(newlineRegex)) {
-      const [lineDigest, lineFn] = line.split(regEx(/\s+/), 2);
-      if (lineFn === releaseFilename) {
-        return lineDigest;
+    for (const asset of assetsBySize) {
+      const assetDigest = await this.downloadAndDigest(asset, algorithm);
+      if (assetDigest === digest) {
+        return {
+          assetName: asset.name,
+          currentVersion: release.tag_name,
+          currentDigest: assetDigest,
+        };
       }
     }
-  } else {
-    const algorithm = inferHashAlg(digestAsset.currentDigest);
-    const newDigest = await downloadAndDigest(releaseAsset, algorithm);
-    return newDigest;
+    return null;
   }
-  return null;
-}
-
-export function getSourceUrlBase(registryUrl: string): string {
-  // default to GitHub.com if no GHE host is specified.
-  return ensureTrailingSlash(registryUrl ?? defaultSourceUrlBase);
-}
-
-export function getApiBaseUrl(registryUrl: string): string {
-  const sourceUrlBase = getSourceUrlBase(registryUrl);
-  return sourceUrlBase === defaultSourceUrlBase
-    ? `https://api.github.com/`
-    : `${sourceUrlBase}api/v3/`;
-}
 
-export function getSourceUrl(lookupName: string, registryUrl?: string): string {
-  const sourceUrlBase = getSourceUrlBase(registryUrl);
-  return `${sourceUrlBase}${lookupName}`;
-}
-
-export async function getGithubRelease(
-  apiBaseUrl: string,
-  repo: string,
-  version: string
-): Promise<GithubRelease> {
-  const url = `${apiBaseUrl}repos/${repo}/releases/tags/${version}`;
-  const res = await http.getJson<GithubRelease>(url);
-  return res.body;
-}
-
-function getReleasesCacheKey(registryUrl: string, repo: string): string {
-  const type = 'tags';
-  return `${registryUrl}:${repo}:${type}`;
-}
+  /** Identify the asset associated with a known digest. */
+  async findDigestAsset(
+    release: GithubRelease,
+    digest: string
+  ): Promise<DigestAsset> {
+    const digestFile = await this.findDigestFile(release, digest);
+    if (digestFile) {
+      return digestFile;
+    }
 
-/**
- * github.getReleases
- *
- * This function can be used to fetch releases with a customisable versioning (e.g. semver) and with releases.
- *
- * This function will:
- *  - Fetch all releases
- *  - Sanitize the versions if desired (e.g. strip out leading 'v')
- *  - Return a dependency object containing sourceUrl string and releases array
- */
-export async function getReleases({
-  lookupName: repo,
-  registryUrl,
-}: GetReleasesConfig): Promise<ReleaseResult | null> {
-  const cacheKey = getReleasesCacheKey(registryUrl, repo);
-  const cachedResult = await packageCache.get<ReleaseResult>(
-    cacheNamespace,
-    cacheKey
-  );
-  // istanbul ignore if
-  if (cachedResult) {
-    return cachedResult;
+    const asset = await this.findAssetWithDigest(release, digest);
+    return asset;
   }
-  const apiBaseUrl = getApiBaseUrl(registryUrl);
-  const url = `${apiBaseUrl}repos/${repo}/releases?per_page=100`;
-  const res = await http.getJson<GithubRelease[]>(url, {
-    paginate: true,
-  });
-  const githubReleases = res.body;
-  const dependency: ReleaseResult = {
-    sourceUrl: getSourceUrl(repo, registryUrl),
-    releases: null,
-  };
-  dependency.releases = githubReleases
-    .filter(({ draft }) => draft !== true)
-    .map(({ tag_name, published_at, prerelease }) => ({
-      version: tag_name,
-      gitRef: tag_name,
-      releaseTimestamp: published_at,
-      isStable: prerelease ? false : undefined,
-    }));
-  const cacheMinutes = 10;
-  await packageCache.set(cacheNamespace, cacheKey, dependency, cacheMinutes);
-  return dependency;
-}
 
-function getDigestCacheKey(
-  { lookupName: repo, currentValue, currentDigest, registryUrl }: DigestConfig,
-  newValue: string
-): string {
-  const type = 'digest';
-  return `${registryUrl}:${repo}:${currentValue}:${currentDigest}:${newValue}:${type}`;
-}
-
-/**
- * github.getDigest
- *
- * The `newValue` supplied here should be a valid tag for the GitHub release.
- * Requires `currentValue` and `currentDigest`.
- *
- * There may be many assets attached to the release. This function will:
- *  - Identify the asset pinned by `currentDigest` in the `currentValue` release
- *     - Download small release assets, parse as checksum manifests (e.g. `SHASUMS.txt`).
- *     - Download individual assets until `currentDigest` is encountered. This is limited to sha256 and sha512.
- *  - Map the hashed asset to `newValue` and return the updated digest as a string
- */
-export async function getDigest(
-  { lookupName: repo, currentValue, currentDigest, registryUrl }: DigestConfig,
-  newValue?: string
-): Promise<string | null> {
-  logger.debug(
-    { repo, currentValue, currentDigest, registryUrl, newValue },
-    'getDigest'
-  );
-  if (!currentDigest) {
+  /** Given a digest asset, find the equivalent digest in a different release. */
+  async mapDigestAssetToRelease(
+    digestAsset: DigestAsset,
+    release: GithubRelease
+  ): Promise<string | null> {
+    const current = digestAsset.currentVersion.replace(regEx(/^v/), '');
+    const next = release.tag_name.replace(regEx(/^v/), '');
+    const releaseChecksumAssetName = digestAsset.assetName.replace(
+      current,
+      next
+    );
+    const releaseAsset = release.assets.find(
+      (a: GithubReleaseAsset) => a.name === releaseChecksumAssetName
+    );
+    if (!releaseAsset) {
+      return null;
+    }
+    if (digestAsset.digestedFileName) {
+      const releaseFilename = digestAsset.digestedFileName.replace(
+        current,
+        next
+      );
+      const res = await this.http.get(releaseAsset.browser_download_url);
+      for (const line of res.body.split(newlineRegex)) {
+        const [lineDigest, lineFn] = line.split(regEx(/\s+/), 2);
+        if (lineFn === releaseFilename) {
+          return lineDigest;
+        }
+      }
+    } else {
+      const algorithm = inferHashAlg(digestAsset.currentDigest);
+      const newDigest = await this.downloadAndDigest(releaseAsset, algorithm);
+      return newDigest;
+    }
     return null;
   }
-  if (!currentValue) {
-    return currentDigest;
-  }
-  const cacheKey = getDigestCacheKey(
-    { lookupName: repo, currentValue, currentDigest, registryUrl },
-    newValue
-  );
-  const cachedResult = await packageCache.get<string>(cacheNamespace, cacheKey);
-  // istanbul ignore if
-  if (cachedResult) {
-    return cachedResult;
-  }
 
-  const apiBaseUrl = getApiBaseUrl(registryUrl);
-  const currentRelease = await getGithubRelease(apiBaseUrl, repo, currentValue);
-  const digestAsset = await findDigestAsset(currentRelease, currentDigest);
-  let newDigest: string;
-  if (!digestAsset || newValue === currentValue) {
-    newDigest = currentDigest;
-  } else {
-    const newRelease = await getGithubRelease(apiBaseUrl, repo, newValue);
-    newDigest = await mapDigestAssetToRelease(digestAsset, newRelease);
+  @cache({
+    ttlMinutes: 1440,
+    namespace: 'datasource-github-releases',
+    key: (
+      {
+        lookupName: repo,
+        currentValue,
+        currentDigest,
+        registryUrl,
+      }: DigestConfig,
+      newValue?: string
+    ) =>
+      `${registryUrl}:${repo}:${currentValue}:${currentDigest}:${newValue}:digest`,
+  })
+  /**
+   * github.getDigest
+   *
+   * The `newValue` supplied here should be a valid tag for the GitHub release.
+   * Requires `currentValue` and `currentDigest`.
+   *
+   * There may be many assets attached to the release. This function will:
+   *  - Identify the asset pinned by `currentDigest` in the `currentValue` release
+   *     - Download small release assets, parse as checksum manifests (e.g. `SHASUMS.txt`).
+   *     - Download individual assets until `currentDigest` is encountered. This is limited to sha256 and sha512.
+   *  - Map the hashed asset to `newValue` and return the updated digest as a string
+   */
+  override async getDigest(
+    {
+      lookupName: repo,
+      currentValue,
+      currentDigest,
+      registryUrl,
+    }: DigestConfig,
+    newValue: string
+  ): Promise<string | null> {
+    logger.debug(
+      { repo, currentValue, currentDigest, registryUrl, newValue },
+      'getDigest'
+    );
+    if (!currentDigest) {
+      return null;
+    }
+    if (!currentValue) {
+      return currentDigest;
+    }
+
+    const apiBaseUrl = getApiBaseUrl(registryUrl);
+    const { body: currentRelease } = await this.http.getJson<GithubRelease>(
+      `${apiBaseUrl}repos/${repo}/releases/tags/${currentValue}`
+    );
+    const digestAsset = await this.findDigestAsset(
+      currentRelease,
+      currentDigest
+    );
+    let newDigest: string;
+    if (!digestAsset || newValue === currentValue) {
+      newDigest = currentDigest;
+    } else {
+      const { body: newRelease } = await this.http.getJson<GithubRelease>(
+        `${apiBaseUrl}repos/${repo}/releases/tags/${newValue}`
+      );
+      newDigest = await this.mapDigestAssetToRelease(digestAsset, newRelease);
+    }
+    return newDigest;
   }
 
-  const cacheMinutes = 1440;
-  await packageCache.set(cacheNamespace, cacheKey, newDigest, cacheMinutes);
-  return newDigest;
+  @cache({
+    namespace: 'datasource-github-releases',
+    key: ({ lookupName: repo, registryUrl }: GetReleasesConfig) =>
+      `${registryUrl}:${repo}:tags`,
+  })
+  /**
+   * github.getReleases
+   *
+   * This function can be used to fetch releases with a customisable versioning (e.g. semver) and with releases.
+   *
+   * This function will:
+   *  - Fetch all releases
+   *  - Sanitize the versions if desired (e.g. strip out leading 'v')
+   *  - Return a dependency object containing sourceUrl string and releases array
+   */
+  async getReleases({
+    lookupName: repo,
+    registryUrl,
+  }: GetReleasesConfig): Promise<ReleaseResult | null> {
+    const apiBaseUrl = getApiBaseUrl(registryUrl);
+    const url = `${apiBaseUrl}repos/${repo}/releases?per_page=100`;
+    const res = await this.http.getJson<GithubRelease[]>(url, {
+      paginate: true,
+    });
+    const githubReleases = res.body;
+    const dependency: ReleaseResult = {
+      sourceUrl: getSourceUrl(repo, registryUrl),
+      releases: githubReleases
+        .filter(({ draft }) => draft !== true)
+        .map(({ tag_name, published_at, prerelease }) => ({
+          version: tag_name,
+          gitRef: tag_name,
+          releaseTimestamp: published_at,
+          isStable: prerelease ? false : undefined,
+        })),
+    };
+    return dependency;
+  }
 }
diff --git a/lib/datasource/github-tags/index.spec.ts b/lib/datasource/github-tags/index.spec.ts
index 4b8edc4ab82ace2bb868759a916f009f09e738eb..0d4d47bf9cc5c5989c9eaac165dc82d6e420bb94 100644
--- a/lib/datasource/github-tags/index.spec.ts
+++ b/lib/datasource/github-tags/index.spec.ts
@@ -1,7 +1,7 @@
 import { getPkgReleases } from '..';
 import * as httpMock from '../../../test/http-mock';
 import * as _hostRules from '../../util/host-rules';
-import * as github from '.';
+import { GithubTagsDatasource } from '.';
 
 jest.mock('../../util/host-rules');
 const hostRules: any = _hostRules;
@@ -10,6 +10,8 @@ const githubApiHost = 'https://api.github.com';
 const githubEnterpriseApiHost = 'https://git.enterprise.com';
 
 describe('datasource/github-tags/index', () => {
+  const github = new GithubTagsDatasource();
+
   beforeEach(() => {
     jest.resetAllMocks();
     hostRules.hosts = jest.fn(() => []);
diff --git a/lib/datasource/github-tags/index.ts b/lib/datasource/github-tags/index.ts
index 26719d6096021427bb932354f6ed8ae1779263c2..e3a57eb52a6560018d5b243312aa79e232d293bd 100644
--- a/lib/datasource/github-tags/index.ts
+++ b/lib/datasource/github-tags/index.ts
@@ -1,185 +1,147 @@
 import { logger } from '../../logger';
-import * as packageCache from '../../util/cache/package';
-import { GithubHttp } from '../../util/http/github';
-import {
-  getApiBaseUrl,
-  getSourceUrl,
-  getReleases as githubGetReleases,
-} from '../github-releases';
+import { cache } from '../../util/cache/package/decorator';
+import { GithubReleasesDatasource } from '../github-releases';
+import { getApiBaseUrl, getSourceUrl } from '../github-releases/common';
 import type { DigestConfig, GetReleasesConfig, ReleaseResult } from '../types';
 import type { GitHubTag, TagResponse } from './types';
 
-export const id = 'github-tags';
-export const customRegistrySupport = true;
-export const defaultRegistryUrls = ['https://github.com'];
-export const registryStrategy = 'first';
+export class GithubTagsDatasource extends GithubReleasesDatasource {
+  static override readonly id = 'github-tags';
 
-const http = new GithubHttp(id);
-
-const cacheNamespace = 'datasource-github-tags';
-
-function getCacheKey(registryUrl: string, repo: string, type: string): string {
-  return `${registryUrl}:${repo}:${type}`;
-}
-
-async function getTagCommit(
-  registryUrl: string,
-  githubRepo: string,
-  tag: string
-): Promise<string | null> {
-  const cachedResult = await packageCache.get<string>(
-    cacheNamespace,
-    getCacheKey(registryUrl, githubRepo, `tag-${tag}`)
-  );
-  // istanbul ignore if
-  if (cachedResult) {
-    return cachedResult;
+  constructor() {
+    super(GithubTagsDatasource.id);
   }
 
-  const apiBaseUrl = getApiBaseUrl(registryUrl);
-  let digest: string;
-  try {
-    const url = `${apiBaseUrl}repos/${githubRepo}/git/refs/tags/${tag}`;
-    const res = (await http.getJson<TagResponse>(url)).body.object;
-    if (res.type === 'commit') {
-      digest = res.sha;
-    } else if (res.type === 'tag') {
-      digest = (await http.getJson<TagResponse>(res.url)).body.object.sha;
-    } else {
-      logger.warn({ res }, 'Unknown git tag refs type');
+  @cache({
+    ttlMinutes: 120,
+    namespace: `datasource-${GithubTagsDatasource.id}`,
+    key: (registryUrl: string, githubRepo: string, tag: string) =>
+      `${registryUrl}:${githubRepo}:tag-${tag}`,
+  })
+  async getTagCommit(
+    registryUrl: string,
+    githubRepo: string,
+    tag: string
+  ): Promise<string | null> {
+    const apiBaseUrl = getApiBaseUrl(registryUrl);
+    let digest: string | null = null;
+    try {
+      const url = `${apiBaseUrl}repos/${githubRepo}/git/refs/tags/${tag}`;
+      const res = (await this.http.getJson<TagResponse>(url)).body.object;
+      if (res.type === 'commit') {
+        digest = res.sha;
+      } else if (res.type === 'tag') {
+        digest = (await this.http.getJson<TagResponse>(res.url)).body.object
+          .sha;
+      } else {
+        logger.warn({ res }, 'Unknown git tag refs type');
+      }
+    } catch (err) {
+      logger.debug(
+        { githubRepo, err },
+        'Error getting tag commit from GitHub repo'
+      );
     }
-  } catch (err) {
-    logger.debug(
-      { githubRepo, err },
-      'Error getting tag commit from GitHub repo'
-    );
+    return digest;
   }
-  if (!digest) {
-    return null;
-  }
-  const cacheMinutes = 120;
-  await packageCache.set(
-    cacheNamespace,
-    getCacheKey(registryUrl, githubRepo, `tag-${tag}`),
-    digest,
-    cacheMinutes
-  );
-  return digest;
-}
 
-/**
- * github.getDigest
- *
- * The `newValue` supplied here should be a valid tag for the docker image.
- *
- * This function will simply return the latest commit hash for the configured repository.
- */
-export async function getDigest(
-  { lookupName: repo, registryUrl }: Partial<DigestConfig>,
-  newValue?: string
-): Promise<string | null> {
-  if (newValue?.length) {
-    return getTagCommit(registryUrl, repo, newValue);
-  }
-  const cachedResult = await packageCache.get<string>(
-    cacheNamespace,
-    getCacheKey(registryUrl, repo, 'commit')
-  );
-  // istanbul ignore if
-  if (cachedResult) {
-    return cachedResult;
-  }
-  const apiBaseUrl = getApiBaseUrl(registryUrl);
-  let digest: string;
-  try {
-    const url = `${apiBaseUrl}repos/${repo}/commits?per_page=1`;
-    const res = await http.getJson<{ sha: string }[]>(url);
-    digest = res.body[0].sha;
-  } catch (err) {
-    logger.debug(
-      { githubRepo: repo, err, registryUrl },
-      'Error getting latest commit from GitHub repo'
-    );
-  }
-  if (!digest) {
-    return null;
+  @cache({
+    ttlMinutes: 10,
+    namespace: `datasource-${GithubTagsDatasource.id}`,
+    key: (registryUrl: string, githubRepo: string) =>
+      `${registryUrl}:${githubRepo}:commit`,
+  })
+  async getCommit(
+    registryUrl: string,
+    githubRepo: string
+  ): Promise<string | null> {
+    const apiBaseUrl = getApiBaseUrl(registryUrl);
+    let digest: string | null = null;
+    try {
+      const url = `${apiBaseUrl}repos/${githubRepo}/commits?per_page=1`;
+      const res = await this.http.getJson<{ sha: string }[]>(url);
+      digest = res.body[0].sha;
+    } catch (err) {
+      logger.debug(
+        { githubRepo: githubRepo, err, registryUrl },
+        'Error getting latest commit from GitHub repo'
+      );
+    }
+    return digest;
   }
-  const cacheMinutes = 10;
-  await packageCache.set(
-    cacheNamespace,
-    getCacheKey(registryUrl, repo, 'commit'),
-    digest,
-    cacheMinutes
-  );
-  return digest;
-}
 
-async function getTags({
-  registryUrl,
-  lookupName: repo,
-}: GetReleasesConfig): Promise<ReleaseResult | null> {
-  const cachedResult = await packageCache.get<ReleaseResult>(
-    cacheNamespace,
-    getCacheKey(registryUrl, repo, 'tags')
-  );
-  // istanbul ignore if
-  if (cachedResult) {
-    return cachedResult;
+  /**
+   * github.getDigest
+   *
+   * The `newValue` supplied here should be a valid tag for the docker image.
+   *
+   * Returns the latest commit hash for the repository.
+   */
+  override getDigest(
+    { lookupName: repo, registryUrl }: Partial<DigestConfig>,
+    newValue?: string
+  ): Promise<string | null> {
+    return newValue
+      ? this.getTagCommit(registryUrl, repo, newValue)
+      : this.getCommit(registryUrl, repo);
   }
 
-  const apiBaseUrl = getApiBaseUrl(registryUrl);
-  // tag
-  const url = `${apiBaseUrl}repos/${repo}/tags?per_page=100`;
+  @cache({
+    ttlMinutes: 10,
+    namespace: `datasource-${GithubTagsDatasource.id}`,
+    key: ({ registryUrl, lookupName: repo }: GetReleasesConfig) =>
+      `${registryUrl}:${repo}:tags`,
+  })
+  async getTags({
+    registryUrl,
+    lookupName: repo,
+  }: GetReleasesConfig): Promise<ReleaseResult | null> {
+    const apiBaseUrl = getApiBaseUrl(registryUrl);
+    // tag
+    const url = `${apiBaseUrl}repos/${repo}/tags?per_page=100`;
 
-  const versions = (
-    await http.getJson<GitHubTag[]>(url, {
-      paginate: true,
-    })
-  ).body.map((o) => o.name);
-  const dependency: ReleaseResult = {
-    sourceUrl: getSourceUrl(repo, registryUrl),
-    releases: null,
-  };
-  dependency.releases = versions.map((version) => ({
-    version,
-    gitRef: version,
-  }));
-  const cacheMinutes = 10;
-  await packageCache.set(
-    cacheNamespace,
-    getCacheKey(registryUrl, repo, 'tags'),
-    dependency,
-    cacheMinutes
-  );
-  return dependency;
-}
+    const versions = (
+      await this.http.getJson<GitHubTag[]>(url, {
+        paginate: true,
+      })
+    ).body.map((o) => o.name);
+    const dependency: ReleaseResult = {
+      sourceUrl: getSourceUrl(repo, registryUrl),
+      releases: versions.map((version) => ({
+        version,
+        gitRef: version,
+      })),
+    };
+    return dependency;
+  }
 
-export async function getReleases(
-  config: GetReleasesConfig
-): Promise<ReleaseResult | null> {
-  const tagsResult = await getTags(config);
+  override async getReleases(
+    config: GetReleasesConfig
+  ): Promise<ReleaseResult | null> {
+    const tagsResult = await this.getTags(config);
 
-  try {
-    // Fetch additional data from releases endpoint when possible
-    const releasesResult = await githubGetReleases(config);
-    const releaseByVersion = {};
-    releasesResult?.releases?.forEach((release) => {
-      const key = release.version;
-      const value = { ...release };
-      delete value.version;
-      releaseByVersion[key] = value;
-    });
+    try {
+      // Fetch additional data from releases endpoint when possible
+      const releasesResult = await super.getReleases(config);
+      const releaseByVersion = {};
+      releasesResult?.releases?.forEach((release) => {
+        const key = release.version;
+        const value = { ...release };
+        delete value.version;
+        releaseByVersion[key] = value;
+      });
 
-    const mergedReleases = [];
-    tagsResult.releases.forEach((tag) => {
-      const release = releaseByVersion[tag.version];
-      mergedReleases.push({ ...release, ...tag });
-    });
+      const mergedReleases = [];
+      tagsResult.releases.forEach((tag) => {
+        const release = releaseByVersion[tag.version];
+        mergedReleases.push({ ...release, ...tag });
+      });
 
-    tagsResult.releases = mergedReleases;
-  } catch (e) {
-    // no-op
-  }
+      tagsResult.releases = mergedReleases;
+    } catch (e) {
+      // no-op
+    }
 
-  return tagsResult;
+    return tagsResult;
+  }
 }
diff --git a/lib/datasource/go/__snapshots__/index.spec.ts.snap b/lib/datasource/go/__snapshots__/index.spec.ts.snap
index 88edf444574ea12be64c32cd1eb977f82e7f5511..e0552d5ce0ec14bb05822a528362e7006301bab3 100644
--- a/lib/datasource/go/__snapshots__/index.spec.ts.snap
+++ b/lib/datasource/go/__snapshots__/index.spec.ts.snap
@@ -11,16 +11,6 @@ Array [
     "method": "GET",
     "url": "https://golang.org/x/text?go-get=1",
   },
-  Object {
-    "headers": Object {
-      "accept": "application/vnd.github.v3+json",
-      "accept-encoding": "gzip, deflate, br",
-      "host": "api.github.com",
-      "user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)",
-    },
-    "method": "GET",
-    "url": "https://api.github.com/repos/golang/text/commits?per_page=1",
-  },
 ]
 `;
 
diff --git a/lib/datasource/go/base.spec.ts b/lib/datasource/go/base.spec.ts
index cfec05559715edc2d0c27c0625f32a560e0b0659..47184e326d1dd4fbec6f19c86089e077c8cb0853 100644
--- a/lib/datasource/go/base.spec.ts
+++ b/lib/datasource/go/base.spec.ts
@@ -1,7 +1,7 @@
 import * as httpMock from '../../../test/http-mock';
 import { loadFixture, mocked } from '../../../test/util';
 import * as _hostRules from '../../util/host-rules';
-import { id as githubDatasource } from '../github-tags';
+import { GithubTagsDatasource } from '../github-tags';
 import { GitlabTagsDatasource } from '../gitlab-tags';
 import { BaseGoDatasource } from './base';
 
@@ -90,7 +90,7 @@ describe('datasource/go/base', () => {
         const res = await BaseGoDatasource.getDatasource('golang.org/x/text');
 
         expect(res).toEqual({
-          datasource: githubDatasource,
+          datasource: GithubTagsDatasource.id,
           lookupName: 'golang/text',
           registryUrl: 'https://github.com',
         });
@@ -107,7 +107,7 @@ describe('datasource/go/base', () => {
         );
 
         expect(res).toEqual({
-          datasource: githubDatasource,
+          datasource: GithubTagsDatasource.id,
           lookupName: 'example/module',
           registryUrl: 'https://git.enterprise.com',
         });
diff --git a/lib/datasource/go/base.ts b/lib/datasource/go/base.ts
index 1dfc69c12f58563061c205958988e906bc85dd5d..b831b8eebf8f511576389172c7f5ec690b66cf9f 100644
--- a/lib/datasource/go/base.ts
+++ b/lib/datasource/go/base.ts
@@ -6,7 +6,7 @@ import { Http } from '../../util/http';
 import { regEx } from '../../util/regex';
 import { trimTrailingSlash } from '../../util/url';
 import { BitBucketTagsDatasource } from '../bitbucket-tags';
-import * as github from '../github-tags';
+import { GithubTagsDatasource } from '../github-tags';
 import { GitlabTagsDatasource } from '../gitlab-tags';
 import type { DataSource } from './types';
 
@@ -27,7 +27,7 @@ export class BaseGoDatasource {
       const [pkg] = goModule.replace('gopkg.in/', '').split('.');
       const lookupName = pkg.includes('/') ? pkg : `go-${pkg}/${pkg}`;
       return {
-        datasource: github.id,
+        datasource: GithubTagsDatasource.id,
         lookupName,
         registryUrl: 'https://github.com',
       };
@@ -37,7 +37,7 @@ export class BaseGoDatasource {
       const split = goModule.split('/');
       const lookupName = split[1] + '/' + split[2];
       return {
-        datasource: github.id,
+        datasource: GithubTagsDatasource.id,
         lookupName,
         registryUrl: 'https://github.com',
       };
@@ -74,7 +74,7 @@ export class BaseGoDatasource {
       logger.debug({ goModule, goSourceUrl }, 'Go lookup source url');
       if (goSourceUrl?.startsWith('https://github.com/')) {
         return {
-          datasource: github.id,
+          datasource: GithubTagsDatasource.id,
           lookupName: goSourceUrl
             .replace('https://github.com/', '')
             .replace(regEx(/\/$/), ''),
@@ -159,7 +159,7 @@ export class BaseGoDatasource {
           .join('/');
 
         return {
-          datasource: github.id,
+          datasource: GithubTagsDatasource.id,
           registryUrl: `${parsedUrl.protocol}//${parsedUrl.host}`,
           lookupName,
         };
diff --git a/lib/datasource/go/common.ts b/lib/datasource/go/common.ts
index 335d4ef952aec008cb559f719df81b348e4ee567..4b928d29fdaba2a3f48d0a8e398367418ad5b2c9 100644
--- a/lib/datasource/go/common.ts
+++ b/lib/datasource/go/common.ts
@@ -1,6 +1,6 @@
 import { BitBucketTagsDatasource } from '../bitbucket-tags';
-import { getSourceUrl as githubSourceUrl } from '../github-releases';
-import { id as githubDatasource } from '../github-tags';
+import { getSourceUrl as githubSourceUrl } from '../github-releases/common';
+import { GithubTagsDatasource } from '../github-tags';
 import { GitlabTagsDatasource } from '../gitlab-tags';
 import { getSourceUrl as gitlabSourceUrl } from '../gitlab-tags/util';
 
@@ -16,7 +16,7 @@ export function getSourceUrl(dataSource?: DataSource): string | undefined {
   if (dataSource) {
     const { datasource, registryUrl, lookupName } = dataSource;
 
-    if (datasource === githubDatasource) {
+    if (datasource === GithubTagsDatasource.id) {
       return githubSourceUrl(lookupName, registryUrl);
     }
 
diff --git a/lib/datasource/go/index.spec.ts b/lib/datasource/go/index.spec.ts
index b9020f5b087c183904b3836f0b4978aed8e5b8bd..25dc3f3b1f0ca18faa18e368f74443bf8387f100 100644
--- a/lib/datasource/go/index.spec.ts
+++ b/lib/datasource/go/index.spec.ts
@@ -7,19 +7,20 @@ jest.mock('../../util/host-rules');
 const hostRules = mocked(_hostRules);
 
 const getReleasesDirectMock = jest.fn();
+
+const getDigestGithubMock = jest.fn();
 const getDigestGitlabMock = jest.fn();
 const getDigestBitbucketMock = jest.fn();
 jest.mock('./releases-direct', () => {
   return {
-    GoDirectDatasource: jest.fn().mockImplementation(() => ({
-      gitlab: {
-        getDigest: () => getDigestGitlabMock(),
-      },
-      bitbucket: {
-        getDigest: () => getDigestBitbucketMock(),
-      },
-      getReleases: () => getReleasesDirectMock(),
-    })),
+    GoDirectDatasource: jest.fn().mockImplementation(() => {
+      return {
+        github: { getDigest: () => getDigestGithubMock() },
+        gitlab: { getDigest: () => getDigestGitlabMock() },
+        bitbucket: { getDigest: () => getDigestBitbucketMock() },
+        getReleases: () => getReleasesDirectMock(),
+      };
+    }),
   };
 });
 
@@ -144,10 +145,7 @@ describe('datasource/go/index', () => {
         .scope('https://golang.org/')
         .get('/x/text?go-get=1')
         .reply(200, loadFixture('go-get-github.html'));
-      httpMock
-        .scope('https://api.github.com/')
-        .get('/repos/golang/text/commits?per_page=1')
-        .reply(200, [{ sha: 'abcdefabcdefabcdefabcdef' }]);
+      getDigestGithubMock.mockResolvedValueOnce('abcdefabcdefabcdefabcdef');
       const res = await datasource.getDigest(
         { lookupName: 'golang.org/x/text' },
         null
diff --git a/lib/datasource/go/index.ts b/lib/datasource/go/index.ts
index 7ae6da45604b333ef0fef43de4e1c0096ccab829..6218d0ff2d76a0d56dc1ded3bec69c01d3d0cc3d 100644
--- a/lib/datasource/go/index.ts
+++ b/lib/datasource/go/index.ts
@@ -1,7 +1,7 @@
 import { cache } from '../../util/cache/package/decorator';
 import { BitBucketTagsDatasource } from '../bitbucket-tags';
 import { Datasource } from '../datasource';
-import * as github from '../github-tags';
+import { GithubTagsDatasource } from '../github-tags';
 import { GitlabTagsDatasource } from '../gitlab-tags';
 import type { DigestConfig, GetReleasesConfig, ReleaseResult } from '../types';
 import { BaseGoDatasource } from './base';
@@ -57,8 +57,8 @@ export class GoDatasource extends Datasource {
     const tag = value && !value.startsWith('v0.0.0-2') ? value : undefined;
 
     switch (source.datasource) {
-      case github.id: {
-        return github.getDigest(source, tag);
+      case GithubTagsDatasource.id: {
+        return this.direct.github.getDigest(source, tag);
       }
       case BitBucketTagsDatasource.id: {
         return this.direct.bitbucket.getDigest(source, tag);
diff --git a/lib/datasource/go/releases-direct.ts b/lib/datasource/go/releases-direct.ts
index 71e9089bcf938a52f3eb732f32a74a586130f3f4..858d169f7cd8ff6b1c7657cca499913ce11219c5 100644
--- a/lib/datasource/go/releases-direct.ts
+++ b/lib/datasource/go/releases-direct.ts
@@ -3,7 +3,7 @@ import { cache } from '../../util/cache/package/decorator';
 import { regEx } from '../../util/regex';
 import { BitBucketTagsDatasource } from '../bitbucket-tags';
 import { Datasource } from '../datasource';
-import * as github from '../github-tags';
+import { GithubTagsDatasource } from '../github-tags';
 import { GitlabTagsDatasource } from '../gitlab-tags';
 import type { DatasourceApi, GetReleasesConfig, ReleaseResult } from '../types';
 import { BaseGoDatasource } from './base';
@@ -12,11 +12,13 @@ import { getSourceUrl } from './common';
 export class GoDirectDatasource extends Datasource {
   static readonly id = 'go-direct';
 
+  github: GithubTagsDatasource;
   gitlab: DatasourceApi;
   bitbucket: DatasourceApi;
 
   constructor() {
     super(GoDirectDatasource.id);
+    this.github = new GithubTagsDatasource();
     this.gitlab = new GitlabTagsDatasource();
     this.bitbucket = new BitBucketTagsDatasource();
   }
@@ -53,8 +55,8 @@ export class GoDirectDatasource extends Datasource {
     }
 
     switch (source.datasource) {
-      case github.id: {
-        res = await github.getReleases(source);
+      case GithubTagsDatasource.id: {
+        res = await this.github.getReleases(source);
         break;
       }
       case GitlabTagsDatasource.id: {
diff --git a/lib/manager/ansible-galaxy/collections.ts b/lib/manager/ansible-galaxy/collections.ts
index 2f5824d557f27e8da0756b9cdd9e7e942a66888a..a062fc1a7c67d4647fe6eee54fbae8cfc042a74b 100644
--- a/lib/manager/ansible-galaxy/collections.ts
+++ b/lib/manager/ansible-galaxy/collections.ts
@@ -1,6 +1,6 @@
 import { GalaxyCollectionDatasource } from '../../datasource/galaxy-collection';
 import { GitTagsDatasource } from '../../datasource/git-tags';
-import * as datasourceGithubTags from '../../datasource/github-tags';
+import { GithubTagsDatasource } from '../../datasource/github-tags';
 import { regEx } from '../../util/regex';
 import type { PackageDependency } from '../types';
 import {
@@ -53,7 +53,7 @@ function handleGitDep(
   if (nameMatch) {
     // if a github.com repository is referenced use github-tags instead of git-tags
     if (nameMatch.groups.hostname === 'github.com') {
-      dep.datasource = datasourceGithubTags.id;
+      dep.datasource = GithubTagsDatasource.id;
     } else {
       dep.datasource = GitTagsDatasource.id;
     }
diff --git a/lib/manager/ansible-galaxy/index.ts b/lib/manager/ansible-galaxy/index.ts
index fc92ebe669faeaeb717b5b98d3defacf68dd6d74..426bef1ad220b018e73094be1d50d3dbf73e96ac 100644
--- a/lib/manager/ansible-galaxy/index.ts
+++ b/lib/manager/ansible-galaxy/index.ts
@@ -1,6 +1,6 @@
 import { GalaxyCollectionDatasource } from '../../datasource/galaxy-collection';
 import { GitTagsDatasource } from '../../datasource/git-tags';
-import * as datasourceGithubTags from '../../datasource/github-tags';
+import { GithubTagsDatasource } from '../../datasource/github-tags';
 
 export { extractPackageFile } from './extract';
 
@@ -11,5 +11,5 @@ export const defaultConfig = {
 export const supportedDatasources = [
   GalaxyCollectionDatasource.id,
   GitTagsDatasource.id,
-  datasourceGithubTags.id,
+  GithubTagsDatasource.id,
 ];
diff --git a/lib/manager/batect-wrapper/extract.spec.ts b/lib/manager/batect-wrapper/extract.spec.ts
index e2fcdd4298cb312f9c793272ed27d9bf68f9317e..00053254a78ffc11af04c92f60bf64ecf5c67005 100644
--- a/lib/manager/batect-wrapper/extract.spec.ts
+++ b/lib/manager/batect-wrapper/extract.spec.ts
@@ -1,5 +1,5 @@
 import { Fixtures } from '../../../test/fixtures';
-import { id as githubReleaseDatasource } from '../../datasource/github-releases';
+import { GithubReleasesDatasource } from '../../datasource/github-releases';
 import { id as semverVersioning } from '../../versioning/semver';
 import type { PackageDependency } from '../types';
 import { extractPackageFile } from './extract';
@@ -21,7 +21,7 @@ describe('manager/batect-wrapper/extract', () => {
         depName: 'batect/batect',
         commitMessageTopic: 'Batect',
         currentValue: '0.60.1',
-        datasource: githubReleaseDatasource,
+        datasource: GithubReleasesDatasource.id,
         versioning: semverVersioning,
       };
 
@@ -35,7 +35,7 @@ describe('manager/batect-wrapper/extract', () => {
         depName: 'batect/batect',
         commitMessageTopic: 'Batect',
         currentValue: '0.60.1',
-        datasource: githubReleaseDatasource,
+        datasource: GithubReleasesDatasource.id,
         versioning: semverVersioning,
       };
 
diff --git a/lib/manager/batect-wrapper/extract.ts b/lib/manager/batect-wrapper/extract.ts
index 3738893207ce8a11f860a898af28bde6bbf7883f..64be79eb1008acffe56b0b30a26f0e28335e430f 100644
--- a/lib/manager/batect-wrapper/extract.ts
+++ b/lib/manager/batect-wrapper/extract.ts
@@ -1,4 +1,4 @@
-import { id as githubReleaseDatasource } from '../../datasource/github-releases';
+import { GithubReleasesDatasource } from '../../datasource/github-releases';
 import { logger } from '../../logger';
 import { regEx } from '../../util/regex';
 import { id as semverVersioning } from '../../versioning/semver';
@@ -18,7 +18,7 @@ export function extractPackageFile(fileContent: string): PackageFile | null {
     depName: 'batect/batect',
     commitMessageTopic: 'Batect',
     currentValue: match[1],
-    datasource: githubReleaseDatasource,
+    datasource: GithubReleasesDatasource.id,
     versioning: semverVersioning,
   };
 
diff --git a/lib/manager/batect-wrapper/index.ts b/lib/manager/batect-wrapper/index.ts
index dcaa1c1e63f28ba08c7a4dd378d2faecb17cf2d2..80732b481d08a8e42b39faf5220ff6b80bcc4f14 100644
--- a/lib/manager/batect-wrapper/index.ts
+++ b/lib/manager/batect-wrapper/index.ts
@@ -1,4 +1,4 @@
-import { id as githubReleaseDatasource } from '../../datasource/github-releases';
+import { GithubReleasesDatasource } from '../../datasource/github-releases';
 import { id as versioning } from '../../versioning/semver';
 
 export { extractPackageFile } from './extract';
@@ -9,4 +9,4 @@ export const defaultConfig = {
   versioning,
 };
 
-export const supportedDatasources = [githubReleaseDatasource];
+export const supportedDatasources = [GithubReleasesDatasource.id];
diff --git a/lib/manager/bazel/extract.ts b/lib/manager/bazel/extract.ts
index a35ac770be7317af3e2f641bdabefaa7f4c753fe..58a8797981bbac417124a0d7335982933402a227 100644
--- a/lib/manager/bazel/extract.ts
+++ b/lib/manager/bazel/extract.ts
@@ -3,8 +3,8 @@ import { parse as _parse } from 'url';
 import parse from 'github-url-from-git';
 import moo from 'moo';
 import * as datasourceDocker from '../../datasource/docker';
-import * as datasourceGithubReleases from '../../datasource/github-releases';
-import * as datasourceGithubTags from '../../datasource/github-tags';
+import { GithubReleasesDatasource } from '../../datasource/github-releases';
+import { GithubTagsDatasource } from '../../datasource/github-tags';
 import { GoDatasource } from '../../datasource/go';
 import { logger } from '../../logger';
 import { regEx } from '../../util/regex';
@@ -26,11 +26,11 @@ function parseUrl(urlString: string): UrlParsedResult | null {
   let datasource: string;
   let currentValue: string = null;
   if (path[2] === 'releases' && path[3] === 'download') {
-    datasource = datasourceGithubReleases.id;
+    datasource = GithubReleasesDatasource.id;
     currentValue = path[4];
   }
   if (path[2] === 'archive') {
-    datasource = datasourceGithubTags.id;
+    datasource = GithubTagsDatasource.id;
     currentValue = path[3];
     // Strip archive extension to get hash or tag.
     // Tolerates formats produced by Git(Hub|Lab) and allowed by http_archive
@@ -241,7 +241,7 @@ export function extractPackageFile(
       const githubURL = parse(remote);
       if (githubURL) {
         const repo = githubURL.substring('https://github.com/'.length);
-        dep.datasource = datasourceGithubReleases.id;
+        dep.datasource = GithubReleasesDatasource.id;
         dep.lookupName = repo;
         deps.push(dep);
       }
diff --git a/lib/manager/bazel/index.ts b/lib/manager/bazel/index.ts
index aa0568fcec5588c5cf0d760a134bd6bf58581b7b..bf8cf264a171116e1eb3ec3a77e9dc57d2fb163b 100644
--- a/lib/manager/bazel/index.ts
+++ b/lib/manager/bazel/index.ts
@@ -1,6 +1,6 @@
 import * as datasourceDocker from '../../datasource/docker';
-import * as datasourceGithubReleases from '../../datasource/github-releases';
-import * as datasourceGithubTags from '../../datasource/github-tags';
+import { GithubReleasesDatasource } from '../../datasource/github-releases';
+import { GithubTagsDatasource } from '../../datasource/github-tags';
 import { GoDatasource } from '../../datasource/go';
 import { extractPackageFile } from './extract';
 import { updateDependency } from './update';
@@ -13,7 +13,7 @@ export const defaultConfig = {
 
 export const supportedDatasources = [
   datasourceDocker.id,
-  datasourceGithubReleases.id,
-  datasourceGithubTags.id,
+  GithubReleasesDatasource.id,
+  GithubTagsDatasource.id,
   GoDatasource.id,
 ];
diff --git a/lib/manager/buildkite/extract.ts b/lib/manager/buildkite/extract.ts
index 802652f221d737e275312f22b0e46c0aee2333ed..75359bd27861564dd59334183a064b9010b55abc 100644
--- a/lib/manager/buildkite/extract.ts
+++ b/lib/manager/buildkite/extract.ts
@@ -1,4 +1,4 @@
-import * as datasourceGithubTags from '../../datasource/github-tags';
+import { GithubTagsDatasource } from '../../datasource/github-tags';
 import { logger } from '../../logger';
 import type { SkipReason } from '../../types';
 import { newlineRegex, regEx } from '../../util/regex';
@@ -47,7 +47,7 @@ export function extractPackageFile(content: string): PackageFile | null {
               depName: gitPluginName,
               currentValue: currentValue,
               registryUrls: ['https://' + registry],
-              datasource: datasourceGithubTags.id,
+              datasource: GithubTagsDatasource.id,
             };
             deps.push(dep);
             continue;
@@ -77,7 +77,7 @@ export function extractPackageFile(content: string): PackageFile | null {
             skipReason,
           };
           if (repo) {
-            dep.datasource = datasourceGithubTags.id;
+            dep.datasource = GithubTagsDatasource.id;
             dep.lookupName = repo;
           }
           deps.push(dep);
diff --git a/lib/manager/buildkite/index.ts b/lib/manager/buildkite/index.ts
index 3350b60ce64d49e0d52159a65d5490cfd8cc1c01..028d54c729708dc59721a746ea620f198f5d8c56 100644
--- a/lib/manager/buildkite/index.ts
+++ b/lib/manager/buildkite/index.ts
@@ -1,4 +1,4 @@
-import * as datasourceGithubTags from '../../datasource/github-tags';
+import { GithubTagsDatasource } from '../../datasource/github-tags';
 import { extractPackageFile } from './extract';
 
 export { extractPackageFile };
@@ -10,4 +10,4 @@ export const defaultConfig = {
     'to {{#if isMajor}}v{{{newMajor}}}{{else}}{{{newValue}}}{{/if}}',
 };
 
-export const supportedDatasources = [datasourceGithubTags.id];
+export const supportedDatasources = [GithubTagsDatasource.id];
diff --git a/lib/manager/cocoapods/extract.ts b/lib/manager/cocoapods/extract.ts
index 84781e1930749badd8fc5a6b32a4f9a7dc6fd257..176f53618832b19dae86a870872fd733e211a32f 100644
--- a/lib/manager/cocoapods/extract.ts
+++ b/lib/manager/cocoapods/extract.ts
@@ -1,5 +1,5 @@
 import { GitTagsDatasource } from '../../datasource/git-tags';
-import * as datasourceGithubTags from '../../datasource/github-tags';
+import { GithubTagsDatasource } from '../../datasource/github-tags';
 import { GitlabTagsDatasource } from '../../datasource/gitlab-tags';
 import { PodDatasource } from '../../datasource/pod';
 import { logger } from '../../logger';
@@ -61,7 +61,7 @@ export function gitDep(parsedLine: ParsedLine): PackageDependency | null {
     if (account && repo) {
       const datasource =
         platform === 'github'
-          ? datasourceGithubTags.id
+          ? GithubTagsDatasource.id
           : GitlabTagsDatasource.id;
       return {
         datasource,
diff --git a/lib/manager/cocoapods/index.ts b/lib/manager/cocoapods/index.ts
index 880639894b2ec9b51a4bcfe06fccd0388e520784..a2230e9dbf4a8f1be1c02c81e1073b4fcae7337a 100644
--- a/lib/manager/cocoapods/index.ts
+++ b/lib/manager/cocoapods/index.ts
@@ -1,5 +1,5 @@
 import { GitTagsDatasource } from '../../datasource/git-tags';
-import * as datasourceGithubTags from '../../datasource/github-tags';
+import { GithubTagsDatasource } from '../../datasource/github-tags';
 import { GitlabTagsDatasource } from '../../datasource/gitlab-tags';
 import { PodDatasource } from '../../datasource/pod';
 import * as rubyVersioning from '../../versioning/ruby';
@@ -14,7 +14,7 @@ export const defaultConfig = {
 
 export const supportedDatasources = [
   GitTagsDatasource.id,
-  datasourceGithubTags.id,
+  GithubTagsDatasource.id,
   GitlabTagsDatasource.id,
   PodDatasource.id,
 ];
diff --git a/lib/manager/flux/extract.ts b/lib/manager/flux/extract.ts
index b60a35dc213897ec6e250c0275ecd4ffaa19b216..7c1cb51b53fc992338330235a8590ad1791137d7 100644
--- a/lib/manager/flux/extract.ts
+++ b/lib/manager/flux/extract.ts
@@ -1,5 +1,5 @@
 import { loadAll } from 'js-yaml';
-import { id as GithubReleasesId } from '../../datasource/github-releases';
+import { GithubReleasesDatasource } from '../../datasource/github-releases';
 import { HelmDatasource } from '../../datasource/helm';
 import { logger } from '../../logger';
 import { readLocalFile } from '../../util/fs';
@@ -77,7 +77,7 @@ function resolveManifest(
       return [
         {
           depName: 'fluxcd/flux2',
-          datasource: GithubReleasesId,
+          datasource: GithubReleasesDatasource.id,
           currentValue: manifest.version,
         },
       ];
diff --git a/lib/manager/flux/index.ts b/lib/manager/flux/index.ts
index f750f47cbe2aa73ac1e6cdc92f45fee44c95c2d3..2bb039bd59ee14574468961721e8a8263a5fde43 100644
--- a/lib/manager/flux/index.ts
+++ b/lib/manager/flux/index.ts
@@ -1,4 +1,4 @@
-import { id as GithubReleasesId } from '../../datasource/github-releases';
+import { GithubReleasesDatasource } from '../../datasource/github-releases';
 import { HelmDatasource } from '../../datasource/helm';
 import { systemManifestRegex } from './common';
 
@@ -9,4 +9,7 @@ export const defaultConfig = {
   fileMatch: [systemManifestRegex],
 };
 
-export const supportedDatasources = [GithubReleasesId, HelmDatasource.id];
+export const supportedDatasources = [
+  GithubReleasesDatasource.id,
+  HelmDatasource.id,
+];
diff --git a/lib/manager/github-actions/extract.ts b/lib/manager/github-actions/extract.ts
index d29f9b2426b61645182cbf9f52a8ddc8d5ad6d53..c322c1cb5dfe5b5c565474df5185f25c7920b6db 100644
--- a/lib/manager/github-actions/extract.ts
+++ b/lib/manager/github-actions/extract.ts
@@ -1,4 +1,4 @@
-import * as githubTagsDatasource from '../../datasource/github-tags';
+import { GithubTagsDatasource } from '../../datasource/github-tags';
 import { logger } from '../../logger';
 import { newlineRegex, regEx } from '../../util/regex';
 import * as dockerVersioning from '../../versioning/docker';
@@ -43,7 +43,7 @@ export function extractPackageFile(content: string): PackageFile | null {
       const dep: PackageDependency = {
         depName,
         commitMessageTopic: '{{{depName}}} action',
-        datasource: githubTagsDatasource.id,
+        datasource: GithubTagsDatasource.id,
         versioning: dockerVersioning.id,
         depType: 'action',
         replaceString,
diff --git a/lib/manager/github-actions/index.ts b/lib/manager/github-actions/index.ts
index 5d39f85406867bb87213d4760915ea8cb1334971..eee8b346fb1d185c4abeb6342807f07bd099eecb 100644
--- a/lib/manager/github-actions/index.ts
+++ b/lib/manager/github-actions/index.ts
@@ -1,4 +1,4 @@
-import * as githubTagsDatasource from '../../datasource/github-tags';
+import { GithubTagsDatasource } from '../../datasource/github-tags';
 import * as dockerVersioning from '../../versioning/docker';
 
 export { extractPackageFile } from './extract';
@@ -11,6 +11,6 @@ export const defaultConfig = {
 };
 
 export const supportedDatasources = [
-  githubTagsDatasource.id,
+  GithubTagsDatasource.id,
   dockerVersioning.id,
 ];
diff --git a/lib/manager/homebrew/extract.ts b/lib/manager/homebrew/extract.ts
index 8f15d69bd14de01d3fe07e50cb72c488519a1879..1de36ed73f1c51d5391b7917a786ff279c0637af 100644
--- a/lib/manager/homebrew/extract.ts
+++ b/lib/manager/homebrew/extract.ts
@@ -1,4 +1,4 @@
-import * as datasourceGithubTags from '../../datasource/github-tags';
+import { GithubTagsDatasource } from '../../datasource/github-tags';
 import { logger } from '../../logger';
 import type { SkipReason } from '../../types';
 import { regEx } from '../../util/regex';
@@ -167,7 +167,7 @@ export function extractPackageFile(content: string): PackageFile | null {
     depName: `${ownerName}/${repoName}`,
     managerData: { ownerName, repoName, sha256, url },
     currentValue,
-    datasource: datasourceGithubTags.id,
+    datasource: GithubTagsDatasource.id,
   };
   if (skipReason) {
     dep.skipReason = skipReason;
diff --git a/lib/manager/homebrew/index.ts b/lib/manager/homebrew/index.ts
index f41a1a84064d78a62341ed11f633737d0dc0a9e2..1a6a2a46a4deaf914eca3cac5e8ff8d9457be61d 100644
--- a/lib/manager/homebrew/index.ts
+++ b/lib/manager/homebrew/index.ts
@@ -1,4 +1,4 @@
-import * as datasourceGithubTags from '../../datasource/github-tags';
+import { GithubTagsDatasource } from '../../datasource/github-tags';
 export { extractPackageFile } from './extract';
 export { updateDependency } from './update';
 
@@ -7,4 +7,4 @@ export const defaultConfig = {
   fileMatch: ['^Formula/[^/]+[.]rb$'],
 };
 
-export const supportedDatasources = [datasourceGithubTags.id];
+export const supportedDatasources = [GithubTagsDatasource.id];
diff --git a/lib/manager/kustomize/extract.spec.ts b/lib/manager/kustomize/extract.spec.ts
index a0120ad4f7aa83d49cb9b5827f37416dc757329a..c7c2fdfb9836dd621b050b754d19f2f87bce02a8 100644
--- a/lib/manager/kustomize/extract.spec.ts
+++ b/lib/manager/kustomize/extract.spec.ts
@@ -1,7 +1,7 @@
 import { loadFixture } from '../../../test/util';
 import * as datasourceDocker from '../../datasource/docker';
 import { GitTagsDatasource } from '../../datasource/git-tags';
-import * as datasourceGitHubTags from '../../datasource/github-tags';
+import { GithubTagsDatasource } from '../../datasource/github-tags';
 import { HelmDatasource } from '../../datasource/helm';
 import {
   extractHelmChart,
@@ -44,7 +44,7 @@ describe('manager/kustomize/extract', () => {
       const version = 'v1.0.0';
       const sample = {
         currentValue: version,
-        datasource: datasourceGitHubTags.id,
+        datasource: GithubTagsDatasource.id,
         depName: 'user/test-repo',
       };
 
@@ -89,7 +89,7 @@ describe('manager/kustomize/extract', () => {
       const version = 'v1.0.0';
       const sample = {
         currentValue: version,
-        datasource: datasourceGitHubTags.id,
+        datasource: GithubTagsDatasource.id,
         depName: 'fluxcd/flux',
       };
 
@@ -101,7 +101,7 @@ describe('manager/kustomize/extract', () => {
       const version = 'v1.0.0';
       const sample = {
         currentValue: version,
-        datasource: datasourceGitHubTags.id,
+        datasource: GithubTagsDatasource.id,
         depName: 'user/repo',
       };
 
@@ -113,7 +113,7 @@ describe('manager/kustomize/extract', () => {
       const version = 'v1.0.0';
       const sample = {
         currentValue: version,
-        datasource: datasourceGitHubTags.id,
+        datasource: GithubTagsDatasource.id,
         depName: 'user/repo',
       };
 
diff --git a/lib/manager/kustomize/extract.ts b/lib/manager/kustomize/extract.ts
index 3b58a1bf6b4107d069a9ff21bd4db8c8fd12cddb..7ce2058fd24cf25d9be1d80527f10c5d4503011d 100644
--- a/lib/manager/kustomize/extract.ts
+++ b/lib/manager/kustomize/extract.ts
@@ -2,7 +2,7 @@ import is from '@sindresorhus/is';
 import { load } from 'js-yaml';
 import * as datasourceDocker from '../../datasource/docker';
 import { GitTagsDatasource } from '../../datasource/git-tags';
-import * as datasourceGitHubTags from '../../datasource/github-tags';
+import { GithubTagsDatasource } from '../../datasource/github-tags';
 import { HelmDatasource } from '../../datasource/helm';
 import { logger } from '../../logger';
 import { regEx } from '../../util/regex';
@@ -27,7 +27,7 @@ export function extractResource(base: string): PackageDependency | null {
   if (path.startsWith('github.com:') || path.startsWith('github.com/')) {
     return {
       currentValue: match.groups.currentValue,
-      datasource: datasourceGitHubTags.id,
+      datasource: GithubTagsDatasource.id,
       depName: match.groups.project.replace('.git', ''),
     };
   }
diff --git a/lib/manager/kustomize/index.ts b/lib/manager/kustomize/index.ts
index c3ac88cd6e180cedab461d045673675be4602e53..0a2d698eb5d72212f46ad80bf8d64bd60c2376fe 100644
--- a/lib/manager/kustomize/index.ts
+++ b/lib/manager/kustomize/index.ts
@@ -1,6 +1,6 @@
 import * as datasourceDocker from '../../datasource/docker';
 import { GitTagsDatasource } from '../../datasource/git-tags';
-import * as datasourceGitHubTags from '../../datasource/github-tags';
+import { GithubTagsDatasource } from '../../datasource/github-tags';
 import { HelmDatasource } from '../../datasource/helm';
 export { extractPackageFile } from './extract';
 
@@ -12,6 +12,6 @@ export const defaultConfig = {
 export const supportedDatasources = [
   datasourceDocker.id,
   GitTagsDatasource.id,
-  datasourceGitHubTags.id,
+  GithubTagsDatasource.id,
   HelmDatasource.id,
 ];
diff --git a/lib/manager/nodenv/extract.ts b/lib/manager/nodenv/extract.ts
index b8b777cd149277a5fe62e360425d6efe2115ac83..ca3a3941cd689af697d9f28bb77ebf83e1863fb8 100644
--- a/lib/manager/nodenv/extract.ts
+++ b/lib/manager/nodenv/extract.ts
@@ -1,11 +1,11 @@
-import * as datasourceGithubTags from '../../datasource/github-tags';
+import { GithubTagsDatasource } from '../../datasource/github-tags';
 import type { PackageDependency, PackageFile } from '../types';
 
 export function extractPackageFile(content: string): PackageFile {
   const dep: PackageDependency = {
     depName: 'node',
     currentValue: content.trim(),
-    datasource: datasourceGithubTags.id,
+    datasource: GithubTagsDatasource.id,
     lookupName: 'nodejs/node',
   };
   return { deps: [dep] };
diff --git a/lib/manager/nodenv/index.ts b/lib/manager/nodenv/index.ts
index cf206a758f8f98c4a2b4cead1b51694d1b634ccd..1b04cf5e93b188e3ac241ecdf32dcac406e7aa7e 100644
--- a/lib/manager/nodenv/index.ts
+++ b/lib/manager/nodenv/index.ts
@@ -1,5 +1,5 @@
 import { ProgrammingLanguage } from '../../constants';
-import * as datasourceGithubTags from '../../datasource/github-tags';
+import { GithubTagsDatasource } from '../../datasource/github-tags';
 import * as nodeVersioning from '../../versioning/node';
 
 export { extractPackageFile } from './extract';
@@ -11,4 +11,4 @@ export const defaultConfig = {
   versioning: nodeVersioning.id,
 };
 
-export const supportedDatasources = [datasourceGithubTags.id];
+export const supportedDatasources = [GithubTagsDatasource.id];
diff --git a/lib/manager/npm/extract/index.ts b/lib/manager/npm/extract/index.ts
index 6ee99165f10e23d0b10bace0e2cef24160d5754b..4b57e051fc91941dc34948347046d8668ac1437e 100644
--- a/lib/manager/npm/extract/index.ts
+++ b/lib/manager/npm/extract/index.ts
@@ -2,7 +2,7 @@ import is from '@sindresorhus/is';
 import validateNpmPackageName from 'validate-npm-package-name';
 import { GlobalConfig } from '../../../config/global';
 import { CONFIG_VALIDATION } from '../../../constants/error-messages';
-import * as datasourceGithubTags from '../../../datasource/github-tags';
+import { GithubTagsDatasource } from '../../../datasource/github-tags';
 import { id as npmId } from '../../../datasource/npm';
 import { logger } from '../../../logger';
 import { getSiblingFileName, readLocalFile } from '../../../util/fs';
@@ -188,7 +188,7 @@ export async function extractPackageFile(
     dep.currentValue = input.trim();
     if (depType === 'engines' || depType === 'packageManager') {
       if (depName === 'node') {
-        dep.datasource = datasourceGithubTags.id;
+        dep.datasource = GithubTagsDatasource.id;
         dep.lookupName = 'nodejs/node';
         dep.versioning = nodeVersioning.id;
         constraints.node = dep.currentValue;
@@ -211,7 +211,7 @@ export async function extractPackageFile(
         dep.commitMessageTopic = 'pnpm';
         constraints.pnpm = dep.currentValue;
       } else if (depName === 'vscode') {
-        dep.datasource = datasourceGithubTags.id;
+        dep.datasource = GithubTagsDatasource.id;
         dep.lookupName = 'microsoft/vscode';
         constraints.vscode = dep.currentValue;
       } else {
@@ -226,7 +226,7 @@ export async function extractPackageFile(
     // support for volta
     if (depType === 'volta') {
       if (depName === 'node') {
-        dep.datasource = datasourceGithubTags.id;
+        dep.datasource = GithubTagsDatasource.id;
         dep.lookupName = 'nodejs/node';
         dep.versioning = nodeVersioning.id;
       } else if (depName === 'yarn') {
@@ -311,7 +311,7 @@ export async function extractPackageFile(
     if (isVersion(depRefPart)) {
       dep.currentRawValue = dep.currentValue;
       dep.currentValue = depRefPart;
-      dep.datasource = datasourceGithubTags.id;
+      dep.datasource = GithubTagsDatasource.id;
       dep.lookupName = githubOwnerRepo;
       dep.pinDigests = false;
     } else if (
@@ -321,7 +321,7 @@ export async function extractPackageFile(
       dep.currentRawValue = dep.currentValue;
       dep.currentValue = null;
       dep.currentDigest = depRefPart;
-      dep.datasource = datasourceGithubTags.id;
+      dep.datasource = GithubTagsDatasource.id;
       dep.lookupName = githubOwnerRepo;
     } else {
       dep.skipReason = 'unversioned-reference';
diff --git a/lib/manager/npm/index.ts b/lib/manager/npm/index.ts
index 0d5bdbf49de3f9f2c7606b18c14ad0ad30f96a7c..653ee81edb490878a102b8098d2985d1422eb591 100644
--- a/lib/manager/npm/index.ts
+++ b/lib/manager/npm/index.ts
@@ -1,5 +1,5 @@
 import { ProgrammingLanguage } from '../../constants';
-import * as datasourceGithubTags from '../../datasource/github-tags';
+import { GithubTagsDatasource } from '../../datasource/github-tags';
 import { id as npmId } from '../../datasource/npm';
 import * as npmVersioning from '../../versioning/npm';
 
@@ -31,4 +31,4 @@ export const defaultConfig = {
   },
 };
 
-export const supportedDatasources = [datasourceGithubTags.id, npmId];
+export const supportedDatasources = [GithubTagsDatasource.id, npmId];
diff --git a/lib/manager/nvm/extract.ts b/lib/manager/nvm/extract.ts
index b8b777cd149277a5fe62e360425d6efe2115ac83..ca3a3941cd689af697d9f28bb77ebf83e1863fb8 100644
--- a/lib/manager/nvm/extract.ts
+++ b/lib/manager/nvm/extract.ts
@@ -1,11 +1,11 @@
-import * as datasourceGithubTags from '../../datasource/github-tags';
+import { GithubTagsDatasource } from '../../datasource/github-tags';
 import type { PackageDependency, PackageFile } from '../types';
 
 export function extractPackageFile(content: string): PackageFile {
   const dep: PackageDependency = {
     depName: 'node',
     currentValue: content.trim(),
-    datasource: datasourceGithubTags.id,
+    datasource: GithubTagsDatasource.id,
     lookupName: 'nodejs/node',
   };
   return { deps: [dep] };
diff --git a/lib/manager/nvm/index.ts b/lib/manager/nvm/index.ts
index 337f088cac9a10d3ac6f81f27a1cdcc2741496ff..43a744996efbd11c8bd40f174a16f4353de6c93d 100644
--- a/lib/manager/nvm/index.ts
+++ b/lib/manager/nvm/index.ts
@@ -1,5 +1,5 @@
 import { ProgrammingLanguage } from '../../constants';
-import * as datasourceGithubTags from '../../datasource/github-tags';
+import { GithubTagsDatasource } from '../../datasource/github-tags';
 import * as nodeVersioning from '../../versioning/node';
 
 export { extractPackageFile } from './extract';
@@ -12,4 +12,4 @@ export const defaultConfig = {
   pinDigests: false,
 };
 
-export const supportedDatasources = [datasourceGithubTags.id];
+export const supportedDatasources = [GithubTagsDatasource.id];
diff --git a/lib/manager/pre-commit/extract.ts b/lib/manager/pre-commit/extract.ts
index b7721e7a5cde134921fe08c80047529687fc3f53..88a15027632a335098e5e1ac983c42920dd75655 100644
--- a/lib/manager/pre-commit/extract.ts
+++ b/lib/manager/pre-commit/extract.ts
@@ -1,7 +1,7 @@
 import is from '@sindresorhus/is';
 import { load } from 'js-yaml';
 import { PlatformId } from '../../constants';
-import { id as githubTagsId } from '../../datasource/github-tags';
+import { GithubTagsDatasource } from '../../datasource/github-tags';
 import { GitlabTagsDatasource } from '../../datasource/gitlab-tags';
 import { logger } from '../../logger';
 import type { SkipReason } from '../../types';
@@ -34,7 +34,7 @@ function determineDatasource(
 ): { datasource?: string; registryUrls?: string[]; skipReason?: SkipReason } {
   if (hostname === 'github.com') {
     logger.debug({ repository, hostname }, 'Found github dependency');
-    return { datasource: githubTagsId };
+    return { datasource: GithubTagsDatasource.id };
   }
   if (hostname === 'gitlab.com') {
     logger.debug({ repository, hostname }, 'Found gitlab dependency');
@@ -52,7 +52,7 @@ function determineDatasource(
   }
   for (const [hostType, sourceId] of [
     [PlatformId.Gitea, GitlabTagsDatasource.id],
-    [PlatformId.Github, githubTagsId],
+    [PlatformId.Github, GithubTagsDatasource.id],
     [PlatformId.Gitlab, GitlabTagsDatasource.id],
   ]) {
     if (!isEmptyObject(find({ hostType, url: hostUrl }))) {
diff --git a/lib/manager/pre-commit/index.ts b/lib/manager/pre-commit/index.ts
index fae8be3dee6dc2b2edf959de2e95039674688afb..f52495f8a172181d12ec9fa7c17d997bf22e9f70 100644
--- a/lib/manager/pre-commit/index.ts
+++ b/lib/manager/pre-commit/index.ts
@@ -1,8 +1,11 @@
-import { id as githubTagsId } from '../../datasource/github-tags';
+import { GithubTagsDatasource } from '../../datasource/github-tags';
 import { GitlabTagsDatasource } from '../../datasource/gitlab-tags';
 export { extractPackageFile } from './extract';
 
-export const supportedDatasources = [githubTagsId, GitlabTagsDatasource.id];
+export const supportedDatasources = [
+  GithubTagsDatasource.id,
+  GitlabTagsDatasource.id,
+];
 
 export const defaultConfig = {
   commitMessageTopic: 'pre-commit hook {{depName}}',
diff --git a/lib/manager/terraform-version/extract.ts b/lib/manager/terraform-version/extract.ts
index 10a886481fad4d0e625a2710006f5a8267bc8b78..99dccb3db8bee3fe89c2f9587b30b15478c2b522 100644
--- a/lib/manager/terraform-version/extract.ts
+++ b/lib/manager/terraform-version/extract.ts
@@ -1,4 +1,4 @@
-import * as datasourceGitHubRelease from '../../datasource/github-releases';
+import { GithubReleasesDatasource } from '../../datasource/github-releases';
 import { logger } from '../../logger';
 import type { PackageDependency, PackageFile } from '../types';
 
@@ -7,7 +7,7 @@ export function extractPackageFile(content: string): PackageFile {
   const dep: PackageDependency = {
     depName: 'hashicorp/terraform',
     currentValue: content.trim(),
-    datasource: datasourceGitHubRelease.id,
+    datasource: GithubReleasesDatasource.id,
   };
   return { deps: [dep] };
 }
diff --git a/lib/manager/terraform-version/index.ts b/lib/manager/terraform-version/index.ts
index 718e39968c88ab6b20e3f4a4fcf537aa4fb9de1c..0f753ba3af381811952c12ca368e91e288ab62f2 100644
--- a/lib/manager/terraform-version/index.ts
+++ b/lib/manager/terraform-version/index.ts
@@ -1,9 +1,9 @@
-import * as datasourceGitHubRelease from '../../datasource/github-releases';
+import { GithubReleasesDatasource } from '../../datasource/github-releases';
 import * as hashicorpVersioning from '../../versioning/hashicorp';
 
 export { extractPackageFile } from './extract';
 
-export const supportedDatasources = [datasourceGitHubRelease.id];
+export const supportedDatasources = [GithubReleasesDatasource.id];
 
 export const defaultConfig = {
   fileMatch: ['(^|/)\\.terraform-version$'],
diff --git a/lib/manager/terraform/index.ts b/lib/manager/terraform/index.ts
index cea16def596a0f253d6e17f2938b37c8071d768e..61bcc7e7a328208fe519b30a81b9d00d11de52a6 100644
--- a/lib/manager/terraform/index.ts
+++ b/lib/manager/terraform/index.ts
@@ -1,6 +1,6 @@
 import { BitBucketTagsDatasource } from '../../datasource/bitbucket-tags';
 import { GitTagsDatasource } from '../../datasource/git-tags';
-import * as datasourceGithubTags from '../../datasource/github-tags';
+import { GithubTagsDatasource } from '../../datasource/github-tags';
 import { HelmDatasource } from '../../datasource/helm';
 import { TerraformModuleDatasource } from '../../datasource/terraform-module';
 import { TerraformProviderDatasource } from '../../datasource/terraform-provider';
@@ -12,7 +12,7 @@ export { extractPackageFile } from './extract';
 export const supportedDatasources = [
   BitBucketTagsDatasource.id,
   GitTagsDatasource.id,
-  datasourceGithubTags.id,
+  GithubTagsDatasource.id,
   HelmDatasource.id,
   TerraformModuleDatasource.id,
   TerraformProviderDatasource.id,
diff --git a/lib/manager/terraform/modules.ts b/lib/manager/terraform/modules.ts
index bf2b0b12127ab7d7b84c6e071013821ebf311cba..18b4a10aac9c395688fdb45b0ce21057d9f4f7ae 100644
--- a/lib/manager/terraform/modules.ts
+++ b/lib/manager/terraform/modules.ts
@@ -1,6 +1,6 @@
 import { BitBucketTagsDatasource } from '../../datasource/bitbucket-tags';
 import { GitTagsDatasource } from '../../datasource/git-tags';
-import * as datasourceGithubTags from '../../datasource/github-tags';
+import { GithubTagsDatasource } from '../../datasource/github-tags';
 import { TerraformModuleDatasource } from '../../datasource/terraform-module';
 import { logger } from '../../logger';
 import { regEx } from '../../util/regex';
@@ -42,7 +42,7 @@ export function analyseTerraformModule(dep: PackageDependency): void {
     dep.depType = 'module';
     dep.depName = 'github.com/' + dep.lookupName;
     dep.currentValue = githubRefMatch.groups.tag;
-    dep.datasource = datasourceGithubTags.id;
+    dep.datasource = GithubTagsDatasource.id;
   } else if (bitbucketRefMatch) {
     dep.depType = 'module';
     dep.depName =
diff --git a/lib/manager/terraform/required-version.ts b/lib/manager/terraform/required-version.ts
index 12f5ad4bdf0f8e5c5394be34d2252355f8cbe958..33969f823aa13d335c3e9a5e0b4807280b3fa710 100644
--- a/lib/manager/terraform/required-version.ts
+++ b/lib/manager/terraform/required-version.ts
@@ -1,4 +1,4 @@
-import * as datasourceGithubTags from '../../datasource/github-tags';
+import { GithubTagsDatasource } from '../../datasource/github-tags';
 import { logger } from '../../logger';
 import { regEx } from '../../util/regex';
 import type { PackageDependency } from '../types';
@@ -47,7 +47,7 @@ export function extractTerraformRequiredVersion(
 
 export function analyseTerraformVersion(dep: PackageDependency): void {
   dep.depType = 'required_version';
-  dep.datasource = datasourceGithubTags.id;
+  dep.datasource = GithubTagsDatasource.id;
   dep.depName = 'hashicorp/terraform';
   dep.extractVersion = 'v(?<version>.*)$';
 }
diff --git a/lib/manager/terragrunt-version/extract.ts b/lib/manager/terragrunt-version/extract.ts
index c6a87213adcf0736a60e2a106480d724be1b3762..fb918e0635e972723772924e45622303efd7902d 100644
--- a/lib/manager/terragrunt-version/extract.ts
+++ b/lib/manager/terragrunt-version/extract.ts
@@ -1,4 +1,4 @@
-import * as datasourceGitHubRelease from '../../datasource/github-releases';
+import { GithubReleasesDatasource } from '../../datasource/github-releases';
 import { logger } from '../../logger';
 import type { PackageDependency, PackageFile } from '../types';
 
@@ -7,7 +7,7 @@ export function extractPackageFile(content: string): PackageFile {
   const dep: PackageDependency = {
     depName: 'gruntwork-io/terragrunt',
     currentValue: content.trim(),
-    datasource: datasourceGitHubRelease.id,
+    datasource: GithubReleasesDatasource.id,
   };
   return { deps: [dep] };
 }
diff --git a/lib/manager/terragrunt-version/index.ts b/lib/manager/terragrunt-version/index.ts
index 1b6aa3b029f620d07bf584b32d03c7daf509cb17..a1286d9721980d1968c22505e2ab09ee24a5df0b 100644
--- a/lib/manager/terragrunt-version/index.ts
+++ b/lib/manager/terragrunt-version/index.ts
@@ -1,9 +1,9 @@
-import * as datasourceGitHubRelease from '../../datasource/github-releases';
+import { GithubReleasesDatasource } from '../../datasource/github-releases';
 import * as hashicorpVersioning from '../../versioning/hashicorp';
 
 export { extractPackageFile } from './extract';
 
-export const supportedDatasources = [datasourceGitHubRelease.id];
+export const supportedDatasources = [GithubReleasesDatasource.id];
 
 export const defaultConfig = {
   fileMatch: ['(^|/)\\.terragrunt-version$'],
diff --git a/lib/manager/terragrunt/index.ts b/lib/manager/terragrunt/index.ts
index ac5b5a06287f32d50cc809cd32fae1a60286631c..126af225f03d766ff437b220b80025c9d3df89a0 100644
--- a/lib/manager/terragrunt/index.ts
+++ b/lib/manager/terragrunt/index.ts
@@ -1,5 +1,5 @@
 import { GitTagsDatasource } from '../../datasource/git-tags';
-import * as datasourceGithubTags from '../../datasource/github-tags';
+import { GithubTagsDatasource } from '../../datasource/github-tags';
 import { TerraformModuleDatasource } from '../../datasource/terraform-module';
 import * as hashicorpVersioning from '../../versioning/hashicorp';
 
@@ -7,7 +7,7 @@ export { extractPackageFile } from './extract';
 
 export const supportedDatasources = [
   GitTagsDatasource.id,
-  datasourceGithubTags.id,
+  GithubTagsDatasource.id,
   TerraformModuleDatasource.id,
 ];
 
diff --git a/lib/manager/terragrunt/modules.ts b/lib/manager/terragrunt/modules.ts
index 1c1e0884f67c2b6bd90960cf344ad021126a38cf..c76ff3c86ffb93c312f99adb9b74b7d7885c04a9 100644
--- a/lib/manager/terragrunt/modules.ts
+++ b/lib/manager/terragrunt/modules.ts
@@ -1,5 +1,5 @@
 import { GitTagsDatasource } from '../../datasource/git-tags';
-import * as datasourceGithubTags from '../../datasource/github-tags';
+import { GithubTagsDatasource } from '../../datasource/github-tags';
 import { TerraformModuleDatasource } from '../../datasource/terraform-module';
 import { logger } from '../../logger';
 import { regEx } from '../../util/regex';
@@ -38,7 +38,7 @@ export function analyseTerragruntModule(dep: PackageDependency): void {
     dep.lookupName = githubRefMatch.groups.project.replace(regEx(/\.git$/), '');
     dep.depName = 'github.com/' + dep.lookupName;
     dep.currentValue = githubRefMatch.groups.tag;
-    dep.datasource = datasourceGithubTags.id;
+    dep.datasource = GithubTagsDatasource.id;
   } else if (gitTagsRefMatch) {
     dep.depType = 'gitTags';
     if (gitTagsRefMatch.groups.path.includes('//')) {
diff --git a/lib/manager/travis/extract.ts b/lib/manager/travis/extract.ts
index c50ad28bf022027067310a10fc2893e5afe0d2b7..52a8648003053c51034dff58709ca080c8e64429 100644
--- a/lib/manager/travis/extract.ts
+++ b/lib/manager/travis/extract.ts
@@ -1,6 +1,6 @@
 import is from '@sindresorhus/is';
 import { load } from 'js-yaml';
-import * as datasourceGithubTags from '../../datasource/github-tags';
+import { GithubTagsDatasource } from '../../datasource/github-tags';
 import { logger } from '../../logger';
 import type { PackageDependency, PackageFile } from '../types';
 import type { TravisMatrixItem, TravisYaml } from './types';
@@ -19,7 +19,7 @@ export function extractPackageFile(content: string): PackageFile | null {
   if (doc && is.array(doc.node_js)) {
     deps = doc.node_js.map((currentValue) => ({
       depName: 'node',
-      datasource: datasourceGithubTags.id,
+      datasource: GithubTagsDatasource.id,
       lookupName: 'nodejs/node',
       currentValue: currentValue.toString(),
     }));
@@ -43,7 +43,7 @@ export function extractPackageFile(content: string): PackageFile | null {
         item.node_js.forEach((currentValue) => {
           deps.push({
             depName: 'node',
-            datasource: datasourceGithubTags.id,
+            datasource: GithubTagsDatasource.id,
             lookupName: 'nodejs/node',
             currentValue: currentValue.toString(),
           });
@@ -51,7 +51,7 @@ export function extractPackageFile(content: string): PackageFile | null {
       } else if (is.string(item.node_js)) {
         deps.push({
           depName: 'node',
-          datasource: datasourceGithubTags.id,
+          datasource: GithubTagsDatasource.id,
           lookupName: 'nodejs/node',
           currentValue: item.node_js.toString(),
         });
diff --git a/lib/manager/travis/index.ts b/lib/manager/travis/index.ts
index ee13640188eefbf5c172a76bbd51ec00e2014263..1fc8e41c03b2059986a4f126f03897ec0c92967e 100644
--- a/lib/manager/travis/index.ts
+++ b/lib/manager/travis/index.ts
@@ -1,12 +1,12 @@
 import { ProgrammingLanguage } from '../../constants';
-import * as datasourceGithubTags from '../../datasource/github-tags';
+import { GithubTagsDatasource } from '../../datasource/github-tags';
 import * as nodeVersioning from '../../versioning/node';
 
 export { extractPackageFile } from './extract';
 
 export const language = ProgrammingLanguage.NodeJS;
 
-export const supportedDatasources = [datasourceGithubTags.id];
+export const supportedDatasources = [GithubTagsDatasource.id];
 
 export const defaultConfig = {
   fileMatch: ['^.travis.yml$'],
diff --git a/lib/util/http/github.spec.ts b/lib/util/http/github.spec.ts
index cbb70841a3688a558342b0541b10e5d3efb38d80..a298cfcafccd4b4740f83d33a2ab6e57e41b0cec 100644
--- a/lib/util/http/github.spec.ts
+++ b/lib/util/http/github.spec.ts
@@ -8,7 +8,7 @@ import {
   PLATFORM_RATE_LIMIT_EXCEEDED,
   REPOSITORY_CHANGED,
 } from '../../constants/error-messages';
-import { id as GITHUB_RELEASES_ID } from '../../datasource/github-releases';
+import { GithubReleasesDatasource } from '../../datasource/github-releases';
 import * as _repositoryCache from '../../util/cache/repository';
 import type { Cache } from '../../util/cache/repository/types';
 import * as hostRules from '../host-rules';
@@ -77,10 +77,10 @@ describe('util/http/github', () => {
     });
 
     it('supports different datasources', async () => {
-      const githubApiDatasource = new GithubHttp(GITHUB_RELEASES_ID);
+      const githubApiDatasource = new GithubHttp(GithubReleasesDatasource.id);
       hostRules.add({ hostType: 'github', token: 'abc' });
       hostRules.add({
-        hostType: GITHUB_RELEASES_ID,
+        hostType: GithubReleasesDatasource.id,
         token: 'def',
       });
       httpMock.scope(githubApiHost).get('/some-url').reply(200);
diff --git a/lib/workers/repository/process/lookup/index.spec.ts b/lib/workers/repository/process/lookup/index.spec.ts
index 1afcb616b05ee3a666804b328cfb455df17385ec..ffb3dd45a46220fd473b383d953a63b8ea4e149e 100644
--- a/lib/workers/repository/process/lookup/index.spec.ts
+++ b/lib/workers/repository/process/lookup/index.spec.ts
@@ -10,8 +10,8 @@ import * as datasourceDocker from '../../../../datasource/docker';
 import { id as datasourceDockerId } from '../../../../datasource/docker';
 import { GitRefsDatasource } from '../../../../datasource/git-refs';
 import { GitDatasource } from '../../../../datasource/git-refs/base';
-import * as datasourceGithubReleases from '../../../../datasource/github-releases';
-import { id as datasourceGithubTagsId } from '../../../../datasource/github-tags';
+import { GithubReleasesDatasource } from '../../../../datasource/github-releases';
+import { GithubTagsDatasource } from '../../../../datasource/github-tags';
 import { id as datasourceNpmId } from '../../../../datasource/npm';
 import { PackagistDatasource } from '../../../../datasource/packagist';
 import { PypiDatasource } from '../../../../datasource/pypi';
@@ -24,7 +24,6 @@ import type { LookupUpdateConfig } from './types';
 import * as lookup from '.';
 
 jest.mock('../../../../datasource/docker');
-jest.mock('../../../../datasource/github-releases');
 
 const fixtureRoot = '../../../../config/npm';
 const qJson = {
@@ -41,9 +40,6 @@ const webpackJson = loadJsonFixture('webpack.json', fixtureRoot);
 
 const docker = mocked(datasourceDocker) as any;
 docker.defaultRegistryUrls = ['https://index.docker.io'];
-const githubReleases = mocked(datasourceGithubReleases);
-
-Object.assign(githubReleases, { defaultRegistryUrls: ['https://github.com'] });
 
 let config: LookupUpdateConfig;
 
@@ -813,21 +809,15 @@ describe('workers/repository/process/lookup/index', () => {
     it('should ignore unstable versions from datasource', async () => {
       config.currentValue = '1.4.4';
       config.depName = 'some/action';
-      config.datasource = datasourceGithubReleases.id;
-      githubReleases.getReleases.mockResolvedValueOnce({
-        releases: [
-          {
-            version: '1.4.4',
-          },
-          {
-            version: '2.0.0',
-          },
-          {
-            version: '2.1.0',
-            isStable: false,
-          },
-        ],
-      });
+      config.datasource = GithubReleasesDatasource.id;
+      httpMock
+        .scope('https://api.github.com')
+        .get('/repos/some/action/releases?per_page=100')
+        .reply(200, [
+          { tag_name: '1.4.4' },
+          { tag_name: '2.0.0' },
+          { tag_name: '2.1.0', prerelease: true },
+        ]);
       expect((await lookup.lookupUpdates(config)).updates).toMatchSnapshot([
         { newValue: '2.0.0', updateType: 'major' },
       ]);
@@ -836,28 +826,21 @@ describe('workers/repository/process/lookup/index', () => {
     it('should return pendingChecks', async () => {
       config.currentValue = '1.4.4';
       config.depName = 'some/action';
-      config.datasource = datasourceGithubReleases.id;
+      config.datasource = GithubReleasesDatasource.id;
       config.stabilityDays = 14;
       config.internalChecksFilter = 'strict';
       const yesterday = new Date();
       yesterday.setDate(yesterday.getDate() - 1);
       const lastWeek = new Date();
       lastWeek.setDate(lastWeek.getDate() - 7);
-      githubReleases.getReleases.mockResolvedValueOnce({
-        releases: [
-          {
-            version: '1.4.4',
-          },
-          {
-            version: '1.4.5',
-            releaseTimestamp: lastWeek.toISOString(),
-          },
-          {
-            version: '1.4.6',
-            releaseTimestamp: yesterday.toISOString(),
-          },
-        ],
-      });
+      httpMock
+        .scope('https://api.github.com')
+        .get('/repos/some/action/releases?per_page=100')
+        .reply(200, [
+          { tag_name: '1.4.4' },
+          { tag_name: '1.4.5', published_at: lastWeek.toISOString() },
+          { tag_name: '1.4.6', published_at: yesterday.toISOString() },
+        ]);
       const res = await lookup.lookupUpdates(config);
       expect(res.updates).toHaveLength(1);
       expect(res.updates[0].newVersion).toBe('1.4.6');
@@ -867,28 +850,21 @@ describe('workers/repository/process/lookup/index', () => {
     it('should return pendingVersions', async () => {
       config.currentValue = '1.4.4';
       config.depName = 'some/action';
-      config.datasource = datasourceGithubReleases.id;
+      config.datasource = GithubReleasesDatasource.id;
       config.stabilityDays = 3;
       config.internalChecksFilter = 'strict';
       const yesterday = new Date();
       yesterday.setDate(yesterday.getDate() - 1);
       const lastWeek = new Date();
       lastWeek.setDate(lastWeek.getDate() - 7);
-      githubReleases.getReleases.mockResolvedValueOnce({
-        releases: [
-          {
-            version: '1.4.4',
-          },
-          {
-            version: '1.4.5',
-            releaseTimestamp: lastWeek.toISOString(),
-          },
-          {
-            version: '1.4.6',
-            releaseTimestamp: yesterday.toISOString(),
-          },
-        ],
-      });
+      httpMock
+        .scope('https://api.github.com')
+        .get('/repos/some/action/releases?per_page=100')
+        .reply(200, [
+          { tag_name: '1.4.4' },
+          { tag_name: '1.4.5', published_at: lastWeek.toISOString() },
+          { tag_name: '1.4.6', published_at: yesterday.toISOString() },
+        ]);
       const res = await lookup.lookupUpdates(config);
       expect(res.updates).toHaveLength(1);
       expect(res.updates[0].newVersion).toBe('1.4.5');
@@ -1201,7 +1177,7 @@ describe('workers/repository/process/lookup/index', () => {
     });
     it('handles github 404', async () => {
       config.depName = 'foo';
-      config.datasource = datasourceGithubTagsId;
+      config.datasource = GithubTagsDatasource.id;
       config.packageFile = 'package.json';
       config.currentValue = '1.0.0';
       httpMock.scope('https://pypi.org').get('/pypi/foo/json').reply(404);