diff --git a/lib/datasource/api.ts b/lib/datasource/api.ts index 4f9fee1d1efbc6e8006867eb1e06c9e012af12d6..36caaae79a91e03dfa28c8ff2e240f2a1eca8eb7 100644 --- a/lib/datasource/api.ts +++ b/lib/datasource/api.ts @@ -19,7 +19,7 @@ import * as jenkinsPlugins from './jenkins-plugins'; import * as maven from './maven'; import * as npm from './npm'; import * as nuget from './nuget'; -import * as orb from './orb'; +import { OrbDatasource } from './orb'; import * as packagist from './packagist'; import * as pod from './pod'; import * as pypi from './pypi'; @@ -56,7 +56,7 @@ api.set('jenkins-plugins', jenkinsPlugins); api.set('maven', maven); api.set('npm', npm); api.set('nuget', nuget); -api.set('orb', orb); +api.set('orb', new OrbDatasource()); api.set('packagist', packagist); api.set('pod', pod); api.set('pypi', pypi); diff --git a/lib/datasource/orb/index.spec.ts b/lib/datasource/orb/index.spec.ts index b3d3940b3e98faf216836c1a3200781b78a8792a..4d8feff26609699ea87c44edc60d9e3dab9b8519 100644 --- a/lib/datasource/orb/index.spec.ts +++ b/lib/datasource/orb/index.spec.ts @@ -1,7 +1,7 @@ import { getPkgReleases } from '..'; import * as httpMock from '../../../test/http-mock'; import { getName } from '../../../test/util'; -import { id as datasource } from '.'; +import { OrbDatasource } from '.'; const orbData = { data: { @@ -26,6 +26,8 @@ const orbData = { const baseUrl = 'https://circleci.com'; +const datasource = OrbDatasource.id; + describe(getName(), () => { describe('getReleases', () => { beforeEach(() => { diff --git a/lib/datasource/orb/index.ts b/lib/datasource/orb/index.ts index 46bd7738570f0e258c7b8be293bc9bda0c33a302..83098ba392322b101242058c779fa9a8556aecef 100644 --- a/lib/datasource/orb/index.ts +++ b/lib/datasource/orb/index.ts @@ -1,64 +1,57 @@ import { logger } from '../../logger'; -import * as packageCache from '../../util/cache/package'; -import { Http } from '../../util/http'; +import { cache } from '../../util/cache/package/decorator'; +import { Datasource } from '../datasource'; import type { GetReleasesConfig, ReleaseResult } from '../types'; import type { OrbRelease } from './types'; -export const id = 'orb'; -export const defaultRegistryUrls = ['https://circleci.com/']; -export const customRegistrySupport = false; +export class OrbDatasource extends Datasource { + static readonly id = 'orb'; -const http = new Http(id); - -/** - * orb.getReleases - * - * This function will fetch an orb from CircleCI and return all semver versions. - */ -export async function getReleases({ - lookupName, - registryUrl, -}: GetReleasesConfig): Promise<ReleaseResult | null> { - logger.debug({ lookupName }, 'orb.getReleases()'); - const cacheNamespace = 'orb'; - const cacheKey = lookupName; - const cachedResult = await packageCache.get<ReleaseResult>( - cacheNamespace, - cacheKey - ); - // istanbul ignore if - if (cachedResult) { - return cachedResult; - } - const url = `${registryUrl}graphql-unstable`; - const body = { - query: `{orb(name:"${lookupName}"){name, homeUrl, versions {version, createdAt}}}`, - variables: {}, - }; - const res: OrbRelease = ( - await http.postJson<{ data: { orb: OrbRelease } }>(url, { - body, - }) - ).body.data.orb; - if (!res) { - logger.debug({ lookupName }, 'Failed to look up orb'); - return null; + constructor() { + super(OrbDatasource.id); } - // Simplify response before caching and returning - const dep: ReleaseResult = { - releases: null, - }; - if (res.homeUrl?.length) { - dep.homepage = res.homeUrl; + + customRegistrySupport = false; + + defaultRegistryUrls = ['https://circleci.com/']; + + @cache({ + namespace: `datasource-${OrbDatasource.id}`, + key: ({ lookupName }: GetReleasesConfig) => lookupName, + }) + async getReleases({ + lookupName, + registryUrl, + }: GetReleasesConfig): Promise<ReleaseResult | null> { + const url = `${registryUrl}graphql-unstable`; + const body = { + query: `{orb(name:"${lookupName}"){name, homeUrl, versions {version, createdAt}}}`, + variables: {}, + }; + const res: OrbRelease = ( + await this.http.postJson<{ data: { orb: OrbRelease } }>(url, { + body, + }) + ).body.data.orb; + if (!res) { + logger.debug({ lookupName }, 'Failed to look up orb'); + return null; + } + // Simplify response before caching and returning + const dep: ReleaseResult = { + releases: null, + }; + if (res.homeUrl?.length) { + dep.homepage = res.homeUrl; + } + dep.homepage = + dep.homepage || `https://circleci.com/developer/orbs/orb/${lookupName}`; + dep.releases = res.versions.map(({ version, createdAt }) => ({ + version, + releaseTimestamp: createdAt || null, + })); + + logger.trace({ dep }, 'dep'); + return dep; } - dep.homepage = - dep.homepage || `https://circleci.com/developer/orbs/orb/${lookupName}`; - dep.releases = res.versions.map(({ version, createdAt }) => ({ - version, - releaseTimestamp: createdAt || null, - })); - logger.trace({ dep }, 'dep'); - const cacheMinutes = 15; - await packageCache.set(cacheNamespace, cacheKey, dep, cacheMinutes); - return dep; } diff --git a/lib/manager/circleci/extract.ts b/lib/manager/circleci/extract.ts index f71a48a3b7a36ec546edc5c6ed4d239268a4a809..0ffe5ce1ea93b12db3a046b576870873b2cd240e 100644 --- a/lib/manager/circleci/extract.ts +++ b/lib/manager/circleci/extract.ts @@ -1,4 +1,4 @@ -import * as datasourceOrb from '../../datasource/orb'; +import { OrbDatasource } from '../../datasource/orb'; import { logger } from '../../logger'; import * as npmVersioning from '../../versioning/npm'; import { getDep } from '../dockerfile/extract'; @@ -36,7 +36,7 @@ export function extractPackageFile(content: string): PackageFile | null { depType: 'orb', depName, currentValue, - datasource: datasourceOrb.id, + datasource: OrbDatasource.id, lookupName: orbName, commitMessageTopic: '{{{depName}}} orb', versioning: npmVersioning.id, diff --git a/lib/util/package-rules.spec.ts b/lib/util/package-rules.spec.ts index ded6c2fe17e3c25db491f7a582cfa1ab88e4f80d..5bd2d52ae0656bfc28a89f6a27f98306546cccc3 100644 --- a/lib/util/package-rules.spec.ts +++ b/lib/util/package-rules.spec.ts @@ -7,7 +7,7 @@ import { } from '../constants/languages'; import * as datasourceDocker from '../datasource/docker'; -import * as datasourceOrb from '../datasource/orb'; +import { OrbDatasource } from '../datasource/orb'; import { applyPackageRules } from './package-rules'; type TestConfig = PackageRuleInputConfig & { @@ -318,14 +318,14 @@ describe('applyPackageRules()', () => { const config: TestConfig = { packageRules: [ { - matchDatasources: [datasourceOrb.id, datasourceDocker.id], + matchDatasources: [OrbDatasource.id, datasourceDocker.id], x: 1, }, ], }; const dep = { depType: 'dependencies', - datasource: datasourceOrb.id, + datasource: OrbDatasource.id, baseBranch: 'master', }; const res = applyPackageRules({ ...config, ...dep }); @@ -342,7 +342,7 @@ describe('applyPackageRules()', () => { }; const dep = { depType: 'dependencies', - datasource: datasourceOrb.id, + datasource: OrbDatasource.id, baseBranch: 'master', }; const res = applyPackageRules({ ...config, ...dep }); @@ -352,7 +352,7 @@ describe('applyPackageRules()', () => { const config: TestConfig = { packageRules: [ { - matchDatasources: [datasourceOrb.id], + matchDatasources: [OrbDatasource.id], x: 1, }, ],