Skip to content

Commit

Permalink
refactor(datasource/deno): Add schema validation (#21329)
Browse files Browse the repository at this point in the history
  • Loading branch information
zharinov committed Apr 11, 2023
1 parent 3b53efe commit 00c8f90
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 89 deletions.
18 changes: 16 additions & 2 deletions lib/modules/datasource/deno/index.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { ZodError } from 'zod';
import * as httpMock from '../../../../test/http-mock';
import { logger } from '../../../../test/util';
import { DenoDatasource } from '.';

describe('modules/datasource/deno/index', () => {
Expand All @@ -10,7 +12,7 @@ describe('modules/datasource/deno/index', () => {
.scope(deno.defaultRegistryUrls[0])
.get('/v2/modules/std')
.reply(200, {
versions: ['0.163.0', '0.162.0'],
versions: ['0.163.0', '0.162.0', '0.161.0'],
tags: [{ value: 'top_5_percent', kind: 'popularity' }],
})
.get('/v2/modules/std/0.163.0')
Expand All @@ -32,7 +34,9 @@ describe('modules/datasource/deno/index', () => {
type: 'github',
},
uploaded_at: '2022-10-20T12:10:21.592Z',
});
})
.get('/v2/modules/std/0.161.0')
.reply(200, { foo: 'bar' });

const result = await deno.getReleases({
packageName: 'https://deno.land/std',
Expand All @@ -50,11 +54,21 @@ describe('modules/datasource/deno/index', () => {
sourceUrl: 'https://github.com/denoland/deno_std',
releaseTimestamp: '2022-10-20T12:10:21.592Z',
},
{
version: '0.161.0',
},
],
tags: {
popularity: 'top_5_percent',
},
});

expect(logger.logger.warn).toHaveBeenCalledWith(
expect.objectContaining({
err: expect.any(ZodError),
}),
`Deno: failed to get version details for 0.161.0`
);
});

it('throws error if module endpoint fails', async () => {
Expand Down
50 changes: 19 additions & 31 deletions lib/modules/datasource/deno/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,7 @@ import * as semanticVersioning from '../../versioning/semver';
import { Datasource } from '../datasource';
import type { Release } from '../index';
import type { GetReleasesConfig, ReleaseResult } from '../types';
import type {
DenoAPIModuleResponse,
DenoAPIModuleVersionResponse,
ReleaseMap,
} from './types';
import { createSourceURL, tagsToRecord } from './utils';
import { DenoAPIModuleResponse, DenoAPIModuleVersionResponse } from './schema';

export class DenoDatasource extends Datasource {
static readonly id = 'deno';
Expand Down Expand Up @@ -45,7 +40,7 @@ export class DenoDatasource extends Datasource {
const massagedRegistryUrl = registryUrl!;

const extractResult = regEx(
'^(https://deno.land/)(?<rawPackageName>[^@\\s]+)'
/^(https:\/\/deno.land\/)(?<rawPackageName>[^@\s]+)/
).exec(packageName);
const rawPackageName = extractResult?.groups?.rawPackageName;
if (is.nullOrUndefined(rawPackageName)) {
Expand Down Expand Up @@ -73,17 +68,17 @@ export class DenoDatasource extends Datasource {
key: (moduleAPIURL) => moduleAPIURL,
})
async getReleaseResult(moduleAPIURL: string): Promise<ReleaseResult> {
const { versions, tags } = (
await this.http.getJson<DenoAPIModuleResponse>(moduleAPIURL)
).body;

const releasesCache =
(await packageCache.get<ReleaseMap>(
const releasesCache: Record<string, Release> =
(await packageCache.get(
`datasource-${DenoDatasource.id}-details`,
moduleAPIURL
)) ?? {};
let cacheModified = false;

const {
body: { versions, tags },
} = await this.http.getJson(moduleAPIURL, DenoAPIModuleResponse);

// get details for the versions
const releases = await pMap(
versions,
Expand All @@ -95,8 +90,16 @@ export class DenoDatasource extends Datasource {
}

// https://apiland.deno.dev/v2/modules/postgres/v0.17.0
const release = await this.getReleaseDetails(
joinUrlParts(moduleAPIURL, version)
const url = joinUrlParts(moduleAPIURL, version);
const { body: release } = await this.http.getJson(
url,
DenoAPIModuleVersionResponse.catch(({ error: err }) => {
logger.warn(
{ err },
`Deno: failed to get version details for ${version}`
);
return { version };
})
);

releasesCache[release.version] = release;
Expand All @@ -117,21 +120,6 @@ export class DenoDatasource extends Datasource {
);
}

return {
releases,
tags: tagsToRecord(tags),
};
}

async getReleaseDetails(moduleAPIVersionURL: string): Promise<Release> {
const { version, uploaded_at, upload_options } = (
await this.http.getJson<DenoAPIModuleVersionResponse>(moduleAPIVersionURL)
).body;
return {
version,
gitRef: upload_options.ref,
releaseTimestamp: uploaded_at,
sourceUrl: createSourceURL(upload_options),
};
return { releases, tags };
}
}
44 changes: 44 additions & 0 deletions lib/modules/datasource/deno/schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { z } from 'zod';
import { getSourceUrl as getGithubSourceUrl } from '../../../util/github/url';
import { looseArray } from '../../../util/schema-utils';
import type { Release } from '../types';

export const DenoApiTag = z.object({
kind: z.string(),
value: z.string(),
});

export const DenoAPIModuleResponse = z.object({
tags: looseArray(DenoApiTag).transform((tags) => {
const record: Record<string, string> = {};
for (const { kind, value } of tags) {
record[kind] = value;
}
return record;
}),
versions: z.array(z.string()),
});

export const DenoAPIUploadOptions = z.object({
ref: z.string(),
type: z.union([z.literal('github'), z.unknown()]),
repository: z.string(),
subdir: z.string().optional(),
});

export const DenoAPIModuleVersionResponse = z
.object({
upload_options: DenoAPIUploadOptions,
uploaded_at: z.string(),
version: z.string(),
})
.transform(
({ version, uploaded_at: releaseTimestamp, upload_options }): Release => {
let sourceUrl: string | undefined = undefined;
const { type, repository, ref: gitRef } = upload_options;
if (type === 'github') {
sourceUrl = getGithubSourceUrl(repository);
}
return { version, gitRef, releaseTimestamp, sourceUrl };
}
);
34 changes: 0 additions & 34 deletions lib/modules/datasource/deno/types.ts

This file was deleted.

22 changes: 0 additions & 22 deletions lib/modules/datasource/deno/utils.ts

This file was deleted.

0 comments on commit 00c8f90

Please sign in to comment.