renovate 42.92.13 → 42.92.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/instrumentation/decorator.js +7 -6
- package/dist/instrumentation/decorator.js.map +1 -1
- package/dist/instrumentation/instrumented.js +22 -0
- package/dist/instrumentation/instrumented.js.map +1 -0
- package/dist/logger/renovate-logger.js +3 -0
- package/dist/logger/renovate-logger.js.map +1 -1
- package/dist/modules/datasource/datasource.js +1 -0
- package/dist/modules/datasource/datasource.js.map +1 -1
- package/dist/modules/datasource/docker/dockerhub-cache.js +2 -0
- package/dist/modules/datasource/docker/dockerhub-cache.js.map +1 -1
- package/dist/modules/datasource/rubygems/metadata-cache.js +1 -0
- package/dist/modules/datasource/rubygems/metadata-cache.js.map +1 -1
- package/dist/modules/datasource/rubygems/versions-endpoint-cache.js +1 -0
- package/dist/modules/datasource/rubygems/versions-endpoint-cache.js.map +1 -1
- package/dist/modules/manager/bazel-module/bazelrc.js +7 -0
- package/dist/modules/manager/bazel-module/bazelrc.js.map +1 -1
- package/dist/modules/platform/bitbucket/pr-cache.js +2 -0
- package/dist/modules/platform/bitbucket/pr-cache.js.map +1 -1
- package/dist/modules/platform/bitbucket-server/pr-cache.js +4 -0
- package/dist/modules/platform/bitbucket-server/pr-cache.js.map +1 -1
- package/dist/modules/platform/forgejo/pr-cache.js +3 -0
- package/dist/modules/platform/forgejo/pr-cache.js.map +1 -1
- package/dist/modules/platform/gitea/pr-cache.js +3 -0
- package/dist/modules/platform/gitea/pr-cache.js.map +1 -1
- package/dist/modules/platform/github/api-cache.js +1 -0
- package/dist/modules/platform/github/api-cache.js.map +1 -1
- package/dist/modules/platform/gitlab/pr-cache.js +2 -0
- package/dist/modules/platform/gitlab/pr-cache.js.map +1 -1
- package/dist/util/cache/package/cached.js +62 -0
- package/dist/util/cache/package/cached.js.map +1 -0
- package/dist/util/cache/package/decorator.js +10 -44
- package/dist/util/cache/package/decorator.js.map +1 -1
- package/dist/util/cache/package/sqlite.js +1 -0
- package/dist/util/cache/package/sqlite.js.map +1 -1
- package/dist/util/cache/repository/impl/base.js +2 -0
- package/dist/util/cache/repository/impl/base.js.map +1 -1
- package/dist/util/git/instrument.js +1 -0
- package/dist/util/git/instrument.js.map +1 -1
- package/dist/util/github/graphql/cache-strategies/abstract-cache-strategy.js +3 -0
- package/dist/util/github/graphql/cache-strategies/abstract-cache-strategy.js.map +1 -1
- package/dist/util/github/graphql/datasource-fetcher.js +2 -0
- package/dist/util/github/graphql/datasource-fetcher.js.map +1 -1
- package/dist/util/http/cache/repository-http-cache-provider.js +1 -0
- package/dist/util/http/cache/repository-http-cache-provider.js.map +1 -1
- package/dist/util/http/http.js +1 -0
- package/dist/util/http/http.js.map +1 -1
- package/dist/util/lazy.js +1 -0
- package/dist/util/lazy.js.map +1 -1
- package/dist/util/result.js +2 -0
- package/dist/util/result.js.map +1 -1
- package/dist/util/template/index.js +1 -0
- package/dist/util/template/index.js.map +1 -1
- package/dist/workers/repository/config-migration/branch/commit-message.js +2 -0
- package/dist/workers/repository/config-migration/branch/commit-message.js.map +1 -1
- package/dist/workers/repository/update/pr/changelog/source.js +2 -0
- package/dist/workers/repository/update/pr/changelog/source.js.map +1 -1
- package/package.json +7 -3
- package/renovate-schema.json +2 -2
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
const require_rolldown_runtime = require('../_virtual/rolldown_runtime.js');
|
|
2
|
-
const
|
|
2
|
+
const require_instrumented = require('./instrumented.js');
|
|
3
3
|
let _opentelemetry_api = require("@opentelemetry/api");
|
|
4
4
|
|
|
5
5
|
//#region lib/instrumentation/decorator.ts
|
|
6
6
|
function instrumentStandalone({ name, attributes, ignoreParentSpan, kind = _opentelemetry_api.SpanKind.INTERNAL }, fn) {
|
|
7
|
-
return async
|
|
8
|
-
return await
|
|
7
|
+
return (async (...args) => {
|
|
8
|
+
return await require_instrumented.instrumented({
|
|
9
|
+
name,
|
|
9
10
|
attributes,
|
|
10
|
-
|
|
11
|
+
ignoreParentSpan,
|
|
11
12
|
kind
|
|
12
|
-
});
|
|
13
|
-
};
|
|
13
|
+
}, () => fn(...args));
|
|
14
|
+
});
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"decorator.js","names":["SpanKind","
|
|
1
|
+
{"version":3,"file":"decorator.js","names":["SpanKind","instrumented"],"sources":["../../lib/instrumentation/decorator.ts"],"sourcesContent":["import { SpanKind } from '@opentelemetry/api';\nimport type { Decorator } from '../util/decorator/index.ts';\nimport { decorate } from '../util/decorator/index.ts';\nimport { instrumented } from './instrumented.ts';\nimport type { SpanParameters } from './types.ts';\n\n/**\n * instruments a decorated method.\n */\nexport function instrument<T>({\n name,\n attributes,\n ignoreParentSpan,\n kind = SpanKind.INTERNAL,\n}: SpanParameters): Decorator<T> {\n return decorate(async ({ callback }) => {\n return await instrumented(\n { name, attributes, ignoreParentSpan, kind },\n callback,\n );\n });\n}\n\nexport function instrumentStandalone<T extends (...args: any[]) => any>(\n {\n name,\n attributes,\n ignoreParentSpan,\n kind = SpanKind.INTERNAL,\n }: SpanParameters,\n fn: T,\n): T {\n return (async (...args: any[]) => {\n return await instrumented(\n { name, attributes, ignoreParentSpan, kind },\n () => fn(...args),\n );\n }) as T;\n}\n"],"mappings":";;;;;AAuBA,SAAgB,qBACd,EACE,MACA,YACA,kBACA,OAAOA,4BAAS,YAElB,IACG;AACH,SAAQ,OAAO,GAAG,SAAgB;AAChC,SAAO,MAAMC,kCACX;GAAE;GAAM;GAAY;GAAkB;GAAM,QACtC,GAAG,GAAG,KAAK,CAClB"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
const require_index = require('./index.js');
|
|
2
|
+
|
|
3
|
+
//#region lib/instrumentation/instrumented.ts
|
|
4
|
+
/**
|
|
5
|
+
* Wraps an async function in an OpenTelemetry span.
|
|
6
|
+
*
|
|
7
|
+
* @param options - Instrumentation options
|
|
8
|
+
* @param fn - The async function to instrument
|
|
9
|
+
* @returns The result of the function
|
|
10
|
+
*/
|
|
11
|
+
function instrumented(options, fn) {
|
|
12
|
+
const { name, attributes, ignoreParentSpan, kind } = options;
|
|
13
|
+
return require_index.instrument(name, fn, {
|
|
14
|
+
attributes,
|
|
15
|
+
root: ignoreParentSpan,
|
|
16
|
+
kind
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
//#endregion
|
|
21
|
+
exports.instrumented = instrumented;
|
|
22
|
+
//# sourceMappingURL=instrumented.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instrumented.js","names":["instrument"],"sources":["../../lib/instrumentation/instrumented.ts"],"sourcesContent":["import type { SpanKind } from '@opentelemetry/api';\nimport { instrument } from './index.ts';\nimport type { RenovateSpanAttributes } from './types.ts';\n\ninterface InstrumentedOptions {\n /**\n * The name of the span.\n */\n name: string;\n\n /**\n * Attributes to add to the span.\n */\n attributes?: RenovateSpanAttributes;\n\n /**\n * When true, creates a root span instead of a child of the current span.\n * @default false\n */\n ignoreParentSpan?: boolean;\n\n /**\n * Type of span. Default: SpanKind.INTERNAL\n */\n kind?: SpanKind;\n}\n\n/**\n * Wraps an async function in an OpenTelemetry span.\n *\n * @param options - Instrumentation options\n * @param fn - The async function to instrument\n * @returns The result of the function\n */\nexport function instrumented<T>(\n options: InstrumentedOptions,\n fn: () => T | Promise<T>,\n): T | Promise<T> {\n const { name, attributes, ignoreParentSpan, kind } = options;\n return instrument(name, fn, {\n attributes,\n root: ignoreParentSpan,\n kind,\n });\n}\n"],"mappings":";;;;;;;;;;AAkCA,SAAgB,aACd,SACA,IACgB;CAChB,MAAM,EAAE,MAAM,YAAY,kBAAkB,SAAS;AACrD,QAAOA,yBAAW,MAAM,IAAI;EAC1B;EACA,MAAM;EACN;EACD,CAAC"}
|
|
@@ -21,6 +21,9 @@ var init_renovate_logger = require_rolldown_runtime.__esmMin((() => {
|
|
|
21
21
|
RenovateLogger = class RenovateLogger {
|
|
22
22
|
logger = { once: { reset: require_once.reset } };
|
|
23
23
|
once = this.logger.once;
|
|
24
|
+
bunyanLogger;
|
|
25
|
+
context;
|
|
26
|
+
meta;
|
|
24
27
|
constructor(bunyanLogger, context, meta) {
|
|
25
28
|
this.bunyanLogger = bunyanLogger;
|
|
26
29
|
this.context = context;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"renovate-logger.js","names":["onceReset","withSanitizer","toMeta","getMessage","getRemappedLevel"],"sources":["../../lib/logger/renovate-logger.ts"],"sourcesContent":["import { isString } from '@sindresorhus/is';\nimport type * as bunyan from 'bunyan';\nimport { once, reset as onceReset } from './once.ts';\nimport { getRemappedLevel } from './remap.ts';\nimport type { Logger } from './types.ts';\nimport { getMessage, toMeta, withSanitizer } from './utils.ts';\n\nconst loggerLevels: bunyan.LogLevelString[] = [\n 'trace',\n 'debug',\n 'info',\n 'warn',\n 'error',\n 'fatal',\n];\n\ntype LoggerFunction = (p1: string | Record<string, any>, p2?: string) => void;\n\nexport class RenovateLogger implements Logger {\n readonly logger: Logger = { once: { reset: onceReset } } as any;\n readonly once = this.logger.once;\n\n constructor(\n
|
|
1
|
+
{"version":3,"file":"renovate-logger.js","names":["onceReset","withSanitizer","toMeta","getMessage","getRemappedLevel"],"sources":["../../lib/logger/renovate-logger.ts"],"sourcesContent":["import { isString } from '@sindresorhus/is';\nimport type * as bunyan from 'bunyan';\nimport { once, reset as onceReset } from './once.ts';\nimport { getRemappedLevel } from './remap.ts';\nimport type { Logger } from './types.ts';\nimport { getMessage, toMeta, withSanitizer } from './utils.ts';\n\nconst loggerLevels: bunyan.LogLevelString[] = [\n 'trace',\n 'debug',\n 'info',\n 'warn',\n 'error',\n 'fatal',\n];\n\ntype LoggerFunction = (p1: string | Record<string, any>, p2?: string) => void;\n\nexport class RenovateLogger implements Logger {\n readonly logger: Logger = { once: { reset: onceReset } } as any;\n readonly once = this.logger.once;\n private readonly bunyanLogger: bunyan;\n private context: string;\n private meta: Record<string, unknown>;\n\n constructor(\n bunyanLogger: bunyan,\n context: string,\n meta: Record<string, unknown>,\n ) {\n this.bunyanLogger = bunyanLogger;\n this.context = context;\n this.meta = meta;\n for (const level of loggerLevels) {\n this.logger[level] = this.logFactory(level) as never;\n this.logger.once[level] = this.logOnceFn(level);\n }\n }\n\n trace(p1: string): void;\n trace(p1: Record<string, any>, p2?: string): void;\n trace(p1: string | Record<string, any>, p2?: string): void {\n this.log('trace', p1, p2);\n }\n\n debug(p1: string): void;\n debug(p1: Record<string, any>, p2?: string): void;\n debug(p1: string | Record<string, any>, p2?: string): void {\n this.log('debug', p1, p2);\n }\n\n info(p1: string): void;\n info(p1: Record<string, any>, p2?: string): void;\n info(p1: string | Record<string, any>, p2?: string): void {\n this.log('info', p1, p2);\n }\n\n warn(p1: string): void;\n warn(p1: Record<string, any>, p2?: string): void;\n warn(p1: string | Record<string, any>, p2?: string): void {\n this.log('warn', p1, p2);\n }\n\n error(p1: string): void;\n error(p1: Record<string, any>, p2?: string): void;\n error(p1: string | Record<string, any>, p2?: string): void {\n this.log('error', p1, p2);\n }\n\n fatal(p1: string): void;\n fatal(p1: Record<string, any>, p2?: string): void;\n fatal(p1: string | Record<string, any>, p2?: string): void {\n this.log('fatal', p1, p2);\n }\n\n addSerializers(serializers: bunyan.Serializers): void {\n this.bunyanLogger.addSerializers(serializers);\n }\n\n addStream(stream: bunyan.Stream): void {\n this.bunyanLogger.addStream(withSanitizer(stream));\n }\n\n childLogger(): RenovateLogger {\n return new RenovateLogger(\n this.bunyanLogger.child({}),\n this.context,\n this.meta,\n );\n }\n\n get logContext(): string {\n return this.context;\n }\n\n set logContext(context: string) {\n this.context = context;\n }\n\n setMeta(obj: Record<string, unknown>): void {\n this.meta = { ...obj };\n }\n\n addMeta(obj: Record<string, unknown>): void {\n this.meta = { ...this.meta, ...obj };\n }\n\n removeMeta(fields: string[]): void {\n for (const key of Object.keys(this.meta)) {\n if (fields.includes(key)) {\n delete this.meta[key];\n }\n }\n }\n\n private logFactory(_level: bunyan.LogLevelString): LoggerFunction {\n return (p1: string | Record<string, any>, p2?: string): void => {\n const meta: Record<string, unknown> = {\n logContext: this.context,\n ...this.meta,\n ...toMeta(p1),\n };\n const msg = getMessage(p1, p2);\n let level = _level;\n\n if (isString(msg)) {\n const remappedLevel = getRemappedLevel(msg);\n /* v8 ignore next 4 -- not easily testable */\n if (remappedLevel) {\n meta.oldLevel = level;\n level = remappedLevel;\n }\n this.bunyanLogger[level](meta, msg);\n } else {\n this.bunyanLogger[level](meta);\n }\n };\n }\n\n private logOnceFn(level: bunyan.LogLevelString): LoggerFunction {\n const logOnceFn = (p1: string | Record<string, any>, p2?: string): void => {\n once(() => {\n const logFn = this[level].bind(this); // bind to the instance.\n if (isString(p1)) {\n logFn(p1);\n } else {\n logFn(p1, p2);\n }\n }, logOnceFn);\n };\n return logOnceFn;\n }\n\n private log(\n level: bunyan.LogLevelString,\n p1: string | Record<string, any>,\n p2?: string,\n ): void {\n const logFn = this.logger[level];\n if (isString(p1)) {\n logFn(p1);\n } else {\n logFn(p1, p2);\n }\n }\n}\n"],"mappings":";;;;;;;;;yBAEqD;2BACP;2BAEiB;CAEzD,eAAwC;EAC5C;EACA;EACA;EACA;EACA;EACA;EACD;CAIY,iBAAb,MAAa,eAAiC;EAC5C,AAAS,SAAiB,EAAE,MAAM,EAAE,OAAOA,oBAAW,EAAE;EACxD,AAAS,OAAO,KAAK,OAAO;EAC5B,AAAiB;EACjB,AAAQ;EACR,AAAQ;EAER,YACE,cACA,SACA,MACA;AACA,QAAK,eAAe;AACpB,QAAK,UAAU;AACf,QAAK,OAAO;AACZ,QAAK,MAAM,SAAS,cAAc;AAChC,SAAK,OAAO,SAAS,KAAK,WAAW,MAAM;AAC3C,SAAK,OAAO,KAAK,SAAS,KAAK,UAAU,MAAM;;;EAMnD,MAAM,IAAkC,IAAmB;AACzD,QAAK,IAAI,SAAS,IAAI,GAAG;;EAK3B,MAAM,IAAkC,IAAmB;AACzD,QAAK,IAAI,SAAS,IAAI,GAAG;;EAK3B,KAAK,IAAkC,IAAmB;AACxD,QAAK,IAAI,QAAQ,IAAI,GAAG;;EAK1B,KAAK,IAAkC,IAAmB;AACxD,QAAK,IAAI,QAAQ,IAAI,GAAG;;EAK1B,MAAM,IAAkC,IAAmB;AACzD,QAAK,IAAI,SAAS,IAAI,GAAG;;EAK3B,MAAM,IAAkC,IAAmB;AACzD,QAAK,IAAI,SAAS,IAAI,GAAG;;EAG3B,eAAe,aAAuC;AACpD,QAAK,aAAa,eAAe,YAAY;;EAG/C,UAAU,QAA6B;AACrC,QAAK,aAAa,UAAUC,4BAAc,OAAO,CAAC;;EAGpD,cAA8B;AAC5B,UAAO,IAAI,eACT,KAAK,aAAa,MAAM,EAAE,CAAC,EAC3B,KAAK,SACL,KAAK,KACN;;EAGH,IAAI,aAAqB;AACvB,UAAO,KAAK;;EAGd,IAAI,WAAW,SAAiB;AAC9B,QAAK,UAAU;;EAGjB,QAAQ,KAAoC;AAC1C,QAAK,OAAO,EAAE,GAAG,KAAK;;EAGxB,QAAQ,KAAoC;AAC1C,QAAK,OAAO;IAAE,GAAG,KAAK;IAAM,GAAG;IAAK;;EAGtC,WAAW,QAAwB;AACjC,QAAK,MAAM,OAAO,OAAO,KAAK,KAAK,KAAK,CACtC,KAAI,OAAO,SAAS,IAAI,CACtB,QAAO,KAAK,KAAK;;EAKvB,AAAQ,WAAW,QAA+C;AAChE,WAAQ,IAAkC,OAAsB;IAC9D,MAAM,OAAgC;KACpC,YAAY,KAAK;KACjB,GAAG,KAAK;KACR,GAAGC,qBAAO,GAAG;KACd;IACD,MAAM,MAAMC,yBAAW,IAAI,GAAG;IAC9B,IAAI,QAAQ;AAEZ,uCAAa,IAAI,EAAE;KACjB,MAAM,gBAAgBC,+BAAiB,IAAI;;AAE3C,SAAI,eAAe;AACjB,WAAK,WAAW;AAChB,cAAQ;;AAEV,UAAK,aAAa,OAAO,MAAM,IAAI;UAEnC,MAAK,aAAa,OAAO,KAAK;;;EAKpC,AAAQ,UAAU,OAA8C;GAC9D,MAAM,aAAa,IAAkC,OAAsB;AACzE,4BAAW;KACT,MAAM,QAAQ,KAAK,OAAO,KAAK,KAAK;AACpC,wCAAa,GAAG,CACd,OAAM,GAAG;SAET,OAAM,IAAI,GAAG;OAEd,UAAU;;AAEf,UAAO;;EAGT,AAAQ,IACN,OACA,IACA,IACM;GACN,MAAM,QAAQ,KAAK,OAAO;AAC1B,sCAAa,GAAG,CACd,OAAM,GAAG;OAET,OAAM,IAAI,GAAG"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"datasource.js","names":["Http","ExternalHostError","HttpError"],"sources":["../../../lib/modules/datasource/datasource.ts"],"sourcesContent":["import { ExternalHostError } from '../../types/errors/external-host-error.ts';\nimport { Http, HttpError } from '../../util/http/index.ts';\nimport type {\n DatasourceApi,\n DigestConfig,\n GetReleasesConfig,\n PostprocessReleaseConfig,\n PostprocessReleaseResult,\n RegistryStrategy,\n Release,\n ReleaseResult,\n SourceUrlSupport,\n} from './types.ts';\n\nexport abstract class Datasource implements DatasourceApi {\n
|
|
1
|
+
{"version":3,"file":"datasource.js","names":["Http","ExternalHostError","HttpError"],"sources":["../../../lib/modules/datasource/datasource.ts"],"sourcesContent":["import { ExternalHostError } from '../../types/errors/external-host-error.ts';\nimport { Http, HttpError } from '../../util/http/index.ts';\nimport type {\n DatasourceApi,\n DigestConfig,\n GetReleasesConfig,\n PostprocessReleaseConfig,\n PostprocessReleaseResult,\n RegistryStrategy,\n Release,\n ReleaseResult,\n SourceUrlSupport,\n} from './types.ts';\n\nexport abstract class Datasource implements DatasourceApi {\n public readonly id: string;\n\n protected constructor(id: string) {\n this.id = id;\n this.http = new Http(id);\n }\n\n caching: boolean | undefined;\n\n customRegistrySupport = true;\n\n defaultConfig: Record<string, unknown> | undefined;\n\n defaultRegistryUrls?: string[] | (() => string[]);\n\n defaultVersioning?: string | undefined;\n\n registryStrategy: RegistryStrategy | undefined = 'first';\n\n releaseTimestampSupport = false;\n releaseTimestampNote?: string | undefined;\n\n sourceUrlSupport: SourceUrlSupport = 'none';\n sourceUrlNote?: string | undefined;\n\n protected http: Http;\n\n abstract getReleases(\n getReleasesConfig: GetReleasesConfig,\n ): Promise<ReleaseResult | null>;\n\n getDigest?(config: DigestConfig, newValue?: string): Promise<string | null>;\n\n handleHttpErrors(_err: HttpError): void {\n // intentionally empty\n }\n\n protected handleGenericErrors(err: Error): never {\n if (err instanceof ExternalHostError) {\n throw err;\n }\n\n if (err instanceof HttpError) {\n this.handleHttpErrors(err);\n\n const statusCode = err.response?.statusCode;\n if (statusCode) {\n if (statusCode === 429 || (statusCode >= 500 && statusCode < 600)) {\n throw new ExternalHostError(err);\n }\n }\n }\n\n throw err;\n }\n\n // istanbul ignore next: no-op implementation, never called\n postprocessRelease(\n _config: PostprocessReleaseConfig,\n release: Release,\n ): Promise<PostprocessReleaseResult> {\n return Promise.resolve(release);\n }\n}\n"],"mappings":";;;;;;AAcA,IAAsB,aAAtB,MAA0D;CACxD,AAAgB;CAEhB,AAAU,YAAY,IAAY;AAChC,OAAK,KAAK;AACV,OAAK,OAAO,IAAIA,mBAAK,GAAG;;CAG1B;CAEA,wBAAwB;CAExB;CAEA;CAEA;CAEA,mBAAiD;CAEjD,0BAA0B;CAC1B;CAEA,mBAAqC;CACrC;CAEA,AAAU;CAQV,iBAAiB,MAAuB;CAIxC,AAAU,oBAAoB,KAAmB;AAC/C,MAAI,eAAeC,8CACjB,OAAM;AAGR,MAAI,eAAeC,kBAAW;AAC5B,QAAK,iBAAiB,IAAI;GAE1B,MAAM,aAAa,IAAI,UAAU;AACjC,OAAI,YACF;QAAI,eAAe,OAAQ,cAAc,OAAO,aAAa,IAC3D,OAAM,IAAID,8CAAkB,IAAI;;;AAKtC,QAAM;;;CAIR,mBACE,SACA,SACmC;AACnC,SAAO,QAAQ,QAAQ,QAAQ"}
|
|
@@ -8,6 +8,8 @@ const cacheNamespace = "datasource-docker-hub-cache";
|
|
|
8
8
|
var DockerHubCache = class DockerHubCache {
|
|
9
9
|
isChanged = false;
|
|
10
10
|
reconciledIds = /* @__PURE__ */ new Set();
|
|
11
|
+
dockerRepository;
|
|
12
|
+
cache;
|
|
11
13
|
constructor(dockerRepository, cache) {
|
|
12
14
|
this.dockerRepository = dockerRepository;
|
|
13
15
|
this.cache = cache;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dockerhub-cache.js","names":["DateTime"],"sources":["../../../../lib/modules/datasource/docker/dockerhub-cache.ts"],"sourcesContent":["import { dequal } from 'dequal';\nimport { DateTime } from 'luxon';\nimport * as packageCache from '../../../util/cache/package/index.ts';\nimport type { DockerHubTag } from './schema.ts';\n\nexport interface DockerHubCacheData {\n items: Record<number, DockerHubTag>;\n updatedAt: string | null;\n}\n\nconst cacheNamespace = 'datasource-docker-hub-cache';\n\nexport class DockerHubCache {\n private isChanged = false;\n private reconciledIds = new Set<number>();\n
|
|
1
|
+
{"version":3,"file":"dockerhub-cache.js","names":["DateTime"],"sources":["../../../../lib/modules/datasource/docker/dockerhub-cache.ts"],"sourcesContent":["import { dequal } from 'dequal';\nimport { DateTime } from 'luxon';\nimport * as packageCache from '../../../util/cache/package/index.ts';\nimport type { DockerHubTag } from './schema.ts';\n\nexport interface DockerHubCacheData {\n items: Record<number, DockerHubTag>;\n updatedAt: string | null;\n}\n\nconst cacheNamespace = 'datasource-docker-hub-cache';\n\nexport class DockerHubCache {\n private isChanged = false;\n private reconciledIds = new Set<number>();\n private dockerRepository: string;\n private cache: DockerHubCacheData;\n\n private constructor(dockerRepository: string, cache: DockerHubCacheData) {\n this.dockerRepository = dockerRepository;\n this.cache = cache;\n }\n\n static async init(dockerRepository: string): Promise<DockerHubCache> {\n let repoCache = await packageCache.get<DockerHubCacheData>(\n cacheNamespace,\n dockerRepository,\n );\n\n repoCache ??= {\n items: {},\n updatedAt: null,\n };\n\n return new DockerHubCache(dockerRepository, repoCache);\n }\n\n reconcile(items: DockerHubTag[], expectedCount: number): boolean {\n let needNextPage = true;\n\n let earliestDate = null;\n\n let { updatedAt } = this.cache;\n let latestDate = updatedAt ? DateTime.fromISO(updatedAt) : null;\n\n for (const newItem of items) {\n const id = newItem.id;\n this.reconciledIds.add(id);\n\n const oldItem = this.cache.items[id];\n\n const itemDate = DateTime.fromISO(newItem.last_updated);\n\n if (!earliestDate || earliestDate > itemDate) {\n earliestDate = itemDate;\n }\n\n if (!latestDate || latestDate < itemDate) {\n latestDate = itemDate;\n updatedAt = newItem.last_updated;\n }\n\n if (dequal(oldItem, newItem)) {\n needNextPage = false;\n continue;\n }\n\n this.cache.items[newItem.id] = newItem;\n this.isChanged = true;\n }\n\n this.cache.updatedAt = updatedAt;\n\n if (earliestDate && latestDate) {\n for (const [key, item] of Object.entries(this.cache.items)) {\n const id = parseInt(key);\n\n const itemDate = DateTime.fromISO(item.last_updated);\n\n if (\n itemDate < earliestDate ||\n itemDate > latestDate ||\n this.reconciledIds.has(id)\n ) {\n continue;\n }\n\n delete this.cache.items[id];\n this.isChanged = true;\n }\n\n if (Object.keys(this.cache.items).length > expectedCount) {\n return true;\n }\n }\n\n return needNextPage;\n }\n\n async save(): Promise<void> {\n if (this.isChanged) {\n await packageCache.set(\n cacheNamespace,\n this.dockerRepository,\n this.cache,\n 3 * 60 * 24 * 30,\n );\n }\n }\n\n getItems(): DockerHubTag[] {\n return Object.values(this.cache.items);\n }\n}\n"],"mappings":";;;;;;AAUA,MAAM,iBAAiB;AAEvB,IAAa,iBAAb,MAAa,eAAe;CAC1B,AAAQ,YAAY;CACpB,AAAQ,gCAAgB,IAAI,KAAa;CACzC,AAAQ;CACR,AAAQ;CAER,AAAQ,YAAY,kBAA0B,OAA2B;AACvE,OAAK,mBAAmB;AACxB,OAAK,QAAQ;;CAGf,aAAa,KAAK,kBAAmD;EACnE,IAAI,YAAY,wBACd,gBACA,iBACD;AAED,gBAAc;GACZ,OAAO,EAAE;GACT,WAAW;GACZ;AAED,SAAO,IAAI,eAAe,kBAAkB,UAAU;;CAGxD,UAAU,OAAuB,eAAgC;EAC/D,IAAI,eAAe;EAEnB,IAAI,eAAe;EAEnB,IAAI,EAAE,cAAc,KAAK;EACzB,IAAI,aAAa,YAAYA,eAAS,QAAQ,UAAU,GAAG;AAE3D,OAAK,MAAM,WAAW,OAAO;GAC3B,MAAM,KAAK,QAAQ;AACnB,QAAK,cAAc,IAAI,GAAG;GAE1B,MAAM,UAAU,KAAK,MAAM,MAAM;GAEjC,MAAM,WAAWA,eAAS,QAAQ,QAAQ,aAAa;AAEvD,OAAI,CAAC,gBAAgB,eAAe,SAClC,gBAAe;AAGjB,OAAI,CAAC,cAAc,aAAa,UAAU;AACxC,iBAAa;AACb,gBAAY,QAAQ;;AAGtB,0BAAW,SAAS,QAAQ,EAAE;AAC5B,mBAAe;AACf;;AAGF,QAAK,MAAM,MAAM,QAAQ,MAAM;AAC/B,QAAK,YAAY;;AAGnB,OAAK,MAAM,YAAY;AAEvB,MAAI,gBAAgB,YAAY;AAC9B,QAAK,MAAM,CAAC,KAAK,SAAS,OAAO,QAAQ,KAAK,MAAM,MAAM,EAAE;IAC1D,MAAM,KAAK,SAAS,IAAI;IAExB,MAAM,WAAWA,eAAS,QAAQ,KAAK,aAAa;AAEpD,QACE,WAAW,gBACX,WAAW,cACX,KAAK,cAAc,IAAI,GAAG,CAE1B;AAGF,WAAO,KAAK,MAAM,MAAM;AACxB,SAAK,YAAY;;AAGnB,OAAI,OAAO,KAAK,KAAK,MAAM,MAAM,CAAC,SAAS,cACzC,QAAO;;AAIX,SAAO;;CAGT,MAAM,OAAsB;AAC1B,MAAI,KAAK,UACP,yBACE,gBACA,KAAK,kBACL,KAAK,OACL,OAAc,GACf;;CAIL,WAA2B;AACzB,SAAO,OAAO,OAAO,KAAK,MAAM,MAAM"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metadata-cache.js","names":["toSha256","Result","parseUrl","getV1Releases"],"sources":["../../../../lib/modules/datasource/rubygems/metadata-cache.ts"],"sourcesContent":["import { logger } from '../../../logger/index.ts';\nimport * as packageCache from '../../../util/cache/package/index.ts';\nimport { toSha256 } from '../../../util/hash.ts';\nimport type { Http } from '../../../util/http/index.ts';\nimport type { AsyncResult } from '../../../util/result.ts';\nimport { Result } from '../../../util/result.ts';\nimport { parseUrl } from '../../../util/url.ts';\nimport type { ReleaseResult } from '../types.ts';\nimport { getV1Releases } from './common.ts';\n\ninterface CacheRecord {\n hash: string;\n data: ReleaseResult;\n isFallback?: true;\n}\n\nfunction hashVersions(versions: string[]): string {\n return toSha256(versions.sort().join(','));\n}\n\nfunction hashReleases(releases: ReleaseResult): string {\n return hashVersions(releases.releases.map((release) => release.version));\n}\n\ninterface CacheNotFoundError {\n type: 'cache-not-found';\n}\ninterface CacheStaleError {\n type: 'cache-stale';\n cache: CacheRecord;\n}\ninterface CacheInvalidError {\n type: 'cache-invalid';\n}\ntype CacheLoadError = CacheNotFoundError | CacheStaleError;\ntype CacheError = CacheNotFoundError | CacheStaleError | CacheInvalidError;\n\nexport class MetadataCache {\n
|
|
1
|
+
{"version":3,"file":"metadata-cache.js","names":["toSha256","Result","parseUrl","getV1Releases"],"sources":["../../../../lib/modules/datasource/rubygems/metadata-cache.ts"],"sourcesContent":["import { logger } from '../../../logger/index.ts';\nimport * as packageCache from '../../../util/cache/package/index.ts';\nimport { toSha256 } from '../../../util/hash.ts';\nimport type { Http } from '../../../util/http/index.ts';\nimport type { AsyncResult } from '../../../util/result.ts';\nimport { Result } from '../../../util/result.ts';\nimport { parseUrl } from '../../../util/url.ts';\nimport type { ReleaseResult } from '../types.ts';\nimport { getV1Releases } from './common.ts';\n\ninterface CacheRecord {\n hash: string;\n data: ReleaseResult;\n isFallback?: true;\n}\n\nfunction hashVersions(versions: string[]): string {\n return toSha256(versions.sort().join(','));\n}\n\nfunction hashReleases(releases: ReleaseResult): string {\n return hashVersions(releases.releases.map((release) => release.version));\n}\n\ninterface CacheNotFoundError {\n type: 'cache-not-found';\n}\ninterface CacheStaleError {\n type: 'cache-stale';\n cache: CacheRecord;\n}\ninterface CacheInvalidError {\n type: 'cache-invalid';\n}\ntype CacheLoadError = CacheNotFoundError | CacheStaleError;\ntype CacheError = CacheNotFoundError | CacheStaleError | CacheInvalidError;\n\nexport class MetadataCache {\n private readonly http: Http;\n\n constructor(http: Http) {\n this.http = http;\n }\n\n async getRelease(\n registryUrl: string,\n packageName: string,\n versions: string[],\n ): Promise<ReleaseResult> {\n const cacheNs = `datasource-rubygems`;\n const cacheKey = `metadata-cache:${registryUrl}:${packageName}`;\n const versionsHash = hashVersions(versions);\n\n const loadCache = (): AsyncResult<ReleaseResult, CacheLoadError> =>\n Result.wrapNullable<CacheRecord, CacheLoadError, CacheLoadError>(\n packageCache.get<CacheRecord>(cacheNs, cacheKey),\n { type: 'cache-not-found' },\n ).transform((cache) => {\n return versionsHash === cache.hash\n ? Result.ok(cache.data)\n : Result.err({ type: 'cache-stale', cache });\n });\n\n const saveCache = async (\n cache: CacheRecord,\n ttlMinutes = 100 * 24 * 60,\n ttlDelta = 10 * 24 * 60,\n ): Promise<void> => {\n const registryHostname = parseUrl(registryUrl)?.hostname;\n if (registryHostname === 'rubygems.org') {\n const ttlRandomDelta = Math.floor(Math.random() * ttlDelta);\n const ttl = ttlMinutes + ttlRandomDelta;\n await packageCache.set(cacheNs, cacheKey, cache, ttl);\n }\n };\n\n return await loadCache()\n .catch((err) =>\n getV1Releases(this.http, registryUrl, packageName).transform(\n async (\n data: ReleaseResult,\n ): Promise<Result<ReleaseResult, CacheError>> => {\n const dataHash = hashReleases(data);\n if (dataHash === versionsHash) {\n await saveCache({\n hash: dataHash,\n data,\n });\n return Result.ok(data);\n }\n\n /**\n * Return stale cache for 24 hours,\n * if metadata is inconsistent with versions list.\n */\n if (err.type === 'cache-stale') {\n const staleCache = err.cache;\n if (!staleCache.isFallback) {\n await saveCache(\n { ...staleCache, isFallback: true },\n 24 * 60,\n 0,\n );\n }\n return Result.ok(staleCache.data);\n }\n\n return Result.err({ type: 'cache-invalid' });\n },\n ),\n )\n .catch((err) => {\n logger.debug(\n { err },\n 'Rubygems: error fetching rubygems data, falling back to versions-only result',\n );\n const releases = versions.map((version) => ({ version }));\n return Result.ok({ releases } as ReleaseResult);\n })\n .unwrapOrThrow();\n }\n}\n"],"mappings":";;;;;;;;2BAAkD;sBAMF;AAUhD,SAAS,aAAa,UAA4B;AAChD,QAAOA,sBAAS,SAAS,MAAM,CAAC,KAAK,IAAI,CAAC;;AAG5C,SAAS,aAAa,UAAiC;AACrD,QAAO,aAAa,SAAS,SAAS,KAAK,YAAY,QAAQ,QAAQ,CAAC;;AAgB1E,IAAa,gBAAb,MAA2B;CACzB,AAAiB;CAEjB,YAAY,MAAY;AACtB,OAAK,OAAO;;CAGd,MAAM,WACJ,aACA,aACA,UACwB;EACxB,MAAM,UAAU;EAChB,MAAM,WAAW,kBAAkB,YAAY,GAAG;EAClD,MAAM,eAAe,aAAa,SAAS;EAE3C,MAAM,kBACJC,sBAAO,iCACyB,SAAS,SAAS,EAChD,EAAE,MAAM,mBAAmB,CAC5B,CAAC,WAAW,UAAU;AACrB,UAAO,iBAAiB,MAAM,OAC1BA,sBAAO,GAAG,MAAM,KAAK,GACrBA,sBAAO,IAAI;IAAE,MAAM;IAAe;IAAO,CAAC;IAC9C;EAEJ,MAAM,YAAY,OAChB,OACA,aAAa,OAAW,IACxB,WAAW,UACO;AAElB,OADyBC,qBAAS,YAAY,EAAE,aACvB,gBAAgB;IAEvC,MAAM,MAAM,aADW,KAAK,MAAM,KAAK,QAAQ,GAAG,SAAS;AAE3D,8BAAuB,SAAS,UAAU,OAAO,IAAI;;;AAIzD,SAAO,MAAM,WAAW,CACrB,OAAO,QACNC,6BAAc,KAAK,MAAM,aAAa,YAAY,CAAC,UACjD,OACE,SAC+C;GAC/C,MAAM,WAAW,aAAa,KAAK;AACnC,OAAI,aAAa,cAAc;AAC7B,UAAM,UAAU;KACd,MAAM;KACN;KACD,CAAC;AACF,WAAOF,sBAAO,GAAG,KAAK;;;;;;AAOxB,OAAI,IAAI,SAAS,eAAe;IAC9B,MAAM,aAAa,IAAI;AACvB,QAAI,CAAC,WAAW,WACd,OAAM,UACJ;KAAE,GAAG;KAAY,YAAY;KAAM,EACnC,MACA,EACD;AAEH,WAAOA,sBAAO,GAAG,WAAW,KAAK;;AAGnC,UAAOA,sBAAO,IAAI,EAAE,MAAM,iBAAiB,CAAC;IAE/C,CACF,CACA,OAAO,QAAQ;AACd,wBAAO,MACL,EAAE,KAAK,EACP,+EACD;GACD,MAAM,WAAW,SAAS,KAAK,aAAa,EAAE,SAAS,EAAE;AACzD,UAAOA,sBAAO,GAAG,EAAE,UAAU,CAAkB;IAC/C,CACD,eAAe"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"versions-endpoint-cache.js","names":["copystr","Result","parseUrl","z","newlineRegex","LooseArray","getElapsedMinutes","HttpError"],"sources":["../../../../lib/modules/datasource/rubygems/versions-endpoint-cache.ts"],"sourcesContent":["import { z } from 'zod';\nimport { logger } from '../../../logger/index.ts';\nimport { getElapsedMinutes } from '../../../util/date.ts';\nimport type { Http } from '../../../util/http/index.ts';\nimport { HttpError } from '../../../util/http/index.ts';\nimport type { HttpOptions } from '../../../util/http/types.ts';\nimport { newlineRegex } from '../../../util/regex.ts';\nimport { Result } from '../../../util/result.ts';\nimport { LooseArray } from '../../../util/schema-utils/index.ts';\nimport { copystr } from '../../../util/string.ts';\nimport { parseUrl } from '../../../util/url.ts';\n\ntype PackageVersions = Map<string, string[]>;\n\ninterface VersionsEndpointData {\n packageVersions: PackageVersions;\n syncedAt: Date;\n contentLength: number;\n\n /**\n * Last 33 characters of the response (32 hex digits + newline)\n */\n contentTail: string;\n}\n\nfunction getContentTail(content: string): string {\n return content.slice(-33);\n}\n\nfunction getContentHead(content: string): string {\n return content.slice(0, 33);\n}\n\nfunction stripContentHead(content: string): string {\n return content.slice(33);\n}\n\nfunction reconcilePackageVersions(\n packageVersions: PackageVersions,\n versionLines: VersionLines,\n): PackageVersions {\n for (const line of versionLines) {\n const packageName = copystr(line.packageName);\n let versions = packageVersions.get(packageName) ?? [];\n\n const { deletedVersions, addedVersions } = line;\n\n if (deletedVersions.size > 0) {\n versions = versions.filter((v) => !deletedVersions.has(v));\n }\n\n if (addedVersions.length > 0) {\n const existingVersions = new Set(versions);\n for (const addedVersion of addedVersions) {\n if (!existingVersions.has(addedVersion)) {\n const version = copystr(addedVersion);\n versions.push(version);\n }\n }\n }\n\n packageVersions.set(packageName, versions);\n }\n\n return packageVersions;\n}\n\nfunction parseFullBody(body: string): VersionsEndpointResult {\n const packageVersions = reconcilePackageVersions(\n new Map<string, string[]>(),\n VersionLines.parse(body),\n );\n const syncedAt = new Date();\n const contentLength = body.length;\n const contentTail = getContentTail(body);\n\n return Result.ok({\n packageVersions,\n syncedAt,\n contentLength,\n contentTail,\n });\n}\n\ntype VersionsEndpointResult = Result<VersionsEndpointData, 'unsupported-api'>;\n\nexport const memCache = new Map<string, VersionsEndpointResult>();\n\nfunction cacheResult(\n registryUrl: string,\n result: VersionsEndpointResult,\n): void {\n const registryHostname = parseUrl(registryUrl)?.hostname;\n if (registryHostname === 'rubygems.org') {\n memCache.set(registryUrl, result);\n }\n}\n\nconst VersionLines = z\n .string()\n .transform((x) => x.split(newlineRegex))\n .pipe(\n LooseArray(\n z\n .string()\n .transform((line) => line.trim())\n .refine((line) => line.length > 0)\n .refine((line) => !line.startsWith('created_at:'))\n .refine((line) => line !== '---')\n .transform((line) => line.split(' '))\n .pipe(z.tuple([z.string(), z.string()]).rest(z.string()))\n .transform(([packageName, versions]) => {\n const deletedVersions = new Set<string>();\n const addedVersions: string[] = [];\n for (const version of versions.split(',')) {\n if (version.startsWith('-')) {\n deletedVersions.add(version.slice(1));\n } else {\n addedVersions.push(version);\n }\n }\n return { packageName, deletedVersions, addedVersions };\n }),\n ),\n );\ntype VersionLines = z.infer<typeof VersionLines>;\n\nfunction isStale(regCache: VersionsEndpointData): boolean {\n return getElapsedMinutes(regCache.syncedAt) >= 15;\n}\n\nexport type VersionsResult = Result<\n string[],\n 'unsupported-api' | 'package-not-found'\n>;\n\nexport class VersionsEndpointCache {\n constructor(private readonly http: Http) {}\n\n private cacheRequests = new Map<string, Promise<VersionsEndpointResult>>();\n\n /**\n * At any given time, there should only be one request for a given registryUrl.\n */\n private async getCache(registryUrl: string): Promise<VersionsEndpointResult> {\n const oldResult = memCache.get(registryUrl);\n if (!oldResult) {\n const newResult = await this.fullSync(registryUrl);\n cacheResult(registryUrl, newResult);\n return newResult;\n }\n\n const { val: data } = oldResult.unwrap();\n if (!data) {\n return oldResult;\n }\n\n if (isStale(data)) {\n memCache.delete(registryUrl); // If no error is thrown, we'll re-set the cache\n const newResult = await this.deltaSync(data, registryUrl);\n cacheResult(registryUrl, newResult);\n return newResult;\n }\n\n return oldResult;\n }\n\n async getVersions(\n registryUrl: string,\n packageName: string,\n ): Promise<VersionsResult> {\n /**\n * Ensure that only one request for a given registryUrl is in flight at a time.\n */\n let cacheRequest = this.cacheRequests.get(registryUrl);\n if (!cacheRequest) {\n cacheRequest = this.getCache(registryUrl);\n this.cacheRequests.set(registryUrl, cacheRequest);\n }\n let cachedResult: VersionsEndpointResult;\n try {\n cachedResult = await cacheRequest;\n } finally {\n this.cacheRequests.delete(registryUrl);\n }\n\n const { val: cachedData } = cachedResult.unwrap();\n if (!cachedData) {\n logger.debug(\n { packageName, registryUrl },\n 'Rubygems: endpoint not supported',\n );\n return Result.err('unsupported-api');\n }\n\n const versions = cachedData.packageVersions.get(packageName);\n if (!versions?.length) {\n logger.debug(\n { packageName, registryUrl },\n 'Rubygems: versions not found',\n );\n return Result.err('package-not-found');\n }\n\n return Result.ok(versions);\n }\n\n private async fullSync(registryUrl: string): Promise<VersionsEndpointResult> {\n try {\n const url = `${registryUrl}/versions`;\n const opts: HttpOptions = { headers: { 'Accept-Encoding': 'gzip' } };\n const { body } = await this.http.getText(url, opts);\n return parseFullBody(body);\n } catch (err) {\n if (err instanceof HttpError && err.response?.statusCode === 404) {\n return Result.err('unsupported-api');\n }\n\n throw err;\n }\n }\n\n private async deltaSync(\n oldCache: VersionsEndpointData,\n registryUrl: string,\n ): Promise<VersionsEndpointResult> {\n try {\n const url = `${registryUrl}/versions`;\n const startByte = oldCache.contentLength - oldCache.contentTail.length;\n const opts: HttpOptions = {\n headers: {\n ['Accept-Encoding']: 'deflate, compress, br', // Note: `gzip` usage breaks http client, when used with `Range` header\n ['Range']: `bytes=${startByte}-`,\n },\n };\n const { statusCode, body } = await this.http.getText(url, opts);\n\n /**\n * Rubygems will return the full body instead of `416 Range Not Satisfiable`.\n * In this case, status code will be 200 instead of 206.\n */\n if (statusCode === 200) {\n return parseFullBody(body);\n }\n\n /**\n * We request data in range that overlaps previously fetched data.\n * If the head of the response doesn't match the tail of the previous response,\n * it means that the data we have is no longer valid.\n * In this case we start over with a full sync.\n */\n const contentHead = getContentHead(body);\n if (contentHead !== oldCache.contentTail) {\n return this.fullSync(registryUrl);\n }\n\n /**\n * Update the cache with the new data.\n */\n const delta = stripContentHead(body);\n const packageVersions = reconcilePackageVersions(\n oldCache.packageVersions,\n VersionLines.parse(delta),\n );\n const syncedAt = new Date();\n const contentLength = oldCache.contentLength + delta.length;\n const contentTail = getContentTail(body);\n\n return Result.ok({\n packageVersions,\n syncedAt,\n contentLength,\n contentTail,\n });\n } catch (err) {\n if (err instanceof HttpError) {\n const responseStatus = err.response?.statusCode;\n\n /**\n * In case of `416 Range Not Satisfiable` we do a full sync.\n * This is unlikely to happen in real life, but anyway.\n */\n if (responseStatus === 416) {\n return this.fullSync(registryUrl);\n }\n\n /**\n * If the endpoint is not supported, we stop trying.\n * This is unlikely to happen in real life, but still.\n */\n if (responseStatus === 404) {\n return Result.err('unsupported-api');\n }\n }\n\n throw err;\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"versions-endpoint-cache.js","names":["copystr","Result","parseUrl","z","newlineRegex","LooseArray","getElapsedMinutes","HttpError"],"sources":["../../../../lib/modules/datasource/rubygems/versions-endpoint-cache.ts"],"sourcesContent":["import { z } from 'zod';\nimport { logger } from '../../../logger/index.ts';\nimport { getElapsedMinutes } from '../../../util/date.ts';\nimport type { Http } from '../../../util/http/index.ts';\nimport { HttpError } from '../../../util/http/index.ts';\nimport type { HttpOptions } from '../../../util/http/types.ts';\nimport { newlineRegex } from '../../../util/regex.ts';\nimport { Result } from '../../../util/result.ts';\nimport { LooseArray } from '../../../util/schema-utils/index.ts';\nimport { copystr } from '../../../util/string.ts';\nimport { parseUrl } from '../../../util/url.ts';\n\ntype PackageVersions = Map<string, string[]>;\n\ninterface VersionsEndpointData {\n packageVersions: PackageVersions;\n syncedAt: Date;\n contentLength: number;\n\n /**\n * Last 33 characters of the response (32 hex digits + newline)\n */\n contentTail: string;\n}\n\nfunction getContentTail(content: string): string {\n return content.slice(-33);\n}\n\nfunction getContentHead(content: string): string {\n return content.slice(0, 33);\n}\n\nfunction stripContentHead(content: string): string {\n return content.slice(33);\n}\n\nfunction reconcilePackageVersions(\n packageVersions: PackageVersions,\n versionLines: VersionLines,\n): PackageVersions {\n for (const line of versionLines) {\n const packageName = copystr(line.packageName);\n let versions = packageVersions.get(packageName) ?? [];\n\n const { deletedVersions, addedVersions } = line;\n\n if (deletedVersions.size > 0) {\n versions = versions.filter((v) => !deletedVersions.has(v));\n }\n\n if (addedVersions.length > 0) {\n const existingVersions = new Set(versions);\n for (const addedVersion of addedVersions) {\n if (!existingVersions.has(addedVersion)) {\n const version = copystr(addedVersion);\n versions.push(version);\n }\n }\n }\n\n packageVersions.set(packageName, versions);\n }\n\n return packageVersions;\n}\n\nfunction parseFullBody(body: string): VersionsEndpointResult {\n const packageVersions = reconcilePackageVersions(\n new Map<string, string[]>(),\n VersionLines.parse(body),\n );\n const syncedAt = new Date();\n const contentLength = body.length;\n const contentTail = getContentTail(body);\n\n return Result.ok({\n packageVersions,\n syncedAt,\n contentLength,\n contentTail,\n });\n}\n\ntype VersionsEndpointResult = Result<VersionsEndpointData, 'unsupported-api'>;\n\nexport const memCache = new Map<string, VersionsEndpointResult>();\n\nfunction cacheResult(\n registryUrl: string,\n result: VersionsEndpointResult,\n): void {\n const registryHostname = parseUrl(registryUrl)?.hostname;\n if (registryHostname === 'rubygems.org') {\n memCache.set(registryUrl, result);\n }\n}\n\nconst VersionLines = z\n .string()\n .transform((x) => x.split(newlineRegex))\n .pipe(\n LooseArray(\n z\n .string()\n .transform((line) => line.trim())\n .refine((line) => line.length > 0)\n .refine((line) => !line.startsWith('created_at:'))\n .refine((line) => line !== '---')\n .transform((line) => line.split(' '))\n .pipe(z.tuple([z.string(), z.string()]).rest(z.string()))\n .transform(([packageName, versions]) => {\n const deletedVersions = new Set<string>();\n const addedVersions: string[] = [];\n for (const version of versions.split(',')) {\n if (version.startsWith('-')) {\n deletedVersions.add(version.slice(1));\n } else {\n addedVersions.push(version);\n }\n }\n return { packageName, deletedVersions, addedVersions };\n }),\n ),\n );\ntype VersionLines = z.infer<typeof VersionLines>;\n\nfunction isStale(regCache: VersionsEndpointData): boolean {\n return getElapsedMinutes(regCache.syncedAt) >= 15;\n}\n\nexport type VersionsResult = Result<\n string[],\n 'unsupported-api' | 'package-not-found'\n>;\n\nexport class VersionsEndpointCache {\n private readonly http: Http;\n\n constructor(http: Http) {\n this.http = http;\n }\n\n private cacheRequests = new Map<string, Promise<VersionsEndpointResult>>();\n\n /**\n * At any given time, there should only be one request for a given registryUrl.\n */\n private async getCache(registryUrl: string): Promise<VersionsEndpointResult> {\n const oldResult = memCache.get(registryUrl);\n if (!oldResult) {\n const newResult = await this.fullSync(registryUrl);\n cacheResult(registryUrl, newResult);\n return newResult;\n }\n\n const { val: data } = oldResult.unwrap();\n if (!data) {\n return oldResult;\n }\n\n if (isStale(data)) {\n memCache.delete(registryUrl); // If no error is thrown, we'll re-set the cache\n const newResult = await this.deltaSync(data, registryUrl);\n cacheResult(registryUrl, newResult);\n return newResult;\n }\n\n return oldResult;\n }\n\n async getVersions(\n registryUrl: string,\n packageName: string,\n ): Promise<VersionsResult> {\n /**\n * Ensure that only one request for a given registryUrl is in flight at a time.\n */\n let cacheRequest = this.cacheRequests.get(registryUrl);\n if (!cacheRequest) {\n cacheRequest = this.getCache(registryUrl);\n this.cacheRequests.set(registryUrl, cacheRequest);\n }\n let cachedResult: VersionsEndpointResult;\n try {\n cachedResult = await cacheRequest;\n } finally {\n this.cacheRequests.delete(registryUrl);\n }\n\n const { val: cachedData } = cachedResult.unwrap();\n if (!cachedData) {\n logger.debug(\n { packageName, registryUrl },\n 'Rubygems: endpoint not supported',\n );\n return Result.err('unsupported-api');\n }\n\n const versions = cachedData.packageVersions.get(packageName);\n if (!versions?.length) {\n logger.debug(\n { packageName, registryUrl },\n 'Rubygems: versions not found',\n );\n return Result.err('package-not-found');\n }\n\n return Result.ok(versions);\n }\n\n private async fullSync(registryUrl: string): Promise<VersionsEndpointResult> {\n try {\n const url = `${registryUrl}/versions`;\n const opts: HttpOptions = { headers: { 'Accept-Encoding': 'gzip' } };\n const { body } = await this.http.getText(url, opts);\n return parseFullBody(body);\n } catch (err) {\n if (err instanceof HttpError && err.response?.statusCode === 404) {\n return Result.err('unsupported-api');\n }\n\n throw err;\n }\n }\n\n private async deltaSync(\n oldCache: VersionsEndpointData,\n registryUrl: string,\n ): Promise<VersionsEndpointResult> {\n try {\n const url = `${registryUrl}/versions`;\n const startByte = oldCache.contentLength - oldCache.contentTail.length;\n const opts: HttpOptions = {\n headers: {\n ['Accept-Encoding']: 'deflate, compress, br', // Note: `gzip` usage breaks http client, when used with `Range` header\n ['Range']: `bytes=${startByte}-`,\n },\n };\n const { statusCode, body } = await this.http.getText(url, opts);\n\n /**\n * Rubygems will return the full body instead of `416 Range Not Satisfiable`.\n * In this case, status code will be 200 instead of 206.\n */\n if (statusCode === 200) {\n return parseFullBody(body);\n }\n\n /**\n * We request data in range that overlaps previously fetched data.\n * If the head of the response doesn't match the tail of the previous response,\n * it means that the data we have is no longer valid.\n * In this case we start over with a full sync.\n */\n const contentHead = getContentHead(body);\n if (contentHead !== oldCache.contentTail) {\n return this.fullSync(registryUrl);\n }\n\n /**\n * Update the cache with the new data.\n */\n const delta = stripContentHead(body);\n const packageVersions = reconcilePackageVersions(\n oldCache.packageVersions,\n VersionLines.parse(delta),\n );\n const syncedAt = new Date();\n const contentLength = oldCache.contentLength + delta.length;\n const contentTail = getContentTail(body);\n\n return Result.ok({\n packageVersions,\n syncedAt,\n contentLength,\n contentTail,\n });\n } catch (err) {\n if (err instanceof HttpError) {\n const responseStatus = err.response?.statusCode;\n\n /**\n * In case of `416 Range Not Satisfiable` we do a full sync.\n * This is unlikely to happen in real life, but anyway.\n */\n if (responseStatus === 416) {\n return this.fullSync(registryUrl);\n }\n\n /**\n * If the endpoint is not supported, we stop trying.\n * This is unlikely to happen in real life, but still.\n */\n if (responseStatus === 404) {\n return Result.err('unsupported-api');\n }\n }\n\n throw err;\n }\n }\n}\n"],"mappings":"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"}
|
|
@@ -14,12 +14,16 @@ const optionRegex = require_regex.regEx(`^(?<command>\\w+)(:(?<config>\\S+))?\\s
|
|
|
14
14
|
const spaceRegex = require_regex.regEx(`\\s+`);
|
|
15
15
|
var ImportEntry = class {
|
|
16
16
|
entryType = "import";
|
|
17
|
+
path;
|
|
18
|
+
isTry;
|
|
17
19
|
constructor(path, isTry) {
|
|
18
20
|
this.path = path;
|
|
19
21
|
this.isTry = isTry;
|
|
20
22
|
}
|
|
21
23
|
};
|
|
22
24
|
var BazelOption = class BazelOption {
|
|
25
|
+
name;
|
|
26
|
+
value;
|
|
23
27
|
constructor(name, value) {
|
|
24
28
|
this.name = name;
|
|
25
29
|
this.value = value;
|
|
@@ -48,6 +52,9 @@ var BazelOption = class BazelOption {
|
|
|
48
52
|
};
|
|
49
53
|
var CommandEntry = class {
|
|
50
54
|
entryType = "command";
|
|
55
|
+
command;
|
|
56
|
+
options;
|
|
57
|
+
config;
|
|
51
58
|
constructor(command, options, config) {
|
|
52
59
|
this.command = command;
|
|
53
60
|
this.options = options;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bazelrc.js","names":["regEx","isNotNullOrUndefined"],"sources":["../../../../lib/modules/manager/bazel-module/bazelrc.ts"],"sourcesContent":["import upath from 'upath';\nimport { logger } from '../../../logger/index.ts';\nimport { isNotNullOrUndefined } from '../../../util/array.ts';\nimport * as fs from '../../../util/fs/index.ts';\nimport { regEx } from '../../../util/regex.ts';\n\nconst importRegex = regEx(`^(?<type>(?:try-)?import)\\\\s+(?<path>\\\\S+)$`);\nconst optionRegex = regEx(\n `^(?<command>\\\\w+)(:(?<config>\\\\S+))?\\\\s+(?<options>.*)$`,\n);\nconst spaceRegex = regEx(`\\\\s+`);\n\nexport class ImportEntry {\n readonly entryType = 'import';\n
|
|
1
|
+
{"version":3,"file":"bazelrc.js","names":["regEx","isNotNullOrUndefined"],"sources":["../../../../lib/modules/manager/bazel-module/bazelrc.ts"],"sourcesContent":["import upath from 'upath';\nimport { logger } from '../../../logger/index.ts';\nimport { isNotNullOrUndefined } from '../../../util/array.ts';\nimport * as fs from '../../../util/fs/index.ts';\nimport { regEx } from '../../../util/regex.ts';\n\nconst importRegex = regEx(`^(?<type>(?:try-)?import)\\\\s+(?<path>\\\\S+)$`);\nconst optionRegex = regEx(\n `^(?<command>\\\\w+)(:(?<config>\\\\S+))?\\\\s+(?<options>.*)$`,\n);\nconst spaceRegex = regEx(`\\\\s+`);\n\nexport class ImportEntry {\n readonly entryType = 'import';\n readonly path: string;\n readonly isTry: boolean;\n\n constructor(path: string, isTry: boolean) {\n this.path = path;\n this.isTry = isTry;\n }\n}\n\nexport class BazelOption {\n readonly name: string;\n readonly value?: string;\n\n constructor(name: string, value?: string) {\n this.name = name;\n this.value = value;\n }\n\n static parse(input: string): BazelOption[] {\n const options: BazelOption[] = [];\n const parts = input.split(spaceRegex);\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i];\n if (!part.startsWith('--')) {\n continue;\n }\n\n const nameStartIdx = 2;\n // Check for --option_name=option_value\n const equalSignIdx = part.indexOf('=');\n if (equalSignIdx >= 0) {\n const name = part.substring(nameStartIdx, equalSignIdx);\n const value = part.substring(equalSignIdx + 1);\n options.push(new BazelOption(name, value));\n continue;\n }\n\n const name = part.substring(nameStartIdx);\n const nextIdx = i + 1;\n // Check for --option_name OR --option_name option_value\n const value =\n nextIdx < parts.length && !parts[nextIdx].startsWith('--')\n ? parts[nextIdx]\n : undefined;\n options.push(new BazelOption(name, value));\n }\n return options;\n }\n}\n\nexport class CommandEntry {\n readonly entryType = 'command';\n readonly command: string;\n readonly options: BazelOption[];\n readonly config?: string;\n\n constructor(command: string, options: BazelOption[], config?: string) {\n this.command = command;\n this.options = options;\n this.config = config;\n }\n\n getOption(name: string): BazelOption | undefined {\n return this.options.find((bo) => bo.name === name);\n }\n}\n\ntype BazelrcEntries = ImportEntry | CommandEntry;\n\nfunction shouldProcessLine(line: string): boolean {\n if (line.length === 0) {\n return false;\n }\n return !line.startsWith('#');\n}\n\nfunction createEntry(line: string): BazelrcEntries | undefined {\n const importResult = importRegex.exec(line);\n if (importResult?.groups) {\n const irGroups = importResult.groups;\n return new ImportEntry(irGroups.path, irGroups.type === 'try-import');\n }\n const optionResult = optionRegex.exec(line);\n if (optionResult?.groups) {\n const orGroups = optionResult.groups;\n return new CommandEntry(\n orGroups.command,\n BazelOption.parse(orGroups.options),\n orGroups.config,\n );\n }\n return undefined;\n}\n\nexport function expandWorkspacePath(\n value: string,\n workspaceDir: string,\n): string | null {\n if (!value.includes('%workspace%')) {\n return value;\n }\n const absolutePath = upath.resolve(workspaceDir);\n const expandedPath = value.replace('%workspace%', absolutePath);\n if (!fs.isValidLocalPath(expandedPath)) {\n return null;\n }\n return expandedPath;\n}\n\nexport function sanitizeOptions(\n options: BazelOption[],\n workspaceDir: string,\n): BazelOption[] {\n return options\n .map((option) => {\n if (!option.value) {\n return option;\n }\n const expandedPath = expandWorkspacePath(option.value, workspaceDir);\n if (!expandedPath) {\n logger.debug(\n `Skipping invalid workspace path: ${option.value} in ${workspaceDir}`,\n );\n return null;\n }\n return new BazelOption(option.name, expandedPath);\n })\n .filter(isNotNullOrUndefined);\n}\n\nexport function parse(contents: string): BazelrcEntries[] {\n return contents\n .split('\\n')\n .map((l) => l.trim())\n .filter(shouldProcessLine)\n .map(createEntry)\n .filter(isNotNullOrUndefined);\n}\n\nasync function readFile(\n file: string,\n workspaceDir: string,\n readFiles: Set<string>,\n): Promise<CommandEntry[]> {\n if (readFiles.has(file)) {\n throw new Error(\n `Attempted to read a bazelrc multiple times. file: ${file}`,\n );\n }\n readFiles.add(file);\n const contents = await fs.readLocalFile(file, 'utf8');\n if (!contents) {\n return [];\n }\n const entries = parse(contents);\n const results: CommandEntry[] = [];\n for (const entry of entries) {\n if (entry.entryType === 'command') {\n const sanitizedOptions = sanitizeOptions(entry.options, workspaceDir);\n results.push(\n new CommandEntry(entry.command, sanitizedOptions, entry.config),\n );\n continue;\n }\n\n const importFile = upath.normalize(\n entry.path.replace('%workspace%', workspaceDir),\n );\n if (fs.isValidLocalPath(importFile)) {\n const importEntries = await readFile(importFile, workspaceDir, readFiles);\n results.push(...importEntries);\n } else {\n logger.debug(`Skipping non-local .bazelrc import ${importFile}`);\n }\n }\n return results;\n}\n\nexport async function read(workspaceDir: string): Promise<CommandEntry[]> {\n const bazelrcPath = upath.join(workspaceDir, '.bazelrc');\n const readFiles = new Set<string>();\n return await readFile(bazelrcPath, workspaceDir, readFiles);\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pr-cache.js","names":["getCache","prInfo","DateTime","prStates","prFieldsFilter","repoCacheProvider","clone"],"sources":["../../../../lib/modules/platform/bitbucket/pr-cache.ts"],"sourcesContent":["import { dequal } from 'dequal';\nimport { DateTime } from 'luxon';\nimport { logger } from '../../../logger/index.ts';\nimport * as memCache from '../../../util/cache/memory/index.ts';\nimport { getCache } from '../../../util/cache/repository/index.ts';\nimport { clone } from '../../../util/clone.ts';\nimport type { BitbucketHttp } from '../../../util/http/bitbucket.ts';\nimport { repoCacheProvider } from '../../../util/http/cache/repository-http-cache-provider.ts';\nimport type { Pr } from '../types.ts';\nimport type { BitbucketPrCacheData, PagedResult, PrResponse } from './types.ts';\nimport { prFieldsFilter, prInfo, prStates } from './utils.ts';\n\nexport class BitbucketPrCache {\n private items: Pr[] = [];\n private cache: BitbucketPrCacheData;\n
|
|
1
|
+
{"version":3,"file":"pr-cache.js","names":["getCache","prInfo","DateTime","prStates","prFieldsFilter","repoCacheProvider","clone"],"sources":["../../../../lib/modules/platform/bitbucket/pr-cache.ts"],"sourcesContent":["import { dequal } from 'dequal';\nimport { DateTime } from 'luxon';\nimport { logger } from '../../../logger/index.ts';\nimport * as memCache from '../../../util/cache/memory/index.ts';\nimport { getCache } from '../../../util/cache/repository/index.ts';\nimport { clone } from '../../../util/clone.ts';\nimport type { BitbucketHttp } from '../../../util/http/bitbucket.ts';\nimport { repoCacheProvider } from '../../../util/http/cache/repository-http-cache-provider.ts';\nimport type { Pr } from '../types.ts';\nimport type { BitbucketPrCacheData, PagedResult, PrResponse } from './types.ts';\nimport { prFieldsFilter, prInfo, prStates } from './utils.ts';\n\nexport class BitbucketPrCache {\n private items: Pr[] = [];\n private cache: BitbucketPrCacheData;\n private repo: string;\n private author: string | null;\n\n private constructor(repo: string, author: string | null) {\n this.repo = repo;\n this.author = author;\n const repoCache = getCache();\n repoCache.platform ??= {};\n repoCache.platform.bitbucket ??= {};\n\n let pullRequestCache = repoCache.platform.bitbucket.pullRequestsCache as\n | BitbucketPrCacheData\n | undefined;\n if (!pullRequestCache) {\n logger.debug('Initializing new PR cache at repository cache');\n pullRequestCache = {\n items: {},\n updated_on: null,\n author,\n };\n } else if (pullRequestCache.author !== author) {\n logger.debug('Resetting PR cache because authors do not match');\n pullRequestCache = {\n items: {},\n updated_on: null,\n author,\n };\n }\n repoCache.platform.bitbucket.pullRequestsCache = pullRequestCache;\n this.cache = pullRequestCache;\n this.updateItems();\n }\n\n private static async init(\n http: BitbucketHttp,\n repo: string,\n author: string | null,\n ): Promise<BitbucketPrCache> {\n const res = new BitbucketPrCache(repo, author);\n const isSynced = memCache.get<true | undefined>(\n 'bitbucket-pr-cache-synced',\n );\n\n if (!isSynced) {\n await res.sync(http);\n memCache.set('bitbucket-pr-cache-synced', true);\n }\n\n return res;\n }\n\n private getPrs(): Pr[] {\n return this.items;\n }\n\n static async getPrs(\n http: BitbucketHttp,\n repo: string,\n author: string | null,\n ): Promise<Pr[]> {\n const prCache = await BitbucketPrCache.init(http, repo, author);\n return prCache.getPrs();\n }\n\n private setPr(pr: Pr): void {\n logger.debug(`Adding PR #${pr.number} to the PR cache`);\n this.cache.items[pr.number] = pr;\n this.updateItems();\n }\n\n static async setPr(\n http: BitbucketHttp,\n repo: string,\n author: string | null,\n item: Pr,\n ): Promise<void> {\n const prCache = await BitbucketPrCache.init(http, repo, author);\n prCache.setPr(item);\n }\n\n private reconcile(rawItems: PrResponse[]): void {\n const { items: oldItems } = this.cache;\n let { updated_on } = this.cache;\n\n for (const rawItem of rawItems) {\n const id = rawItem.id;\n\n const oldItem = oldItems[id];\n const newItem = prInfo(rawItem);\n\n const itemNewTime = DateTime.fromISO(rawItem.updated_on);\n\n if (!dequal(oldItem, newItem)) {\n oldItems[id] = newItem;\n }\n\n const cacheOldTime = updated_on ? DateTime.fromISO(updated_on) : null;\n if (!cacheOldTime || itemNewTime > cacheOldTime) {\n updated_on = rawItem.updated_on;\n }\n }\n\n this.cache.updated_on = updated_on;\n }\n\n private getUrl(): string {\n const params = new URLSearchParams();\n\n for (const state of prStates.all) {\n params.append('state', state);\n }\n\n params.append('fields', prFieldsFilter);\n\n const q: string[] = [];\n if (this.author) {\n q.push(`author.uuid = \"${this.author}\"`);\n }\n if (this.cache.updated_on) {\n q.push(`updated_on > \"${this.cache.updated_on}\"`);\n }\n params.append('q', q.join(' AND '));\n\n const query = params.toString();\n return `/2.0/repositories/${this.repo}/pullrequests?${query}`;\n }\n\n private async sync(http: BitbucketHttp): Promise<BitbucketPrCache> {\n logger.debug('Syncing PR list');\n const url = this.getUrl();\n const opts = {\n paginate: true,\n pagelen: 50,\n cacheProvider: repoCacheProvider,\n };\n const res = await http.getJsonUnchecked<PagedResult<PrResponse>>(url, opts);\n\n const items = res.body.values;\n logger.debug(`Fetched ${items.length} PRs to sync with cache`);\n const oldCache = clone(this.cache.items);\n\n this.reconcile(items);\n\n logger.debug(`Total PRs cached: ${Object.values(this.cache.items).length}`);\n logger.trace(\n {\n items,\n oldCache,\n newCache: this.cache.items,\n },\n `PR cache sync finished`,\n );\n\n this.updateItems();\n return this;\n }\n\n /**\n * Ensure the pr cache starts with the most recent PRs.\n * JavaScript ensures that the cache is sorted by PR number.\n */\n private updateItems(): void {\n this.items = Object.values(this.cache.items).reverse();\n }\n}\n"],"mappings":";;;;;;;;;;;6BAEkD;2BACc;AAShE,IAAa,mBAAb,MAAa,iBAAiB;CAC5B,AAAQ,QAAc,EAAE;CACxB,AAAQ;CACR,AAAQ;CACR,AAAQ;CAER,AAAQ,YAAY,MAAc,QAAuB;AACvD,OAAK,OAAO;AACZ,OAAK,SAAS;EACd,MAAM,YAAYA,0BAAU;AAC5B,YAAU,aAAa,EAAE;AACzB,YAAU,SAAS,cAAc,EAAE;EAEnC,IAAI,mBAAmB,UAAU,SAAS,UAAU;AAGpD,MAAI,CAAC,kBAAkB;AACrB,0BAAO,MAAM,gDAAgD;AAC7D,sBAAmB;IACjB,OAAO,EAAE;IACT,YAAY;IACZ;IACD;aACQ,iBAAiB,WAAW,QAAQ;AAC7C,0BAAO,MAAM,kDAAkD;AAC/D,sBAAmB;IACjB,OAAO,EAAE;IACT,YAAY;IACZ;IACD;;AAEH,YAAU,SAAS,UAAU,oBAAoB;AACjD,OAAK,QAAQ;AACb,OAAK,aAAa;;CAGpB,aAAqB,KACnB,MACA,MACA,QAC2B;EAC3B,MAAM,MAAM,IAAI,iBAAiB,MAAM,OAAO;AAK9C,MAAI,mBAHF,4BACD,EAEc;AACb,SAAM,IAAI,KAAK,KAAK;AACpB,qBAAa,6BAA6B,KAAK;;AAGjD,SAAO;;CAGT,AAAQ,SAAe;AACrB,SAAO,KAAK;;CAGd,aAAa,OACX,MACA,MACA,QACe;AAEf,UADgB,MAAM,iBAAiB,KAAK,MAAM,MAAM,OAAO,EAChD,QAAQ;;CAGzB,AAAQ,MAAM,IAAc;AAC1B,yBAAO,MAAM,cAAc,GAAG,OAAO,kBAAkB;AACvD,OAAK,MAAM,MAAM,GAAG,UAAU;AAC9B,OAAK,aAAa;;CAGpB,aAAa,MACX,MACA,MACA,QACA,MACe;AAEf,GADgB,MAAM,iBAAiB,KAAK,MAAM,MAAM,OAAO,EACvD,MAAM,KAAK;;CAGrB,AAAQ,UAAU,UAA8B;EAC9C,MAAM,EAAE,OAAO,aAAa,KAAK;EACjC,IAAI,EAAE,eAAe,KAAK;AAE1B,OAAK,MAAM,WAAW,UAAU;GAC9B,MAAM,KAAK,QAAQ;GAEnB,MAAM,UAAU,SAAS;GACzB,MAAM,UAAUC,qBAAO,QAAQ;GAE/B,MAAM,cAAcC,eAAS,QAAQ,QAAQ,WAAW;AAExD,OAAI,oBAAQ,SAAS,QAAQ,CAC3B,UAAS,MAAM;GAGjB,MAAM,eAAe,aAAaA,eAAS,QAAQ,WAAW,GAAG;AACjE,OAAI,CAAC,gBAAgB,cAAc,aACjC,cAAa,QAAQ;;AAIzB,OAAK,MAAM,aAAa;;CAG1B,AAAQ,SAAiB;EACvB,MAAM,SAAS,IAAI,iBAAiB;AAEpC,OAAK,MAAM,SAASC,uBAAS,IAC3B,QAAO,OAAO,SAAS,MAAM;AAG/B,SAAO,OAAO,UAAUC,6BAAe;EAEvC,MAAM,IAAc,EAAE;AACtB,MAAI,KAAK,OACP,GAAE,KAAK,kBAAkB,KAAK,OAAO,GAAG;AAE1C,MAAI,KAAK,MAAM,WACb,GAAE,KAAK,iBAAiB,KAAK,MAAM,WAAW,GAAG;AAEnD,SAAO,OAAO,KAAK,EAAE,KAAK,QAAQ,CAAC;EAEnC,MAAM,QAAQ,OAAO,UAAU;AAC/B,SAAO,qBAAqB,KAAK,KAAK,gBAAgB;;CAGxD,MAAc,KAAK,MAAgD;AACjE,yBAAO,MAAM,kBAAkB;EAC/B,MAAM,MAAM,KAAK,QAAQ;EACzB,MAAM,OAAO;GACX,UAAU;GACV,SAAS;GACT,eAAeC;GAChB;EAGD,MAAM,SAFM,MAAM,KAAK,iBAA0C,KAAK,KAAK,EAEzD,KAAK;AACvB,yBAAO,MAAM,WAAW,MAAM,OAAO,yBAAyB;EAC9D,MAAM,WAAWC,oBAAM,KAAK,MAAM,MAAM;AAExC,OAAK,UAAU,MAAM;AAErB,yBAAO,MAAM,qBAAqB,OAAO,OAAO,KAAK,MAAM,MAAM,CAAC,SAAS;AAC3E,yBAAO,MACL;GACE;GACA;GACA,UAAU,KAAK,MAAM;GACtB,EACD,yBACD;AAED,OAAK,aAAa;AAClB,SAAO;;;;;;CAOT,AAAQ,cAAoB;AAC1B,OAAK,QAAQ,OAAO,OAAO,KAAK,MAAM,MAAM,CAAC,SAAS"}
|
|
@@ -22,6 +22,10 @@ function migrateBitbucketServerCache(platform) {
|
|
|
22
22
|
var BbsPrCache = class BbsPrCache {
|
|
23
23
|
cache;
|
|
24
24
|
items = [];
|
|
25
|
+
projectKey;
|
|
26
|
+
repo;
|
|
27
|
+
ignorePrAuthor;
|
|
28
|
+
author;
|
|
25
29
|
constructor(projectKey, repo, ignorePrAuthor, author) {
|
|
26
30
|
this.projectKey = projectKey;
|
|
27
31
|
this.repo = repo;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pr-cache.js","names":["getCache","DateTime","prInfo","getQueryString"],"sources":["../../../../lib/modules/platform/bitbucket-server/pr-cache.ts"],"sourcesContent":["import { isNullOrUndefined, isPlainObject, isString } from '@sindresorhus/is';\nimport { dequal } from 'dequal';\nimport { DateTime } from 'luxon';\nimport { logger } from '../../../logger/index.ts';\nimport * as memCache from '../../../util/cache/memory/index.ts';\nimport { getCache } from '../../../util/cache/repository/index.ts';\nimport type { BitbucketServerHttp } from '../../../util/http/bitbucket-server.ts';\nimport { getQueryString } from '../../../util/url.ts';\nimport type { BbsPr, BbsPrCacheData, BbsRestPr } from './types.ts';\nimport { prInfo } from './utils.ts';\n\n/* v8 ignore next */\nfunction migrateBitbucketServerCache(platform: unknown): void {\n if (!isPlainObject(platform)) {\n return;\n }\n\n if (!isPlainObject(platform.bitbucketServer)) {\n return;\n }\n\n platform['bitbucket-server'] = platform.bitbucketServer;\n delete platform.bitbucketServer;\n}\n\nexport class BbsPrCache {\n private cache: BbsPrCacheData;\n private items: BbsPr[] = [];\n\n private constructor(\n
|
|
1
|
+
{"version":3,"file":"pr-cache.js","names":["getCache","DateTime","prInfo","getQueryString"],"sources":["../../../../lib/modules/platform/bitbucket-server/pr-cache.ts"],"sourcesContent":["import { isNullOrUndefined, isPlainObject, isString } from '@sindresorhus/is';\nimport { dequal } from 'dequal';\nimport { DateTime } from 'luxon';\nimport { logger } from '../../../logger/index.ts';\nimport * as memCache from '../../../util/cache/memory/index.ts';\nimport { getCache } from '../../../util/cache/repository/index.ts';\nimport type { BitbucketServerHttp } from '../../../util/http/bitbucket-server.ts';\nimport { getQueryString } from '../../../util/url.ts';\nimport type { BbsPr, BbsPrCacheData, BbsRestPr } from './types.ts';\nimport { prInfo } from './utils.ts';\n\n/* v8 ignore next */\nfunction migrateBitbucketServerCache(platform: unknown): void {\n if (!isPlainObject(platform)) {\n return;\n }\n\n if (!isPlainObject(platform.bitbucketServer)) {\n return;\n }\n\n platform['bitbucket-server'] = platform.bitbucketServer;\n delete platform.bitbucketServer;\n}\n\nexport class BbsPrCache {\n private cache: BbsPrCacheData;\n private items: BbsPr[] = [];\n private projectKey: string;\n private repo: string;\n private readonly ignorePrAuthor: boolean;\n private author: string | null;\n\n private constructor(\n projectKey: string,\n repo: string,\n ignorePrAuthor: boolean,\n author: string | null,\n ) {\n this.projectKey = projectKey;\n this.repo = repo;\n this.ignorePrAuthor = ignorePrAuthor;\n this.author = author;\n const repoCache = getCache();\n repoCache.platform ??= {};\n migrateBitbucketServerCache(repoCache.platform);\n repoCache.platform['bitbucket-server'] ??= {};\n let pullRequestCache = repoCache.platform['bitbucket-server']\n .pullRequestsCache as BbsPrCacheData;\n if (\n isNullOrUndefined(pullRequestCache) ||\n pullRequestCache.author !== author\n ) {\n pullRequestCache = {\n items: {},\n updatedDate: null,\n author,\n };\n }\n repoCache.platform['bitbucket-server'].pullRequestsCache = pullRequestCache;\n this.cache = pullRequestCache;\n this.updateItems();\n }\n\n private static async init(\n http: BitbucketServerHttp,\n projectKey: string,\n repo: string,\n ignorePrAuthor: boolean,\n author: string | null,\n ): Promise<BbsPrCache> {\n const res = new BbsPrCache(projectKey, repo, ignorePrAuthor, author);\n const isSynced = memCache.get<true | undefined>('bbs-pr-cache-synced');\n\n if (!isSynced) {\n await res.sync(http);\n memCache.set('bbs-pr-cache-synced', true);\n }\n\n return res;\n }\n\n private getPrs(): BbsPr[] {\n return this.items;\n }\n\n static async getPrs(\n http: BitbucketServerHttp,\n projectKey: string,\n repo: string,\n ignorePrAuthor: boolean,\n author: string,\n ): Promise<BbsPr[]> {\n const prCache = await BbsPrCache.init(\n http,\n projectKey,\n repo,\n ignorePrAuthor,\n author,\n );\n return prCache.getPrs();\n }\n\n private setPr(item: BbsPr): void {\n this.cache.items[item.number] = item;\n this.updateItems();\n }\n\n static async setPr(\n http: BitbucketServerHttp,\n projectKey: string,\n repo: string,\n ignorePrAuthor: boolean,\n author: string,\n item: BbsPr,\n ): Promise<void> {\n const prCache = await BbsPrCache.init(\n http,\n projectKey,\n repo,\n ignorePrAuthor,\n author,\n );\n prCache.setPr(item);\n }\n\n private reconcile(rawItems: BbsRestPr[]): boolean {\n logger.debug('reconciled');\n const { items } = this.cache;\n let { updatedDate } = this.cache;\n const cacheTime = updatedDate ? DateTime.fromMillis(updatedDate) : null;\n\n let needNextPage = true;\n\n for (const rawItem of rawItems) {\n const id = rawItem.id;\n\n const newItem = prInfo(rawItem);\n\n const oldItem = items[id];\n if (dequal(oldItem, newItem)) {\n needNextPage = false;\n continue;\n }\n\n items[id] = newItem;\n\n const itemTime = DateTime.fromMillis(rawItem.updatedDate);\n if (!cacheTime || itemTime > cacheTime) {\n updatedDate = rawItem.updatedDate;\n }\n }\n\n this.cache.updatedDate = updatedDate;\n\n return needNextPage;\n }\n\n private async sync(http: BitbucketServerHttp): Promise<BbsPrCache> {\n const searchParams: Record<string, string> = {\n state: 'ALL',\n limit: this.items.length ? '20' : '100',\n };\n if (!this.ignorePrAuthor && isString(this.author)) {\n searchParams['role.1'] = 'AUTHOR';\n searchParams['username.1'] = this.author;\n }\n let query: string | null = getQueryString(searchParams);\n\n while (query) {\n const res = await http.getJsonUnchecked<{\n nextPageStart: string;\n values: BbsRestPr[];\n }>(\n `./rest/api/1.0/projects/${this.projectKey}/repos/${this.repo}/pull-requests?${query}`,\n {\n memCache: false,\n },\n );\n\n const needNextPage = this.reconcile(res.body.values);\n if (!needNextPage) {\n break;\n }\n\n if (res.body.nextPageStart) {\n searchParams.start = res.body.nextPageStart.toString();\n } else {\n query = null;\n }\n }\n\n this.updateItems();\n\n return this;\n }\n\n /**\n * Ensure the pr cache starts with the most recent PRs.\n * JavaScript ensures that the cache is sorted by PR number.\n */\n private updateItems(): void {\n this.items = Object.values(this.cache.items).reverse();\n }\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pr-cache.js","names":["getCache","DateTime","TEMPORARY_ERROR","toRenovatePR","getQueryString","API_PATH","parseUrl","parseLinkHeader"],"sources":["../../../../lib/modules/platform/forgejo/pr-cache.ts"],"sourcesContent":["import { isNullOrUndefined } from '@sindresorhus/is';\nimport { dequal } from 'dequal';\nimport { DateTime } from 'luxon';\nimport { TEMPORARY_ERROR } from '../../../constants/error-messages.ts';\nimport { logger } from '../../../logger/index.ts';\nimport * as memCache from '../../../util/cache/memory/index.ts';\nimport { getCache } from '../../../util/cache/repository/index.ts';\nimport type { ForgejoHttp } from '../../../util/http/forgejo.ts';\nimport type { HttpResponse } from '../../../util/http/types.ts';\nimport {\n getQueryString,\n parseLinkHeader,\n parseUrl,\n} from '../../../util/url.ts';\nimport type { Pr } from '../types.ts';\nimport type { ForgejoPrCacheData, PR } from './types.ts';\nimport { API_PATH, toRenovatePR } from './utils.ts';\n\nexport class ForgejoPrCache {\n private cache: ForgejoPrCacheData;\n private items: Pr[] = [];\n\n private constructor(\n
|
|
1
|
+
{"version":3,"file":"pr-cache.js","names":["getCache","DateTime","TEMPORARY_ERROR","toRenovatePR","getQueryString","API_PATH","parseUrl","parseLinkHeader"],"sources":["../../../../lib/modules/platform/forgejo/pr-cache.ts"],"sourcesContent":["import { isNullOrUndefined } from '@sindresorhus/is';\nimport { dequal } from 'dequal';\nimport { DateTime } from 'luxon';\nimport { TEMPORARY_ERROR } from '../../../constants/error-messages.ts';\nimport { logger } from '../../../logger/index.ts';\nimport * as memCache from '../../../util/cache/memory/index.ts';\nimport { getCache } from '../../../util/cache/repository/index.ts';\nimport type { ForgejoHttp } from '../../../util/http/forgejo.ts';\nimport type { HttpResponse } from '../../../util/http/types.ts';\nimport {\n getQueryString,\n parseLinkHeader,\n parseUrl,\n} from '../../../util/url.ts';\nimport type { Pr } from '../types.ts';\nimport type { ForgejoPrCacheData, PR } from './types.ts';\nimport { API_PATH, toRenovatePR } from './utils.ts';\n\nexport class ForgejoPrCache {\n private cache: ForgejoPrCacheData;\n private items: Pr[] = [];\n private repo: string;\n private readonly ignorePrAuthor: boolean;\n private author: string | null;\n\n private constructor(\n repo: string,\n ignorePrAuthor: boolean,\n author: string | null,\n ) {\n this.repo = repo;\n this.ignorePrAuthor = ignorePrAuthor;\n this.author = author;\n const repoCache = getCache();\n repoCache.platform ??= {};\n repoCache.platform.forgejo ??= {};\n let pullRequestCache = repoCache.platform.forgejo.pullRequestsCache as\n | ForgejoPrCacheData\n | undefined;\n if (\n isNullOrUndefined(pullRequestCache) ||\n pullRequestCache.author !== author\n ) {\n pullRequestCache = {\n items: {},\n updated_at: null,\n author,\n };\n }\n repoCache.platform.forgejo.pullRequestsCache = pullRequestCache;\n this.cache = pullRequestCache;\n this.updateItems();\n }\n\n static forceSync(): void {\n memCache.set('forgejo-pr-cache-synced', false);\n }\n\n private static async init(\n http: ForgejoHttp,\n repo: string,\n ignorePrAuthor: boolean,\n author: string | null,\n ): Promise<ForgejoPrCache> {\n const res = new ForgejoPrCache(repo, ignorePrAuthor, author);\n const isSynced = memCache.get<true | undefined>('forgejo-pr-cache-synced');\n\n if (!isSynced) {\n await res.sync(http);\n memCache.set('forgejo-pr-cache-synced', true);\n }\n\n return res;\n }\n\n private getPrs(): Pr[] {\n return this.items;\n }\n\n static async getPrs(\n http: ForgejoHttp,\n repo: string,\n ignorePrAuthor: boolean,\n author: string,\n ): Promise<Pr[]> {\n const prCache = await ForgejoPrCache.init(\n http,\n repo,\n ignorePrAuthor,\n author,\n );\n return prCache.getPrs();\n }\n\n private setPr(item: Pr): void {\n this.cache.items[item.number] = item;\n this.updateItems();\n }\n\n static async setPr(\n http: ForgejoHttp,\n repo: string,\n ignorePrAuthor: boolean,\n author: string,\n item: Pr,\n ): Promise<void> {\n const prCache = await ForgejoPrCache.init(\n http,\n repo,\n ignorePrAuthor,\n author,\n );\n prCache.setPr(item);\n }\n\n private reconcile(rawItems: (PR | null)[]): boolean {\n const { items } = this.cache;\n let { updated_at } = this.cache;\n const cacheTime = updated_at ? DateTime.fromISO(updated_at) : null;\n\n let needNextPage = true;\n\n for (const rawItem of rawItems) {\n if (!rawItem) {\n logger.warn('Forgejo PR is empty, throwing temporary error');\n // Forgejo API sometimes returns empty PRs, so we throw a temporary error\n // https://github.com/go-forgejo/forgejo/blob/fcd096231ac2deaefbca10a7db1b9b01f1da93d7/services/convert/pull.go#L34-L52\n throw new Error(TEMPORARY_ERROR);\n }\n const id = rawItem.number;\n\n const newItem = toRenovatePR(rawItem, this.author);\n if (!newItem) {\n continue;\n }\n\n const oldItem = items[id];\n if (dequal(oldItem, newItem)) {\n needNextPage = false;\n continue;\n }\n\n items[id] = newItem;\n\n const itemTime = DateTime.fromISO(rawItem.updated_at);\n if (!cacheTime || itemTime > cacheTime) {\n updated_at = rawItem.updated_at;\n }\n }\n\n this.cache.updated_at = updated_at;\n\n return needNextPage;\n }\n\n private async sync(http: ForgejoHttp): Promise<ForgejoPrCache> {\n let query: string | null = getQueryString({\n state: 'all',\n sort: 'recentupdate',\n // Fetch 100 PRs on the first run to ensure we have the most recent PRs.\n // Forgejo will cap appropriate (50 by default, see `MAX_RESPONSE_ITEMS`).\n // https://docs.forgejo.com/administration/config-cheat-sheet#api-api\n // https://forgejo.org/docs/latest/admin/config-cheat-sheet/#api-api\n limit: this.items.length ? 20 : 100,\n // Supported since Forgejo v10.0.0.\n // Will be ignored by older instances.\n ...(this.ignorePrAuthor ? {} : { poster: this.author }),\n });\n\n while (query) {\n // TODO: use zod, typescript can't infer the type of the response #22198\n const res: HttpResponse<(PR | null)[]> = await http.getJsonUnchecked(\n `${API_PATH}/repos/${this.repo}/pulls?${query}`,\n {\n memCache: false,\n paginate: false,\n },\n );\n\n const needNextPage = this.reconcile(res.body);\n if (!needNextPage) {\n break;\n }\n\n const uri = parseUrl(parseLinkHeader(res.headers.link)?.next?.url);\n query = uri ? uri.search : null;\n }\n\n this.updateItems();\n\n return this;\n }\n\n /**\n * Ensure the pr cache starts with the most recent PRs.\n * JavaScript ensures that the cache is sorted by PR number.\n */\n private updateItems(): void {\n this.items = Object.values(this.cache.items).reverse();\n }\n}\n"],"mappings":";;;;;;;;;;;;4CAGuE;6BACrB;2BACc;sBAQlC;AAK9B,IAAa,iBAAb,MAAa,eAAe;CAC1B,AAAQ;CACR,AAAQ,QAAc,EAAE;CACxB,AAAQ;CACR,AAAiB;CACjB,AAAQ;CAER,AAAQ,YACN,MACA,gBACA,QACA;AACA,OAAK,OAAO;AACZ,OAAK,iBAAiB;AACtB,OAAK,SAAS;EACd,MAAM,YAAYA,0BAAU;AAC5B,YAAU,aAAa,EAAE;AACzB,YAAU,SAAS,YAAY,EAAE;EACjC,IAAI,mBAAmB,UAAU,SAAS,QAAQ;AAGlD,8CACoB,iBAAiB,IACnC,iBAAiB,WAAW,OAE5B,oBAAmB;GACjB,OAAO,EAAE;GACT,YAAY;GACZ;GACD;AAEH,YAAU,SAAS,QAAQ,oBAAoB;AAC/C,OAAK,QAAQ;AACb,OAAK,aAAa;;CAGpB,OAAO,YAAkB;AACvB,oBAAa,2BAA2B,MAAM;;CAGhD,aAAqB,KACnB,MACA,MACA,gBACA,QACyB;EACzB,MAAM,MAAM,IAAI,eAAe,MAAM,gBAAgB,OAAO;AAG5D,MAAI,mBAF4C,0BAA0B,EAE3D;AACb,SAAM,IAAI,KAAK,KAAK;AACpB,qBAAa,2BAA2B,KAAK;;AAG/C,SAAO;;CAGT,AAAQ,SAAe;AACrB,SAAO,KAAK;;CAGd,aAAa,OACX,MACA,MACA,gBACA,QACe;AAOf,UANgB,MAAM,eAAe,KACnC,MACA,MACA,gBACA,OACD,EACc,QAAQ;;CAGzB,AAAQ,MAAM,MAAgB;AAC5B,OAAK,MAAM,MAAM,KAAK,UAAU;AAChC,OAAK,aAAa;;CAGpB,aAAa,MACX,MACA,MACA,gBACA,QACA,MACe;AAOf,GANgB,MAAM,eAAe,KACnC,MACA,MACA,gBACA,OACD,EACO,MAAM,KAAK;;CAGrB,AAAQ,UAAU,UAAkC;EAClD,MAAM,EAAE,UAAU,KAAK;EACvB,IAAI,EAAE,eAAe,KAAK;EAC1B,MAAM,YAAY,aAAaC,eAAS,QAAQ,WAAW,GAAG;EAE9D,IAAI,eAAe;AAEnB,OAAK,MAAM,WAAW,UAAU;AAC9B,OAAI,CAAC,SAAS;AACZ,2BAAO,KAAK,gDAAgD;AAG5D,UAAM,IAAI,MAAMC,uCAAgB;;GAElC,MAAM,KAAK,QAAQ;GAEnB,MAAM,UAAUC,2BAAa,SAAS,KAAK,OAAO;AAClD,OAAI,CAAC,QACH;GAGF,MAAM,UAAU,MAAM;AACtB,0BAAW,SAAS,QAAQ,EAAE;AAC5B,mBAAe;AACf;;AAGF,SAAM,MAAM;GAEZ,MAAM,WAAWF,eAAS,QAAQ,QAAQ,WAAW;AACrD,OAAI,CAAC,aAAa,WAAW,UAC3B,cAAa,QAAQ;;AAIzB,OAAK,MAAM,aAAa;AAExB,SAAO;;CAGT,MAAc,KAAK,MAA4C;EAC7D,IAAI,QAAuBG,2BAAe;GACxC,OAAO;GACP,MAAM;GAKN,OAAO,KAAK,MAAM,SAAS,KAAK;GAGhC,GAAI,KAAK,iBAAiB,EAAE,GAAG,EAAE,QAAQ,KAAK,QAAQ;GACvD,CAAC;AAEF,SAAO,OAAO;GAEZ,MAAM,MAAmC,MAAM,KAAK,iBAClD,GAAGC,uBAAS,SAAS,KAAK,KAAK,SAAS,SACxC;IACE,UAAU;IACV,UAAU;IACX,CACF;AAGD,OAAI,CADiB,KAAK,UAAU,IAAI,KAAK,CAE3C;GAGF,MAAM,MAAMC,qBAASC,4BAAgB,IAAI,QAAQ,KAAK,EAAE,MAAM,IAAI;AAClE,WAAQ,MAAM,IAAI,SAAS;;AAG7B,OAAK,aAAa;AAElB,SAAO;;;;;;CAOT,AAAQ,cAAoB;AAC1B,OAAK,QAAQ,OAAO,OAAO,KAAK,MAAM,MAAM,CAAC,SAAS"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pr-cache.js","names":["getCache","DateTime","TEMPORARY_ERROR","toRenovatePR","getQueryString","API_PATH","parseUrl","parseLinkHeader"],"sources":["../../../../lib/modules/platform/gitea/pr-cache.ts"],"sourcesContent":["import { isNullOrUndefined } from '@sindresorhus/is';\nimport { dequal } from 'dequal';\nimport { DateTime } from 'luxon';\nimport { TEMPORARY_ERROR } from '../../../constants/error-messages.ts';\nimport { logger } from '../../../logger/index.ts';\nimport * as memCache from '../../../util/cache/memory/index.ts';\nimport { getCache } from '../../../util/cache/repository/index.ts';\nimport type { GiteaHttp } from '../../../util/http/gitea.ts';\nimport type { HttpResponse } from '../../../util/http/types.ts';\nimport {\n getQueryString,\n parseLinkHeader,\n parseUrl,\n} from '../../../util/url.ts';\nimport type { Pr } from '../types.ts';\nimport type { GiteaPrCacheData, PR } from './types.ts';\nimport { API_PATH, toRenovatePR } from './utils.ts';\n\nexport class GiteaPrCache {\n private cache: GiteaPrCacheData;\n private items: Pr[] = [];\n\n private constructor(\n
|
|
1
|
+
{"version":3,"file":"pr-cache.js","names":["getCache","DateTime","TEMPORARY_ERROR","toRenovatePR","getQueryString","API_PATH","parseUrl","parseLinkHeader"],"sources":["../../../../lib/modules/platform/gitea/pr-cache.ts"],"sourcesContent":["import { isNullOrUndefined } from '@sindresorhus/is';\nimport { dequal } from 'dequal';\nimport { DateTime } from 'luxon';\nimport { TEMPORARY_ERROR } from '../../../constants/error-messages.ts';\nimport { logger } from '../../../logger/index.ts';\nimport * as memCache from '../../../util/cache/memory/index.ts';\nimport { getCache } from '../../../util/cache/repository/index.ts';\nimport type { GiteaHttp } from '../../../util/http/gitea.ts';\nimport type { HttpResponse } from '../../../util/http/types.ts';\nimport {\n getQueryString,\n parseLinkHeader,\n parseUrl,\n} from '../../../util/url.ts';\nimport type { Pr } from '../types.ts';\nimport type { GiteaPrCacheData, PR } from './types.ts';\nimport { API_PATH, toRenovatePR } from './utils.ts';\n\nexport class GiteaPrCache {\n private cache: GiteaPrCacheData;\n private items: Pr[] = [];\n private repo: string;\n private readonly ignorePrAuthor: boolean;\n private author: string | null;\n\n private constructor(\n repo: string,\n ignorePrAuthor: boolean,\n author: string | null,\n ) {\n this.repo = repo;\n this.ignorePrAuthor = ignorePrAuthor;\n this.author = author;\n const repoCache = getCache();\n repoCache.platform ??= {};\n repoCache.platform.gitea ??= {};\n let pullRequestCache = repoCache.platform.gitea.pullRequestsCache as\n | GiteaPrCacheData\n | undefined;\n if (\n isNullOrUndefined(pullRequestCache) ||\n pullRequestCache.author !== author\n ) {\n pullRequestCache = {\n items: {},\n updated_at: null,\n author,\n };\n }\n repoCache.platform.gitea.pullRequestsCache = pullRequestCache;\n this.cache = pullRequestCache;\n this.updateItems();\n }\n\n static forceSync(): void {\n memCache.set('gitea-pr-cache-synced', false);\n }\n\n private static async init(\n http: GiteaHttp,\n repo: string,\n ignorePrAuthor: boolean,\n author: string | null,\n ): Promise<GiteaPrCache> {\n const res = new GiteaPrCache(repo, ignorePrAuthor, author);\n const isSynced = memCache.get<true | undefined>('gitea-pr-cache-synced');\n\n if (!isSynced) {\n await res.sync(http);\n memCache.set('gitea-pr-cache-synced', true);\n }\n\n return res;\n }\n\n private getPrs(): Pr[] {\n return this.items;\n }\n\n static async getPrs(\n http: GiteaHttp,\n repo: string,\n ignorePrAuthor: boolean,\n author: string,\n ): Promise<Pr[]> {\n const prCache = await GiteaPrCache.init(http, repo, ignorePrAuthor, author);\n return prCache.getPrs();\n }\n\n private setPr(item: Pr): void {\n this.cache.items[item.number] = item;\n this.updateItems();\n }\n\n static async setPr(\n http: GiteaHttp,\n repo: string,\n ignorePrAuthor: boolean,\n author: string,\n item: Pr,\n ): Promise<void> {\n const prCache = await GiteaPrCache.init(http, repo, ignorePrAuthor, author);\n prCache.setPr(item);\n }\n\n private reconcile(rawItems: (PR | null)[]): boolean {\n const { items } = this.cache;\n let { updated_at } = this.cache;\n const cacheTime = updated_at ? DateTime.fromISO(updated_at) : null;\n\n let needNextPage = true;\n\n for (const rawItem of rawItems) {\n if (!rawItem) {\n logger.warn('Gitea PR is empty, throwing temporary error');\n // Gitea API sometimes returns empty PRs, so we throw a temporary error\n // https://github.com/go-gitea/gitea/blob/fcd096231ac2deaefbca10a7db1b9b01f1da93d7/services/convert/pull.go#L34-L52\n throw new Error(TEMPORARY_ERROR);\n }\n const id = rawItem.number;\n\n const newItem = toRenovatePR(rawItem, this.author);\n if (!newItem) {\n continue;\n }\n\n const oldItem = items[id];\n if (dequal(oldItem, newItem)) {\n needNextPage = false;\n continue;\n }\n\n items[id] = newItem;\n\n const itemTime = DateTime.fromISO(rawItem.updated_at);\n if (!cacheTime || itemTime > cacheTime) {\n updated_at = rawItem.updated_at;\n }\n }\n\n this.cache.updated_at = updated_at;\n\n return needNextPage;\n }\n\n private async sync(http: GiteaHttp): Promise<GiteaPrCache> {\n let query: string | null = getQueryString({\n state: 'all',\n sort: 'recentupdate',\n // Fetch 100 PRs on the first run to ensure we have the most recent PRs.\n // Gitea / Forgejo will cap appropriate (50 by default, see `MAX_RESPONSE_ITEMS`).\n // https://docs.gitea.com/administration/config-cheat-sheet#api-api\n // https://forgejo.org/docs/latest/admin/config-cheat-sheet/#api-api\n limit: this.items.length ? 20 : 100,\n // Supported since Gitea 1.23.0 and Forgejo v10.0.0.\n // Will be ignoded by older instances.\n ...(this.ignorePrAuthor ? {} : { poster: this.author }),\n });\n\n while (query) {\n // TODO: use zod, typescript can't infer the type of the response #22198\n const res: HttpResponse<(PR | null)[]> = await http.getJsonUnchecked(\n `${API_PATH}/repos/${this.repo}/pulls?${query}`,\n {\n memCache: false,\n paginate: false,\n },\n );\n\n const needNextPage = this.reconcile(res.body);\n if (!needNextPage) {\n break;\n }\n\n const uri = parseUrl(parseLinkHeader(res.headers.link)?.next?.url);\n query = uri ? uri.search : null;\n }\n\n this.updateItems();\n\n return this;\n }\n\n /**\n * Ensure the pr cache starts with the most recent PRs.\n * JavaScript ensures that the cache is sorted by PR number.\n */\n private updateItems(): void {\n this.items = Object.values(this.cache.items).reverse();\n }\n}\n"],"mappings":";;;;;;;;;;;;4CAGuE;6BACrB;2BACc;sBAQlC;AAK9B,IAAa,eAAb,MAAa,aAAa;CACxB,AAAQ;CACR,AAAQ,QAAc,EAAE;CACxB,AAAQ;CACR,AAAiB;CACjB,AAAQ;CAER,AAAQ,YACN,MACA,gBACA,QACA;AACA,OAAK,OAAO;AACZ,OAAK,iBAAiB;AACtB,OAAK,SAAS;EACd,MAAM,YAAYA,0BAAU;AAC5B,YAAU,aAAa,EAAE;AACzB,YAAU,SAAS,UAAU,EAAE;EAC/B,IAAI,mBAAmB,UAAU,SAAS,MAAM;AAGhD,8CACoB,iBAAiB,IACnC,iBAAiB,WAAW,OAE5B,oBAAmB;GACjB,OAAO,EAAE;GACT,YAAY;GACZ;GACD;AAEH,YAAU,SAAS,MAAM,oBAAoB;AAC7C,OAAK,QAAQ;AACb,OAAK,aAAa;;CAGpB,OAAO,YAAkB;AACvB,oBAAa,yBAAyB,MAAM;;CAG9C,aAAqB,KACnB,MACA,MACA,gBACA,QACuB;EACvB,MAAM,MAAM,IAAI,aAAa,MAAM,gBAAgB,OAAO;AAG1D,MAAI,mBAF4C,wBAAwB,EAEzD;AACb,SAAM,IAAI,KAAK,KAAK;AACpB,qBAAa,yBAAyB,KAAK;;AAG7C,SAAO;;CAGT,AAAQ,SAAe;AACrB,SAAO,KAAK;;CAGd,aAAa,OACX,MACA,MACA,gBACA,QACe;AAEf,UADgB,MAAM,aAAa,KAAK,MAAM,MAAM,gBAAgB,OAAO,EAC5D,QAAQ;;CAGzB,AAAQ,MAAM,MAAgB;AAC5B,OAAK,MAAM,MAAM,KAAK,UAAU;AAChC,OAAK,aAAa;;CAGpB,aAAa,MACX,MACA,MACA,gBACA,QACA,MACe;AAEf,GADgB,MAAM,aAAa,KAAK,MAAM,MAAM,gBAAgB,OAAO,EACnE,MAAM,KAAK;;CAGrB,AAAQ,UAAU,UAAkC;EAClD,MAAM,EAAE,UAAU,KAAK;EACvB,IAAI,EAAE,eAAe,KAAK;EAC1B,MAAM,YAAY,aAAaC,eAAS,QAAQ,WAAW,GAAG;EAE9D,IAAI,eAAe;AAEnB,OAAK,MAAM,WAAW,UAAU;AAC9B,OAAI,CAAC,SAAS;AACZ,2BAAO,KAAK,8CAA8C;AAG1D,UAAM,IAAI,MAAMC,uCAAgB;;GAElC,MAAM,KAAK,QAAQ;GAEnB,MAAM,UAAUC,2BAAa,SAAS,KAAK,OAAO;AAClD,OAAI,CAAC,QACH;GAGF,MAAM,UAAU,MAAM;AACtB,0BAAW,SAAS,QAAQ,EAAE;AAC5B,mBAAe;AACf;;AAGF,SAAM,MAAM;GAEZ,MAAM,WAAWF,eAAS,QAAQ,QAAQ,WAAW;AACrD,OAAI,CAAC,aAAa,WAAW,UAC3B,cAAa,QAAQ;;AAIzB,OAAK,MAAM,aAAa;AAExB,SAAO;;CAGT,MAAc,KAAK,MAAwC;EACzD,IAAI,QAAuBG,2BAAe;GACxC,OAAO;GACP,MAAM;GAKN,OAAO,KAAK,MAAM,SAAS,KAAK;GAGhC,GAAI,KAAK,iBAAiB,EAAE,GAAG,EAAE,QAAQ,KAAK,QAAQ;GACvD,CAAC;AAEF,SAAO,OAAO;GAEZ,MAAM,MAAmC,MAAM,KAAK,iBAClD,GAAGC,uBAAS,SAAS,KAAK,KAAK,SAAS,SACxC;IACE,UAAU;IACV,UAAU;IACX,CACF;AAGD,OAAI,CADiB,KAAK,UAAU,IAAI,KAAK,CAE3C;GAGF,MAAM,MAAMC,qBAASC,4BAAgB,IAAI,QAAQ,KAAK,EAAE,MAAM,IAAI;AAClE,WAAQ,MAAM,IAAI,SAAS;;AAG7B,OAAK,aAAa;AAElB,SAAO;;;;;;CAOT,AAAQ,cAAoB;AAC1B,OAAK,QAAQ,OAAO,OAAO,KAAK,MAAM,MAAM,CAAC,SAAS"}
|