feat: add dart version datasource (#19277)

This commit is contained in:
Joshua Tang 2022-12-21 06:29:37 +11:00 committed by GitHub
parent 943efc50ae
commit aab79f15d1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 202 additions and 0 deletions

View file

@ -11,6 +11,7 @@ import { CondaDatasource } from './conda';
import { CpanDatasource } from './cpan';
import { CrateDatasource } from './crate';
import { DartDatasource } from './dart';
import { DartVersionDatasource } from './dart-version';
import { DenoDatasource } from './deno';
import { DockerDatasource } from './docker';
import { DotnetDatasource } from './dotnet';
@ -67,6 +68,7 @@ api.set(CondaDatasource.id, new CondaDatasource());
api.set(CpanDatasource.id, new CpanDatasource());
api.set(CrateDatasource.id, new CrateDatasource());
api.set(DartDatasource.id, new DartDatasource());
api.set(DartVersionDatasource.id, new DartVersionDatasource());
api.set(DenoDatasource.id, new DenoDatasource());
api.set(DockerDatasource.id, new DockerDatasource());
api.set(DotnetDatasource.id, new DotnetDatasource());

View file

@ -0,0 +1,15 @@
{
"kind": "storage#objects",
"prefixes": [
"channels/beta/release/2.17.0-69.2.beta/",
"channels/beta/release/2.17.0/",
"channels/beta/release/2.17.1/",
"channels/beta/release/2.18.0-271.8.beta/",
"channels/beta/release/2.18.0-44.1.beta/",
"channels/beta/release/2.18.0/",
"channels/beta/release/2.19.0-255.2.beta/",
"channels/beta/release/2.19.0-374.1.beta/",
"channels/beta/release/2.19.0-374.2.beta/",
"channels/beta/release/latest/"
]
}

View file

@ -0,0 +1,15 @@
{
"kind": "storage#objects",
"prefixes": [
"channels/dev/release/2.17.0-7.0.dev/",
"channels/dev/release/2.17.0-85.0.dev/",
"channels/dev/release/2.17.0-91.0.dev/",
"channels/dev/release/2.18.0-82.0.dev/",
"channels/dev/release/2.18.0-9.0.dev/",
"channels/dev/release/2.18.0-99.0.dev/",
"channels/dev/release/2.19.0-59.0.dev/",
"channels/dev/release/2.19.0-70.0.dev/",
"channels/dev/release/2.19.0-81.0.dev/",
"channels/dev/release/latest/"
]
}

View file

@ -0,0 +1,12 @@
{
"kind": "storage#objects",
"prefixes": [
"channels/stable/release/2.17.5/",
"channels/stable/release/2.17.6/",
"channels/stable/release/2.17.7/",
"channels/stable/release/2.18.0/",
"channels/stable/release/2.18.4/",
"channels/stable/release/2.18.5/",
"channels/stable/release/latest/"
]
}

View file

@ -0,0 +1,74 @@
import { getPkgReleases } from '..';
import { Fixtures } from '../../../../test/fixtures';
import * as httpMock from '../../../../test/http-mock';
import { EXTERNAL_HOST_ERROR } from '../../../constants/error-messages';
import { DartVersionDatasource } from '.';
const baseUrl = 'https://storage.googleapis.com';
const urlPath =
'/storage/v1/b/dart-archive/o?delimiter=%2F&prefix=channels%2Fstable%2Frelease%2F&alt=json';
const datasource = DartVersionDatasource.id;
const depName = 'dart';
const channels = ['stable', 'beta', 'dev'];
describe('modules/datasource/dart-version/index', () => {
describe('getReleases', () => {
it('throws for 500', async () => {
httpMock.scope(baseUrl).get(urlPath).reply(500);
await expect(
getPkgReleases({
datasource,
depName,
})
).rejects.toThrow(EXTERNAL_HOST_ERROR);
});
it('returns null for error', async () => {
httpMock.scope(baseUrl).get(urlPath).replyWithError('error');
expect(
await getPkgReleases({
datasource,
depName,
})
).toBeNull();
});
it('returns null for empty 200 OK', async () => {
httpMock.scope(baseUrl).get(urlPath).reply(200, []);
expect(
await getPkgReleases({
datasource,
depName,
})
).toBeNull();
});
it('processes real data', async () => {
for (const channel of channels) {
httpMock
.scope(baseUrl)
.get(
`/storage/v1/b/dart-archive/o?delimiter=%2F&prefix=channels%2F${channel}%2Frelease%2F&alt=json`
)
.reply(200, Fixtures.get(`${channel}.json`));
}
const res = await getPkgReleases({
datasource,
depName,
});
expect(res).toBeDefined();
expect(res?.sourceUrl).toBe('https://github.com/dart-lang/sdk');
expect(res?.releases).toHaveLength(21);
expect(res?.releases).toIncludeAllPartialMembers([
{ version: '2.18.0', isStable: true },
{ version: '2.17.7', isStable: true },
{ version: '2.19.0-374.2.beta', isStable: false },
{ version: '2.18.0-44.1.beta', isStable: false },
{ version: '2.19.0-81.0.dev', isStable: false },
{ version: '2.18.0-99.0.dev', isStable: false },
]);
});
});
});

View file

@ -0,0 +1,80 @@
import is from '@sindresorhus/is';
import { regEx } from '../../../util/regex';
import { Datasource } from '../datasource';
import type { GetReleasesConfig, Release, ReleaseResult } from '../types';
import type { DartResponse } from './types';
export const stableVersionRegex = regEx(/^\d+\.\d+\.\d+$/);
export class DartVersionDatasource extends Datasource {
static readonly id = 'dart-version';
constructor() {
super(DartVersionDatasource.id);
}
override readonly customRegistrySupport = false;
override readonly defaultRegistryUrls = ['https://storage.googleapis.com'];
override readonly caching = true;
private readonly channels = ['stable', 'beta', 'dev'];
async getReleases({
registryUrl,
}: GetReleasesConfig): Promise<ReleaseResult | null> {
// istanbul ignore if
if (!registryUrl) {
return null;
}
const result: ReleaseResult = {
homepage: 'https://dart.dev/',
sourceUrl: 'https://github.com/dart-lang/sdk',
registryUrl,
releases: [],
};
try {
for (const channel of this.channels) {
const resp = (
await this.http.getJson<DartResponse>(
`${registryUrl}/storage/v1/b/dart-archive/o?delimiter=%2F&prefix=channels%2F${channel}%2Frelease%2F&alt=json`
)
).body;
const releases = this.getReleasesFromResponse(channel, resp.prefixes);
result.releases.push(...releases);
}
} catch (err) {
this.handleGenericErrors(err);
}
return result.releases.length ? result : null;
}
private getReleasesFromResponse(
channel: string,
prefixes: string[]
): Release[] {
return prefixes
.map((prefix) => this.getVersionFromPrefix(prefix))
.filter(is.string)
.filter((version) => {
if (
version === 'latest' ||
// The API response contains a stable version being released as a non-stable
// release. So we filter out these releases here.
(channel !== 'stable' && stableVersionRegex.test(version))
) {
return false;
}
return true;
})
.map((version) => ({ version, isStable: channel === 'stable' }));
}
// Prefix should have a format of "channels/stable/release/2.9.3/"
private getVersionFromPrefix(prefix: string): string | undefined {
const parts = prefix.split('/');
return parts[parts.length - 2];
}
}

View file

@ -0,0 +1,4 @@
export interface DartResponse {
kind: string;
prefixes: string[];
}