mirror of
https://github.com/renovatebot/renovate.git
synced 2026-11-01 02:00:10 +00:00
196101a6bb
* chore(deps): update dependency oxlint-tsgolint to v0.25.0 | datasource | package | from | to | | ---------- | --------------- | ------ | ------ | | npm | oxlint-tsgolint | 0.23.0 | 0.25.0 | * chore: fix new no-unnecessary-type-assertion findings Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Sebastian Poxhofer <sebastian.poxhofer@stedi.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
124 lines
3.7 KiB
TypeScript
124 lines
3.7 KiB
TypeScript
import { logger } from '../../../logger/index.ts';
|
|
import * as packageCache from '../../../util/cache/package/index.ts';
|
|
import { toSha256 } from '../../../util/hash.ts';
|
|
import type { Http } from '../../../util/http/index.ts';
|
|
import type { AsyncResult } from '../../../util/result.ts';
|
|
import { Result } from '../../../util/result.ts';
|
|
import { parseUrl } from '../../../util/url.ts';
|
|
import type { ReleaseResult } from '../types.ts';
|
|
import { getV1Releases } from './common.ts';
|
|
|
|
interface CacheRecord {
|
|
hash: string;
|
|
data: ReleaseResult;
|
|
isFallback?: true;
|
|
}
|
|
|
|
function hashVersions(versions: string[]): string {
|
|
return toSha256(versions.sort().join(','));
|
|
}
|
|
|
|
function hashReleases(releases: ReleaseResult): string {
|
|
return hashVersions(releases.releases.map((release) => release.version));
|
|
}
|
|
|
|
interface CacheNotFoundError {
|
|
type: 'cache-not-found';
|
|
}
|
|
interface CacheStaleError {
|
|
type: 'cache-stale';
|
|
cache: CacheRecord;
|
|
}
|
|
interface CacheInvalidError {
|
|
type: 'cache-invalid';
|
|
}
|
|
type CacheLoadError = CacheNotFoundError | CacheStaleError;
|
|
type CacheError = CacheNotFoundError | CacheStaleError | CacheInvalidError;
|
|
|
|
export class MetadataCache {
|
|
private readonly http: Http;
|
|
|
|
constructor(http: Http) {
|
|
this.http = http;
|
|
}
|
|
|
|
async getRelease(
|
|
registryUrl: string,
|
|
packageName: string,
|
|
versions: string[],
|
|
): Promise<ReleaseResult> {
|
|
const cacheNs = `datasource-rubygems`;
|
|
const cacheKey = `metadata-cache:${registryUrl}:${packageName}`;
|
|
const versionsHash = hashVersions(versions);
|
|
|
|
function loadCache(): AsyncResult<ReleaseResult, CacheLoadError> {
|
|
return Result.wrapNullable<CacheRecord, CacheLoadError, CacheLoadError>(
|
|
packageCache.get<CacheRecord>(cacheNs, cacheKey),
|
|
{ type: 'cache-not-found' },
|
|
).transform((cache) => {
|
|
return versionsHash === cache.hash
|
|
? Result.ok(cache.data)
|
|
: Result.err({ type: 'cache-stale', cache });
|
|
});
|
|
}
|
|
|
|
async function saveCache(
|
|
cache: CacheRecord,
|
|
ttlMinutes = 100 * 24 * 60,
|
|
ttlDelta = 10 * 24 * 60,
|
|
): Promise<void> {
|
|
const registryHostname = parseUrl(registryUrl)?.hostname;
|
|
if (registryHostname === 'rubygems.org') {
|
|
const ttlRandomDelta = Math.floor(Math.random() * ttlDelta);
|
|
const ttl = ttlMinutes + ttlRandomDelta;
|
|
await packageCache.set(cacheNs, cacheKey, cache, ttl);
|
|
}
|
|
}
|
|
|
|
return await loadCache()
|
|
.catch((err) =>
|
|
getV1Releases(this.http, registryUrl, packageName).transform(
|
|
async (
|
|
data: ReleaseResult,
|
|
): Promise<Result<ReleaseResult, CacheError>> => {
|
|
const dataHash = hashReleases(data);
|
|
if (dataHash === versionsHash) {
|
|
await saveCache({
|
|
hash: dataHash,
|
|
data,
|
|
});
|
|
return Result.ok(data);
|
|
}
|
|
|
|
/**
|
|
* Return stale cache for 24 hours,
|
|
* if metadata is inconsistent with versions list.
|
|
*/
|
|
if (err.type === 'cache-stale') {
|
|
const staleCache = err.cache;
|
|
if (!staleCache.isFallback) {
|
|
await saveCache(
|
|
{ ...staleCache, isFallback: true },
|
|
24 * 60,
|
|
0,
|
|
);
|
|
}
|
|
return Result.ok(staleCache.data);
|
|
}
|
|
|
|
return Result.err({ type: 'cache-invalid' });
|
|
},
|
|
),
|
|
)
|
|
.catch((err) => {
|
|
logger.debug(
|
|
{ err },
|
|
'Rubygems: error fetching rubygems data, falling back to versions-only result',
|
|
);
|
|
const releases = versions.map((version) => ({ version }));
|
|
return Result.ok({ releases });
|
|
})
|
|
.unwrapOrThrow();
|
|
}
|
|
}
|