diff --git a/lib/modules/datasource/bitbucket-tags/index.ts b/lib/modules/datasource/bitbucket-tags/index.ts index c41a68add215817bdcdd80d91daf02b4c89e3d14..7a2457c0c3a324828c391b5e88edd1466d64ad61 100644 --- a/lib/modules/datasource/bitbucket-tags/index.ts +++ b/lib/modules/datasource/bitbucket-tags/index.ts @@ -1,4 +1,5 @@ import { cache } from '../../../util/cache/package/decorator'; +import type { PackageCacheNamespace } from '../../../util/cache/package/types'; import { BitbucketHttp } from '../../../util/http/bitbucket'; import { ensureTrailingSlash } from '../../../util/url'; import type { PagedResult, RepoInfoBody } from '../../platform/bitbucket/types'; @@ -17,7 +18,7 @@ export class BitbucketTagsDatasource extends Datasource { static readonly defaultRegistryUrls = ['https://bitbucket.org']; - static readonly cacheNamespace = `datasource-${BitbucketTagsDatasource.id}`; + static readonly cacheNamespace: PackageCacheNamespace = `datasource-${BitbucketTagsDatasource.id}`; constructor() { super(BitbucketTagsDatasource.id); diff --git a/lib/modules/datasource/git-refs/base.ts b/lib/modules/datasource/git-refs/base.ts index 261a0a8543aa2c6c4ab383f870f7c8165d9fe714..36bf5aacde17b889603f9641183dc695e903c193 100644 --- a/lib/modules/datasource/git-refs/base.ts +++ b/lib/modules/datasource/git-refs/base.ts @@ -13,16 +13,18 @@ import type { RawRefs } from './types'; const refMatch = regEx(/(?<hash>.*?)\s+refs\/(?<type>.*?)\/(?<value>.*)/); const headMatch = regEx(/(?<hash>.*?)\s+HEAD/); +const gitId = 'git'; + // TODO: extract to a separate directory structure (#10532) export abstract class GitDatasource extends Datasource { - static id = 'git'; + static id = gitId; constructor(id: string) { super(id); } @cache({ - namespace: `datasource-${GitDatasource.id}`, + namespace: `datasource-${gitId}`, key: ({ packageName }: GetReleasesConfig) => packageName, }) async getRawRefs({ diff --git a/lib/modules/datasource/gitea-releases/index.ts b/lib/modules/datasource/gitea-releases/index.ts index a679c7786c3fda983d284443fe40274f4cffb306..66d41f61c11ca90f1534b7e5d00b87b33e71e90b 100644 --- a/lib/modules/datasource/gitea-releases/index.ts +++ b/lib/modules/datasource/gitea-releases/index.ts @@ -1,4 +1,5 @@ import { cache } from '../../../util/cache/package/decorator'; +import type { PackageCacheNamespace } from '../../../util/cache/package/types'; import { GiteaHttp } from '../../../util/http/gitea'; import { Datasource } from '../datasource'; import { GiteaTagsDatasource } from '../gitea-tags'; @@ -13,7 +14,7 @@ export class GiteaReleasesDatasource extends Datasource { static readonly defaultRegistryUrls = ['https://gitea.com']; - private static readonly cacheNamespace = `datasource-${GiteaReleasesDatasource.id}`; + private static readonly cacheNamespace: PackageCacheNamespace = `datasource-${GiteaReleasesDatasource.id}`; constructor() { super(GiteaReleasesDatasource.id); diff --git a/lib/modules/datasource/gitea-tags/index.ts b/lib/modules/datasource/gitea-tags/index.ts index 7dd85b5e6e9391e000cd1799c2ac09e2e6077c55..d177a50f560e41ffbb2c4ae05f2049c103480540 100644 --- a/lib/modules/datasource/gitea-tags/index.ts +++ b/lib/modules/datasource/gitea-tags/index.ts @@ -1,4 +1,5 @@ import { cache } from '../../../util/cache/package/decorator'; +import type { PackageCacheNamespace } from '../../../util/cache/package/types'; import { GiteaHttp } from '../../../util/http/gitea'; import { regEx } from '../../../util/regex'; import { ensureTrailingSlash } from '../../../util/url'; @@ -13,7 +14,7 @@ export class GiteaTagsDatasource extends Datasource { static readonly defaultRegistryUrls = ['https://gitea.com']; - private static readonly cacheNamespace = `datasource-${GiteaTagsDatasource.id}`; + private static readonly cacheNamespace: PackageCacheNamespace = `datasource-${GiteaTagsDatasource.id}`; constructor() { super(GiteaTagsDatasource.id); diff --git a/lib/modules/datasource/terraform-module/base.ts b/lib/modules/datasource/terraform-module/base.ts index e88b16eaf15a96afb4d2ddc5a5fce2f981d0cf1a..24f6a62493e9494090086b41cd80c44dca8ec1ac 100644 --- a/lib/modules/datasource/terraform-module/base.ts +++ b/lib/modules/datasource/terraform-module/base.ts @@ -5,12 +5,14 @@ import { ensureTrailingSlash } from '../../../util/url'; import { Datasource } from '../datasource'; import type { ServiceDiscoveryResult } from './types'; +const terraformId = 'terraform'; + // TODO: extract to a separate directory structure (#10532) export abstract class TerraformDatasource extends Datasource { - static id = 'terraform'; + static id = terraformId; @cache({ - namespace: `datasource-${TerraformDatasource.id}`, + namespace: `datasource-${terraformId}`, key: (registryUrl: string) => TerraformDatasource.getDiscoveryUrl(registryUrl), ttlMinutes: 1440, diff --git a/lib/util/cache/package/decorator.spec.ts b/lib/util/cache/package/decorator.spec.ts index 7dea4e7e6c52713d6a4dc1303f0d8620bc1669f7..c8716c410f3313590875c72501de41066651f7ec 100644 --- a/lib/util/cache/package/decorator.spec.ts +++ b/lib/util/cache/package/decorator.spec.ts @@ -26,7 +26,7 @@ describe('util/cache/package/decorator', () => { it('should cache string', async () => { class Class { - @cache({ namespace: 'some-namespace', key: 'some-key' }) + @cache({ namespace: '_test-namespace', key: 'some-key' }) public fn(): Promise<string> { return getValue(); } @@ -39,7 +39,7 @@ describe('util/cache/package/decorator', () => { expect(getValue).toHaveBeenCalledTimes(1); expect(setCache).toHaveBeenCalledExactlyOnceWith( - 'some-namespace', + '_test-namespace', 'cache-decorator:some-key', { cachedAt: expect.any(String), value: '111' }, 30, @@ -48,7 +48,11 @@ describe('util/cache/package/decorator', () => { it('disables cache if cacheability check is false', async () => { class Class { - @cache({ namespace: 'namespace', key: 'key', cacheable: () => false }) + @cache({ + namespace: '_test-namespace', + key: 'key', + cacheable: () => false, + }) public fn(): Promise<string | null> { return getValue(); } @@ -65,7 +69,7 @@ describe('util/cache/package/decorator', () => { it('caches null values', async () => { class Class { - @cache({ namespace: 'namespace', key: 'key' }) + @cache({ namespace: '_test-namespace', key: 'key' }) public async fn(val: string | null): Promise<string | null> { await getValue(); return val; @@ -79,7 +83,7 @@ describe('util/cache/package/decorator', () => { expect(getValue).toHaveBeenCalledTimes(1); expect(setCache).toHaveBeenCalledExactlyOnceWith( - 'namespace', + '_test-namespace', 'cache-decorator:key', { cachedAt: expect.any(String), value: null }, 30, @@ -88,7 +92,7 @@ describe('util/cache/package/decorator', () => { it('does not cache undefined', async () => { class Class { - @cache({ namespace: 'namespace', key: 'key' }) + @cache({ namespace: '_test-namespace', key: 'key' }) public async fn(): Promise<string | undefined> { await getValue(); return undefined; @@ -112,23 +116,23 @@ describe('util/cache/package/decorator', () => { class Class { @cache({ - namespace: (prefix: string, arg: Arg) => `${prefix}-${arg.foo}`, - key: (prefix: string, arg: Arg) => `${prefix}-${arg.bar}`, + namespace: (prefix: '_test', arg: Arg) => `${prefix}-${arg.foo}`, + key: (prefix: '_test', arg: Arg) => `${prefix}-${arg.bar}`, }) - public fn(_prefix: string, _arg: Arg): Promise<string> { + public fn(_prefix: '_test', _arg: Arg): Promise<string> { return getValue(); } } const obj = new Class(); const arg: Arg = { foo: 'namespace', bar: 'key' }; - expect(await obj.fn('some', arg)).toBe('111'); - expect(await obj.fn('some', arg)).toBe('111'); + expect(await obj.fn('_test', arg)).toBe('111'); + expect(await obj.fn('_test', arg)).toBe('111'); expect(getValue).toHaveBeenCalledTimes(1); expect(setCache).toHaveBeenCalledExactlyOnceWith( - 'some-namespace', - 'cache-decorator:some-key', + '_test-namespace', + 'cache-decorator:_test-key', { cachedAt: expect.any(String), value: '111' }, 30, ); @@ -140,7 +144,7 @@ describe('util/cache/package/decorator', () => { return getValue(); } } - const decorator = cache({ namespace: 'namespace', key: 'key' }); + const decorator = cache({ namespace: '_test-namespace', key: 'key' }); const fn = decorator(Class.prototype, 'fn', undefined as never); expect(await fn.value?.()).toBe('111'); @@ -149,7 +153,7 @@ describe('util/cache/package/decorator', () => { expect(getValue).toHaveBeenCalledTimes(1); expect(setCache).toHaveBeenCalledExactlyOnceWith( - 'namespace', + '_test-namespace', 'cache-decorator:key', { cachedAt: expect.any(String), value: '111' }, 30, @@ -159,7 +163,7 @@ describe('util/cache/package/decorator', () => { describe('Fallbacks with hard TTL', () => { class Class { @cache({ - namespace: 'namespace', + namespace: '_test-namespace', key: 'key', ttlMinutes: 1, }) @@ -185,7 +189,7 @@ describe('util/cache/package/decorator', () => { expect(await obj.getReleases()).toBe('111'); expect(getValue).toHaveBeenCalledTimes(1); expect(setCache).toHaveBeenLastCalledWith( - 'namespace', + '_test-namespace', 'cache-decorator:key', { cachedAt: expect.any(String), value: '111' }, 2, @@ -195,7 +199,7 @@ describe('util/cache/package/decorator', () => { expect(await obj.getReleases()).toBe('222'); expect(getValue).toHaveBeenCalledTimes(2); expect(setCache).toHaveBeenLastCalledWith( - 'namespace', + '_test-namespace', 'cache-decorator:key', { cachedAt: expect.any(String), value: '222' }, 2, @@ -204,7 +208,7 @@ describe('util/cache/package/decorator', () => { it('overrides soft ttl and updates result', async () => { GlobalConfig.set({ - cacheTtlOverride: { namespace: 2 }, + cacheTtlOverride: { '_test-namespace': 2 }, cacheHardTtlMinutes: 3, }); const obj = new Class(); @@ -212,7 +216,7 @@ describe('util/cache/package/decorator', () => { expect(await obj.getReleases()).toBe('111'); expect(getValue).toHaveBeenCalledTimes(1); expect(setCache).toHaveBeenLastCalledWith( - 'namespace', + '_test-namespace', 'cache-decorator:key', { cachedAt: expect.any(String), value: '111' }, 3, @@ -227,7 +231,7 @@ describe('util/cache/package/decorator', () => { expect(await obj.getReleases()).toBe('222'); expect(getValue).toHaveBeenCalledTimes(2); expect(setCache).toHaveBeenLastCalledWith( - 'namespace', + '_test-namespace', 'cache-decorator:key', { cachedAt: expect.any(String), value: '222' }, 3, @@ -240,7 +244,7 @@ describe('util/cache/package/decorator', () => { expect(await obj.getReleases()).toBe('111'); expect(getValue).toHaveBeenCalledTimes(1); expect(setCache).toHaveBeenLastCalledWith( - 'namespace', + '_test-namespace', 'cache-decorator:key', { cachedAt: expect.any(String), value: '111' }, 2, @@ -259,7 +263,7 @@ describe('util/cache/package/decorator', () => { expect(await obj.getReleases()).toBe('111'); expect(getValue).toHaveBeenCalledTimes(1); expect(setCache).toHaveBeenLastCalledWith( - 'namespace', + '_test-namespace', 'cache-decorator:key', { cachedAt: expect.any(String), value: '111' }, 2, diff --git a/lib/util/cache/package/decorator.ts b/lib/util/cache/package/decorator.ts index bbdceb2c12be09736a80cd06c96838bc8dc0484d..a6da3b877067b004ec48ba3222ca780b46354bbb 100644 --- a/lib/util/cache/package/decorator.ts +++ b/lib/util/cache/package/decorator.ts @@ -3,10 +3,13 @@ import { DateTime } from 'luxon'; import { GlobalConfig } from '../../../config/global'; import { logger } from '../../../logger'; import { Decorator, decorate } from '../../decorator'; -import type { DecoratorCachedRecord } from './types'; +import type { DecoratorCachedRecord, PackageCacheNamespace } from './types'; import * as packageCache from '.'; type HashFunction<T extends any[] = any[]> = (...args: T) => string; +type NamespaceFunction<T extends any[] = any[]> = ( + ...args: T +) => PackageCacheNamespace; type BooleanFunction<T extends any[] = any[]> = (...args: T) => boolean; /** @@ -17,7 +20,7 @@ interface CacheParameters { * The cache namespace * Either a string or a hash function that generates a string */ - namespace: string | HashFunction; + namespace: PackageCacheNamespace | NamespaceFunction; /** * The cache key @@ -51,7 +54,7 @@ export function cache<T>({ return callback(); } - let finalNamespace: string | undefined; + let finalNamespace: PackageCacheNamespace | undefined; if (is.string(namespace)) { finalNamespace = namespace; } else if (is.function_(namespace)) { diff --git a/lib/util/cache/package/file.spec.ts b/lib/util/cache/package/file.spec.ts index 281ed5e20b8fd76013d1940c6ed42e9688ce4d9d..756162b194598c3037d1bbb6b19881bb4a93950f 100644 --- a/lib/util/cache/package/file.spec.ts +++ b/lib/util/cache/package/file.spec.ts @@ -4,34 +4,34 @@ import { cleanup, get, init, set } from './file'; describe('util/cache/package/file', () => { it('returns if uninitiated', async () => { - await set('test', 'key', 1234); - expect(await get('test', 'key')).toBeUndefined(); + await set('_test-namespace', 'key', 1234); + expect(await get('_test-namespace', 'key')).toBeUndefined(); }); it('gets null', async () => { init(os.tmpdir()); - expect(await get('test', 'missing-key')).toBeUndefined(); + expect(await get('_test-namespace', 'missing-key')).toBeUndefined(); }); it('sets and gets', async () => { init(os.tmpdir()); - await set('test', 'key', 1234); - expect(await get('test', 'key')).toBe(1234); + await set('_test-namespace', 'key', 1234); + expect(await get('_test-namespace', 'key')).toBe(1234); }); it('expires', async () => { init(os.tmpdir()); - await set('test', 'key', 1234, -5); - expect(await get('test', 'key')).toBeUndefined(); + await set('_test-namespace', 'key', 1234, -5); + expect(await get('_test-namespace', 'key')).toBeUndefined(); }); it('cleans up', async () => { const cacheFileName = init(os.tmpdir()); - await set('test', 'valid', 1234); - await set('test', 'expired', 1234, -5); + await set('_test-namespace', 'valid', 1234); + await set('_test-namespace', 'expired', 1234, -5); await cacache.put(cacheFileName, 'invalid', 'not json'); await cleanup(); const entries = await cacache.ls(cacheFileName); - expect(Object.keys(entries)).toEqual(['test-valid']); + expect(Object.keys(entries)).toEqual(['_test-namespace-valid']); }); }); diff --git a/lib/util/cache/package/file.ts b/lib/util/cache/package/file.ts index 2669478986cf4197f010deb0a3c6114cb7fa842d..9c57cb3ae8596ba7d216ffbd0bf837774504712a 100644 --- a/lib/util/cache/package/file.ts +++ b/lib/util/cache/package/file.ts @@ -3,20 +3,24 @@ import { DateTime } from 'luxon'; import upath from 'upath'; import { logger } from '../../../logger'; import { compressToBase64, decompressFromBase64 } from '../../compress'; +import type { PackageCacheNamespace } from './types'; -function getKey(namespace: string, key: string): string { +function getKey(namespace: PackageCacheNamespace, key: string): string { return `${namespace}-${key}`; } let cacheFileName: string; -async function rm(namespace: string, key: string): Promise<void> { +async function rm( + namespace: PackageCacheNamespace, + key: string, +): Promise<void> { logger.trace({ namespace, key }, 'Removing cache entry'); await cacache.rm.entry(cacheFileName, getKey(namespace, key)); } export async function get<T = never>( - namespace: string, + namespace: PackageCacheNamespace, key: string, ): Promise<T | undefined> { if (!cacheFileName) { @@ -44,7 +48,7 @@ export async function get<T = never>( } export async function set( - namespace: string, + namespace: PackageCacheNamespace, key: string, value: unknown, ttlMinutes = 5, diff --git a/lib/util/cache/package/index.spec.ts b/lib/util/cache/package/index.spec.ts index 75fed5dad88389cd454de16f6afb3a0c26e9404a..b4cb217c4e7fea205b16fc28436900569b91b47f 100644 --- a/lib/util/cache/package/index.spec.ts +++ b/lib/util/cache/package/index.spec.ts @@ -10,8 +10,10 @@ describe('util/cache/package/index', () => { }); it('returns undefined if not initialized', async () => { - expect(await get('test', 'missing-key')).toBeUndefined(); - expect(await set('test', 'some-key', 'some-value', 5)).toBeUndefined(); + expect(await get('_test-namespace', 'missing-key')).toBeUndefined(); + expect( + await set('_test-namespace', 'some-key', 'some-value', 5), + ).toBeUndefined(); expect(async () => { await cleanup({}); }).not.toThrow(); @@ -20,17 +22,17 @@ describe('util/cache/package/index', () => { it('sets and gets file', async () => { await init({ cacheDir: 'some-dir' }); expect( - await set('some-namespace', 'some-key', 'some-value', 1), + await set('_test-namespace', 'some-key', 'some-value', 1), ).toBeUndefined(); - expect(await get('some-namespace', 'unknown-key')).toBeUndefined(); + expect(await get('_test-namespace', 'unknown-key')).toBeUndefined(); }); it('sets and gets redis', async () => { await init({ redisUrl: 'some-url' }); expect( - await set('some-namespace', 'some-key', 'some-value', 1), + await set('_test-namespace', 'some-key', 'some-value', 1), ).toBeUndefined(); - expect(await get('some-namespace', 'unknown-key')).toBeUndefined(); + expect(await get('_test-namespace', 'unknown-key')).toBeUndefined(); expect(await cleanup({ redisUrl: 'some-url' })).toBeUndefined(); }); @@ -38,9 +40,9 @@ describe('util/cache/package/index', () => { process.env.RENOVATE_X_SQLITE_PACKAGE_CACHE = 'true'; await init({ cacheDir: 'some-dir' }); expect( - await set('some-namespace', 'some-key', 'some-value', 1), + await set('_test-namespace', 'some-key', 'some-value', 1), ).toBeUndefined(); - expect(await get('some-namespace', 'unknown-key')).toBeUndefined(); + expect(await get('_test-namespace', 'unknown-key')).toBeUndefined(); expect(await cleanup({ redisUrl: 'some-url' })).toBeUndefined(); }); }); diff --git a/lib/util/cache/package/index.ts b/lib/util/cache/package/index.ts index 5afcf60cd1f1a3cdd529dcd202680c3720cf6e06..6151dee52c5f6419498de4f44f7a876999aca2b7 100644 --- a/lib/util/cache/package/index.ts +++ b/lib/util/cache/package/index.ts @@ -3,7 +3,7 @@ import * as memCache from '../memory'; import * as fileCache from './file'; import * as redisCache from './redis'; import { SqlitePackageCache } from './sqlite'; -import type { PackageCache } from './types'; +import type { PackageCache, PackageCacheNamespace } from './types'; let cacheProxy: PackageCache | undefined; @@ -12,7 +12,7 @@ function getGlobalKey(namespace: string, key: string): string { } export async function get<T = any>( - namespace: string, + namespace: PackageCacheNamespace, key: string, ): Promise<T | undefined> { if (!cacheProxy) { @@ -36,7 +36,7 @@ export async function get<T = any>( } export async function set( - namespace: string, + namespace: PackageCacheNamespace, key: string, value: unknown, minutes: number, diff --git a/lib/util/cache/package/redis.ts b/lib/util/cache/package/redis.ts index f1b8603d444bd54d738c3befd37fa875438e75ee..c803b9580428eb0ac77e139a4a69551270731406 100644 --- a/lib/util/cache/package/redis.ts +++ b/lib/util/cache/package/redis.ts @@ -3,11 +3,12 @@ import { DateTime } from 'luxon'; import { createClient } from 'redis'; import { logger } from '../../../logger'; import { compressToBase64, decompressFromBase64 } from '../../compress'; +import type { PackageCacheNamespace } from './types'; let client: ReturnType<typeof createClient> | undefined; let rprefix: string | undefined; -function getKey(namespace: string, key: string): string { +function getKey(namespace: PackageCacheNamespace, key: string): string { return `${rprefix}${namespace}-${key}`; } @@ -20,13 +21,16 @@ export async function end(): Promise<void> { } } -async function rm(namespace: string, key: string): Promise<void> { +async function rm( + namespace: PackageCacheNamespace, + key: string, +): Promise<void> { logger.trace({ rprefix, namespace, key }, 'Removing cache entry'); await client?.del(getKey(namespace, key)); } export async function get<T = never>( - namespace: string, + namespace: PackageCacheNamespace, key: string, ): Promise<T | undefined> { if (!client) { @@ -56,7 +60,7 @@ export async function get<T = never>( } export async function set( - namespace: string, + namespace: PackageCacheNamespace, key: string, value: unknown, ttlMinutes = 5, diff --git a/lib/util/cache/package/sqlite.spec.ts b/lib/util/cache/package/sqlite.spec.ts index 93edaa1331ab9d0fee9ef15ef92433435039f0e3..ea93a84f52ca027a127f7b58a1770b62c7604904 100644 --- a/lib/util/cache/package/sqlite.spec.ts +++ b/lib/util/cache/package/sqlite.spec.ts @@ -19,16 +19,18 @@ function withSqlite<T>( describe('util/cache/package/sqlite', () => { it('should get undefined', async () => { - const res = await withSqlite((sqlite) => sqlite.get('foo', 'bar')); + const res = await withSqlite((sqlite) => + sqlite.get('_test-namespace', 'bar'), + ); expect(res).toBeUndefined(); }); it('should set and get', async () => { const res = await withSqlite(async (sqlite) => { - await sqlite.set('foo', 'bar', { foo: 'foo' }); - await sqlite.set('foo', 'bar', { bar: 'bar' }); - await sqlite.set('foo', 'bar', { baz: 'baz' }); - return sqlite.get('foo', 'bar'); + await sqlite.set('_test-namespace', 'bar', { foo: 'foo' }); + await sqlite.set('_test-namespace', 'bar', { bar: 'bar' }); + await sqlite.set('_test-namespace', 'bar', { baz: 'baz' }); + return sqlite.get('_test-namespace', 'bar'); }); expect(res).toEqual({ baz: 'baz' }); }); @@ -39,11 +41,11 @@ describe('util/cache/package/sqlite', () => { GlobalConfig.set({ cacheDir: path }); const client1 = await SqlitePackageCache.init(path); - await client1.set('foo', 'bar', 'baz'); + await client1.set('_test-namespace', 'bar', 'baz'); await client1.cleanup(); const client2 = await SqlitePackageCache.init(path); - const res = await client2.get('foo', 'bar'); + const res = await client2.get('_test-namespace', 'bar'); await client2.cleanup(); return res; }, diff --git a/lib/util/cache/package/sqlite.ts b/lib/util/cache/package/sqlite.ts index d8d6967e8028049ef8467c88a73abce2668053ad..486a6ac1048ac0db6ccc4056b30509b798ff8bbe 100644 --- a/lib/util/cache/package/sqlite.ts +++ b/lib/util/cache/package/sqlite.ts @@ -6,6 +6,7 @@ import { exists } from 'fs-extra'; import * as upath from 'upath'; import { logger } from '../../../logger'; import { ensureDir } from '../../fs'; +import type { PackageCacheNamespace } from './types'; const brotliCompress = promisify(zlib.brotliCompress); const brotliDecompress = promisify(zlib.brotliDecompress); @@ -103,7 +104,7 @@ export class SqlitePackageCache { } async set( - namespace: string, + namespace: PackageCacheNamespace, key: string, value: unknown, ttlMinutes = 5, @@ -115,7 +116,7 @@ export class SqlitePackageCache { } async get<T = unknown>( - namespace: string, + namespace: PackageCacheNamespace, key: string, ): Promise<T | undefined> { const data = this.getStatement.get({ namespace, key }) as diff --git a/lib/util/cache/package/types.ts b/lib/util/cache/package/types.ts index 700ef95c88a1b1541dc79934109428ba108591b3..57a5ffc1dc3a1a26abf1a209a4d92dbeed4a9f4b 100644 --- a/lib/util/cache/package/types.ts +++ b/lib/util/cache/package/types.ts @@ -15,3 +15,93 @@ export interface DecoratorCachedRecord { value: unknown; cachedAt: string; } + +export type PackageCacheNamespace = + | '_test-namespace' + | 'changelog-bitbucket-notes@v2' + | 'changelog-bitbucket-release' + | 'changelog-gitea-notes@v2' + | 'changelog-gitea-release' + | 'changelog-github-notes@v2' + | 'changelog-github-release' + | 'changelog-gitlab-notes@v2' + | 'changelog-gitlab-release' + | 'datasource-artifactory' + | 'datasource-aws-machine-image' + | 'datasource-aws-rds' + | 'datasource-azure-bicep-resource' + | 'datasource-azure-pipelines-tasks' + | 'datasource-bazel' + | 'datasource-bitbucket-tags' + | 'datasource-conan-revisions' + | 'datasource-conan' + | 'datasource-conda' + | 'datasource-cpan' + | 'datasource-crate-metadata' + | 'datasource-crate' + | 'datasource-deno-details' + | 'datasource-deno-versions' + | 'datasource-deno' + | 'datasource-docker-architecture' + | 'datasource-docker-digest' + | 'datasource-docker-hub-tags' + | 'datasource-docker-imageconfig' + | 'datasource-docker-labels' + | 'datasource-docker-releases-v2' + | 'datasource-docker-tags' + | 'datasource-dotnet-version' + | 'datasource-endoflife-date' + | 'datasource-galaxy-collection-detailed-version' + | 'datasource-galaxy-collection' + | 'datasource-galaxy' + | 'datasource-git-refs' + | 'datasource-git-tags' + | 'datasource-git' + | 'datasource-gitea-releases' + | 'datasource-gitea-tags' + | 'datasource-github-releases' + | 'datasource-gitlab-packages' + | 'datasource-gitlab-releases' + | 'datasource-gitlab-tags-commit' + | 'datasource-gitlab-tags' + | 'datasource-go-direct' + | 'datasource-go-proxy' + | 'datasource-go' + | 'datasource-golang-version' + | 'datasource-gradle-version' + | 'datasource-helm' + | 'datasource-hermit-package' + | 'datasource-hermit-search-manifest' + | 'datasource-hex' + | 'datasource-hexpm-bob' + | 'datasource-java-version' + | 'datasource-maven:head-requests-timeout' + | 'datasource-maven:head-requests' + | 'datasource-maven:index-html-releases' + | 'datasource-maven:metadata-xml' + | 'datasource-node-version' + | 'datasource-npm:data' + | 'datasource-nuget' + | 'datasource-orb' + | 'datasource-packagist-org' + | 'datasource-packagist-public-files' + | 'datasource-packagist' + | 'datasource-pod' + | 'datasource-releases' + | 'datasource-repology-list' + | 'datasource-ruby-version' + | 'datasource-rubygems' + | 'datasource-terraform-module' + | 'datasource-terraform-provider-build-hashes' + | 'datasource-terraform-provider-builds' + | 'datasource-terraform-provider-releaseBackendIndex' + | 'datasource-terraform-provider-zip-hashes' + | 'datasource-terraform-provider' + | 'datasource-terraform' + | 'github-releases-datasource-v2' + | 'github-tags-datasource-v2' + | 'go' + | 'jenkins-plugins' + | 'merge-confidence' + | 'preset' + | 'url-sha256'; diff --git a/lib/util/github/graphql/cache-strategies/abstract-cache-strategy.ts b/lib/util/github/graphql/cache-strategies/abstract-cache-strategy.ts index 004fa16bfb4851a9337e3a06b7e0905a226740c3..47abb66e58455b394c3fc8e9016779e198001045 100644 --- a/lib/util/github/graphql/cache-strategies/abstract-cache-strategy.ts +++ b/lib/util/github/graphql/cache-strategies/abstract-cache-strategy.ts @@ -1,5 +1,6 @@ import { dequal } from 'dequal'; import { DateTime } from 'luxon'; +import type { PackageCacheNamespace } from '../../../cache/package/types'; import type { GithubDatasourceItem, GithubGraphqlCacheRecord, @@ -51,7 +52,7 @@ export abstract class AbstractGithubGraphqlCacheStrategy< ): Promise<void>; constructor( - protected readonly cacheNs: string, + protected readonly cacheNs: PackageCacheNamespace, protected readonly cacheKey: string, ) {} diff --git a/lib/util/github/graphql/cache-strategies/memory-cache-strategy.spec.ts b/lib/util/github/graphql/cache-strategies/memory-cache-strategy.spec.ts index 5d693996290f0385a2442b0251f84d50ead67ce4..5428923efe39c6cfd907d803fedfea4d14c956fc 100644 --- a/lib/util/github/graphql/cache-strategies/memory-cache-strategy.spec.ts +++ b/lib/util/github/graphql/cache-strategies/memory-cache-strategy.spec.ts @@ -44,31 +44,41 @@ describe('util/github/graphql/cache-strategies/memory-cache-strategy', () => { items, createdAt: isoTs('2022-10-01 15:30'), }; - memCache.set('github-graphql-cache:foo:bar', clone(cacheRecord)); + memCache.set( + 'github-graphql-cache:_test-namespace:bar', + clone(cacheRecord), + ); // At this moment, cache is valid let now = '2022-10-31 15:29:59'; mockTime(now); - let strategy = new GithubGraphqlMemoryCacheStrategy('foo', 'bar'); + let strategy = new GithubGraphqlMemoryCacheStrategy( + '_test-namespace', + 'bar', + ); let isPaginationDone = await strategy.reconcile([items['1']]); let res = await strategy.finalize(); expect(res).toEqual(Object.values(items)); expect(isPaginationDone).toBe(true); - expect(memCache.get('github-graphql-cache:foo:bar')).toEqual(cacheRecord); + expect(memCache.get('github-graphql-cache:_test-namespace:bar')).toEqual( + cacheRecord, + ); // One second later, the cache is invalid now = '2022-10-31 15:30:00'; mockTime(now); - strategy = new GithubGraphqlMemoryCacheStrategy('foo', 'bar'); + strategy = new GithubGraphqlMemoryCacheStrategy('_test-namespace', 'bar'); isPaginationDone = await strategy.reconcile([]); res = await strategy.finalize(); expect(res).toEqual([]); expect(isPaginationDone).toBe(false); - expect(memCache.get('github-graphql-cache:foo:bar')).toEqual(cacheRecord); + expect(memCache.get('github-graphql-cache:_test-namespace:bar')).toEqual( + cacheRecord, + ); }); it('reconciles old cache record with new items', async () => { @@ -81,7 +91,10 @@ describe('util/github/graphql/cache-strategies/memory-cache-strategy', () => { items: oldItems, createdAt: isoTs('2022-10-30 12:00'), }; - memCache.set('github-graphql-cache:foo:bar', clone(cacheRecord)); + memCache.set( + 'github-graphql-cache:_test-namespace:bar', + clone(cacheRecord), + ); const now = '2022-10-31 15:30'; mockTime(now); @@ -92,13 +105,16 @@ describe('util/github/graphql/cache-strategies/memory-cache-strategy', () => { }; const page = [newItem]; - const strategy = new GithubGraphqlMemoryCacheStrategy('foo', 'bar'); + const strategy = new GithubGraphqlMemoryCacheStrategy( + '_test-namespace', + 'bar', + ); const isPaginationDone = await strategy.reconcile(page); const res = await strategy.finalize(); expect(res).toEqual([...Object.values(oldItems), newItem]); expect(isPaginationDone).toBe(false); - expect(memCache.get('github-graphql-cache:foo:bar')).toEqual({ + expect(memCache.get('github-graphql-cache:_test-namespace:bar')).toEqual({ items: { ...oldItems, '4': newItem, @@ -117,7 +133,10 @@ describe('util/github/graphql/cache-strategies/memory-cache-strategy', () => { items: oldItems, createdAt: isoTs('2022-10-30 12:00'), }; - memCache.set('github-graphql-cache:foo:bar', clone(cacheRecord)); + memCache.set( + 'github-graphql-cache:_test-namespace:bar', + clone(cacheRecord), + ); const now = '2022-10-31 15:30'; mockTime(now); @@ -127,7 +146,10 @@ describe('util/github/graphql/cache-strategies/memory-cache-strategy', () => { { version: '4', releaseTimestamp: isoTs('2022-10-15 18:00') }, ].reverse(); - const strategy = new GithubGraphqlMemoryCacheStrategy('foo', 'bar'); + const strategy = new GithubGraphqlMemoryCacheStrategy( + '_test-namespace', + 'bar', + ); const isPaginationDone = await strategy.reconcile(page); expect(isPaginationDone).toBe(true); @@ -143,7 +165,10 @@ describe('util/github/graphql/cache-strategies/memory-cache-strategy', () => { items: oldItems, createdAt: isoTs('2022-12-31 12:00'), }; - memCache.set('github-graphql-cache:foo:bar', clone(cacheRecord)); + memCache.set( + 'github-graphql-cache:_test-namespace:bar', + clone(cacheRecord), + ); const now = '2022-12-31 23:59'; mockTime(now); @@ -155,11 +180,16 @@ describe('util/github/graphql/cache-strategies/memory-cache-strategy', () => { { version: '4', releaseTimestamp: isoTs('2022-12-31 13:00') }, ].reverse(); - const strategy = new GithubGraphqlMemoryCacheStrategy('foo', 'bar'); + const strategy = new GithubGraphqlMemoryCacheStrategy( + '_test-namespace', + 'bar', + ); const isPaginationDone = await strategy.reconcile(page); expect(isPaginationDone).toBe(true); - expect(memCache.get('github-graphql-cache:foo:bar')).toMatchObject({ + expect( + memCache.get('github-graphql-cache:_test-namespace:bar'), + ).toMatchObject({ items: { '1': { releaseTimestamp: isoTs('2022-12-31 10:00') }, '2': { releaseTimestamp: isoTs('2022-12-31 11:00') }, @@ -187,7 +217,10 @@ describe('util/github/graphql/cache-strategies/memory-cache-strategy', () => { items, createdAt: isoTs('2022-10-30 12:00'), }; - memCache.set('github-graphql-cache:foo:bar', clone(cacheRecord)); + memCache.set( + 'github-graphql-cache:_test-namespace:bar', + clone(cacheRecord), + ); const now = '2022-10-31 15:30'; mockTime(now); @@ -200,7 +233,10 @@ describe('util/github/graphql/cache-strategies/memory-cache-strategy', () => { items['8'], ].reverse(); - const strategy = new GithubGraphqlMemoryCacheStrategy('foo', 'bar'); + const strategy = new GithubGraphqlMemoryCacheStrategy( + '_test-namespace', + 'bar', + ); const isPaginationDone = await strategy.reconcile(page); const res = await strategy.finalize(); @@ -213,7 +249,7 @@ describe('util/github/graphql/cache-strategies/memory-cache-strategy', () => { { version: '8', releaseTimestamp: isoTs('2022-10-08 10:00') }, ]); expect(isPaginationDone).toBe(true); - expect(memCache.get('github-graphql-cache:foo:bar')).toEqual({ + expect(memCache.get('github-graphql-cache:_test-namespace:bar')).toEqual({ items: { '0': { version: '0', releaseTimestamp: isoTs('2022-09-30 10:00') }, '1': { version: '1', releaseTimestamp: isoTs('2022-10-01 10:00') }, diff --git a/lib/util/github/graphql/cache-strategies/package-cache-strategy.spec.ts b/lib/util/github/graphql/cache-strategies/package-cache-strategy.spec.ts index b07e7cc762a475d200aecfcaa4385031a17e19a7..166f206a7d33d691deddd701e5b6966bef43ed23 100644 --- a/lib/util/github/graphql/cache-strategies/package-cache-strategy.spec.ts +++ b/lib/util/github/graphql/cache-strategies/package-cache-strategy.spec.ts @@ -42,7 +42,10 @@ describe('util/github/graphql/cache-strategies/package-cache-strategy', () => { }; const page = [newItem, item3, item2, item1]; - const strategy = new GithubGraphqlPackageCacheStrategy('foo', 'bar'); + const strategy = new GithubGraphqlPackageCacheStrategy( + '_test-namespace', + 'bar', + ); const isPaginationDone = await strategy.reconcile(page); const res = await strategy.finalize(); @@ -50,7 +53,7 @@ describe('util/github/graphql/cache-strategies/package-cache-strategy', () => { expect(isPaginationDone).toBe(true); expect(cacheSet.mock.calls).toEqual([ [ - 'foo', + '_test-namespace', 'bar', { items: { diff --git a/lib/util/github/graphql/datasource-fetcher.spec.ts b/lib/util/github/graphql/datasource-fetcher.spec.ts index b95722867ddd1b47807f9dcf972405fa1ac8f468..8c5300702836807889e301eda015a580ec5777d5 100644 --- a/lib/util/github/graphql/datasource-fetcher.spec.ts +++ b/lib/util/github/graphql/datasource-fetcher.spec.ts @@ -27,7 +27,7 @@ const adapter: GithubGraphqlDatasourceAdapter< TestAdapterInput, TestAdapterOutput > = { - key: 'test-adapter', + key: '_test-namespace', query: ` items { pageInfo { diff --git a/lib/util/github/graphql/datasource-fetcher.ts b/lib/util/github/graphql/datasource-fetcher.ts index a8bb090fbc8b099a35b71df2ed1876ffc373bb47..82569082422a5b08e11029f0b92450732e8920f3 100644 --- a/lib/util/github/graphql/datasource-fetcher.ts +++ b/lib/util/github/graphql/datasource-fetcher.ts @@ -2,6 +2,7 @@ import AggregateError from 'aggregate-error'; import { logger } from '../../../logger'; import { ExternalHostError } from '../../../types/errors/external-host-error'; import * as memCache from '../../cache/memory'; +import type { PackageCacheNamespace } from '../../cache/package/types'; import type { GithubGraphqlResponse, GithubHttp, @@ -83,7 +84,7 @@ export class GithubGraphqlDatasourceFetcher< this.baseUrl = getApiBaseUrl(registryUrl).replace(/\/v3\/$/, '/'); // Replace for GHE } - private getCacheNs(): string { + private getCacheNs(): PackageCacheNamespace { return this.datasourceAdapter.key; } diff --git a/lib/util/github/graphql/types.ts b/lib/util/github/graphql/types.ts index fb39074109aeaff38df7924a4c8263d75df53722..b8dcab5ef1eb0020b97dce362239a61382deeadc 100644 --- a/lib/util/github/graphql/types.ts +++ b/lib/util/github/graphql/types.ts @@ -1,3 +1,5 @@ +import type { PackageCacheNamespace } from '../../cache/package/types'; + export interface GithubDatasourceItem { version: string; releaseTimestamp: string; @@ -13,7 +15,7 @@ export interface GithubGraphqlDatasourceAdapter< /** * Used for creating datasource-unique cache key */ - key: string; + key: PackageCacheNamespace; /** * Used to define datasource-unique GraphQL query diff --git a/lib/workers/repository/update/pr/changelog/release-notes.ts b/lib/workers/repository/update/pr/changelog/release-notes.ts index 4d78fba79e89f9817b7206f61b58eb9869ce607b..79d62f5d0ade941ca637356fafae836cb51a5c75 100644 --- a/lib/workers/repository/update/pr/changelog/release-notes.ts +++ b/lib/workers/repository/update/pr/changelog/release-notes.ts @@ -4,6 +4,7 @@ import MarkdownIt from 'markdown-it'; import { logger } from '../../../../../logger'; import * as memCache from '../../../../../util/cache/memory'; import * as packageCache from '../../../../../util/cache/package'; +import type { PackageCacheNamespace } from '../../../../../util/cache/package/types'; import { detectPlatform } from '../../../../../util/common'; import { linkify } from '../../../../../util/markdown'; import { newlineRegex, regEx } from '../../../../../util/regex'; @@ -425,7 +426,7 @@ export async function addReleaseNotes( }; const { repository, sourceDirectory, type: projectType } = input.project; - const cacheNamespace = `changelog-${projectType}-notes@v2`; + const cacheNamespace: PackageCacheNamespace = `changelog-${projectType}-notes@v2`; const cacheKeyPrefix = sourceDirectory ? `${repository}:${sourceDirectory}` : `${repository}`; diff --git a/lib/workers/repository/update/pr/changelog/source.ts b/lib/workers/repository/update/pr/changelog/source.ts index 1444e0d6f2f91d591e28baa43f6309f9647878f0..71a9f65caf8b4c4b08540efcc7fcf31753b1789c 100644 --- a/lib/workers/repository/update/pr/changelog/source.ts +++ b/lib/workers/repository/update/pr/changelog/source.ts @@ -4,6 +4,7 @@ import { getPkgReleases } from '../../../../../modules/datasource'; import type { Release } from '../../../../../modules/datasource/types'; import * as allVersioning from '../../../../../modules/versioning'; import * as packageCache from '../../../../../util/cache/package'; +import type { PackageCacheNamespace } from '../../../../../util/cache/package/types'; import { memoize } from '../../../../../util/memoize'; import { regEx } from '../../../../../util/regex'; import { parseUrl, trimSlashes } from '../../../../../util/url'; @@ -19,7 +20,7 @@ import type { } from './types'; export abstract class ChangeLogSource { - private readonly cacheNamespace: string; + private readonly cacheNamespace: PackageCacheNamespace; constructor( private readonly platform: ChangeLogPlatform,