mirror of
https://github.com/renovatebot/renovate.git
synced 2025-01-15 00:56:26 +00:00
feat: add dart version datasource (#19277)
This commit is contained in:
parent
943efc50ae
commit
aab79f15d1
7 changed files with 202 additions and 0 deletions
|
@ -11,6 +11,7 @@ import { CondaDatasource } from './conda';
|
||||||
import { CpanDatasource } from './cpan';
|
import { CpanDatasource } from './cpan';
|
||||||
import { CrateDatasource } from './crate';
|
import { CrateDatasource } from './crate';
|
||||||
import { DartDatasource } from './dart';
|
import { DartDatasource } from './dart';
|
||||||
|
import { DartVersionDatasource } from './dart-version';
|
||||||
import { DenoDatasource } from './deno';
|
import { DenoDatasource } from './deno';
|
||||||
import { DockerDatasource } from './docker';
|
import { DockerDatasource } from './docker';
|
||||||
import { DotnetDatasource } from './dotnet';
|
import { DotnetDatasource } from './dotnet';
|
||||||
|
@ -67,6 +68,7 @@ api.set(CondaDatasource.id, new CondaDatasource());
|
||||||
api.set(CpanDatasource.id, new CpanDatasource());
|
api.set(CpanDatasource.id, new CpanDatasource());
|
||||||
api.set(CrateDatasource.id, new CrateDatasource());
|
api.set(CrateDatasource.id, new CrateDatasource());
|
||||||
api.set(DartDatasource.id, new DartDatasource());
|
api.set(DartDatasource.id, new DartDatasource());
|
||||||
|
api.set(DartVersionDatasource.id, new DartVersionDatasource());
|
||||||
api.set(DenoDatasource.id, new DenoDatasource());
|
api.set(DenoDatasource.id, new DenoDatasource());
|
||||||
api.set(DockerDatasource.id, new DockerDatasource());
|
api.set(DockerDatasource.id, new DockerDatasource());
|
||||||
api.set(DotnetDatasource.id, new DotnetDatasource());
|
api.set(DotnetDatasource.id, new DotnetDatasource());
|
||||||
|
|
15
lib/modules/datasource/dart-version/__fixtures__/beta.json
Normal file
15
lib/modules/datasource/dart-version/__fixtures__/beta.json
Normal 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/"
|
||||||
|
]
|
||||||
|
}
|
15
lib/modules/datasource/dart-version/__fixtures__/dev.json
Normal file
15
lib/modules/datasource/dart-version/__fixtures__/dev.json
Normal 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/"
|
||||||
|
]
|
||||||
|
}
|
12
lib/modules/datasource/dart-version/__fixtures__/stable.json
Normal file
12
lib/modules/datasource/dart-version/__fixtures__/stable.json
Normal 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/"
|
||||||
|
]
|
||||||
|
}
|
74
lib/modules/datasource/dart-version/index.spec.ts
Normal file
74
lib/modules/datasource/dart-version/index.spec.ts
Normal 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 },
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
80
lib/modules/datasource/dart-version/index.ts
Normal file
80
lib/modules/datasource/dart-version/index.ts
Normal 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];
|
||||||
|
}
|
||||||
|
}
|
4
lib/modules/datasource/dart-version/types.ts
Normal file
4
lib/modules/datasource/dart-version/types.ts
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
export interface DartResponse {
|
||||||
|
kind: string;
|
||||||
|
prefixes: string[];
|
||||||
|
}
|
Loading…
Reference in a new issue