From e631cae60126ea70ef78ccb3a12cd2d235610e76 Mon Sep 17 00:00:00 2001
From: Sebastian Poxhofer <secustor@users.noreply.github.com>
Date: Thu, 29 Jul 2021 10:10:45 +0200
Subject: [PATCH] refactor(bitbucket-tags): move datasource to class (#10957)

Co-authored-by: Jamie Magee <jamie.magee@gmail.com>
Co-authored-by: Michael Kriese <michael.kriese@visualon.de>
---
 lib/datasource/api.ts                         |   4 +-
 lib/datasource/bitbucket-tags/index.spec.ts   |   4 +-
 lib/datasource/bitbucket-tags/index.ts        | 209 +++++++++---------
 .../go/__snapshots__/index.spec.ts.snap       |   1 +
 lib/datasource/go/index.ts                    |   3 +-
 5 files changed, 111 insertions(+), 110 deletions(-)

diff --git a/lib/datasource/api.ts b/lib/datasource/api.ts
index 3dd5e93b2f..5dde26a33a 100644
--- a/lib/datasource/api.ts
+++ b/lib/datasource/api.ts
@@ -1,4 +1,4 @@
-import * as bitbucketTags from './bitbucket-tags';
+import { BitBucketTagsDatasource } from './bitbucket-tags';
 import { CdnJsDatasource } from './cdnjs';
 import { ClojureDatasource } from './clojure';
 import * as crate from './crate';
@@ -35,7 +35,7 @@ import type { DatasourceApi } from './types';
 const api = new Map<string, DatasourceApi>();
 export default api;
 
-api.set('bitbucket-tags', bitbucketTags);
+api.set('bitbucket-tags', new BitBucketTagsDatasource());
 api.set('cdnjs', new CdnJsDatasource());
 api.set('clojure', new ClojureDatasource());
 api.set('crate', crate);
diff --git a/lib/datasource/bitbucket-tags/index.spec.ts b/lib/datasource/bitbucket-tags/index.spec.ts
index 83290ddd9b..89487dd107 100644
--- a/lib/datasource/bitbucket-tags/index.spec.ts
+++ b/lib/datasource/bitbucket-tags/index.spec.ts
@@ -1,7 +1,9 @@
 import { getDigest, getPkgReleases } from '..';
 import * as httpMock from '../../../test/http-mock';
 import { getName } from '../../../test/util';
-import { id as datasource } from '.';
+import { BitBucketTagsDatasource } from '.';
+
+const datasource = BitBucketTagsDatasource.id;
 
 describe(getName(), () => {
   describe('getReleases', () => {
diff --git a/lib/datasource/bitbucket-tags/index.ts b/lib/datasource/bitbucket-tags/index.ts
index 3e06f3b4f0..33be94ef77 100644
--- a/lib/datasource/bitbucket-tags/index.ts
+++ b/lib/datasource/bitbucket-tags/index.ts
@@ -1,133 +1,130 @@
 import * as utils from '../../platform/bitbucket/utils';
-import * as packageCache from '../../util/cache/package';
+import { cache } from '../../util/cache/package/decorator';
 import { BitbucketHttp } from '../../util/http/bitbucket';
 import { ensureTrailingSlash } from '../../util/url';
+import { Datasource } from '../datasource';
 import type { DigestConfig, GetReleasesConfig, ReleaseResult } from '../types';
 import { BitbucketCommit, BitbucketTag } from './types';
 
-const bitbucketHttp = new BitbucketHttp();
+export class BitBucketTagsDatasource extends Datasource {
+  bitbucketHttp = new BitbucketHttp();
 
-export const id = 'bitbucket-tags';
-export const customRegistrySupport = true;
-export const registryStrategy = 'first';
-export const defaultRegistryUrls = ['https://bitbucket.org'];
+  static readonly id = 'bitbucket-tags';
 
-function getRegistryURL(registryUrl: string): string {
-  // fallback to default API endpoint if custom not provided
-  return registryUrl ?? defaultRegistryUrls[0];
-}
-
-const cacheNamespace = 'datasource-bitbucket';
+  static readonly customRegistrySupport = true;
 
-function getCacheKey(registryUrl: string, repo: string, type: string): string {
-  return `${getRegistryURL(registryUrl)}:${repo}:${type}`;
-}
+  static readonly registryStrategy = 'first';
 
-// getReleases fetches list of tags for the repository
-export async function getReleases({
-  registryUrl,
-  lookupName: repo,
-}: GetReleasesConfig): Promise<ReleaseResult | null> {
-  const cacheKey = getCacheKey(registryUrl, repo, 'tags');
-  const cachedResult = await packageCache.get<ReleaseResult>(
-    cacheNamespace,
-    cacheKey
-  );
-  // istanbul ignore if
-  if (cachedResult) {
-    return cachedResult;
-  }
+  static readonly defaultRegistryUrls = ['https://bitbucket.org'];
 
-  const url = `/2.0/repositories/${repo}/refs/tags`;
-
-  const bitbucketTags = (
-    await bitbucketHttp.getJson<utils.PagedResult<BitbucketTag>>(url)
-  ).body;
-
-  const dependency: ReleaseResult = {
-    sourceUrl: `${ensureTrailingSlash(getRegistryURL(registryUrl))}${repo}`,
-    releases: null,
-  };
-  dependency.releases = bitbucketTags.values.map(({ name, target }) => ({
-    version: name,
-    gitRef: name,
-    releaseTimestamp: target?.date,
-  }));
-
-  const cacheMinutes = 10;
-  await packageCache.set(cacheNamespace, cacheKey, dependency, cacheMinutes);
-  return dependency;
-}
+  static readonly cacheNamespace = `datasource-${BitBucketTagsDatasource.id}`;
 
-// getTagCommit fetched the commit has for specified tag
-async function getTagCommit(
-  registryUrl: string,
-  repo: string,
-  tag: string
-): Promise<string | null> {
-  const cacheKey = getCacheKey(registryUrl, repo, `tag-${tag}`);
-  const cachedResult = await packageCache.get<string>(cacheNamespace, cacheKey);
-  // istanbul ignore if
-  if (cachedResult) {
-    return cachedResult;
+  constructor() {
+    super(BitBucketTagsDatasource.id);
   }
 
-  const url = `/2.0/repositories/${repo}/refs/tags/${tag}`;
-
-  const bitbucketTag = (await bitbucketHttp.getJson<BitbucketTag>(url)).body;
-
-  const hash = bitbucketTag.target.hash;
-
-  const cacheMinutes = 10;
-  await packageCache.set(cacheNamespace, cacheKey, hash, cacheMinutes);
+  static getRegistryURL(registryUrl: string): string {
+    // fallback to default API endpoint if custom not provided
+    return registryUrl ?? this.defaultRegistryUrls[0];
+  }
 
-  return hash;
-}
+  static getCacheKey(registryUrl: string, repo: string, type: string): string {
+    return `${BitBucketTagsDatasource.getRegistryURL(
+      registryUrl
+    )}:${repo}:${type}`;
+  }
 
-// getDigest fetched the latest commit for repository main branch
-// however, if newValue is provided, then getTagCommit is called
-export async function getDigest(
-  { lookupName: repo, registryUrl }: DigestConfig,
-  newValue?: string
-): Promise<string | null> {
-  if (newValue?.length) {
-    return getTagCommit(registryUrl, repo, newValue);
+  // getReleases fetches list of tags for the repository
+  @cache({
+    namespace: BitBucketTagsDatasource.cacheNamespace,
+    key: ({ registryUrl, lookupName }: GetReleasesConfig) =>
+      BitBucketTagsDatasource.getCacheKey(registryUrl, lookupName, 'tags'),
+  })
+  async getReleases({
+    registryUrl,
+    lookupName: repo,
+  }: GetReleasesConfig): Promise<ReleaseResult | null> {
+    const url = `/2.0/repositories/${repo}/refs/tags`;
+
+    const bitbucketTags = (
+      await this.bitbucketHttp.getJson<utils.PagedResult<BitbucketTag>>(url)
+    ).body;
+
+    const dependency: ReleaseResult = {
+      sourceUrl: `${ensureTrailingSlash(
+        BitBucketTagsDatasource.getRegistryURL(registryUrl)
+      )}${repo}`,
+      registryUrl: BitBucketTagsDatasource.getRegistryURL(registryUrl),
+      releases: null,
+    };
+    dependency.releases = bitbucketTags.values.map(({ name, target }) => ({
+      version: name,
+      gitRef: name,
+      releaseTimestamp: target?.date,
+    }));
+
+    return dependency;
   }
 
-  const cacheKey = getCacheKey(registryUrl, repo, 'digest');
-  const cachedResult = await packageCache.get<string>(cacheNamespace, cacheKey);
-  // istanbul ignore if
-  if (cachedResult) {
-    return cachedResult;
+  // getTagCommit fetched the commit has for specified tag
+  @cache({
+    namespace: BitBucketTagsDatasource.cacheNamespace,
+    key: (registryUrl, repo, tag: string) =>
+      BitBucketTagsDatasource.getCacheKey(registryUrl, repo, `tag-${tag}`),
+  })
+  async getTagCommit(
+    registryUrl: string,
+    repo: string,
+    tag: string
+  ): Promise<string | null> {
+    const url = `/2.0/repositories/${repo}/refs/tags/${tag}`;
+
+    const bitbucketTag = (await this.bitbucketHttp.getJson<BitbucketTag>(url))
+      .body;
+
+    return bitbucketTag.target.hash;
   }
 
-  const branchCacheKey = getCacheKey(registryUrl, repo, 'mainbranch');
-  let mainBranch = await packageCache.get<string>(
-    cacheNamespace,
-    branchCacheKey
-  );
-  if (!mainBranch) {
-    mainBranch = (
-      await bitbucketHttp.getJson<utils.RepoInfoBody>(
+  @cache({
+    namespace: BitBucketTagsDatasource.cacheNamespace,
+    key: (registryUrl: string, repo: string) =>
+      BitBucketTagsDatasource.getCacheKey(registryUrl, repo, 'mainbranch'),
+    ttlMinutes: 60,
+  })
+  async getMainBranch(repo: string): Promise<string> {
+    return (
+      await this.bitbucketHttp.getJson<utils.RepoInfoBody>(
         `/2.0/repositories/${repo}`
       )
     ).body.mainbranch.name;
-    await packageCache.set(cacheNamespace, branchCacheKey, mainBranch, 60);
   }
 
-  const url = `/2.0/repositories/${repo}/commits/${mainBranch}`;
-  const bitbucketCommits = (
-    await bitbucketHttp.getJson<utils.PagedResult<BitbucketCommit>>(url)
-  ).body;
-
-  if (bitbucketCommits.values.length === 0) {
-    return null;
+  // getDigest fetched the latest commit for repository main branch
+  // however, if newValue is provided, then getTagCommit is called
+  @cache({
+    namespace: BitBucketTagsDatasource.cacheNamespace,
+    key: ({ registryUrl, lookupName }: DigestConfig) =>
+      BitBucketTagsDatasource.getCacheKey(registryUrl, lookupName, 'digest'),
+  })
+  async getDigest(
+    { lookupName: repo, registryUrl }: DigestConfig,
+    newValue?: string
+  ): Promise<string | null> {
+    if (newValue?.length) {
+      return this.getTagCommit(registryUrl, repo, newValue);
+    }
+
+    const mainBranch = await this.getMainBranch(repo);
+
+    const url = `/2.0/repositories/${repo}/commits/${mainBranch}`;
+    const bitbucketCommits = (
+      await this.bitbucketHttp.getJson<utils.PagedResult<BitbucketCommit>>(url)
+    ).body;
+
+    if (bitbucketCommits.values.length === 0) {
+      return null;
+    }
+
+    return bitbucketCommits.values[0].hash;
   }
-
-  const latestCommit = bitbucketCommits.values[0].hash;
-
-  const cacheMinutes = 10;
-  await packageCache.set(cacheNamespace, cacheKey, latestCommit, cacheMinutes);
-
-  return latestCommit;
 }
diff --git a/lib/datasource/go/__snapshots__/index.spec.ts.snap b/lib/datasource/go/__snapshots__/index.spec.ts.snap
index 9d40fee4c3..6ea4039550 100644
--- a/lib/datasource/go/__snapshots__/index.spec.ts.snap
+++ b/lib/datasource/go/__snapshots__/index.spec.ts.snap
@@ -329,6 +329,7 @@ Array [
 
 exports[`datasource/go/index getReleases support bitbucket tags 1`] = `
 Object {
+  "registryUrl": "https://bitbucket.org",
   "releases": Array [
     Object {
       "gitRef": "v1.0.0",
diff --git a/lib/datasource/go/index.ts b/lib/datasource/go/index.ts
index 781bd3db45..527473d89c 100644
--- a/lib/datasource/go/index.ts
+++ b/lib/datasource/go/index.ts
@@ -5,7 +5,7 @@ import * as hostRules from '../../util/host-rules';
 import { Http } from '../../util/http';
 import { regEx } from '../../util/regex';
 import { trimTrailingSlash } from '../../util/url';
-import * as bitbucket from '../bitbucket-tags';
+import { BitBucketTagsDatasource } from '../bitbucket-tags';
 import * as github from '../github-tags';
 import * as gitlab from '../gitlab-tags';
 import type { DigestConfig, GetReleasesConfig, ReleaseResult } from '../types';
@@ -16,6 +16,7 @@ export const customRegistrySupport = false;
 
 const http = new Http(id);
 const gitlabRegExp = /^(https:\/\/[^/]*gitlab.[^/]*)\/(.*)$/;
+const bitbucket = new BitBucketTagsDatasource();
 
 async function getDatasource(goModule: string): Promise<DataSource | null> {
   if (goModule.startsWith('gopkg.in/')) {
-- 
GitLab