renovate 44.149.0 → 44.149.2
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/config/options/index.js +1 -1
- package/dist/config/options/index.js.map +1 -1
- package/dist/config/presets/index.js +2 -1
- package/dist/config/presets/index.js.map +1 -1
- package/dist/global-config-option-defaults.generated.js +1 -1
- package/dist/global-config-option-defaults.generated.js.map +1 -1
- package/dist/modules/datasource/artifactory/index.js +2 -1
- package/dist/modules/datasource/artifactory/index.js.map +1 -1
- package/dist/modules/datasource/aws-eks-addon/index.js +6 -5
- package/dist/modules/datasource/aws-eks-addon/index.js.map +1 -1
- package/dist/modules/datasource/aws-machine-image/index.js +4 -3
- package/dist/modules/datasource/aws-machine-image/index.js.map +1 -1
- package/dist/modules/datasource/aws-rds/index.js +2 -1
- package/dist/modules/datasource/aws-rds/index.js.map +1 -1
- package/dist/modules/datasource/azure-bicep-resource/index.js +2 -1
- package/dist/modules/datasource/azure-bicep-resource/index.js.map +1 -1
- package/dist/modules/datasource/bazel/index.js +2 -1
- package/dist/modules/datasource/bazel/index.js.map +1 -1
- package/dist/modules/datasource/bitrise/index.js +2 -1
- package/dist/modules/datasource/bitrise/index.js.map +1 -1
- package/dist/modules/datasource/buildpacks-registry/index.js +2 -1
- package/dist/modules/datasource/buildpacks-registry/index.js.map +1 -1
- package/dist/modules/datasource/cdnjs/index.js +3 -2
- package/dist/modules/datasource/cdnjs/index.js.map +1 -1
- package/dist/modules/datasource/conan/index.js +3 -2
- package/dist/modules/datasource/conan/index.js.map +1 -1
- package/dist/modules/datasource/conda/index.js +2 -1
- package/dist/modules/datasource/conda/index.js.map +1 -1
- package/dist/modules/datasource/cpan/index.js +1 -1
- package/dist/modules/datasource/cpan/index.js.map +1 -1
- package/dist/modules/datasource/crate/index.js +17 -9
- package/dist/modules/datasource/crate/index.js.map +1 -1
- package/dist/modules/datasource/deb/index.js +3 -2
- package/dist/modules/datasource/deb/index.js.map +1 -1
- package/dist/modules/datasource/deno/index.js +4 -3
- package/dist/modules/datasource/deno/index.js.map +1 -1
- package/dist/modules/datasource/docker/index.js +9 -9
- package/dist/modules/datasource/docker/index.js.map +1 -1
- package/dist/modules/datasource/dotnet-version/index.js +2 -1
- package/dist/modules/datasource/dotnet-version/index.js.map +1 -1
- package/dist/modules/datasource/elm-package/index.js +2 -1
- package/dist/modules/datasource/elm-package/index.js.map +1 -1
- package/dist/modules/datasource/endoflife-date/index.js +2 -1
- package/dist/modules/datasource/endoflife-date/index.js.map +1 -1
- package/dist/modules/datasource/galaxy-collection/index.js +3 -2
- package/dist/modules/datasource/galaxy-collection/index.js.map +1 -1
- package/dist/modules/datasource/git-host-tags.js +6 -5
- package/dist/modules/datasource/git-host-tags.js.map +1 -1
- package/dist/modules/datasource/gitea-tags/base.js +5 -4
- package/dist/modules/datasource/gitea-tags/base.js.map +1 -1
- package/dist/modules/datasource/gitea-tags/util.js +2 -5
- package/dist/modules/datasource/gitea-tags/util.js.map +1 -1
- package/dist/modules/datasource/github-digest/index.js +3 -5
- package/dist/modules/datasource/github-digest/index.js.map +1 -1
- package/dist/modules/datasource/github-release-attachments/index.js +3 -2
- package/dist/modules/datasource/github-release-attachments/index.js.map +1 -1
- package/dist/modules/datasource/gitlab-packages/index.js +2 -1
- package/dist/modules/datasource/gitlab-packages/index.js.map +1 -1
- package/dist/modules/datasource/gitlab-releases/index.js +2 -1
- package/dist/modules/datasource/gitlab-releases/index.js.map +1 -1
- package/dist/modules/datasource/gitlab-tags/index.js +3 -2
- package/dist/modules/datasource/gitlab-tags/index.js.map +1 -1
- package/dist/modules/datasource/glasskube-packages/index.js +2 -1
- package/dist/modules/datasource/glasskube-packages/index.js.map +1 -1
- package/dist/modules/datasource/go/goproxy-parser.js +3 -2
- package/dist/modules/datasource/go/goproxy-parser.js.map +1 -1
- package/dist/modules/datasource/go/index.js +4 -3
- package/dist/modules/datasource/go/index.js.map +1 -1
- package/dist/modules/datasource/go/releases-goproxy.js +6 -3
- package/dist/modules/datasource/go/releases-goproxy.js.map +1 -1
- package/dist/modules/datasource/go/timestamp-cache.js +3 -1
- package/dist/modules/datasource/go/timestamp-cache.js.map +1 -1
- package/dist/modules/datasource/golang-version/index.js +1 -1
- package/dist/modules/datasource/golang-version/index.js.map +1 -1
- package/dist/modules/datasource/gradle-version/index.js +1 -1
- package/dist/modules/datasource/gradle-version/index.js.map +1 -1
- package/dist/modules/datasource/helm/index.js +2 -1
- package/dist/modules/datasource/helm/index.js.map +1 -1
- package/dist/modules/datasource/hermit/index.js +3 -2
- package/dist/modules/datasource/hermit/index.js.map +1 -1
- package/dist/modules/datasource/hex/index.js +3 -2
- package/dist/modules/datasource/hex/index.js.map +1 -1
- package/dist/modules/datasource/hexpm-bob/index.js +2 -1
- package/dist/modules/datasource/hexpm-bob/index.js.map +1 -1
- package/dist/modules/datasource/index.js +4 -3
- package/dist/modules/datasource/index.js.map +1 -1
- package/dist/modules/datasource/java-version/index.js +2 -1
- package/dist/modules/datasource/java-version/index.js.map +1 -1
- package/dist/modules/datasource/jsr/index.js +2 -1
- package/dist/modules/datasource/jsr/index.js.map +1 -1
- package/dist/modules/datasource/maven/index.js +2 -1
- package/dist/modules/datasource/maven/index.js.map +1 -1
- package/dist/modules/datasource/nextcloud/index.js +2 -1
- package/dist/modules/datasource/nextcloud/index.js.map +1 -1
- package/dist/modules/datasource/node-version/index.js +1 -1
- package/dist/modules/datasource/node-version/index.js.map +1 -1
- package/dist/modules/datasource/nuget/v3.js +3 -2
- package/dist/modules/datasource/nuget/v3.js.map +1 -1
- package/dist/modules/datasource/orb/index.js +2 -1
- package/dist/modules/datasource/orb/index.js.map +1 -1
- package/dist/modules/datasource/packagist/index.js +4 -3
- package/dist/modules/datasource/packagist/index.js.map +1 -1
- package/dist/modules/datasource/pod/index.js +2 -1
- package/dist/modules/datasource/pod/index.js.map +1 -1
- package/dist/modules/datasource/python-version/index.js +1 -1
- package/dist/modules/datasource/python-version/index.js.map +1 -1
- package/dist/modules/datasource/repology/index.js +2 -1
- package/dist/modules/datasource/repology/index.js.map +1 -1
- package/dist/modules/datasource/rpm/index.js +2 -1
- package/dist/modules/datasource/rpm/index.js.map +1 -1
- package/dist/modules/datasource/rubygems/index.js +2 -1
- package/dist/modules/datasource/rubygems/index.js.map +1 -1
- package/dist/modules/datasource/rubygems/metadata-cache.js +2 -1
- package/dist/modules/datasource/rubygems/metadata-cache.js.map +1 -1
- package/dist/modules/datasource/sbt-package/index.js +11 -10
- package/dist/modules/datasource/sbt-package/index.js.map +1 -1
- package/dist/modules/datasource/terraform-module/index.js +2 -1
- package/dist/modules/datasource/terraform-module/index.js.map +1 -1
- package/dist/modules/datasource/terraform-provider/index.js +6 -5
- package/dist/modules/datasource/terraform-provider/index.js.map +1 -1
- package/dist/modules/datasource/unity3d/index.js +2 -1
- package/dist/modules/datasource/unity3d/index.js.map +1 -1
- package/dist/modules/datasource/unity3d-packages/index.js +2 -1
- package/dist/modules/datasource/unity3d-packages/index.js.map +1 -1
- package/dist/modules/manager/bazel/parser.js +3 -1
- package/dist/modules/manager/bazel/parser.js.map +1 -1
- package/dist/modules/manager/github-actions/extract.js +2 -1
- package/dist/modules/manager/github-actions/extract.js.map +1 -1
- package/dist/modules/manager/terraform/lockfile/hash.js +2 -1
- package/dist/modules/manager/terraform/lockfile/hash.js.map +1 -1
- package/dist/modules/platform/bitbucket/pr-cache.js +3 -2
- package/dist/modules/platform/bitbucket/pr-cache.js.map +1 -1
- package/dist/modules/platform/bitbucket-server/pr-cache.js +3 -2
- package/dist/modules/platform/bitbucket-server/pr-cache.js.map +1 -1
- package/dist/modules/platform/gitea/pr-cache.js +7 -6
- package/dist/modules/platform/gitea/pr-cache.js.map +1 -1
- package/dist/modules/platform/gitlab/pr-cache.js +3 -2
- package/dist/modules/platform/gitlab/pr-cache.js.map +1 -1
- package/dist/util/cache/package/index.js +1 -1
- package/dist/util/cache/package/key.js +8 -1
- package/dist/util/cache/package/key.js.map +1 -1
- package/dist/util/cache/package/with-cache.js +2 -1
- package/dist/util/cache/package/with-cache.js.map +1 -1
- package/dist/util/exec/containerbase.js +2 -1
- package/dist/util/exec/containerbase.js.map +1 -1
- package/dist/util/github/graphql/cache-strategies/memory-cache-strategy.js +2 -1
- package/dist/util/github/graphql/cache-strategies/memory-cache-strategy.js.map +1 -1
- package/dist/util/github/graphql/datasource-fetcher.js +5 -8
- package/dist/util/github/graphql/datasource-fetcher.js.map +1 -1
- package/dist/util/http/cache/memory-http-cache-provider.js +2 -1
- package/dist/util/http/cache/memory-http-cache-provider.js.map +1 -1
- package/dist/util/http/cache/package-http-cache-provider.js +2 -1
- package/dist/util/http/cache/package-http-cache-provider.js.map +1 -1
- package/dist/util/jsonata.js +2 -1
- package/dist/util/jsonata.js.map +1 -1
- package/dist/util/merge-confidence/index.js +10 -7
- package/dist/util/merge-confidence/index.js.map +1 -1
- package/dist/workers/repository/update/pr/changelog/release-notes.js +4 -5
- package/dist/workers/repository/update/pr/changelog/release-notes.js.map +1 -1
- package/dist/workers/repository/update/pr/changelog/source.js +2 -1
- package/dist/workers/repository/update/pr/changelog/source.js.map +1 -1
- package/package.json +2 -2
- package/renovate-schema.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"package-http-cache-provider.js","names":["packageCache.get","packageCache.setWithRawTtl"],"sources":["../../../../lib/util/http/cache/package-http-cache-provider.ts"],"sourcesContent":["import { isString } from '@sindresorhus/is';\nimport { DateTime } from 'luxon';\nimport type { ZodType } from 'zod/v4';\nimport { GlobalConfig } from '../../../config/global.ts';\nimport { logger } from '../../../logger/index.ts';\nimport * as packageCache from '../../cache/package/index.ts';\nimport { resolveTtlValues } from '../../cache/package/ttl.ts';\nimport type { PackageCacheNamespace } from '../../cache/package/types.ts';\nimport { regEx } from '../../regex.ts';\nimport { HttpCacheStats } from '../../stats.ts';\nimport type { HttpResponse } from '../types.ts';\nimport { copyResponse } from '../util.ts';\nimport { AbstractHttpCacheProvider } from './abstract-http-cache-provider.ts';\nimport type { HttpCache } from './schema.ts';\n\nexport interface PackageHttpCacheProviderOptions {\n namespace: PackageCacheNamespace;\n softTtlMinutes?: number;\n checkCacheControlHeader: boolean;\n checkAuthorizationHeader: boolean;\n writeSchema?: ZodType;\n}\n\nexport class PackageHttpCacheProvider extends AbstractHttpCacheProvider {\n private namespace: PackageCacheNamespace;\n private defaultTtlMinutes: number;\n private writeSchema?: ZodType;\n\n checkCacheControlHeader: boolean;\n checkAuthorizationHeader: boolean;\n\n constructor({\n namespace,\n softTtlMinutes = 15,\n checkCacheControlHeader,\n checkAuthorizationHeader,\n writeSchema,\n }: PackageHttpCacheProviderOptions) {\n super();\n this.namespace = namespace;\n this.defaultTtlMinutes = softTtlMinutes;\n this.checkCacheControlHeader = checkCacheControlHeader;\n this.checkAuthorizationHeader = checkAuthorizationHeader;\n this.writeSchema = writeSchema;\n }\n\n private get softTtlMinutes(): number {\n const { softTtlMinutes } = resolveTtlValues(\n this.namespace,\n this.defaultTtlMinutes,\n );\n return softTtlMinutes;\n }\n\n private get hardTtlMinutes(): number {\n const { hardTtlMinutes } = resolveTtlValues(\n this.namespace,\n this.defaultTtlMinutes,\n );\n return hardTtlMinutes;\n }\n\n private cacheKey(method: string, url: string): string {\n if (method !== 'get') {\n return
|
|
1
|
+
{"version":3,"file":"package-http-cache-provider.js","names":["packageCache.get","packageCache.setWithRawTtl"],"sources":["../../../../lib/util/http/cache/package-http-cache-provider.ts"],"sourcesContent":["import { isString } from '@sindresorhus/is';\nimport { DateTime } from 'luxon';\nimport type { ZodType } from 'zod/v4';\nimport { GlobalConfig } from '../../../config/global.ts';\nimport { logger } from '../../../logger/index.ts';\nimport * as packageCache from '../../cache/package/index.ts';\nimport { buildCacheKey } from '../../cache/package/key.ts';\nimport { resolveTtlValues } from '../../cache/package/ttl.ts';\nimport type { PackageCacheNamespace } from '../../cache/package/types.ts';\nimport { regEx } from '../../regex.ts';\nimport { HttpCacheStats } from '../../stats.ts';\nimport type { HttpResponse } from '../types.ts';\nimport { copyResponse } from '../util.ts';\nimport { AbstractHttpCacheProvider } from './abstract-http-cache-provider.ts';\nimport type { HttpCache } from './schema.ts';\n\nexport interface PackageHttpCacheProviderOptions {\n namespace: PackageCacheNamespace;\n softTtlMinutes?: number;\n checkCacheControlHeader: boolean;\n checkAuthorizationHeader: boolean;\n writeSchema?: ZodType;\n}\n\nexport class PackageHttpCacheProvider extends AbstractHttpCacheProvider {\n private namespace: PackageCacheNamespace;\n private defaultTtlMinutes: number;\n private writeSchema?: ZodType;\n\n checkCacheControlHeader: boolean;\n checkAuthorizationHeader: boolean;\n\n constructor({\n namespace,\n softTtlMinutes = 15,\n checkCacheControlHeader,\n checkAuthorizationHeader,\n writeSchema,\n }: PackageHttpCacheProviderOptions) {\n super();\n this.namespace = namespace;\n this.defaultTtlMinutes = softTtlMinutes;\n this.checkCacheControlHeader = checkCacheControlHeader;\n this.checkAuthorizationHeader = checkAuthorizationHeader;\n this.writeSchema = writeSchema;\n }\n\n private get softTtlMinutes(): number {\n const { softTtlMinutes } = resolveTtlValues(\n this.namespace,\n this.defaultTtlMinutes,\n );\n return softTtlMinutes;\n }\n\n private get hardTtlMinutes(): number {\n const { hardTtlMinutes } = resolveTtlValues(\n this.namespace,\n this.defaultTtlMinutes,\n );\n return hardTtlMinutes;\n }\n\n private cacheKey(method: string, url: string): string {\n if (method !== 'get') {\n return buildCacheKey(method, url);\n }\n return url;\n }\n\n async load(method: string, url: string): Promise<unknown> {\n return await packageCache.get(this.namespace, this.cacheKey(method, url));\n }\n\n async persist(method: string, url: string, data: HttpCache): Promise<void> {\n if (!data) {\n return;\n }\n\n if (!this.writeSchema) {\n await packageCache.setWithRawTtl(\n this.namespace,\n this.cacheKey(method, url),\n data,\n this.hardTtlMinutes,\n );\n return;\n }\n\n const httpResponse = copyResponse(data.httpResponse, false);\n\n const { data: body, error: err } = this.writeSchema.safeParse(\n httpResponse.body,\n );\n\n if (err) {\n logger.once.debug(\n { err, method, namespace: this.namespace, url },\n 'http cache: writeSchema validation failed for response body, skipping cache write',\n );\n return;\n }\n\n httpResponse.body = body;\n\n await packageCache.setWithRawTtl(\n this.namespace,\n this.cacheKey(method, url),\n { ...data, httpResponse },\n this.hardTtlMinutes,\n );\n }\n\n override async bypassServer<T>(\n method: string,\n url: string,\n ignoreSoftTtl = false,\n ): Promise<HttpResponse<T> | null> {\n const cached = await this.get(method, url);\n if (!cached) {\n return null;\n }\n\n if (ignoreSoftTtl) {\n return cached.httpResponse as HttpResponse<T>;\n }\n\n const cachedAt = DateTime.fromISO(cached.timestamp);\n const deadline = cachedAt.plus({ minutes: this.softTtlMinutes });\n const now = DateTime.now();\n if (now >= deadline) {\n HttpCacheStats.incLocalMisses(url);\n return null;\n }\n\n HttpCacheStats.incLocalHits(url);\n return cached.httpResponse as HttpResponse<T>;\n }\n\n cacheAllowed<T>(resp: HttpResponse<T>): boolean {\n const allowedViaGlobalConfig = GlobalConfig.get('cachePrivatePackages');\n if (allowedViaGlobalConfig) {\n return true;\n }\n\n if (this.checkCacheControlHeader) {\n const cacheControl = resp.headers['cache-control'];\n const isPublic =\n isString(cacheControl) &&\n cacheControl\n .toLocaleLowerCase()\n .split(regEx(/\\s*,\\s*/))\n .includes('public');\n\n if (!isPublic) {\n return false;\n }\n }\n\n if (this.checkAuthorizationHeader && resp.authorization) {\n return false;\n }\n\n return true;\n }\n\n override async wrapServerResponse<T>(\n method: string,\n url: string,\n resp: HttpResponse<T>,\n ): Promise<HttpResponse<T>> {\n if (resp.statusCode === 200 && !this.cacheAllowed(resp)) {\n return resp;\n }\n\n return await super.wrapServerResponse(method, url, resp);\n }\n}\n"],"mappings":";;;;;;;;;;;;AAwBA,IAAa,2BAAb,cAA8C,0BAA0B;CACtE;CACA;CACA;CAEA;CACA;CAEA,YAAY,EACV,WACA,iBAAiB,IACjB,yBACA,0BACA,eACkC;EAClC,MAAM;EACN,KAAK,YAAY;EACjB,KAAK,oBAAoB;EACzB,KAAK,0BAA0B;EAC/B,KAAK,2BAA2B;EAChC,KAAK,cAAc;CACrB;CAEA,IAAY,iBAAyB;EACnC,MAAM,EAAE,mBAAmB,iBACzB,KAAK,WACL,KAAK,iBACP;EACA,OAAO;CACT;CAEA,IAAY,iBAAyB;EACnC,MAAM,EAAE,mBAAmB,iBACzB,KAAK,WACL,KAAK,iBACP;EACA,OAAO;CACT;CAEA,SAAiB,QAAgB,KAAqB;EACpD,IAAI,WAAW,OACb,OAAO,cAAc,QAAQ,GAAG;EAElC,OAAO;CACT;CAEA,MAAM,KAAK,QAAgB,KAA+B;EACxD,OAAO,MAAMA,IAAiB,KAAK,WAAW,KAAK,SAAS,QAAQ,GAAG,CAAC;CAC1E;CAEA,MAAM,QAAQ,QAAgB,KAAa,MAAgC;EACzE,IAAI,CAAC,MACH;EAGF,IAAI,CAAC,KAAK,aAAa;GACrB,MAAMC,cACJ,KAAK,WACL,KAAK,SAAS,QAAQ,GAAG,GACzB,MACA,KAAK,cACP;GACA;EACF;EAEA,MAAM,eAAe,aAAa,KAAK,cAAc,KAAK;EAE1D,MAAM,EAAE,MAAM,MAAM,OAAO,QAAQ,KAAK,YAAY,UAClD,aAAa,IACf;EAEA,IAAI,KAAK;GACP,OAAO,KAAK,MACV;IAAE;IAAK;IAAQ,WAAW,KAAK;IAAW;GAAI,GAC9C,mFACF;GACA;EACF;EAEA,aAAa,OAAO;EAEpB,MAAMA,cACJ,KAAK,WACL,KAAK,SAAS,QAAQ,GAAG,GACzB;GAAE,GAAG;GAAM;EAAa,GACxB,KAAK,cACP;CACF;CAEA,MAAe,aACb,QACA,KACA,gBAAgB,OACiB;EACjC,MAAM,SAAS,MAAM,KAAK,IAAI,QAAQ,GAAG;EACzC,IAAI,CAAC,QACH,OAAO;EAGT,IAAI,eACF,OAAO,OAAO;EAIhB,MAAM,WADW,SAAS,QAAQ,OAAO,SACjB,CAAC,CAAC,KAAK,EAAE,SAAS,KAAK,eAAe,CAAC;EAE/D,IADY,SAAS,IACf,KAAK,UAAU;GACnB,eAAe,eAAe,GAAG;GACjC,OAAO;EACT;EAEA,eAAe,aAAa,GAAG;EAC/B,OAAO,OAAO;CAChB;CAEA,aAAgB,MAAgC;EAE9C,IAD+B,aAAa,IAAI,sBACvB,GACvB,OAAO;EAGT,IAAI,KAAK,yBAAyB;GAChC,MAAM,eAAe,KAAK,QAAQ;GAQlC,IAAI,EANF,SAAS,YAAY,KACrB,aACG,kBAAkB,CAAC,CACnB,MAAM,MAAM,SAAS,CAAC,CAAC,CACvB,SAAS,QAAQ,IAGpB,OAAO;EAEX;EAEA,IAAI,KAAK,4BAA4B,KAAK,eACxC,OAAO;EAGT,OAAO;CACT;CAEA,MAAe,mBACb,QACA,KACA,MAC0B;EAC1B,IAAI,KAAK,eAAe,OAAO,CAAC,KAAK,aAAa,IAAI,GACpD,OAAO;EAGT,OAAO,MAAM,MAAM,mBAAmB,QAAQ,KAAK,IAAI;CACzD;AACF"}
|
package/dist/util/jsonata.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { get, set } from "./cache/memory/index.js";
|
|
2
2
|
import { anyMatchRegexOrGlobList, matchRegexOrGlobList } from "./string-match.js";
|
|
3
3
|
import { detectPlatform } from "./common.js";
|
|
4
|
+
import { buildCacheKey } from "./cache/package/key.js";
|
|
4
5
|
import { toSha256 } from "./hash.js";
|
|
5
6
|
import { isArray, isNonEmptyArray, isString } from "@sindresorhus/is";
|
|
6
7
|
import jsonata from "jsonata";
|
|
@@ -18,7 +19,7 @@ function matchRegexOrGlob(input, patterns) {
|
|
|
18
19
|
return false;
|
|
19
20
|
}
|
|
20
21
|
function getExpression(input) {
|
|
21
|
-
const cacheKey =
|
|
22
|
+
const cacheKey = buildCacheKey("jsonata", toSha256(input));
|
|
22
23
|
const cachedExpression = get(cacheKey);
|
|
23
24
|
// istanbul ignore if: cannot test
|
|
24
25
|
if (cachedExpression) return cachedExpression;
|
package/dist/util/jsonata.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jsonata.js","names":["memCache.get"],"sources":["../../lib/util/jsonata.ts"],"sourcesContent":["import { isArray, isNonEmptyArray, isString } from '@sindresorhus/is';\nimport jsonata from 'jsonata';\nimport * as memCache from './cache/memory/index.ts';\nimport { detectPlatform } from './common.ts';\nimport { toSha256 } from './hash.ts';\nimport {\n anyMatchRegexOrGlobList,\n matchRegexOrGlobList,\n} from './string-match.ts';\n\nexport interface JsonataExpression {\n evaluate(data: unknown, bindings?: Record<string, unknown>): Promise<unknown>;\n}\n\n/**\n * Matches `input` against Renovate string patterns (globs, regex, negation).\n * If `input` is an array, returns true if any string element matches.\n * Returns false for missing or non-string inputs and invalid patterns.\n */\nexport function matchRegexOrGlob(input: unknown, patterns: unknown): boolean {\n const patternList = isString(patterns) ? [patterns] : patterns;\n if (!isNonEmptyArray(patternList) || !patternList.every(isString)) {\n return false;\n }\n\n if (isString(input)) {\n return matchRegexOrGlobList(input, patternList);\n }\n\n if (isArray(input)) {\n return anyMatchRegexOrGlobList(input.filter(isString), patternList);\n }\n\n return false;\n}\n\nexport function getExpression(input: string): JsonataExpression | Error {\n const cacheKey =
|
|
1
|
+
{"version":3,"file":"jsonata.js","names":["memCache.get"],"sources":["../../lib/util/jsonata.ts"],"sourcesContent":["import { isArray, isNonEmptyArray, isString } from '@sindresorhus/is';\nimport jsonata from 'jsonata';\nimport * as memCache from './cache/memory/index.ts';\nimport { buildCacheKey } from './cache/package/key.ts';\nimport { detectPlatform } from './common.ts';\nimport { toSha256 } from './hash.ts';\nimport {\n anyMatchRegexOrGlobList,\n matchRegexOrGlobList,\n} from './string-match.ts';\n\nexport interface JsonataExpression {\n evaluate(data: unknown, bindings?: Record<string, unknown>): Promise<unknown>;\n}\n\n/**\n * Matches `input` against Renovate string patterns (globs, regex, negation).\n * If `input` is an array, returns true if any string element matches.\n * Returns false for missing or non-string inputs and invalid patterns.\n */\nexport function matchRegexOrGlob(input: unknown, patterns: unknown): boolean {\n const patternList = isString(patterns) ? [patterns] : patterns;\n if (!isNonEmptyArray(patternList) || !patternList.every(isString)) {\n return false;\n }\n\n if (isString(input)) {\n return matchRegexOrGlobList(input, patternList);\n }\n\n if (isArray(input)) {\n return anyMatchRegexOrGlobList(input.filter(isString), patternList);\n }\n\n return false;\n}\n\nexport function getExpression(input: string): JsonataExpression | Error {\n const cacheKey = buildCacheKey('jsonata', toSha256(input));\n const cachedExpression = memCache.get<jsonata.Expression | Error>(cacheKey);\n // istanbul ignore if: cannot test\n if (cachedExpression) {\n return cachedExpression;\n }\n let result: jsonata.Expression | Error;\n try {\n const expression = jsonata(input);\n expression.registerFunction(\n 'detectPlatform',\n (url: string) => detectPlatform(url),\n '<s-:s>',\n );\n // No signature: JSONata would reject arrays and `undefined` inputs otherwise\n expression.registerFunction('matchRegexOrGlob', matchRegexOrGlob);\n // Wrap the evaluate method to default bindings to {} for concurrent evaluation safety.\n // This prevents race conditions when the same cached expression is evaluated\n // concurrently with different data. See #40311 for background.\n const originalEvaluate = expression.evaluate.bind(expression);\n expression.evaluate = (\n data: unknown,\n bindings: Record<string, unknown> = {},\n ) => {\n return originalEvaluate(data, bindings);\n };\n result = expression;\n } catch (err) {\n // JSONata errors aren't detected as TypeOf Error\n result = new Error(err.message);\n }\n memCache.set(cacheKey, result);\n return result;\n}\n"],"mappings":";;;;;;;;;;;;;AAoBA,SAAgB,iBAAiB,OAAgB,UAA4B;CAC3E,MAAM,cAAc,SAAS,QAAQ,IAAI,CAAC,QAAQ,IAAI;CACtD,IAAI,CAAC,gBAAgB,WAAW,KAAK,CAAC,YAAY,MAAM,QAAQ,GAC9D,OAAO;CAGT,IAAI,SAAS,KAAK,GAChB,OAAO,qBAAqB,OAAO,WAAW;CAGhD,IAAI,QAAQ,KAAK,GACf,OAAO,wBAAwB,MAAM,OAAO,QAAQ,GAAG,WAAW;CAGpE,OAAO;AACT;AAEA,SAAgB,cAAc,OAA0C;CACtE,MAAM,WAAW,cAAc,WAAW,SAAS,KAAK,CAAC;CACzD,MAAM,mBAAmBA,IAAyC,QAAQ;;CAE1E,IAAI,kBACF,OAAO;CAET,IAAI;CACJ,IAAI;EACF,MAAM,aAAa,QAAQ,KAAK;EAChC,WAAW,iBACT,mBACC,QAAgB,eAAe,GAAG,GACnC,QACF;EAEA,WAAW,iBAAiB,oBAAoB,gBAAgB;EAIhE,MAAM,mBAAmB,WAAW,SAAS,KAAK,UAAU;EAC5D,WAAW,YACT,MACA,WAAoC,CAAC,MAClC;GACH,OAAO,iBAAiB,MAAM,QAAQ;EACxC;EACA,SAAS;CACX,SAAS,KAAK;EAEZ,SAAS,IAAI,MAAM,IAAI,OAAO;CAChC;CACA,IAAa,UAAU,MAAM;CAC7B,OAAO;AACT"}
|
|
@@ -5,6 +5,8 @@ import { ensureTrailingSlash, joinUrlParts, parseUrl } from "../url.js";
|
|
|
5
5
|
import { ATTR_RENOVATE_DATASOURCE, ATTR_RENOVATE_PACKAGE_NAME } from "../../instrumentation/types.js";
|
|
6
6
|
import { instrument } from "../../instrumentation/index.js";
|
|
7
7
|
import { find } from "../host-rules.js";
|
|
8
|
+
import { buildCacheKey } from "../cache/package/key.js";
|
|
9
|
+
import { toSha256 } from "../hash.js";
|
|
8
10
|
import { ExternalHostError } from "../../types/errors/external-host-error.js";
|
|
9
11
|
import { get, set } from "../cache/package/index.js";
|
|
10
12
|
import { Http } from "../http/index.js";
|
|
@@ -15,7 +17,7 @@ import { isNullOrUndefined } from "@sindresorhus/is";
|
|
|
15
17
|
//#region lib/util/merge-confidence/index.ts
|
|
16
18
|
const hostType = "merge-confidence";
|
|
17
19
|
const http = new Http(hostType);
|
|
18
|
-
let
|
|
20
|
+
let tokenHash;
|
|
19
21
|
let apiBaseUrl;
|
|
20
22
|
let supportedDatasources = [];
|
|
21
23
|
const confidenceLevels = {
|
|
@@ -26,9 +28,10 @@ const confidenceLevels = {
|
|
|
26
28
|
};
|
|
27
29
|
function initConfig({ mergeConfidenceEndpoint, mergeConfidenceDatasources }) {
|
|
28
30
|
apiBaseUrl = getApiBaseUrl(mergeConfidenceEndpoint);
|
|
29
|
-
token = getApiToken();
|
|
31
|
+
const token = getApiToken();
|
|
32
|
+
tokenHash = isNullOrUndefined(token) ? void 0 : toSha256(token);
|
|
30
33
|
supportedDatasources = mergeConfidenceDatasources ?? supportedDatasources$1;
|
|
31
|
-
if (!isNullOrUndefined(
|
|
34
|
+
if (!isNullOrUndefined(tokenHash)) logger.debug(`Merge confidence token found for ${apiBaseUrl}`);
|
|
32
35
|
}
|
|
33
36
|
function isMergeConfidence(value) {
|
|
34
37
|
return MERGE_CONFIDENCE.includes(value);
|
|
@@ -66,7 +69,7 @@ const updateTypeConfidenceMapping = {
|
|
|
66
69
|
*/
|
|
67
70
|
async function getMergeConfidenceLevel(datasource, packageName, currentVersion, newVersion, updateType) {
|
|
68
71
|
return await instrument("getMergeConfidenceLevel", async () => {
|
|
69
|
-
if (isNullOrUndefined(apiBaseUrl) || isNullOrUndefined(
|
|
72
|
+
if (isNullOrUndefined(apiBaseUrl) || isNullOrUndefined(tokenHash)) return;
|
|
70
73
|
if (!supportedDatasources.includes(datasource)) return;
|
|
71
74
|
if (!(currentVersion && newVersion && updateType)) return "neutral";
|
|
72
75
|
const mappedConfidence = updateTypeConfidenceMapping[updateType];
|
|
@@ -93,10 +96,10 @@ async function getMergeConfidenceLevel(datasource, packageName, currentVersion,
|
|
|
93
96
|
*/
|
|
94
97
|
async function queryApi(datasource, packageName, currentVersion, newVersion) {
|
|
95
98
|
// istanbul ignore if: defensive, already been validated before calling this function
|
|
96
|
-
if (isNullOrUndefined(apiBaseUrl) || isNullOrUndefined(
|
|
99
|
+
if (isNullOrUndefined(apiBaseUrl) || isNullOrUndefined(tokenHash)) return "neutral";
|
|
97
100
|
const escapedPackageName = packageName.replace(regEx(/\//g), "%2f").replace(regEx(/:/g), "%3A");
|
|
98
101
|
const url = joinUrlParts(apiBaseUrl, "api/mc/json", datasource, escapedPackageName, currentVersion, newVersion);
|
|
99
|
-
const cacheKey =
|
|
102
|
+
const cacheKey = buildCacheKey(tokenHash, url);
|
|
100
103
|
const cachedResult = await get(hostType, cacheKey);
|
|
101
104
|
// istanbul ignore if
|
|
102
105
|
if (cachedResult) {
|
|
@@ -133,7 +136,7 @@ async function queryApi(datasource, packageName, currentVersion, newVersion) {
|
|
|
133
136
|
*/
|
|
134
137
|
async function initMergeConfidence(config) {
|
|
135
138
|
initConfig(config);
|
|
136
|
-
if (isNullOrUndefined(apiBaseUrl) || isNullOrUndefined(
|
|
139
|
+
if (isNullOrUndefined(apiBaseUrl) || isNullOrUndefined(tokenHash)) {
|
|
137
140
|
logger.trace("merge confidence API usage is disabled");
|
|
138
141
|
return;
|
|
139
142
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["presetSupportedDatasources","packageCache.get","packageCache.set","hostRules.find"],"sources":["../../../lib/util/merge-confidence/index.ts"],"sourcesContent":["import { isNullOrUndefined } from '@sindresorhus/is';\nimport { supportedDatasources as presetSupportedDatasources } from '../../config/presets/internal/merge-confidence.preset.ts';\nimport type { AllConfig, UpdateType } from '../../config/types.ts';\nimport { instrument } from '../../instrumentation/index.ts';\nimport {\n ATTR_RENOVATE_DATASOURCE,\n ATTR_RENOVATE_PACKAGE_NAME,\n} from '../../instrumentation/types.ts';\nimport { logger } from '../../logger/index.ts';\nimport { ExternalHostError } from '../../types/errors/external-host-error.ts';\nimport * as packageCache from '../cache/package/index.ts';\nimport * as hostRules from '../host-rules.ts';\nimport { memCacheProvider } from '../http/cache/memory-http-cache-provider.ts';\nimport { Http } from '../http/index.ts';\nimport { regEx } from '../regex.ts';\nimport { ensureTrailingSlash, joinUrlParts, parseUrl } from '../url.ts';\nimport { MERGE_CONFIDENCE } from './common.ts';\nimport { MergeConfidenceResponse } from './schema.ts';\nimport type { MergeConfidence } from './types.ts';\n\nconst hostType = 'merge-confidence';\nconst http = new Http(hostType);\nlet token: string | undefined;\nlet apiBaseUrl: string | undefined;\nlet supportedDatasources: string[] = [];\n\nexport const confidenceLevels: Record<MergeConfidence, number> = {\n low: -1,\n neutral: 0,\n high: 1,\n 'very high': 2,\n};\n\nexport function initConfig({\n mergeConfidenceEndpoint,\n mergeConfidenceDatasources,\n}: AllConfig): void {\n apiBaseUrl = getApiBaseUrl(mergeConfidenceEndpoint);\n token = getApiToken();\n\n supportedDatasources =\n mergeConfidenceDatasources ?? presetSupportedDatasources;\n\n if (!isNullOrUndefined(token)) {\n logger.debug(`Merge confidence token found for ${apiBaseUrl}`);\n }\n}\n\nexport function resetConfig(): void {\n token = undefined;\n apiBaseUrl = undefined;\n supportedDatasources = [];\n}\n\nexport function isMergeConfidence(value: string): value is MergeConfidence {\n return MERGE_CONFIDENCE.includes(value as MergeConfidence);\n}\n\nexport function isActiveConfidenceLevel(confidence: string): boolean {\n return isMergeConfidence(confidence) && confidence !== 'low';\n}\n\nexport function satisfiesConfidenceLevel(\n confidence: MergeConfidence,\n minimumConfidence: MergeConfidence,\n): boolean {\n return confidenceLevels[confidence] >= confidenceLevels[minimumConfidence];\n}\n\nconst updateTypeConfidenceMapping: Record<UpdateType, MergeConfidence | null> =\n {\n pin: 'high',\n digest: 'neutral',\n pinDigest: 'high',\n bump: 'neutral',\n lockFileMaintenance: 'neutral',\n lockfileUpdate: 'neutral',\n rollback: 'neutral',\n replacement: 'neutral',\n major: null,\n minor: null,\n patch: null,\n };\n\n/**\n * Retrieves the merge confidence of a package update if the merge confidence API is enabled. Otherwise, undefined is returned.\n *\n * @param datasource\n * @param packageName\n * @param currentVersion\n * @param newVersion\n * @param updateType\n *\n * @returns The merge confidence level for the given package release.\n * @throws {ExternalHostError} If a request has been made and an error occurs during the request, such as a timeout, connection reset, authentication failure, or internal server error.\n */\nexport async function getMergeConfidenceLevel(\n datasource: string,\n packageName: string,\n currentVersion: string,\n newVersion: string,\n updateType: UpdateType,\n): Promise<MergeConfidence | undefined> {\n return await instrument(\n 'getMergeConfidenceLevel',\n async () => {\n if (isNullOrUndefined(apiBaseUrl) || isNullOrUndefined(token)) {\n return undefined;\n }\n\n if (!supportedDatasources.includes(datasource)) {\n return undefined;\n }\n\n if (!(currentVersion && newVersion && updateType)) {\n return 'neutral';\n }\n\n const mappedConfidence = updateTypeConfidenceMapping[updateType];\n if (mappedConfidence) {\n return mappedConfidence;\n }\n\n return await queryApi(\n datasource,\n packageName,\n currentVersion,\n newVersion,\n );\n },\n {\n attributes: {\n [ATTR_RENOVATE_DATASOURCE]: datasource,\n [ATTR_RENOVATE_PACKAGE_NAME]: packageName,\n },\n },\n );\n}\n\n/**\n * Queries the Merge Confidence API with the given package release information.\n *\n * @param datasource\n * @param packageName\n * @param currentVersion\n * @param newVersion\n *\n * @returns The merge confidence level for the given package release.\n * @throws {ExternalHostError} if a timeout or connection reset error, authentication failure, or internal server error occurs during the request.\n *\n * @remarks\n * Results are cached for 60 minutes to reduce the number of API calls.\n */\nasync function queryApi(\n datasource: string,\n packageName: string,\n currentVersion: string,\n newVersion: string,\n): Promise<MergeConfidence> {\n // istanbul ignore if: defensive, already been validated before calling this function\n if (isNullOrUndefined(apiBaseUrl) || isNullOrUndefined(token)) {\n return 'neutral';\n }\n\n const escapedPackageName = packageName\n .replace(regEx(/\\//g), '%2f')\n .replace(regEx(/:/g), '%3A');\n const url = joinUrlParts(\n apiBaseUrl,\n 'api/mc/json',\n datasource,\n escapedPackageName,\n currentVersion,\n newVersion,\n );\n const cacheKey = `${token}:${url}`;\n const cachedResult = await packageCache.get(hostType, cacheKey);\n\n // istanbul ignore if\n if (cachedResult) {\n logger.debug(\n {\n datasource,\n packageName,\n currentVersion,\n newVersion,\n cachedResult,\n },\n 'using merge confidence cached result',\n );\n return cachedResult;\n }\n\n let confidence: MergeConfidence = 'neutral';\n try {\n const res = (\n await http.getJson(\n url,\n { cacheProvider: memCacheProvider },\n MergeConfidenceResponse,\n )\n ).body;\n if (isMergeConfidence(res.confidence)) {\n confidence = res.confidence;\n }\n } catch (err) {\n apiErrorHandler(err);\n }\n\n await packageCache.set(hostType, cacheKey, confidence, 60);\n return confidence;\n}\n\n/**\n * Checks the health of the Merge Confidence API by attempting to authenticate with it.\n *\n * @returns Resolves when the API health check is completed successfully.\n *\n * @throws {ExternalHostError} if a timeout, connection reset error, authentication failure, or internal server error occurs during the request.\n *\n * @remarks\n * This function first checks that the API base URL and an authentication bearer token are defined before attempting to\n * authenticate with the API. If either the base URL or token is not defined, it will immediately return\n * without making a request.\n */\nexport async function initMergeConfidence(config: AllConfig): Promise<void> {\n initConfig(config);\n\n if (isNullOrUndefined(apiBaseUrl) || isNullOrUndefined(token)) {\n logger.trace('merge confidence API usage is disabled');\n return;\n }\n\n const url = joinUrlParts(apiBaseUrl, 'api/mc/availability');\n try {\n await http.get(url);\n } catch (err) {\n apiErrorHandler(err);\n }\n\n logger.debug(\n { supportedDatasources },\n 'merge confidence API - successfully authenticated',\n );\n return;\n}\n\nfunction getApiBaseUrl(mergeConfidenceEndpoint: string | undefined): string {\n const defaultBaseUrl = 'https://developer.mend.io/';\n const baseFromEnv = mergeConfidenceEndpoint ?? defaultBaseUrl;\n\n const parsedBaseUrl = parseUrl(baseFromEnv)?.toString();\n if (!parsedBaseUrl) {\n logger.warn(\n { baseFromEnv },\n 'invalid merge confidence API base URL found in environment variables - using default value instead',\n );\n return defaultBaseUrl;\n }\n logger.trace(\n { baseUrl: parsedBaseUrl },\n 'using merge confidence API base found in environment variables',\n );\n return ensureTrailingSlash(parsedBaseUrl);\n}\n\nexport function getApiToken(): string | undefined {\n return hostRules.find({\n url: apiBaseUrl,\n hostType,\n })?.token;\n}\n\n/**\n * Handles errors returned by the Merge Confidence API.\n *\n * @param err - The error object returned by the API.\n * @throws {ExternalHostError} if a timeout or connection reset error, authentication failure, or internal server error occurs during the request.\n */\nfunction apiErrorHandler(err: any): void {\n if (err.code === 'ETIMEDOUT' || err.code === 'ECONNRESET') {\n logger.error({ err }, 'merge confidence API request failed - aborting run');\n throw new ExternalHostError(err, hostType);\n }\n\n if (err.statusCode === 403) {\n logger.error({ err }, 'merge confidence API token rejected - aborting run');\n throw new ExternalHostError(err, hostType);\n }\n\n if (err.statusCode >= 500 && err.statusCode < 600) {\n logger.error({ err }, 'merge confidence API failure: 5xx - aborting run');\n throw new ExternalHostError(err, hostType);\n }\n\n logger.warn({ err }, 'error fetching merge confidence data');\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["presetSupportedDatasources","packageCache.get","packageCache.set","hostRules.find"],"sources":["../../../lib/util/merge-confidence/index.ts"],"sourcesContent":["import { isNullOrUndefined } from '@sindresorhus/is';\nimport { supportedDatasources as presetSupportedDatasources } from '../../config/presets/internal/merge-confidence.preset.ts';\nimport type { AllConfig, UpdateType } from '../../config/types.ts';\nimport { instrument } from '../../instrumentation/index.ts';\nimport {\n ATTR_RENOVATE_DATASOURCE,\n ATTR_RENOVATE_PACKAGE_NAME,\n} from '../../instrumentation/types.ts';\nimport { logger } from '../../logger/index.ts';\nimport { ExternalHostError } from '../../types/errors/external-host-error.ts';\nimport * as packageCache from '../cache/package/index.ts';\nimport { buildCacheKey } from '../cache/package/key.ts';\nimport { toSha256 } from '../hash.ts';\nimport * as hostRules from '../host-rules.ts';\nimport { memCacheProvider } from '../http/cache/memory-http-cache-provider.ts';\nimport { Http } from '../http/index.ts';\nimport { regEx } from '../regex.ts';\nimport { ensureTrailingSlash, joinUrlParts, parseUrl } from '../url.ts';\nimport { MERGE_CONFIDENCE } from './common.ts';\nimport { MergeConfidenceResponse } from './schema.ts';\nimport type { MergeConfidence } from './types.ts';\n\nconst hostType = 'merge-confidence';\nconst http = new Http(hostType);\nlet tokenHash: string | undefined;\nlet apiBaseUrl: string | undefined;\nlet supportedDatasources: string[] = [];\n\nexport const confidenceLevels: Record<MergeConfidence, number> = {\n low: -1,\n neutral: 0,\n high: 1,\n 'very high': 2,\n};\n\nexport function initConfig({\n mergeConfidenceEndpoint,\n mergeConfidenceDatasources,\n}: AllConfig): void {\n apiBaseUrl = getApiBaseUrl(mergeConfidenceEndpoint);\n const token = getApiToken();\n tokenHash = isNullOrUndefined(token) ? undefined : toSha256(token);\n\n supportedDatasources =\n mergeConfidenceDatasources ?? presetSupportedDatasources;\n\n if (!isNullOrUndefined(tokenHash)) {\n logger.debug(`Merge confidence token found for ${apiBaseUrl}`);\n }\n}\n\nexport function resetConfig(): void {\n tokenHash = undefined;\n apiBaseUrl = undefined;\n supportedDatasources = [];\n}\n\nexport function isMergeConfidence(value: string): value is MergeConfidence {\n return MERGE_CONFIDENCE.includes(value as MergeConfidence);\n}\n\nexport function isActiveConfidenceLevel(confidence: string): boolean {\n return isMergeConfidence(confidence) && confidence !== 'low';\n}\n\nexport function satisfiesConfidenceLevel(\n confidence: MergeConfidence,\n minimumConfidence: MergeConfidence,\n): boolean {\n return confidenceLevels[confidence] >= confidenceLevels[minimumConfidence];\n}\n\nconst updateTypeConfidenceMapping: Record<UpdateType, MergeConfidence | null> =\n {\n pin: 'high',\n digest: 'neutral',\n pinDigest: 'high',\n bump: 'neutral',\n lockFileMaintenance: 'neutral',\n lockfileUpdate: 'neutral',\n rollback: 'neutral',\n replacement: 'neutral',\n major: null,\n minor: null,\n patch: null,\n };\n\n/**\n * Retrieves the merge confidence of a package update if the merge confidence API is enabled. Otherwise, undefined is returned.\n *\n * @param datasource\n * @param packageName\n * @param currentVersion\n * @param newVersion\n * @param updateType\n *\n * @returns The merge confidence level for the given package release.\n * @throws {ExternalHostError} If a request has been made and an error occurs during the request, such as a timeout, connection reset, authentication failure, or internal server error.\n */\nexport async function getMergeConfidenceLevel(\n datasource: string,\n packageName: string,\n currentVersion: string,\n newVersion: string,\n updateType: UpdateType,\n): Promise<MergeConfidence | undefined> {\n return await instrument(\n 'getMergeConfidenceLevel',\n async () => {\n if (isNullOrUndefined(apiBaseUrl) || isNullOrUndefined(tokenHash)) {\n return undefined;\n }\n\n if (!supportedDatasources.includes(datasource)) {\n return undefined;\n }\n\n if (!(currentVersion && newVersion && updateType)) {\n return 'neutral';\n }\n\n const mappedConfidence = updateTypeConfidenceMapping[updateType];\n if (mappedConfidence) {\n return mappedConfidence;\n }\n\n return await queryApi(\n datasource,\n packageName,\n currentVersion,\n newVersion,\n );\n },\n {\n attributes: {\n [ATTR_RENOVATE_DATASOURCE]: datasource,\n [ATTR_RENOVATE_PACKAGE_NAME]: packageName,\n },\n },\n );\n}\n\n/**\n * Queries the Merge Confidence API with the given package release information.\n *\n * @param datasource\n * @param packageName\n * @param currentVersion\n * @param newVersion\n *\n * @returns The merge confidence level for the given package release.\n * @throws {ExternalHostError} if a timeout or connection reset error, authentication failure, or internal server error occurs during the request.\n *\n * @remarks\n * Results are cached for 60 minutes to reduce the number of API calls.\n */\nasync function queryApi(\n datasource: string,\n packageName: string,\n currentVersion: string,\n newVersion: string,\n): Promise<MergeConfidence> {\n // istanbul ignore if: defensive, already been validated before calling this function\n if (isNullOrUndefined(apiBaseUrl) || isNullOrUndefined(tokenHash)) {\n return 'neutral';\n }\n\n const escapedPackageName = packageName\n .replace(regEx(/\\//g), '%2f')\n .replace(regEx(/:/g), '%3A');\n const url = joinUrlParts(\n apiBaseUrl,\n 'api/mc/json',\n datasource,\n escapedPackageName,\n currentVersion,\n newVersion,\n );\n const cacheKey = buildCacheKey(tokenHash, url);\n const cachedResult = await packageCache.get(hostType, cacheKey);\n\n // istanbul ignore if\n if (cachedResult) {\n logger.debug(\n {\n datasource,\n packageName,\n currentVersion,\n newVersion,\n cachedResult,\n },\n 'using merge confidence cached result',\n );\n return cachedResult;\n }\n\n let confidence: MergeConfidence = 'neutral';\n try {\n const res = (\n await http.getJson(\n url,\n { cacheProvider: memCacheProvider },\n MergeConfidenceResponse,\n )\n ).body;\n if (isMergeConfidence(res.confidence)) {\n confidence = res.confidence;\n }\n } catch (err) {\n apiErrorHandler(err);\n }\n\n await packageCache.set(hostType, cacheKey, confidence, 60);\n return confidence;\n}\n\n/**\n * Checks the health of the Merge Confidence API by attempting to authenticate with it.\n *\n * @returns Resolves when the API health check is completed successfully.\n *\n * @throws {ExternalHostError} if a timeout, connection reset error, authentication failure, or internal server error occurs during the request.\n *\n * @remarks\n * This function first checks that the API base URL and an authentication bearer token are defined before attempting to\n * authenticate with the API. If either the base URL or token is not defined, it will immediately return\n * without making a request.\n */\nexport async function initMergeConfidence(config: AllConfig): Promise<void> {\n initConfig(config);\n\n if (isNullOrUndefined(apiBaseUrl) || isNullOrUndefined(tokenHash)) {\n logger.trace('merge confidence API usage is disabled');\n return;\n }\n\n const url = joinUrlParts(apiBaseUrl, 'api/mc/availability');\n try {\n await http.get(url);\n } catch (err) {\n apiErrorHandler(err);\n }\n\n logger.debug(\n { supportedDatasources },\n 'merge confidence API - successfully authenticated',\n );\n return;\n}\n\nfunction getApiBaseUrl(mergeConfidenceEndpoint: string | undefined): string {\n const defaultBaseUrl = 'https://developer.mend.io/';\n const baseFromEnv = mergeConfidenceEndpoint ?? defaultBaseUrl;\n\n const parsedBaseUrl = parseUrl(baseFromEnv)?.toString();\n if (!parsedBaseUrl) {\n logger.warn(\n { baseFromEnv },\n 'invalid merge confidence API base URL found in environment variables - using default value instead',\n );\n return defaultBaseUrl;\n }\n logger.trace(\n { baseUrl: parsedBaseUrl },\n 'using merge confidence API base found in environment variables',\n );\n return ensureTrailingSlash(parsedBaseUrl);\n}\n\nexport function getApiToken(): string | undefined {\n return hostRules.find({\n url: apiBaseUrl,\n hostType,\n })?.token;\n}\n\n/**\n * Handles errors returned by the Merge Confidence API.\n *\n * @param err - The error object returned by the API.\n * @throws {ExternalHostError} if a timeout or connection reset error, authentication failure, or internal server error occurs during the request.\n */\nfunction apiErrorHandler(err: any): void {\n if (err.code === 'ETIMEDOUT' || err.code === 'ECONNRESET') {\n logger.error({ err }, 'merge confidence API request failed - aborting run');\n throw new ExternalHostError(err, hostType);\n }\n\n if (err.statusCode === 403) {\n logger.error({ err }, 'merge confidence API token rejected - aborting run');\n throw new ExternalHostError(err, hostType);\n }\n\n if (err.statusCode >= 500 && err.statusCode < 600) {\n logger.error({ err }, 'merge confidence API failure: 5xx - aborting run');\n throw new ExternalHostError(err, hostType);\n }\n\n logger.warn({ err }, 'error fetching merge confidence data');\n}\n"],"mappings":"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"}
|
|
@@ -5,6 +5,7 @@ import { logger } from "../../../../../logger/index.js";
|
|
|
5
5
|
import { isHttpUrl } from "../../../../../util/url.js";
|
|
6
6
|
import { instrument } from "../../../../../instrumentation/index.js";
|
|
7
7
|
import { detectPlatform } from "../../../../../util/common.js";
|
|
8
|
+
import { buildCacheKey } from "../../../../../util/cache/package/key.js";
|
|
8
9
|
import { get as get$1, set as set$1 } from "../../../../../util/cache/package/index.js";
|
|
9
10
|
import { platform } from "../../../../../modules/platform/index.js";
|
|
10
11
|
import { linkify } from "../../../../../util/markdown.js";
|
|
@@ -42,7 +43,7 @@ async function getReleaseList(project, release, source) {
|
|
|
42
43
|
}
|
|
43
44
|
function getCachedReleaseList(project, release, source) {
|
|
44
45
|
const { repository, apiBaseUrl } = project;
|
|
45
|
-
const cacheKey =
|
|
46
|
+
const cacheKey = buildCacheKey("getReleaseList", apiBaseUrl, repository);
|
|
46
47
|
const cachedResult = get(cacheKey);
|
|
47
48
|
// istanbul ignore if
|
|
48
49
|
if (cachedResult !== void 0) return cachedResult;
|
|
@@ -178,7 +179,7 @@ async function getReleaseNotesMdFileInner(project, source) {
|
|
|
178
179
|
}
|
|
179
180
|
function getReleaseNotesMdFile(project, source) {
|
|
180
181
|
const { sourceDirectory, repository, apiBaseUrl } = project;
|
|
181
|
-
const cacheKey =
|
|
182
|
+
const cacheKey = buildCacheKey("getReleaseNotesMdFile@v2", repository, sourceDirectory, apiBaseUrl);
|
|
182
183
|
const cachedResult = get(cacheKey);
|
|
183
184
|
// istanbul ignore if
|
|
184
185
|
if (cachedResult !== void 0) return cachedResult;
|
|
@@ -273,15 +274,13 @@ async function addReleaseNotes(input, config, source) {
|
|
|
273
274
|
};
|
|
274
275
|
const { repository, sourceDirectory, type: projectType } = input.project;
|
|
275
276
|
const cacheNamespace = `changelog-${projectType}-notes@v2`;
|
|
276
|
-
const cacheKeyPrefix = sourceDirectory ? `${repository}:${sourceDirectory}` : `${repository}`;
|
|
277
277
|
const shouldTruncateToPlatformLimit = config.fetchChangeLogs === "pr";
|
|
278
278
|
const maxBodyLength = shouldTruncateToPlatformLimit ? platform.maxBodyLength() : 0;
|
|
279
279
|
let fetchedNotesLength = 0;
|
|
280
280
|
for (const v of input.versions) {
|
|
281
281
|
let releaseNotes;
|
|
282
282
|
if (!shouldTruncateToPlatformLimit || fetchedNotesLength < maxBodyLength) {
|
|
283
|
-
const
|
|
284
|
-
const cacheKey = `${cacheKeyPrefix}:${v.version}${gitRefCachePart}`;
|
|
283
|
+
const cacheKey = buildCacheKey(repository, sourceDirectory, v.version, v.gitRef);
|
|
285
284
|
releaseNotes = await get$1(cacheNamespace, cacheKey);
|
|
286
285
|
if (!releaseNotes) {
|
|
287
286
|
releaseNotes = await getReleaseNotesMd(input.project, v, source);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"release-notes.js","names":["memCache.get","packageCache.get","packageCache.set"],"sources":["../../../../../../lib/workers/repository/update/pr/changelog/release-notes.ts"],"sourcesContent":["import {\n isDate,\n isNonEmptyString,\n isTruthy,\n isUndefined,\n} from '@sindresorhus/is';\nimport { DateTime } from 'luxon';\nimport MarkdownIt from 'markdown-it';\nimport { instrument } from '../../../../../instrumentation/index.ts';\nimport { logger } from '../../../../../logger/index.ts';\nimport { platform } from '../../../../../modules/platform/index.ts';\nimport * as memCache from '../../../../../util/cache/memory/index.ts';\nimport * as packageCache from '../../../../../util/cache/package/index.ts';\nimport type { PackageCacheNamespace } from '../../../../../util/cache/package/types.ts';\nimport { detectPlatform } from '../../../../../util/common.ts';\nimport { linkify } from '../../../../../util/markdown.ts';\nimport { newlineRegex, regEx } from '../../../../../util/regex.ts';\nimport { coerceString } from '../../../../../util/string.ts';\nimport { isHttpUrl } from '../../../../../util/url.ts';\nimport type { BranchUpgradeConfig } from '../../../../types.ts';\nimport type { ChangeLogSource } from './source.ts';\nimport type {\n ChangeLogFile,\n ChangeLogNotes,\n ChangeLogProject,\n ChangeLogRelease,\n ChangeLogResult,\n} from './types.ts';\n\nconst markdown = new MarkdownIt('zero');\nmarkdown.enable(['heading', 'lheading', 'fence']);\n\nconst repositoriesToSkipMdFetching = [\n 'facebook/react-native',\n 'react/react-native',\n];\n\n// Per the OCI distribution reference grammar a leading path segment is a host\n// when it contains a `.` or a `:`. Go module paths are qualified the same way.\nconst hostQualifiedNameRegex = regEx(\n /^(?:localhost(?::\\d+)?|[^/]+[.:][^/]*)\\/(?<unqualifiedName>.+)$/,\n);\n\nexport async function getReleaseList(\n project: ChangeLogProject,\n release: ChangeLogRelease,\n source: ChangeLogSource,\n): Promise<ChangeLogNotes[]> {\n logger.trace('getReleaseList()');\n const { apiBaseUrl, repository, type } = project;\n try {\n return await source.getReleaseList(project, release);\n } catch (err) /* istanbul ignore next */ {\n if (err.statusCode === 404) {\n logger.debug({ repository, type, apiBaseUrl }, 'getReleaseList 404');\n } else {\n logger.debug(\n { repository, type, apiBaseUrl, err },\n 'getReleaseList error',\n );\n }\n }\n return [];\n}\n\nexport function getCachedReleaseList(\n project: ChangeLogProject,\n release: ChangeLogRelease,\n source: ChangeLogSource,\n): Promise<ChangeLogNotes[]> {\n const { repository, apiBaseUrl } = project;\n // TODO: types (#22198)\n const cacheKey = `getReleaseList-${apiBaseUrl}-${repository}`;\n const cachedResult = memCache.get<Promise<ChangeLogNotes[]>>(cacheKey);\n // istanbul ignore if\n if (cachedResult !== undefined) {\n return cachedResult;\n }\n const promisedRes = getReleaseList(project, release, source);\n memCache.set(cacheKey, promisedRes);\n return promisedRes;\n}\n\nexport function massageBody(\n input: string | undefined | null,\n baseUrl: string,\n): string {\n let body = coerceString(input);\n // Convert line returns\n body = body.replace(regEx(/\\r\\n/g), '\\n');\n // semantic-release cleanup\n body = body.replace(regEx(/^<a name=\"[^\"]*\"><\\/a>\\n/), '');\n body = body.replace(\n regEx(\n `^##? \\\\[[^\\\\]]*\\\\]\\\\(${baseUrl}[^/]*/[^/]*/compare/.*?\\\\n`,\n undefined,\n false,\n ),\n '',\n );\n // Clean-up unnecessary commits link\n body = `\\n${body}\\n`.replace(\n regEx(`\\\\n${baseUrl}[^/]+/[^/]+/compare/[^\\\\n]+(\\\\n|$)`),\n '\\n',\n );\n // Reduce headings size\n body = body\n .split(regEx(/(?<codeBlock>```[\\s\\S]*?```)/g))\n .map((part) =>\n part.startsWith('```') // do not modify # inside of codeblocks\n ? part\n : part\n .replace(regEx(/\\n\\s*####? /g), '\\n##### ')\n .replace(regEx(/\\n\\s*## /g), '\\n#### ')\n .replace(regEx(/\\n\\s*# /g), '\\n### '),\n )\n .join('');\n // Trim whitespace\n return body.trim();\n}\n\nexport function massageName(\n input: string | undefined | null,\n version: string | undefined,\n): string | undefined {\n let name = input ?? '';\n\n if (version) {\n name = name.replace(RegExp(`^(Release )?v?${version}`, 'i'), '').trim();\n }\n\n name = name.trim();\n if (!name.length) {\n return undefined;\n }\n\n return name;\n}\n\nexport async function getReleaseNotes(\n project: ChangeLogProject,\n release: ChangeLogRelease,\n config: BranchUpgradeConfig,\n source: ChangeLogSource,\n): Promise<ChangeLogNotes | null> {\n return await instrument('getReleaseNotes', async () => {\n const { packageName, depName, repository } = project;\n const { version, gitRef } = release;\n // TODO: types (#22198)\n logger.trace(\n `getReleaseNotes(${repository}, ${version}, ${packageName!}, ${depName!})`,\n );\n const releases = await getCachedReleaseList(project, release, source);\n logger.trace({ releases }, 'Release list from getReleaseList');\n let releaseNotes: ChangeLogNotes | null = null;\n\n let matchedRelease = getExactReleaseMatch(\n packageName,\n depName,\n version,\n releases,\n );\n if (isUndefined(matchedRelease)) {\n // no exact match of a release then check other cases\n matchedRelease = releases.find(\n (r) =>\n r.tag === version ||\n r.tag === `v${version}` ||\n r.tag === gitRef ||\n r.tag === `v${gitRef}`,\n );\n }\n if (isUndefined(matchedRelease) && config.extractVersion) {\n const extractVersionRegEx = regEx(config.extractVersion);\n matchedRelease = releases.find((r) => {\n const extractedVersion = extractVersionRegEx.exec(r.tag!)?.groups\n ?.version;\n return version === extractedVersion;\n });\n }\n releaseNotes = await releaseNotesResult(matchedRelease, project);\n logger.trace({ releaseNotes });\n return releaseNotes;\n });\n}\n\nfunction getExactReleaseMatch(\n packageName: string | undefined,\n depName: string | undefined,\n version: string,\n releases: ChangeLogNotes[],\n): ChangeLogNotes | undefined {\n const namePatterns = getNamePatterns(packageName, depName);\n if (!namePatterns.length) {\n return undefined;\n }\n\n const exactReleaseReg = regEx(\n `(?:^|/)(?:${namePatterns.join('|')})[@_/-]v?${RegExp.escape(version)}`,\n );\n const candidateReleases = releases.filter((r) => r.tag?.endsWith(version));\n const matchedRelease = candidateReleases.find((r) =>\n exactReleaseReg.test(r.tag!),\n );\n return matchedRelease;\n}\n\n/**\n * A registry host never appears in a Git tag, so a host-qualified name such as\n * an OCI chart `<registry>/<org>/<repo>/<chart>` can never match the tag that\n * publishes it, which is scoped by the chart name alone: `<chart>-<version>`.\n * For those names, also match against the name with its host stripped, and\n * against the trailing path segment alone. Names that are not host-qualified,\n * such as scoped npm packages, keep matching in full only, so their tag\n * prefixes stay as specific as they are today.\n */\nfunction getNamePatterns(\n packageName: string | undefined,\n depName: string | undefined,\n): string[] {\n const names = new Set<string>();\n for (const name of [packageName, depName]) {\n if (!isNonEmptyString(name)) {\n continue;\n }\n names.add(name);\n\n const unqualifiedName =\n hostQualifiedNameRegex.exec(name)?.groups?.unqualifiedName;\n if (isNonEmptyString(unqualifiedName)) {\n names.add(unqualifiedName);\n\n const trailingName = unqualifiedName.split('/').pop();\n if (isNonEmptyString(trailingName)) {\n names.add(trailingName);\n }\n }\n }\n return [...names].map((name) => RegExp.escape(name));\n}\n\nasync function releaseNotesResult(\n releaseMatch: ChangeLogNotes | undefined,\n project: ChangeLogProject,\n): Promise<ChangeLogNotes | null> {\n if (!releaseMatch) {\n return null;\n }\n const { baseUrl, repository } = project;\n const releaseNotes: ChangeLogNotes = releaseMatch;\n if (detectPlatform(baseUrl) === 'gitlab') {\n releaseNotes.url = `${baseUrl}${repository}/tags/${releaseMatch.tag!}`;\n } else {\n // v8 ignore next -- a matched release always carries its own url\n releaseNotes.url = releaseMatch.url\n ? releaseMatch.url\n : /* istanbul ignore next */\n `${baseUrl}${repository}/releases/${releaseMatch.tag!}`;\n }\n // set body for release notes\n releaseNotes.body = massageBody(releaseNotes.body, baseUrl);\n releaseNotes.name = massageName(releaseNotes.name, releaseNotes.tag);\n if (releaseNotes.body.length || releaseNotes.name?.length) {\n try {\n if (baseUrl !== 'https://gitlab.com/') {\n releaseNotes.body = await linkify(releaseNotes.body, {\n repository: `${baseUrl}${repository}`,\n });\n }\n } catch (err) /* istanbul ignore next */ {\n logger.warn({ err, baseUrl, repository }, 'Error linkifying');\n }\n } else {\n return null;\n }\n\n return releaseNotes;\n}\n\nfunction sectionize(text: string, level: number): string[] {\n const sections: [number, number][] = [];\n const lines = text.split(newlineRegex);\n const tokens = markdown.parse(text, {});\n tokens.forEach((token) => {\n if (token.type === 'heading_open') {\n const lev = +token.tag.substring(1);\n if (lev <= level) {\n sections.push([lev, token.map![0]]);\n }\n }\n });\n sections.push([-1, lines.length]);\n const result: string[] = [];\n for (let i = 1; i < sections.length; i += 1) {\n const [lev, start] = sections[i - 1];\n const [, end] = sections[i];\n if (lev === level) {\n result.push(lines.slice(start, end).join('\\n'));\n }\n }\n return result;\n}\n\nexport async function getReleaseNotesMdFileInner(\n project: ChangeLogProject,\n source: ChangeLogSource,\n): Promise<ChangeLogFile | null> {\n const { repository, type, apiBaseUrl, sourceDirectory } = project;\n try {\n return await source.getReleaseNotesMd(\n repository,\n apiBaseUrl,\n sourceDirectory,\n );\n } catch (err) /* istanbul ignore next */ {\n if (err.statusCode === 404) {\n logger.debug(\n { repository, type, apiBaseUrl },\n 'Error 404 getting changelog md',\n );\n } else {\n logger.debug(\n { err, repository, type, apiBaseUrl },\n 'Error getting changelog md',\n );\n }\n }\n return null;\n}\n\nexport function getReleaseNotesMdFile(\n project: ChangeLogProject,\n source: ChangeLogSource,\n): Promise<ChangeLogFile | null> {\n const { sourceDirectory, repository, apiBaseUrl } = project;\n // TODO: types (#22198)\n const cacheKey = sourceDirectory\n ? `getReleaseNotesMdFile@v2-${repository}-${sourceDirectory}-${apiBaseUrl}`\n : `getReleaseNotesMdFile@v2-${repository}-${apiBaseUrl}`;\n const cachedResult = memCache.get<Promise<ChangeLogFile | null>>(cacheKey);\n // istanbul ignore if\n if (cachedResult !== undefined) {\n return cachedResult;\n }\n const promisedRes = getReleaseNotesMdFileInner(project, source);\n memCache.set(cacheKey, promisedRes);\n return promisedRes;\n}\n\nexport async function getReleaseNotesMd(\n project: ChangeLogProject,\n release: ChangeLogRelease,\n source: ChangeLogSource,\n): Promise<ChangeLogNotes | null> {\n const { baseUrl, repository, packageName } = project;\n const version = release.version;\n logger.trace(`getReleaseNotesMd(${repository}, ${version})`);\n\n if (shouldSkipChangelogMd(repository)) {\n return null;\n }\n\n const changelog = await getReleaseNotesMdFile(project, source);\n if (!changelog) {\n return null;\n }\n const { changelogFile } = changelog;\n const changelogMd = changelog.changelogMd.replace(\n regEx(/\\n\\s*<a name=\"[^\"]*\">.*?<\\/a>\\n/g),\n '\\n',\n );\n for (const level of [1, 2, 3, 4, 5, 6, 7]) {\n const changelogParsed = sectionize(changelogMd, level);\n if (changelogParsed.length >= 2) {\n for (const section of changelogParsed) {\n try {\n // replace brackets and parenthesis with space\n const deParenthesizedSection = section.replace(\n regEx(/[[\\]()]/g),\n ' ',\n );\n const [heading] = deParenthesizedSection.split(newlineRegex);\n const [parenthesizedHeading] = section.split(newlineRegex);\n const title = heading\n .replace(regEx(/^\\s*#*\\s*/), '')\n .split(' ')\n .filter(isTruthy);\n const body = section.replace(regEx(/.*?\\n(?:-{3,}\\n)?/), '').trim();\n const notesSourceUrl = source.getNotesSourceUrl(\n baseUrl,\n repository,\n changelogFile,\n );\n const url = source.getReleaseNotesMdAnchorUrl(\n notesSourceUrl,\n parenthesizedHeading,\n );\n // Look for version in title\n for (const word of title) {\n if (word.includes(version) && !isHttpUrl(word)) {\n logger.trace({ body }, `Found release notes for v${version}`);\n return {\n body: await linkifyBody(project, body),\n url,\n notesSourceUrl,\n };\n }\n }\n // Look for version in body - useful for monorepos. First check for heading with \"(yyyy-mm-dd)\"\n const releasesRegex = regEx(/(?:[0-9]{4}-[0-9]{2}-[0-9]{2})/);\n if (packageName && heading.search(releasesRegex) !== -1) {\n // Now check if any line contains both the package name and the version\n // Skip Markdown link reference definitions (e.g. `[1.2.3]: https://…/compare/...`)\n // which Keep-a-Changelog files list at the bottom and would otherwise match every version.\n const linkRefDefRegex = regEx(/^\\s*\\[[^\\]]+\\]:\\s*\\S+/);\n const bodyLines = body.split('\\n');\n if (\n bodyLines.some(\n (line) =>\n line.includes(packageName) &&\n line.includes(version) &&\n !isHttpUrl(line) &&\n !linkRefDefRegex.test(line),\n )\n ) {\n logger.trace({ body }, `Found release notes for v${version}`);\n return {\n body: await linkifyBody(project, body),\n url,\n notesSourceUrl,\n };\n }\n }\n } catch (err) /* istanbul ignore next */ {\n logger.warn(\n { file: changelogFile, err },\n `Error parsing changelog file`,\n );\n }\n }\n }\n logger.trace({ repository }, `No level ${level} changelogs headings found`);\n }\n logger.trace({ repository, version }, `No entry found in ${changelogFile}`);\n return null;\n}\n\n/**\n * Determine how long to cache release notes based on when the version was released.\n *\n * It's not uncommon for release notes to be updated shortly after the release itself,\n * so only cache for about an hour when the release is less than a week old. Otherwise,\n * cache for days.\n */\nexport function releaseNotesCacheMinutes(releaseDate?: string | Date): number {\n const dt = isDate(releaseDate)\n ? DateTime.fromJSDate(releaseDate)\n : DateTime.fromISO(releaseDate!);\n\n const now = DateTime.local();\n\n if (!dt.isValid || now.diff(dt, 'days').days < 7) {\n return 55;\n }\n\n if (now.diff(dt, 'months').months < 6) {\n return 1435; // 5 minutes shy of one day\n }\n\n return 14495; // 5 minutes shy of 10 days\n}\n\nexport async function addReleaseNotes(\n input: ChangeLogResult | null | undefined,\n config: BranchUpgradeConfig,\n source: ChangeLogSource,\n): Promise<ChangeLogResult | null> {\n return await instrument(`addReleaseNotes`, async () => {\n if (!input?.versions || !input.project?.type) {\n logger.debug('Missing project or versions');\n return input ?? null;\n }\n const output: ChangeLogResult = {\n ...input,\n versions: [],\n hasReleaseNotes: false,\n };\n\n const { repository, sourceDirectory, type: projectType } = input.project;\n const cacheNamespace: PackageCacheNamespace = `changelog-${projectType}-notes@v2`;\n const cacheKeyPrefix = sourceDirectory\n ? `${repository}:${sourceDirectory}`\n : `${repository}`;\n\n const shouldTruncateToPlatformLimit = config.fetchChangeLogs === 'pr';\n const maxBodyLength = shouldTruncateToPlatformLimit\n ? platform.maxBodyLength()\n : 0;\n let fetchedNotesLength = 0;\n\n for (const v of input.versions) {\n let releaseNotes: ChangeLogNotes | null | undefined;\n\n if (\n !shouldTruncateToPlatformLimit ||\n fetchedNotesLength < maxBodyLength\n ) {\n const gitRefCachePart = v.gitRef ? `:${v.gitRef}` : '';\n const cacheKey = `${cacheKeyPrefix}:${v.version}${gitRefCachePart}`;\n releaseNotes = await packageCache.get(cacheNamespace, cacheKey);\n if (!releaseNotes) {\n releaseNotes = await getReleaseNotesMd(input.project, v, source);\n releaseNotes ??= await getReleaseNotes(\n input.project,\n v,\n config,\n source,\n );\n\n // If there is no release notes, at least try to show the compare URL\n if (!releaseNotes && v.compare.url) {\n releaseNotes = { url: v.compare.url, notesSourceUrl: '' };\n }\n\n // only write on a miss: writing a hit back would refresh its TTL, so a cached compare-only fallback would never be retried\n const cacheMinutes = releaseNotesCacheMinutes(v.date);\n await packageCache.set(\n cacheNamespace,\n cacheKey,\n releaseNotes,\n cacheMinutes,\n );\n }\n\n // when we have received enough changelog content to exceed the platform's limit, we should stop trying to look up more changelog entries, as we fetch newest releases first, so the most recent changelog entries will be visible in the PR\n if (shouldTruncateToPlatformLimit) {\n fetchedNotesLength += releaseNotes?.body?.length ?? 0;\n if (fetchedNotesLength >= maxBodyLength) {\n logger.debug(\n {\n repository,\n project: input.project,\n skippingVersionFrom: v.version,\n maxBodyLength,\n },\n `Already fetched enough changelogs to hit the platform PR body limit, skipping version ${v.version} and below`,\n );\n }\n }\n } else if (v.compare.url) {\n releaseNotes = { url: v.compare.url, notesSourceUrl: '' };\n }\n\n output.versions!.push({\n ...v,\n releaseNotes: releaseNotes!,\n });\n\n if (releaseNotes) {\n output.hasReleaseNotes = true;\n }\n }\n return output;\n });\n}\n\n/**\n * Skip fetching changelog/release-notes markdown files.\n * Will force a fallback to using GitHub release notes\n */\nexport function shouldSkipChangelogMd(repository: string): boolean {\n return repositoriesToSkipMdFetching.includes(repository);\n}\n\nasync function linkifyBody(\n { baseUrl, repository }: ChangeLogProject,\n bodyStr: string,\n): Promise<string> {\n const body = massageBody(bodyStr, baseUrl);\n if (body?.length) {\n try {\n return await linkify(body, {\n repository: `${baseUrl}${repository}`,\n });\n } catch (err) /* istanbul ignore next */ {\n logger.warn({ body, err }, 'linkify error');\n }\n }\n return body;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"release-notes.js","names":["memCache.get","packageCache.get","packageCache.set"],"sources":["../../../../../../lib/workers/repository/update/pr/changelog/release-notes.ts"],"sourcesContent":["import {\n isDate,\n isNonEmptyString,\n isTruthy,\n isUndefined,\n} from '@sindresorhus/is';\nimport { DateTime } from 'luxon';\nimport MarkdownIt from 'markdown-it';\nimport { instrument } from '../../../../../instrumentation/index.ts';\nimport { logger } from '../../../../../logger/index.ts';\nimport { platform } from '../../../../../modules/platform/index.ts';\nimport * as memCache from '../../../../../util/cache/memory/index.ts';\nimport * as packageCache from '../../../../../util/cache/package/index.ts';\nimport { buildCacheKey } from '../../../../../util/cache/package/key.ts';\nimport type { PackageCacheNamespace } from '../../../../../util/cache/package/types.ts';\nimport { detectPlatform } from '../../../../../util/common.ts';\nimport { linkify } from '../../../../../util/markdown.ts';\nimport { newlineRegex, regEx } from '../../../../../util/regex.ts';\nimport { coerceString } from '../../../../../util/string.ts';\nimport { isHttpUrl } from '../../../../../util/url.ts';\nimport type { BranchUpgradeConfig } from '../../../../types.ts';\nimport type { ChangeLogSource } from './source.ts';\nimport type {\n ChangeLogFile,\n ChangeLogNotes,\n ChangeLogProject,\n ChangeLogRelease,\n ChangeLogResult,\n} from './types.ts';\n\nconst markdown = new MarkdownIt('zero');\nmarkdown.enable(['heading', 'lheading', 'fence']);\n\nconst repositoriesToSkipMdFetching = [\n 'facebook/react-native',\n 'react/react-native',\n];\n\n// Per the OCI distribution reference grammar a leading path segment is a host\n// when it contains a `.` or a `:`. Go module paths are qualified the same way.\nconst hostQualifiedNameRegex = regEx(\n /^(?:localhost(?::\\d+)?|[^/]+[.:][^/]*)\\/(?<unqualifiedName>.+)$/,\n);\n\nexport async function getReleaseList(\n project: ChangeLogProject,\n release: ChangeLogRelease,\n source: ChangeLogSource,\n): Promise<ChangeLogNotes[]> {\n logger.trace('getReleaseList()');\n const { apiBaseUrl, repository, type } = project;\n try {\n return await source.getReleaseList(project, release);\n } catch (err) /* istanbul ignore next */ {\n if (err.statusCode === 404) {\n logger.debug({ repository, type, apiBaseUrl }, 'getReleaseList 404');\n } else {\n logger.debug(\n { repository, type, apiBaseUrl, err },\n 'getReleaseList error',\n );\n }\n }\n return [];\n}\n\nexport function getCachedReleaseList(\n project: ChangeLogProject,\n release: ChangeLogRelease,\n source: ChangeLogSource,\n): Promise<ChangeLogNotes[]> {\n const { repository, apiBaseUrl } = project;\n const cacheKey = buildCacheKey('getReleaseList', apiBaseUrl, repository);\n const cachedResult = memCache.get<Promise<ChangeLogNotes[]>>(cacheKey);\n // istanbul ignore if\n if (cachedResult !== undefined) {\n return cachedResult;\n }\n const promisedRes = getReleaseList(project, release, source);\n memCache.set(cacheKey, promisedRes);\n return promisedRes;\n}\n\nexport function massageBody(\n input: string | undefined | null,\n baseUrl: string,\n): string {\n let body = coerceString(input);\n // Convert line returns\n body = body.replace(regEx(/\\r\\n/g), '\\n');\n // semantic-release cleanup\n body = body.replace(regEx(/^<a name=\"[^\"]*\"><\\/a>\\n/), '');\n body = body.replace(\n regEx(\n `^##? \\\\[[^\\\\]]*\\\\]\\\\(${baseUrl}[^/]*/[^/]*/compare/.*?\\\\n`,\n undefined,\n false,\n ),\n '',\n );\n // Clean-up unnecessary commits link\n body = `\\n${body}\\n`.replace(\n regEx(`\\\\n${baseUrl}[^/]+/[^/]+/compare/[^\\\\n]+(\\\\n|$)`),\n '\\n',\n );\n // Reduce headings size\n body = body\n .split(regEx(/(?<codeBlock>```[\\s\\S]*?```)/g))\n .map((part) =>\n part.startsWith('```') // do not modify # inside of codeblocks\n ? part\n : part\n .replace(regEx(/\\n\\s*####? /g), '\\n##### ')\n .replace(regEx(/\\n\\s*## /g), '\\n#### ')\n .replace(regEx(/\\n\\s*# /g), '\\n### '),\n )\n .join('');\n // Trim whitespace\n return body.trim();\n}\n\nexport function massageName(\n input: string | undefined | null,\n version: string | undefined,\n): string | undefined {\n let name = input ?? '';\n\n if (version) {\n name = name.replace(RegExp(`^(Release )?v?${version}`, 'i'), '').trim();\n }\n\n name = name.trim();\n if (!name.length) {\n return undefined;\n }\n\n return name;\n}\n\nexport async function getReleaseNotes(\n project: ChangeLogProject,\n release: ChangeLogRelease,\n config: BranchUpgradeConfig,\n source: ChangeLogSource,\n): Promise<ChangeLogNotes | null> {\n return await instrument('getReleaseNotes', async () => {\n const { packageName, depName, repository } = project;\n const { version, gitRef } = release;\n // TODO: types (#22198)\n logger.trace(\n `getReleaseNotes(${repository}, ${version}, ${packageName!}, ${depName!})`,\n );\n const releases = await getCachedReleaseList(project, release, source);\n logger.trace({ releases }, 'Release list from getReleaseList');\n let releaseNotes: ChangeLogNotes | null = null;\n\n let matchedRelease = getExactReleaseMatch(\n packageName,\n depName,\n version,\n releases,\n );\n if (isUndefined(matchedRelease)) {\n // no exact match of a release then check other cases\n matchedRelease = releases.find(\n (r) =>\n r.tag === version ||\n r.tag === `v${version}` ||\n r.tag === gitRef ||\n r.tag === `v${gitRef}`,\n );\n }\n if (isUndefined(matchedRelease) && config.extractVersion) {\n const extractVersionRegEx = regEx(config.extractVersion);\n matchedRelease = releases.find((r) => {\n const extractedVersion = extractVersionRegEx.exec(r.tag!)?.groups\n ?.version;\n return version === extractedVersion;\n });\n }\n releaseNotes = await releaseNotesResult(matchedRelease, project);\n logger.trace({ releaseNotes });\n return releaseNotes;\n });\n}\n\nfunction getExactReleaseMatch(\n packageName: string | undefined,\n depName: string | undefined,\n version: string,\n releases: ChangeLogNotes[],\n): ChangeLogNotes | undefined {\n const namePatterns = getNamePatterns(packageName, depName);\n if (!namePatterns.length) {\n return undefined;\n }\n\n const exactReleaseReg = regEx(\n `(?:^|/)(?:${namePatterns.join('|')})[@_/-]v?${RegExp.escape(version)}`,\n );\n const candidateReleases = releases.filter((r) => r.tag?.endsWith(version));\n const matchedRelease = candidateReleases.find((r) =>\n exactReleaseReg.test(r.tag!),\n );\n return matchedRelease;\n}\n\n/**\n * A registry host never appears in a Git tag, so a host-qualified name such as\n * an OCI chart `<registry>/<org>/<repo>/<chart>` can never match the tag that\n * publishes it, which is scoped by the chart name alone: `<chart>-<version>`.\n * For those names, also match against the name with its host stripped, and\n * against the trailing path segment alone. Names that are not host-qualified,\n * such as scoped npm packages, keep matching in full only, so their tag\n * prefixes stay as specific as they are today.\n */\nfunction getNamePatterns(\n packageName: string | undefined,\n depName: string | undefined,\n): string[] {\n const names = new Set<string>();\n for (const name of [packageName, depName]) {\n if (!isNonEmptyString(name)) {\n continue;\n }\n names.add(name);\n\n const unqualifiedName =\n hostQualifiedNameRegex.exec(name)?.groups?.unqualifiedName;\n if (isNonEmptyString(unqualifiedName)) {\n names.add(unqualifiedName);\n\n const trailingName = unqualifiedName.split('/').pop();\n if (isNonEmptyString(trailingName)) {\n names.add(trailingName);\n }\n }\n }\n return [...names].map((name) => RegExp.escape(name));\n}\n\nasync function releaseNotesResult(\n releaseMatch: ChangeLogNotes | undefined,\n project: ChangeLogProject,\n): Promise<ChangeLogNotes | null> {\n if (!releaseMatch) {\n return null;\n }\n const { baseUrl, repository } = project;\n const releaseNotes: ChangeLogNotes = releaseMatch;\n if (detectPlatform(baseUrl) === 'gitlab') {\n releaseNotes.url = `${baseUrl}${repository}/tags/${releaseMatch.tag!}`;\n } else {\n // v8 ignore next -- a matched release always carries its own url\n releaseNotes.url = releaseMatch.url\n ? releaseMatch.url\n : /* istanbul ignore next */\n `${baseUrl}${repository}/releases/${releaseMatch.tag!}`;\n }\n // set body for release notes\n releaseNotes.body = massageBody(releaseNotes.body, baseUrl);\n releaseNotes.name = massageName(releaseNotes.name, releaseNotes.tag);\n if (releaseNotes.body.length || releaseNotes.name?.length) {\n try {\n if (baseUrl !== 'https://gitlab.com/') {\n releaseNotes.body = await linkify(releaseNotes.body, {\n repository: `${baseUrl}${repository}`,\n });\n }\n } catch (err) /* istanbul ignore next */ {\n logger.warn({ err, baseUrl, repository }, 'Error linkifying');\n }\n } else {\n return null;\n }\n\n return releaseNotes;\n}\n\nfunction sectionize(text: string, level: number): string[] {\n const sections: [number, number][] = [];\n const lines = text.split(newlineRegex);\n const tokens = markdown.parse(text, {});\n tokens.forEach((token) => {\n if (token.type === 'heading_open') {\n const lev = +token.tag.substring(1);\n if (lev <= level) {\n sections.push([lev, token.map![0]]);\n }\n }\n });\n sections.push([-1, lines.length]);\n const result: string[] = [];\n for (let i = 1; i < sections.length; i += 1) {\n const [lev, start] = sections[i - 1];\n const [, end] = sections[i];\n if (lev === level) {\n result.push(lines.slice(start, end).join('\\n'));\n }\n }\n return result;\n}\n\nexport async function getReleaseNotesMdFileInner(\n project: ChangeLogProject,\n source: ChangeLogSource,\n): Promise<ChangeLogFile | null> {\n const { repository, type, apiBaseUrl, sourceDirectory } = project;\n try {\n return await source.getReleaseNotesMd(\n repository,\n apiBaseUrl,\n sourceDirectory,\n );\n } catch (err) /* istanbul ignore next */ {\n if (err.statusCode === 404) {\n logger.debug(\n { repository, type, apiBaseUrl },\n 'Error 404 getting changelog md',\n );\n } else {\n logger.debug(\n { err, repository, type, apiBaseUrl },\n 'Error getting changelog md',\n );\n }\n }\n return null;\n}\n\nexport function getReleaseNotesMdFile(\n project: ChangeLogProject,\n source: ChangeLogSource,\n): Promise<ChangeLogFile | null> {\n const { sourceDirectory, repository, apiBaseUrl } = project;\n const cacheKey = buildCacheKey(\n 'getReleaseNotesMdFile@v2',\n repository,\n sourceDirectory,\n apiBaseUrl,\n );\n const cachedResult = memCache.get<Promise<ChangeLogFile | null>>(cacheKey);\n // istanbul ignore if\n if (cachedResult !== undefined) {\n return cachedResult;\n }\n const promisedRes = getReleaseNotesMdFileInner(project, source);\n memCache.set(cacheKey, promisedRes);\n return promisedRes;\n}\n\nexport async function getReleaseNotesMd(\n project: ChangeLogProject,\n release: ChangeLogRelease,\n source: ChangeLogSource,\n): Promise<ChangeLogNotes | null> {\n const { baseUrl, repository, packageName } = project;\n const version = release.version;\n logger.trace(`getReleaseNotesMd(${repository}, ${version})`);\n\n if (shouldSkipChangelogMd(repository)) {\n return null;\n }\n\n const changelog = await getReleaseNotesMdFile(project, source);\n if (!changelog) {\n return null;\n }\n const { changelogFile } = changelog;\n const changelogMd = changelog.changelogMd.replace(\n regEx(/\\n\\s*<a name=\"[^\"]*\">.*?<\\/a>\\n/g),\n '\\n',\n );\n for (const level of [1, 2, 3, 4, 5, 6, 7]) {\n const changelogParsed = sectionize(changelogMd, level);\n if (changelogParsed.length >= 2) {\n for (const section of changelogParsed) {\n try {\n // replace brackets and parenthesis with space\n const deParenthesizedSection = section.replace(\n regEx(/[[\\]()]/g),\n ' ',\n );\n const [heading] = deParenthesizedSection.split(newlineRegex);\n const [parenthesizedHeading] = section.split(newlineRegex);\n const title = heading\n .replace(regEx(/^\\s*#*\\s*/), '')\n .split(' ')\n .filter(isTruthy);\n const body = section.replace(regEx(/.*?\\n(?:-{3,}\\n)?/), '').trim();\n const notesSourceUrl = source.getNotesSourceUrl(\n baseUrl,\n repository,\n changelogFile,\n );\n const url = source.getReleaseNotesMdAnchorUrl(\n notesSourceUrl,\n parenthesizedHeading,\n );\n // Look for version in title\n for (const word of title) {\n if (word.includes(version) && !isHttpUrl(word)) {\n logger.trace({ body }, `Found release notes for v${version}`);\n return {\n body: await linkifyBody(project, body),\n url,\n notesSourceUrl,\n };\n }\n }\n // Look for version in body - useful for monorepos. First check for heading with \"(yyyy-mm-dd)\"\n const releasesRegex = regEx(/(?:[0-9]{4}-[0-9]{2}-[0-9]{2})/);\n if (packageName && heading.search(releasesRegex) !== -1) {\n // Now check if any line contains both the package name and the version\n // Skip Markdown link reference definitions (e.g. `[1.2.3]: https://…/compare/...`)\n // which Keep-a-Changelog files list at the bottom and would otherwise match every version.\n const linkRefDefRegex = regEx(/^\\s*\\[[^\\]]+\\]:\\s*\\S+/);\n const bodyLines = body.split('\\n');\n if (\n bodyLines.some(\n (line) =>\n line.includes(packageName) &&\n line.includes(version) &&\n !isHttpUrl(line) &&\n !linkRefDefRegex.test(line),\n )\n ) {\n logger.trace({ body }, `Found release notes for v${version}`);\n return {\n body: await linkifyBody(project, body),\n url,\n notesSourceUrl,\n };\n }\n }\n } catch (err) /* istanbul ignore next */ {\n logger.warn(\n { file: changelogFile, err },\n `Error parsing changelog file`,\n );\n }\n }\n }\n logger.trace({ repository }, `No level ${level} changelogs headings found`);\n }\n logger.trace({ repository, version }, `No entry found in ${changelogFile}`);\n return null;\n}\n\n/**\n * Determine how long to cache release notes based on when the version was released.\n *\n * It's not uncommon for release notes to be updated shortly after the release itself,\n * so only cache for about an hour when the release is less than a week old. Otherwise,\n * cache for days.\n */\nexport function releaseNotesCacheMinutes(releaseDate?: string | Date): number {\n const dt = isDate(releaseDate)\n ? DateTime.fromJSDate(releaseDate)\n : DateTime.fromISO(releaseDate!);\n\n const now = DateTime.local();\n\n if (!dt.isValid || now.diff(dt, 'days').days < 7) {\n return 55;\n }\n\n if (now.diff(dt, 'months').months < 6) {\n return 1435; // 5 minutes shy of one day\n }\n\n return 14495; // 5 minutes shy of 10 days\n}\n\nexport async function addReleaseNotes(\n input: ChangeLogResult | null | undefined,\n config: BranchUpgradeConfig,\n source: ChangeLogSource,\n): Promise<ChangeLogResult | null> {\n return await instrument(`addReleaseNotes`, async () => {\n if (!input?.versions || !input.project?.type) {\n logger.debug('Missing project or versions');\n return input ?? null;\n }\n const output: ChangeLogResult = {\n ...input,\n versions: [],\n hasReleaseNotes: false,\n };\n\n const { repository, sourceDirectory, type: projectType } = input.project;\n const cacheNamespace: PackageCacheNamespace = `changelog-${projectType}-notes@v2`;\n\n const shouldTruncateToPlatformLimit = config.fetchChangeLogs === 'pr';\n const maxBodyLength = shouldTruncateToPlatformLimit\n ? platform.maxBodyLength()\n : 0;\n let fetchedNotesLength = 0;\n\n for (const v of input.versions) {\n let releaseNotes: ChangeLogNotes | null | undefined;\n\n if (\n !shouldTruncateToPlatformLimit ||\n fetchedNotesLength < maxBodyLength\n ) {\n const cacheKey = buildCacheKey(\n repository,\n sourceDirectory,\n v.version,\n v.gitRef,\n );\n releaseNotes = await packageCache.get(cacheNamespace, cacheKey);\n if (!releaseNotes) {\n releaseNotes = await getReleaseNotesMd(input.project, v, source);\n releaseNotes ??= await getReleaseNotes(\n input.project,\n v,\n config,\n source,\n );\n\n // If there is no release notes, at least try to show the compare URL\n if (!releaseNotes && v.compare.url) {\n releaseNotes = { url: v.compare.url, notesSourceUrl: '' };\n }\n\n // only write on a miss: writing a hit back would refresh its TTL, so a cached compare-only fallback would never be retried\n const cacheMinutes = releaseNotesCacheMinutes(v.date);\n await packageCache.set(\n cacheNamespace,\n cacheKey,\n releaseNotes,\n cacheMinutes,\n );\n }\n\n // when we have received enough changelog content to exceed the platform's limit, we should stop trying to look up more changelog entries, as we fetch newest releases first, so the most recent changelog entries will be visible in the PR\n if (shouldTruncateToPlatformLimit) {\n fetchedNotesLength += releaseNotes?.body?.length ?? 0;\n if (fetchedNotesLength >= maxBodyLength) {\n logger.debug(\n {\n repository,\n project: input.project,\n skippingVersionFrom: v.version,\n maxBodyLength,\n },\n `Already fetched enough changelogs to hit the platform PR body limit, skipping version ${v.version} and below`,\n );\n }\n }\n } else if (v.compare.url) {\n releaseNotes = { url: v.compare.url, notesSourceUrl: '' };\n }\n\n output.versions!.push({\n ...v,\n releaseNotes: releaseNotes!,\n });\n\n if (releaseNotes) {\n output.hasReleaseNotes = true;\n }\n }\n return output;\n });\n}\n\n/**\n * Skip fetching changelog/release-notes markdown files.\n * Will force a fallback to using GitHub release notes\n */\nexport function shouldSkipChangelogMd(repository: string): boolean {\n return repositoriesToSkipMdFetching.includes(repository);\n}\n\nasync function linkifyBody(\n { baseUrl, repository }: ChangeLogProject,\n bodyStr: string,\n): Promise<string> {\n const body = massageBody(bodyStr, baseUrl);\n if (body?.length) {\n try {\n return await linkify(body, {\n repository: `${baseUrl}${repository}`,\n });\n } catch (err) /* istanbul ignore next */ {\n logger.warn({ body, err }, 'linkify error');\n }\n }\n return body;\n}\n"],"mappings":"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"}
|
|
@@ -3,6 +3,7 @@ import { logger } from "../../../../../logger/index.js";
|
|
|
3
3
|
import { PLATFORM_FAMILIES } from "../../../../../constants/platforms.js";
|
|
4
4
|
import { isHttpUrl, joinUrlParts, parseUrl, trimSlashes } from "../../../../../util/url.js";
|
|
5
5
|
import { instrument } from "../../../../../instrumentation/index.js";
|
|
6
|
+
import { buildCacheKey } from "../../../../../util/cache/package/key.js";
|
|
6
7
|
import { get } from "../../../../../modules/versioning/index.js";
|
|
7
8
|
import { get as get$1, set } from "../../../../../util/cache/package/index.js";
|
|
8
9
|
import { getPkgReleases } from "../../../../../modules/datasource/index.js";
|
|
@@ -144,7 +145,7 @@ var ChangeLogSource = class {
|
|
|
144
145
|
return null;
|
|
145
146
|
}
|
|
146
147
|
getCacheKey(sourceUrl, packageName, prev, next) {
|
|
147
|
-
return
|
|
148
|
+
return buildCacheKey(slugifyUrl(sourceUrl), packageName, prev, next);
|
|
148
149
|
}
|
|
149
150
|
getBaseUrl(config) {
|
|
150
151
|
const parsedUrl = parseUrl(config.sourceUrl);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"source.js","names":["allVersioning.get","packageCache.get","packageCache.set"],"sources":["../../../../../../lib/workers/repository/update/pr/changelog/source.ts"],"sourcesContent":["import {\n isEmptyArray,\n isFalsy,\n isNonEmptyString,\n isNullOrUndefined,\n isTruthy,\n} from '@sindresorhus/is';\nimport { PLATFORM_FAMILIES } from '../../../../../constants/index.ts';\nimport { instrument } from '../../../../../instrumentation/index.ts';\nimport { logger } from '../../../../../logger/index.ts';\nimport { getPkgReleases } from '../../../../../modules/datasource/index.ts';\nimport type { Release } from '../../../../../modules/datasource/types.ts';\nimport * as allVersioning from '../../../../../modules/versioning/index.ts';\nimport * as packageCache from '../../../../../util/cache/package/index.ts';\nimport type { PackageCacheNamespace } from '../../../../../util/cache/package/types.ts';\nimport { memoize } from '../../../../../util/memoize.ts';\nimport { regEx } from '../../../../../util/regex.ts';\nimport {\n isHttpUrl,\n joinUrlParts,\n parseUrl,\n trimSlashes,\n} from '../../../../../util/url.ts';\nimport type { BranchUpgradeConfig } from '../../../../types.ts';\nimport { slugifyUrl } from './common.ts';\nimport { addReleaseNotes } from './release-notes.ts';\nimport { getInRangeReleases } from './releases.ts';\nimport type {\n ChangeLogError,\n ChangeLogFile,\n ChangeLogNotes,\n ChangeLogPlatform,\n ChangeLogProject,\n ChangeLogRelease,\n ChangeLogResult,\n} from './types.ts';\n\n// Number of dot-separated segments, used as a proxy for how precise a tag is,\n// e.g. `v7` (0) < `v7.0` (1) < `v7.0.0` (2).\nfunction tagPrecision(tag: string): number {\n return tag.split('.').length - 1;\n}\n\nexport abstract class ChangeLogSource {\n private readonly cacheNamespace: PackageCacheNamespace;\n protected readonly platform: ChangeLogPlatform;\n private readonly family: (typeof PLATFORM_FAMILIES)[ChangeLogPlatform];\n\n constructor(platform: ChangeLogPlatform) {\n this.platform = platform;\n this.family = PLATFORM_FAMILIES[platform];\n this.cacheNamespace = `changelog-${platform}-release`;\n }\n\n abstract getCompareURL(\n baseUrl: string,\n repository: string,\n prevHead: string,\n nextHead: string,\n ): string;\n\n getAPIBaseUrl(config: BranchUpgradeConfig): string {\n return this.family.apiBaseUrl(this.getBaseUrl(config));\n }\n\n /**\n * Fetch the repository's changelog markdown file, if it has one.\n */\n abstract getReleaseNotesMd(\n repository: string,\n apiBaseUrl: string,\n sourceDirectory?: string,\n ): Promise<ChangeLogFile | null>;\n\n /**\n * Fetch the platform's list of releases for the project. Platforms without a\n * releases API keep this default.\n */\n getReleaseList(\n _project: ChangeLogProject,\n _release: ChangeLogRelease,\n ): Promise<ChangeLogNotes[]> {\n logger.trace(`${this.platform}: release lists are not supported`);\n return Promise.resolve([]);\n }\n\n async getAllTags(endpoint: string, repository: string): Promise<string[]> {\n const tags = (\n await getPkgReleases({\n registryUrls: [endpoint],\n datasource: this.family.tagsDatasource,\n packageName: repository,\n versioning:\n 'regex:(?<major>\\\\d+)(\\\\.(?<minor>\\\\d+))?(\\\\.(?<patch>\\\\d+))?',\n })\n )?.releases;\n\n if (isNullOrUndefined(tags) || isEmptyArray(tags)) {\n logger.debug(\n `No ${this.family.tagsDatasource} tags found for repository: ${repository}`,\n );\n\n return [];\n }\n\n return tags.map(({ version }) => version);\n }\n\n public async getChangeLogJSON(\n config: BranchUpgradeConfig,\n ): Promise<ChangeLogResult | null> {\n return await instrument(\n `source.getChangeLogJSON(${this.platform})`,\n async () => {\n logger.trace(`getChangeLogJSON for ${this.platform}`);\n\n const versioning = config.versioning!;\n const currentVersion = config.currentVersion!;\n const newVersion = config.newVersion!;\n const sourceUrl = config.sourceUrl!;\n const packageName = config.packageName!;\n const depName = config.depName!;\n const sourceDirectory = config.sourceDirectory;\n const versioningApi = allVersioning.get(versioning);\n\n if (this.shouldSkipPackage(config)) {\n return null;\n }\n\n const baseUrl = this.getBaseUrl(config);\n const apiBaseUrl = this.getAPIBaseUrl(config);\n const repository = this.getRepositoryFromUrl(config);\n\n const tokenResponse = this.hasValidToken(config);\n if (!tokenResponse.isValid) {\n if (tokenResponse.error) {\n return {\n error: tokenResponse.error,\n };\n }\n return null;\n }\n\n if (isFalsy(this.hasValidRepository(repository))) {\n logger.debug(`Invalid ${this.platform} URL found: ${sourceUrl}`);\n return null;\n }\n\n const releases = config.releases ?? (await getInRangeReleases(config));\n // v8 ignore next -- `getInRangeReleases` only returns null on paths it already ignores\n if (!releases?.length) {\n logger.debug('No releases');\n return null;\n }\n // This extra filter/sort should not be necessary, but better safe than sorry\n const validReleases = [...releases]\n .filter((release) => versioningApi.isVersion(release.version))\n .sort((a, b) => versioningApi.sortVersions(a.version, b.version))\n // Drop versions equal under this versioning, e.g. the Docker tags\n // `3.7.12` and `v3.7.12`, else their notes are rendered twice\n .filter(\n (release, index, sorted) =>\n index === sorted.length - 1 ||\n !versioningApi.equals(release.version, sorted[index + 1].version),\n );\n\n if (validReleases.length < 2) {\n logger.debug(\n `Not enough valid releases for dep ${depName} (${packageName})`,\n );\n return null;\n }\n\n const changelogReleases: ChangeLogRelease[] = [];\n\n // Check if `v` belongs to the range (currentVersion, newVersion]\n function inRange(v: string): boolean {\n return (\n versioningApi.isGreaterThan(v, currentVersion) &&\n !versioningApi.isGreaterThan(v, newVersion)\n );\n }\n\n const getTags = memoize(() => this.getAllTags(apiBaseUrl, repository));\n // Fetch releases newest-first, matching the order they're shown in the PR body.\n for (let i = validReleases.length - 1; i >= 1; i -= 1) {\n const prev = validReleases[i - 1];\n const next = validReleases[i];\n if (!inRange(next.version)) {\n continue;\n }\n let release = await packageCache.get(\n this.cacheNamespace,\n this.getCacheKey(\n sourceUrl,\n packageName,\n prev.version,\n next.version,\n ),\n );\n if (!release) {\n release = {\n version: next.version,\n date: next.releaseTimestamp,\n gitRef: next.gitRef,\n // put empty changes so that existing templates won't break\n changes: [],\n compare: {},\n };\n const tags = await getTags();\n const prevHead = this.getRef(\n versioningApi,\n packageName,\n depName,\n prev,\n tags,\n );\n const nextHead = this.getRef(\n versioningApi,\n packageName,\n depName,\n next,\n tags,\n );\n if (isNonEmptyString(prevHead) && isNonEmptyString(nextHead)) {\n release.compare.url = this.getCompareURL(\n baseUrl,\n repository,\n prevHead,\n nextHead,\n );\n }\n const cacheMinutes = 55;\n await packageCache.set(\n this.cacheNamespace,\n this.getCacheKey(\n sourceUrl,\n packageName,\n prev.version,\n next.version,\n ),\n release,\n cacheMinutes,\n );\n }\n changelogReleases.push(release);\n }\n\n let res: ChangeLogResult | null = {\n project: {\n apiBaseUrl,\n baseUrl,\n type: this.platform,\n repository,\n sourceUrl,\n sourceDirectory,\n packageName,\n depName,\n },\n versions: changelogReleases,\n };\n\n res = await addReleaseNotes(res, config, this);\n\n return res;\n },\n );\n }\n\n private findTagOfRelease(\n versioningApi: allVersioning.VersioningApi,\n packageName: string,\n depName: string,\n depNewVersion: string,\n tags: string[],\n ): string | undefined {\n const releaseRegexPrefix = `^(?:${packageName}|${depName}|release)[@_-]v?`;\n const regex = regEx(releaseRegexPrefix, undefined, false);\n const exactReleaseRegex = regEx(`${releaseRegexPrefix}${depNewVersion}`);\n const exactTagsList = tags.filter((tag) => {\n return exactReleaseRegex.test(tag);\n });\n const tagList = exactTagsList.length ? exactTagsList : tags;\n const candidates = tagList\n .filter((tag) => versioningApi.isVersion(tag.replace(regex, '')))\n .filter((tag) =>\n versioningApi.equals(tag.replace(regex, ''), depNewVersion),\n );\n if (!candidates.length) {\n return undefined;\n }\n // Some versioning schemes (e.g. `github-actions`) treat a floating tag\n // like `v7` as equal to a precise one like `v7.0.0` via coercion, so more\n // than one tag can match the same release. Prefer the most precise tag\n // (most dot-separated segments), else keep the first match found.\n return candidates.reduce((mostPrecise, candidate) =>\n tagPrecision(candidate) > tagPrecision(mostPrecise)\n ? candidate\n : mostPrecise,\n );\n }\n\n private getRef(\n versioningApi: allVersioning.VersioningApi,\n packageName: string,\n depName: string,\n release: Release,\n tags: string[],\n ): string | null {\n const tagName = this.findTagOfRelease(\n versioningApi,\n packageName,\n depName,\n release.version,\n tags,\n );\n if (isNonEmptyString(tagName)) {\n return tagName;\n }\n if (isNonEmptyString(release.gitRef)) {\n return release.gitRef;\n }\n return null;\n }\n\n private getCacheKey(\n sourceUrl: string,\n packageName: string,\n prev: string,\n next: string,\n ): string {\n return `${slugifyUrl(sourceUrl)}:${packageName}:${prev}:${next}`;\n }\n\n getBaseUrl(config: BranchUpgradeConfig): string {\n const parsedUrl = parseUrl(config.sourceUrl);\n if (isNullOrUndefined(parsedUrl)) {\n return '';\n }\n const protocol = parsedUrl.protocol.replace(regEx(/^git\\+/), '');\n const host = parsedUrl.host;\n return `${protocol}//${host}/`;\n }\n\n getRepositoryFromUrl(config: BranchUpgradeConfig): string {\n const parsedUrl = parseUrl(config.sourceUrl);\n if (isNullOrUndefined(parsedUrl)) {\n return '';\n }\n const pathname = parsedUrl.pathname;\n return trimSlashes(pathname).replace(regEx(/\\.git$/), '');\n }\n\n protected hasValidToken(_config: BranchUpgradeConfig): {\n isValid: boolean;\n error?: ChangeLogError;\n } {\n return { isValid: true };\n }\n\n protected shouldSkipPackage(_config: BranchUpgradeConfig): boolean {\n return false;\n }\n\n hasValidRepository(repository: string): boolean {\n return repository.split('/').length === 2;\n }\n\n /**\n * Build the URL to the changelog markdown file for the release notes.\n * Platform sources can override this to match their web UI conventions.\n */\n getNotesSourceUrl(\n baseUrl: string,\n repository: string,\n changelogFile: string,\n ): string {\n return joinUrlParts(baseUrl, repository, 'blob', 'HEAD', changelogFile);\n }\n\n /**\n * Build the URL pointing to a specific heading within the changelog markdown\n * file. Platform sources can override this to match their anchor conventions.\n */\n getReleaseNotesMdAnchorUrl(notesSourceUrl: string, heading: string): string {\n const mdHeadingLink = heading\n .replace(regEx(/[[\\]()]/g), ' ')\n .replace(regEx(/^\\s*#*\\s*/), '')\n .split(' ')\n .filter(isTruthy)\n .filter((word) => !isHttpUrl(word))\n .join('-')\n .replace(regEx(/[^A-Za-z0-9-]/g), '');\n return `${notesSourceUrl}#${mdHeadingLink}`;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"source.js","names":["allVersioning.get","packageCache.get","packageCache.set"],"sources":["../../../../../../lib/workers/repository/update/pr/changelog/source.ts"],"sourcesContent":["import {\n isEmptyArray,\n isFalsy,\n isNonEmptyString,\n isNullOrUndefined,\n isTruthy,\n} from '@sindresorhus/is';\nimport { PLATFORM_FAMILIES } from '../../../../../constants/index.ts';\nimport { instrument } from '../../../../../instrumentation/index.ts';\nimport { logger } from '../../../../../logger/index.ts';\nimport { getPkgReleases } from '../../../../../modules/datasource/index.ts';\nimport type { Release } from '../../../../../modules/datasource/types.ts';\nimport * as allVersioning from '../../../../../modules/versioning/index.ts';\nimport * as packageCache from '../../../../../util/cache/package/index.ts';\nimport { buildCacheKey } from '../../../../../util/cache/package/key.ts';\nimport type { PackageCacheNamespace } from '../../../../../util/cache/package/types.ts';\nimport { memoize } from '../../../../../util/memoize.ts';\nimport { regEx } from '../../../../../util/regex.ts';\nimport {\n isHttpUrl,\n joinUrlParts,\n parseUrl,\n trimSlashes,\n} from '../../../../../util/url.ts';\nimport type { BranchUpgradeConfig } from '../../../../types.ts';\nimport { slugifyUrl } from './common.ts';\nimport { addReleaseNotes } from './release-notes.ts';\nimport { getInRangeReleases } from './releases.ts';\nimport type {\n ChangeLogError,\n ChangeLogFile,\n ChangeLogNotes,\n ChangeLogPlatform,\n ChangeLogProject,\n ChangeLogRelease,\n ChangeLogResult,\n} from './types.ts';\n\n// Number of dot-separated segments, used as a proxy for how precise a tag is,\n// e.g. `v7` (0) < `v7.0` (1) < `v7.0.0` (2).\nfunction tagPrecision(tag: string): number {\n return tag.split('.').length - 1;\n}\n\nexport abstract class ChangeLogSource {\n private readonly cacheNamespace: PackageCacheNamespace;\n protected readonly platform: ChangeLogPlatform;\n private readonly family: (typeof PLATFORM_FAMILIES)[ChangeLogPlatform];\n\n constructor(platform: ChangeLogPlatform) {\n this.platform = platform;\n this.family = PLATFORM_FAMILIES[platform];\n this.cacheNamespace = `changelog-${platform}-release`;\n }\n\n abstract getCompareURL(\n baseUrl: string,\n repository: string,\n prevHead: string,\n nextHead: string,\n ): string;\n\n getAPIBaseUrl(config: BranchUpgradeConfig): string {\n return this.family.apiBaseUrl(this.getBaseUrl(config));\n }\n\n /**\n * Fetch the repository's changelog markdown file, if it has one.\n */\n abstract getReleaseNotesMd(\n repository: string,\n apiBaseUrl: string,\n sourceDirectory?: string,\n ): Promise<ChangeLogFile | null>;\n\n /**\n * Fetch the platform's list of releases for the project. Platforms without a\n * releases API keep this default.\n */\n getReleaseList(\n _project: ChangeLogProject,\n _release: ChangeLogRelease,\n ): Promise<ChangeLogNotes[]> {\n logger.trace(`${this.platform}: release lists are not supported`);\n return Promise.resolve([]);\n }\n\n async getAllTags(endpoint: string, repository: string): Promise<string[]> {\n const tags = (\n await getPkgReleases({\n registryUrls: [endpoint],\n datasource: this.family.tagsDatasource,\n packageName: repository,\n versioning:\n 'regex:(?<major>\\\\d+)(\\\\.(?<minor>\\\\d+))?(\\\\.(?<patch>\\\\d+))?',\n })\n )?.releases;\n\n if (isNullOrUndefined(tags) || isEmptyArray(tags)) {\n logger.debug(\n `No ${this.family.tagsDatasource} tags found for repository: ${repository}`,\n );\n\n return [];\n }\n\n return tags.map(({ version }) => version);\n }\n\n public async getChangeLogJSON(\n config: BranchUpgradeConfig,\n ): Promise<ChangeLogResult | null> {\n return await instrument(\n `source.getChangeLogJSON(${this.platform})`,\n async () => {\n logger.trace(`getChangeLogJSON for ${this.platform}`);\n\n const versioning = config.versioning!;\n const currentVersion = config.currentVersion!;\n const newVersion = config.newVersion!;\n const sourceUrl = config.sourceUrl!;\n const packageName = config.packageName!;\n const depName = config.depName!;\n const sourceDirectory = config.sourceDirectory;\n const versioningApi = allVersioning.get(versioning);\n\n if (this.shouldSkipPackage(config)) {\n return null;\n }\n\n const baseUrl = this.getBaseUrl(config);\n const apiBaseUrl = this.getAPIBaseUrl(config);\n const repository = this.getRepositoryFromUrl(config);\n\n const tokenResponse = this.hasValidToken(config);\n if (!tokenResponse.isValid) {\n if (tokenResponse.error) {\n return {\n error: tokenResponse.error,\n };\n }\n return null;\n }\n\n if (isFalsy(this.hasValidRepository(repository))) {\n logger.debug(`Invalid ${this.platform} URL found: ${sourceUrl}`);\n return null;\n }\n\n const releases = config.releases ?? (await getInRangeReleases(config));\n // v8 ignore next -- `getInRangeReleases` only returns null on paths it already ignores\n if (!releases?.length) {\n logger.debug('No releases');\n return null;\n }\n // This extra filter/sort should not be necessary, but better safe than sorry\n const validReleases = [...releases]\n .filter((release) => versioningApi.isVersion(release.version))\n .sort((a, b) => versioningApi.sortVersions(a.version, b.version))\n // Drop versions equal under this versioning, e.g. the Docker tags\n // `3.7.12` and `v3.7.12`, else their notes are rendered twice\n .filter(\n (release, index, sorted) =>\n index === sorted.length - 1 ||\n !versioningApi.equals(release.version, sorted[index + 1].version),\n );\n\n if (validReleases.length < 2) {\n logger.debug(\n `Not enough valid releases for dep ${depName} (${packageName})`,\n );\n return null;\n }\n\n const changelogReleases: ChangeLogRelease[] = [];\n\n // Check if `v` belongs to the range (currentVersion, newVersion]\n function inRange(v: string): boolean {\n return (\n versioningApi.isGreaterThan(v, currentVersion) &&\n !versioningApi.isGreaterThan(v, newVersion)\n );\n }\n\n const getTags = memoize(() => this.getAllTags(apiBaseUrl, repository));\n // Fetch releases newest-first, matching the order they're shown in the PR body.\n for (let i = validReleases.length - 1; i >= 1; i -= 1) {\n const prev = validReleases[i - 1];\n const next = validReleases[i];\n if (!inRange(next.version)) {\n continue;\n }\n let release = await packageCache.get(\n this.cacheNamespace,\n this.getCacheKey(\n sourceUrl,\n packageName,\n prev.version,\n next.version,\n ),\n );\n if (!release) {\n release = {\n version: next.version,\n date: next.releaseTimestamp,\n gitRef: next.gitRef,\n // put empty changes so that existing templates won't break\n changes: [],\n compare: {},\n };\n const tags = await getTags();\n const prevHead = this.getRef(\n versioningApi,\n packageName,\n depName,\n prev,\n tags,\n );\n const nextHead = this.getRef(\n versioningApi,\n packageName,\n depName,\n next,\n tags,\n );\n if (isNonEmptyString(prevHead) && isNonEmptyString(nextHead)) {\n release.compare.url = this.getCompareURL(\n baseUrl,\n repository,\n prevHead,\n nextHead,\n );\n }\n const cacheMinutes = 55;\n await packageCache.set(\n this.cacheNamespace,\n this.getCacheKey(\n sourceUrl,\n packageName,\n prev.version,\n next.version,\n ),\n release,\n cacheMinutes,\n );\n }\n changelogReleases.push(release);\n }\n\n let res: ChangeLogResult | null = {\n project: {\n apiBaseUrl,\n baseUrl,\n type: this.platform,\n repository,\n sourceUrl,\n sourceDirectory,\n packageName,\n depName,\n },\n versions: changelogReleases,\n };\n\n res = await addReleaseNotes(res, config, this);\n\n return res;\n },\n );\n }\n\n private findTagOfRelease(\n versioningApi: allVersioning.VersioningApi,\n packageName: string,\n depName: string,\n depNewVersion: string,\n tags: string[],\n ): string | undefined {\n const releaseRegexPrefix = `^(?:${packageName}|${depName}|release)[@_-]v?`;\n const regex = regEx(releaseRegexPrefix, undefined, false);\n const exactReleaseRegex = regEx(`${releaseRegexPrefix}${depNewVersion}`);\n const exactTagsList = tags.filter((tag) => {\n return exactReleaseRegex.test(tag);\n });\n const tagList = exactTagsList.length ? exactTagsList : tags;\n const candidates = tagList\n .filter((tag) => versioningApi.isVersion(tag.replace(regex, '')))\n .filter((tag) =>\n versioningApi.equals(tag.replace(regex, ''), depNewVersion),\n );\n if (!candidates.length) {\n return undefined;\n }\n // Some versioning schemes (e.g. `github-actions`) treat a floating tag\n // like `v7` as equal to a precise one like `v7.0.0` via coercion, so more\n // than one tag can match the same release. Prefer the most precise tag\n // (most dot-separated segments), else keep the first match found.\n return candidates.reduce((mostPrecise, candidate) =>\n tagPrecision(candidate) > tagPrecision(mostPrecise)\n ? candidate\n : mostPrecise,\n );\n }\n\n private getRef(\n versioningApi: allVersioning.VersioningApi,\n packageName: string,\n depName: string,\n release: Release,\n tags: string[],\n ): string | null {\n const tagName = this.findTagOfRelease(\n versioningApi,\n packageName,\n depName,\n release.version,\n tags,\n );\n if (isNonEmptyString(tagName)) {\n return tagName;\n }\n if (isNonEmptyString(release.gitRef)) {\n return release.gitRef;\n }\n return null;\n }\n\n private getCacheKey(\n sourceUrl: string,\n packageName: string,\n prev: string,\n next: string,\n ): string {\n return buildCacheKey(slugifyUrl(sourceUrl), packageName, prev, next);\n }\n\n getBaseUrl(config: BranchUpgradeConfig): string {\n const parsedUrl = parseUrl(config.sourceUrl);\n if (isNullOrUndefined(parsedUrl)) {\n return '';\n }\n const protocol = parsedUrl.protocol.replace(regEx(/^git\\+/), '');\n const host = parsedUrl.host;\n return `${protocol}//${host}/`;\n }\n\n getRepositoryFromUrl(config: BranchUpgradeConfig): string {\n const parsedUrl = parseUrl(config.sourceUrl);\n if (isNullOrUndefined(parsedUrl)) {\n return '';\n }\n const pathname = parsedUrl.pathname;\n return trimSlashes(pathname).replace(regEx(/\\.git$/), '');\n }\n\n protected hasValidToken(_config: BranchUpgradeConfig): {\n isValid: boolean;\n error?: ChangeLogError;\n } {\n return { isValid: true };\n }\n\n protected shouldSkipPackage(_config: BranchUpgradeConfig): boolean {\n return false;\n }\n\n hasValidRepository(repository: string): boolean {\n return repository.split('/').length === 2;\n }\n\n /**\n * Build the URL to the changelog markdown file for the release notes.\n * Platform sources can override this to match their web UI conventions.\n */\n getNotesSourceUrl(\n baseUrl: string,\n repository: string,\n changelogFile: string,\n ): string {\n return joinUrlParts(baseUrl, repository, 'blob', 'HEAD', changelogFile);\n }\n\n /**\n * Build the URL pointing to a specific heading within the changelog markdown\n * file. Platform sources can override this to match their anchor conventions.\n */\n getReleaseNotesMdAnchorUrl(notesSourceUrl: string, heading: string): string {\n const mdHeadingLink = heading\n .replace(regEx(/[[\\]()]/g), ' ')\n .replace(regEx(/^\\s*#*\\s*/), '')\n .split(' ')\n .filter(isTruthy)\n .filter((word) => !isHttpUrl(word))\n .join('-')\n .replace(regEx(/[^A-Za-z0-9-]/g), '');\n return `${notesSourceUrl}#${mdHeadingLink}`;\n }\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "renovate",
|
|
3
3
|
"description": "Automated dependency updates. Flexible so you don't need to be.",
|
|
4
|
-
"version": "44.149.
|
|
4
|
+
"version": "44.149.2",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"renovate": "dist/renovate.js",
|
|
@@ -118,7 +118,7 @@
|
|
|
118
118
|
"@pnpm/parse-overrides": "1001.0.4",
|
|
119
119
|
"@qnighy/marshal": "0.1.3",
|
|
120
120
|
"@redis/client": "6.3.0",
|
|
121
|
-
"@renovatebot/base-image": "13.118.
|
|
121
|
+
"@renovatebot/base-image": "13.118.1",
|
|
122
122
|
"@renovatebot/detect-tools": "4.0.21",
|
|
123
123
|
"@renovatebot/good-enough-parser": "2.0.1",
|
|
124
124
|
"@renovatebot/osv-offline": "3.0.12",
|
package/renovate-schema.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$id": "https://docs.renovatebot.com/renovate-schema.json",
|
|
3
|
-
"title": "JSON schema for Renovate 44.149.
|
|
3
|
+
"title": "JSON schema for Renovate 44.149.2 config files (https://renovatebot.com/)",
|
|
4
4
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
5
|
-
"x-renovate-version": "44.149.
|
|
5
|
+
"x-renovate-version": "44.149.2",
|
|
6
6
|
"allowComments": true,
|
|
7
7
|
"type": "object",
|
|
8
8
|
"definitions": {
|