aboutsummaryrefslogtreecommitdiffhomepage
path: root/lib/modules/datasource/orb/index.ts
blob: 12e3bc834d5eee5eec1c0f0d39c24a124f407169 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
import { logger } from '../../../logger';
import { cache } from '../../../util/cache/package/decorator';
import { Datasource } from '../datasource';
import type { GetReleasesConfig, ReleaseResult } from '../types';
import type { OrbResponse } from './types';

const MAX_VERSIONS = 100;

const query = `
query($packageName: String!, $maxVersions: Int!) {
  orb(name: $packageName) {
    name,
    homeUrl,
    isPrivate,
    versions(count: $maxVersions) {
      version,
      createdAt
    }
  }
}
`;

export class OrbDatasource extends Datasource {
  static readonly id = 'orb';

  constructor() {
    super(OrbDatasource.id);
  }

  override readonly customRegistrySupport = false;

  override readonly defaultRegistryUrls = ['https://circleci.com/'];

  override readonly releaseTimestampSupport = true;
  override readonly releaseTimestampNote =
    'The release timestamp is determined from the `createdAt` field in the results.';

  @cache({
    namespace: `datasource-${OrbDatasource.id}`,
    key: ({ packageName }: GetReleasesConfig) => packageName,
  })
  async getReleases({
    packageName,
    registryUrl,
  }: GetReleasesConfig): Promise<ReleaseResult | null> {
    // istanbul ignore if
    if (!registryUrl) {
      return null;
    }
    const url = `${registryUrl}graphql-unstable`;
    const body = {
      query,
      variables: { packageName, maxVersions: MAX_VERSIONS },
    };
    const res = (
      await this.http.postJson<OrbResponse>(url, {
        body,
      })
    ).body;
    if (!res?.data?.orb) {
      logger.debug({ res }, `Failed to look up orb ${packageName}`);
      return null;
    }

    const { orb } = res.data;
    // Simplify response before caching and returning
    const homepage = orb.homeUrl?.length
      ? orb.homeUrl
      : `https://circleci.com/developer/orbs/orb/${packageName}`;
    const releases = orb.versions.map(({ version, createdAt }) => ({
      version,
      releaseTimestamp: createdAt ?? null,
    }));

    const dep = { homepage, isPrivate: !!orb.isPrivate, releases };
    logger.trace({ dep }, 'dep');
    return dep;
  }
}