Skip to content

Commit 748b258

Browse files
zharinovrarkins
andauthored
feat(crate): Support releaseTimestamp (#31467)
Co-authored-by: Rhys Arkins <[email protected]>
1 parent b1e42a0 commit 748b258

File tree

3 files changed

+88
-1
lines changed

3 files changed

+88
-1
lines changed

lib/modules/datasource/crate/index.spec.ts

+42
Original file line numberDiff line numberDiff line change
@@ -389,4 +389,46 @@ describe('modules/datasource/crate/index', () => {
389389
).toReject();
390390
});
391391
});
392+
393+
describe('postprocessRelease', () => {
394+
const datasource = new CrateDatasource();
395+
396+
it('no-op for registries other than crates.io', async () => {
397+
const releaseOrig = { version: '4.5.17' };
398+
399+
const res = await datasource.postprocessRelease(
400+
{
401+
packageName: 'clap',
402+
registryUrl: 'https://example.com',
403+
},
404+
releaseOrig,
405+
);
406+
407+
expect(res).toBe(releaseOrig);
408+
});
409+
410+
it('fetches releaseTimestamp', async () => {
411+
httpMock
412+
.scope(API_BASE_URL)
413+
.get('/crates/clap/4.5.17')
414+
.reply(200, {
415+
version: {
416+
created_at: '2024-09-04T19:16:41.355243+00:00',
417+
},
418+
});
419+
420+
const res = await datasource.postprocessRelease(
421+
{
422+
packageName: 'clap',
423+
registryUrl: 'https://crates.io',
424+
},
425+
{ version: '4.5.17' },
426+
);
427+
428+
expect(res).toEqual({
429+
version: '4.5.17',
430+
releaseTimestamp: '2024-09-04T19:16:41.355243+00:00',
431+
});
432+
});
433+
});
392434
});

lib/modules/datasource/crate/index.ts

+35-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,14 @@ import { newlineRegex, regEx } from '../../../util/regex';
1111
import { joinUrlParts, parseUrl } from '../../../util/url';
1212
import * as cargoVersioning from '../../versioning/cargo';
1313
import { Datasource } from '../datasource';
14-
import type { GetReleasesConfig, Release, ReleaseResult } from '../types';
14+
import type {
15+
GetReleasesConfig,
16+
PostprocessReleaseConfig,
17+
PostprocessReleaseResult,
18+
Release,
19+
ReleaseResult,
20+
} from '../types';
21+
import { ReleaseTimestampSchema } from './schema';
1522
import type {
1623
CrateMetadata,
1724
CrateRecord,
@@ -371,4 +378,31 @@ export class CrateDatasource extends Datasource {
371378

372379
return [packageName.slice(0, 2), packageName.slice(2, 4), packageName];
373380
}
381+
382+
@cache({
383+
namespace: `datasource-crate`,
384+
key: (
385+
{ registryUrl, packageName }: PostprocessReleaseConfig,
386+
{ version }: Release,
387+
) => `postprocessRelease:${registryUrl}:${packageName}:${version}`,
388+
ttlMinutes: 7 * 24 * 60,
389+
cacheable: ({ registryUrl }: PostprocessReleaseConfig, _: Release) =>
390+
registryUrl === 'https://crates.io',
391+
})
392+
override async postprocessRelease(
393+
{ packageName, registryUrl }: PostprocessReleaseConfig,
394+
release: Release,
395+
): Promise<PostprocessReleaseResult> {
396+
if (registryUrl !== 'https://crates.io') {
397+
return release;
398+
}
399+
400+
const url = `https://crates.io/api/v1/crates/${packageName}/${release.version}`;
401+
const { body: releaseTimestamp } = await this.http.getJson(
402+
url,
403+
ReleaseTimestampSchema,
404+
);
405+
release.releaseTimestamp = releaseTimestamp;
406+
return release;
407+
}
374408
}
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { z } from 'zod';
2+
3+
export const ReleaseTimestampSchema = z
4+
.object({
5+
version: z.object({
6+
created_at: z.string(),
7+
}),
8+
})
9+
.transform(({ version: { created_at } }) => created_at)
10+
.nullable()
11+
.catch(null);

0 commit comments

Comments
 (0)