renovate 44.149.1 → 44.149.3

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.
Files changed (163) hide show
  1. package/dist/config/options/index.js +1 -1
  2. package/dist/config/options/index.js.map +1 -1
  3. package/dist/config/presets/index.js +2 -1
  4. package/dist/config/presets/index.js.map +1 -1
  5. package/dist/global-config-option-defaults.generated.js +1 -1
  6. package/dist/global-config-option-defaults.generated.js.map +1 -1
  7. package/dist/modules/datasource/artifactory/index.js +2 -1
  8. package/dist/modules/datasource/artifactory/index.js.map +1 -1
  9. package/dist/modules/datasource/aws-eks-addon/index.js +6 -5
  10. package/dist/modules/datasource/aws-eks-addon/index.js.map +1 -1
  11. package/dist/modules/datasource/aws-machine-image/index.js +4 -3
  12. package/dist/modules/datasource/aws-machine-image/index.js.map +1 -1
  13. package/dist/modules/datasource/aws-rds/index.js +2 -1
  14. package/dist/modules/datasource/aws-rds/index.js.map +1 -1
  15. package/dist/modules/datasource/azure-bicep-resource/index.js +2 -1
  16. package/dist/modules/datasource/azure-bicep-resource/index.js.map +1 -1
  17. package/dist/modules/datasource/bazel/index.js +2 -1
  18. package/dist/modules/datasource/bazel/index.js.map +1 -1
  19. package/dist/modules/datasource/bitrise/index.js +2 -1
  20. package/dist/modules/datasource/bitrise/index.js.map +1 -1
  21. package/dist/modules/datasource/buildpacks-registry/index.js +2 -1
  22. package/dist/modules/datasource/buildpacks-registry/index.js.map +1 -1
  23. package/dist/modules/datasource/cdnjs/index.js +3 -2
  24. package/dist/modules/datasource/cdnjs/index.js.map +1 -1
  25. package/dist/modules/datasource/conan/index.js +3 -2
  26. package/dist/modules/datasource/conan/index.js.map +1 -1
  27. package/dist/modules/datasource/conda/index.js +2 -1
  28. package/dist/modules/datasource/conda/index.js.map +1 -1
  29. package/dist/modules/datasource/cpan/index.js +1 -1
  30. package/dist/modules/datasource/cpan/index.js.map +1 -1
  31. package/dist/modules/datasource/crate/index.js +17 -9
  32. package/dist/modules/datasource/crate/index.js.map +1 -1
  33. package/dist/modules/datasource/deb/index.js +3 -2
  34. package/dist/modules/datasource/deb/index.js.map +1 -1
  35. package/dist/modules/datasource/deno/index.js +4 -3
  36. package/dist/modules/datasource/deno/index.js.map +1 -1
  37. package/dist/modules/datasource/docker/index.js +9 -9
  38. package/dist/modules/datasource/docker/index.js.map +1 -1
  39. package/dist/modules/datasource/dotnet-version/index.js +2 -1
  40. package/dist/modules/datasource/dotnet-version/index.js.map +1 -1
  41. package/dist/modules/datasource/elm-package/index.js +2 -1
  42. package/dist/modules/datasource/elm-package/index.js.map +1 -1
  43. package/dist/modules/datasource/endoflife-date/index.js +2 -1
  44. package/dist/modules/datasource/endoflife-date/index.js.map +1 -1
  45. package/dist/modules/datasource/galaxy-collection/index.js +3 -2
  46. package/dist/modules/datasource/galaxy-collection/index.js.map +1 -1
  47. package/dist/modules/datasource/git-host-tags.js +6 -5
  48. package/dist/modules/datasource/git-host-tags.js.map +1 -1
  49. package/dist/modules/datasource/gitea-tags/base.js +5 -4
  50. package/dist/modules/datasource/gitea-tags/base.js.map +1 -1
  51. package/dist/modules/datasource/gitea-tags/util.js +2 -5
  52. package/dist/modules/datasource/gitea-tags/util.js.map +1 -1
  53. package/dist/modules/datasource/github-digest/index.js +3 -5
  54. package/dist/modules/datasource/github-digest/index.js.map +1 -1
  55. package/dist/modules/datasource/github-release-attachments/index.js +3 -2
  56. package/dist/modules/datasource/github-release-attachments/index.js.map +1 -1
  57. package/dist/modules/datasource/gitlab-packages/index.js +2 -1
  58. package/dist/modules/datasource/gitlab-packages/index.js.map +1 -1
  59. package/dist/modules/datasource/gitlab-releases/index.js +2 -1
  60. package/dist/modules/datasource/gitlab-releases/index.js.map +1 -1
  61. package/dist/modules/datasource/gitlab-tags/index.js +3 -2
  62. package/dist/modules/datasource/gitlab-tags/index.js.map +1 -1
  63. package/dist/modules/datasource/glasskube-packages/index.js +2 -1
  64. package/dist/modules/datasource/glasskube-packages/index.js.map +1 -1
  65. package/dist/modules/datasource/go/goproxy-parser.js +3 -2
  66. package/dist/modules/datasource/go/goproxy-parser.js.map +1 -1
  67. package/dist/modules/datasource/go/index.js +4 -3
  68. package/dist/modules/datasource/go/index.js.map +1 -1
  69. package/dist/modules/datasource/go/releases-goproxy.js +6 -3
  70. package/dist/modules/datasource/go/releases-goproxy.js.map +1 -1
  71. package/dist/modules/datasource/go/timestamp-cache.js +3 -1
  72. package/dist/modules/datasource/go/timestamp-cache.js.map +1 -1
  73. package/dist/modules/datasource/golang-version/index.js +1 -1
  74. package/dist/modules/datasource/golang-version/index.js.map +1 -1
  75. package/dist/modules/datasource/gradle-version/index.js +1 -1
  76. package/dist/modules/datasource/gradle-version/index.js.map +1 -1
  77. package/dist/modules/datasource/helm/index.js +2 -1
  78. package/dist/modules/datasource/helm/index.js.map +1 -1
  79. package/dist/modules/datasource/hermit/index.js +3 -2
  80. package/dist/modules/datasource/hermit/index.js.map +1 -1
  81. package/dist/modules/datasource/hex/index.js +3 -2
  82. package/dist/modules/datasource/hex/index.js.map +1 -1
  83. package/dist/modules/datasource/hexpm-bob/index.js +2 -1
  84. package/dist/modules/datasource/hexpm-bob/index.js.map +1 -1
  85. package/dist/modules/datasource/index.js +4 -3
  86. package/dist/modules/datasource/index.js.map +1 -1
  87. package/dist/modules/datasource/java-version/index.js +2 -1
  88. package/dist/modules/datasource/java-version/index.js.map +1 -1
  89. package/dist/modules/datasource/jsr/index.js +2 -1
  90. package/dist/modules/datasource/jsr/index.js.map +1 -1
  91. package/dist/modules/datasource/maven/index.js +2 -1
  92. package/dist/modules/datasource/maven/index.js.map +1 -1
  93. package/dist/modules/datasource/nextcloud/index.js +2 -1
  94. package/dist/modules/datasource/nextcloud/index.js.map +1 -1
  95. package/dist/modules/datasource/node-version/index.js +1 -1
  96. package/dist/modules/datasource/node-version/index.js.map +1 -1
  97. package/dist/modules/datasource/nuget/v3.js +3 -2
  98. package/dist/modules/datasource/nuget/v3.js.map +1 -1
  99. package/dist/modules/datasource/orb/index.js +2 -1
  100. package/dist/modules/datasource/orb/index.js.map +1 -1
  101. package/dist/modules/datasource/packagist/index.js +4 -3
  102. package/dist/modules/datasource/packagist/index.js.map +1 -1
  103. package/dist/modules/datasource/pod/index.js +2 -1
  104. package/dist/modules/datasource/pod/index.js.map +1 -1
  105. package/dist/modules/datasource/python-version/index.js +1 -1
  106. package/dist/modules/datasource/python-version/index.js.map +1 -1
  107. package/dist/modules/datasource/repology/index.js +2 -1
  108. package/dist/modules/datasource/repology/index.js.map +1 -1
  109. package/dist/modules/datasource/rpm/index.js +2 -1
  110. package/dist/modules/datasource/rpm/index.js.map +1 -1
  111. package/dist/modules/datasource/rubygems/index.js +2 -1
  112. package/dist/modules/datasource/rubygems/index.js.map +1 -1
  113. package/dist/modules/datasource/rubygems/metadata-cache.js +2 -1
  114. package/dist/modules/datasource/rubygems/metadata-cache.js.map +1 -1
  115. package/dist/modules/datasource/sbt-package/index.js +11 -10
  116. package/dist/modules/datasource/sbt-package/index.js.map +1 -1
  117. package/dist/modules/datasource/terraform-module/index.js +2 -1
  118. package/dist/modules/datasource/terraform-module/index.js.map +1 -1
  119. package/dist/modules/datasource/terraform-provider/index.js +6 -5
  120. package/dist/modules/datasource/terraform-provider/index.js.map +1 -1
  121. package/dist/modules/datasource/unity3d/index.js +2 -1
  122. package/dist/modules/datasource/unity3d/index.js.map +1 -1
  123. package/dist/modules/datasource/unity3d-packages/index.js +2 -1
  124. package/dist/modules/datasource/unity3d-packages/index.js.map +1 -1
  125. package/dist/modules/manager/bazel/parser.js +3 -1
  126. package/dist/modules/manager/bazel/parser.js.map +1 -1
  127. package/dist/modules/manager/github-actions/extract.js +2 -1
  128. package/dist/modules/manager/github-actions/extract.js.map +1 -1
  129. package/dist/modules/manager/terraform/lockfile/hash.js +2 -1
  130. package/dist/modules/manager/terraform/lockfile/hash.js.map +1 -1
  131. package/dist/modules/platform/bitbucket/pr-cache.js +3 -2
  132. package/dist/modules/platform/bitbucket/pr-cache.js.map +1 -1
  133. package/dist/modules/platform/bitbucket-server/pr-cache.js +3 -2
  134. package/dist/modules/platform/bitbucket-server/pr-cache.js.map +1 -1
  135. package/dist/modules/platform/gitea/pr-cache.js +7 -6
  136. package/dist/modules/platform/gitea/pr-cache.js.map +1 -1
  137. package/dist/modules/platform/gitlab/pr-cache.js +3 -2
  138. package/dist/modules/platform/gitlab/pr-cache.js.map +1 -1
  139. package/dist/util/cache/package/index.js +1 -1
  140. package/dist/util/cache/package/key.js +8 -1
  141. package/dist/util/cache/package/key.js.map +1 -1
  142. package/dist/util/cache/package/with-cache.js +2 -1
  143. package/dist/util/cache/package/with-cache.js.map +1 -1
  144. package/dist/util/exec/containerbase.js +2 -1
  145. package/dist/util/exec/containerbase.js.map +1 -1
  146. package/dist/util/github/graphql/cache-strategies/memory-cache-strategy.js +2 -1
  147. package/dist/util/github/graphql/cache-strategies/memory-cache-strategy.js.map +1 -1
  148. package/dist/util/github/graphql/datasource-fetcher.js +5 -8
  149. package/dist/util/github/graphql/datasource-fetcher.js.map +1 -1
  150. package/dist/util/http/cache/memory-http-cache-provider.js +2 -1
  151. package/dist/util/http/cache/memory-http-cache-provider.js.map +1 -1
  152. package/dist/util/http/cache/package-http-cache-provider.js +2 -1
  153. package/dist/util/http/cache/package-http-cache-provider.js.map +1 -1
  154. package/dist/util/jsonata.js +2 -1
  155. package/dist/util/jsonata.js.map +1 -1
  156. package/dist/util/merge-confidence/index.js +10 -7
  157. package/dist/util/merge-confidence/index.js.map +1 -1
  158. package/dist/workers/repository/update/pr/changelog/release-notes.js +4 -5
  159. package/dist/workers/repository/update/pr/changelog/release-notes.js.map +1 -1
  160. package/dist/workers/repository/update/pr/changelog/source.js +2 -1
  161. package/dist/workers/repository/update/pr/changelog/source.js.map +1 -1
  162. package/package.json +2 -2
  163. package/renovate-schema.json +2 -2
@@ -5,6 +5,7 @@ import { GlobalConfig } from "../../../config/global.js";
5
5
  import { isDockerDigest } from "../../../util/string-match.js";
6
6
  import { logger } from "../../../logger/index.js";
7
7
  import { ensurePathPrefix, joinUrlParts, parseLinkHeader, parseUrl } from "../../../util/url.js";
8
+ import { buildCacheKey } from "../../../util/cache/package/key.js";
8
9
  import { ExternalHostError } from "../../../types/errors/external-host-error.js";
9
10
  import { id } from "../../versioning/docker/index.js";
10
11
  import { withCache } from "../../../util/cache/package/with-cache.js";
@@ -128,7 +129,7 @@ var DockerDatasource = class DockerDatasource extends Datasource {
128
129
  getImageConfig(registryHost, dockerRepository, configDigest) {
129
130
  return withCache({
130
131
  namespace: "datasource-docker-imageconfig",
131
- key: `${registryHost}:${dockerRepository}@${configDigest}`,
132
+ key: buildCacheKey(registryHost, dockerRepository, configDigest),
132
133
  ttlMinutes: 40320
133
134
  }, () => this._getImageConfig(registryHost, dockerRepository, configDigest));
134
135
  }
@@ -149,7 +150,7 @@ var DockerDatasource = class DockerDatasource extends Datasource {
149
150
  getHelmConfig(registryHost, dockerRepository, configDigest) {
150
151
  return withCache({
151
152
  namespace: "datasource-docker-imageconfig",
152
- key: `${registryHost}:${dockerRepository}@${configDigest}`,
153
+ key: buildCacheKey(registryHost, dockerRepository, configDigest),
153
154
  ttlMinutes: 40320
154
155
  }, () => this._getHelmConfig(registryHost, dockerRepository, configDigest));
155
156
  }
@@ -234,7 +235,7 @@ var DockerDatasource = class DockerDatasource extends Datasource {
234
235
  getImageArchitecture(registryHost, dockerRepository, currentDigest) {
235
236
  return withCache({
236
237
  namespace: "datasource-docker-architecture",
237
- key: `${registryHost}:${dockerRepository}@${currentDigest}`,
238
+ key: buildCacheKey(registryHost, dockerRepository, currentDigest),
238
239
  ttlMinutes: 40320,
239
240
  shouldCacheResult: isNonEmptyString
240
241
  }, () => this._getImageArchitecture(registryHost, dockerRepository, currentDigest));
@@ -343,7 +344,7 @@ var DockerDatasource = class DockerDatasource extends Datasource {
343
344
  getLabels(registryHost, dockerRepository, tag) {
344
345
  return withCache({
345
346
  namespace: "datasource-docker-labels",
346
- key: `${registryHost}:${dockerRepository}:${tag}`,
347
+ key: buildCacheKey(registryHost, dockerRepository, tag),
347
348
  ttlMinutes: 1440
348
349
  }, () => this._getLabels(registryHost, dockerRepository, tag));
349
350
  }
@@ -491,7 +492,7 @@ var DockerDatasource = class DockerDatasource extends Datasource {
491
492
  getTags(registryHost, dockerRepository) {
492
493
  return withCache({
493
494
  namespace: "datasource-docker-tags",
494
- key: `${registryHost}:${dockerRepository}`,
495
+ key: buildCacheKey(registryHost, dockerRepository),
495
496
  cacheable: registryHost === DOCKER_HUB
496
497
  }, () => this._getTags(registryHost, dockerRepository));
497
498
  }
@@ -587,10 +588,9 @@ var DockerDatasource = class DockerDatasource extends Datasource {
587
588
  getDigest(config, newValue) {
588
589
  const newTag = newValue ?? "latest";
589
590
  const { registryHost, dockerRepository } = getRegistryRepository(config.packageName, config.registryUrl);
590
- const digest = config.currentDigest ? `@${config.currentDigest}` : "";
591
591
  return withCache({
592
592
  namespace: "datasource-docker-digest",
593
- key: `${registryHost}:${dockerRepository}:${newTag}${digest}`,
593
+ key: buildCacheKey(registryHost, dockerRepository, newTag, config.currentDigest),
594
594
  fallback: true,
595
595
  shouldCacheResult: isNonEmptyString
596
596
  }, () => this._getDigest(config, newValue));
@@ -632,7 +632,7 @@ var DockerDatasource = class DockerDatasource extends Datasource {
632
632
  getDockerHubTags(dockerRepository) {
633
633
  return withCache({
634
634
  namespace: "datasource-docker-hub-tags",
635
- key: `${dockerRepository}`
635
+ key: dockerRepository
636
636
  }, () => this._getDockerHubTags(dockerRepository));
637
637
  }
638
638
  /**
@@ -677,7 +677,7 @@ var DockerDatasource = class DockerDatasource extends Datasource {
677
677
  const { registryHost, dockerRepository } = getRegistryRepository(config.packageName, config.registryUrl);
678
678
  return withCache({
679
679
  namespace: "datasource-docker-releases-v2",
680
- key: `${registryHost}:${dockerRepository}`,
680
+ key: buildCacheKey(registryHost, dockerRepository),
681
681
  cacheable: registryHost === DOCKER_HUB,
682
682
  fallback: true
683
683
  }, () => this._getReleases(config));
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["dockerVersioningId","HttpError"],"sources":["../../../../lib/modules/datasource/docker/index.ts"],"sourcesContent":["import { isNonEmptyString } from '@sindresorhus/is';\nimport { GlobalConfig } from '../../../config/global.ts';\nimport { PAGE_NOT_FOUND_ERROR } from '../../../constants/error-messages.ts';\nimport { logger } from '../../../logger/index.ts';\nimport { ExternalHostError } from '../../../types/errors/external-host-error.ts';\nimport { withCache } from '../../../util/cache/package/with-cache.ts';\nimport { getEnv } from '../../../util/env.ts';\nimport { memCacheProvider } from '../../../util/http/cache/memory-http-cache-provider.ts';\nimport { HttpError } from '../../../util/http/index.ts';\nimport type { HttpResponse } from '../../../util/http/types.ts';\nimport { hasKey } from '../../../util/object.ts';\nimport { type AsyncResult, Result } from '../../../util/result.ts';\nimport { isDockerDigest } from '../../../util/string-match.ts';\nimport { asTimestamp } from '../../../util/timestamp.ts';\nimport {\n ensurePathPrefix,\n joinUrlParts,\n parseLinkHeader,\n parseUrl,\n} from '../../../util/url.ts';\nimport { id as dockerVersioningId } from '../../versioning/docker/index.ts';\nimport { Datasource } from '../datasource.ts';\nimport type {\n DigestConfig,\n GetReleasesConfig,\n Release,\n ReleaseResult,\n} from '../types.ts';\nimport {\n isArtifactoryServer,\n isCrossOriginPaginationAllowed,\n resolvePaginationUrl,\n} from '../util.ts';\nimport {\n DOCKER_HUB,\n dockerDatasourceId,\n extractDigestFromResponseBody,\n findHelmSourceUrl,\n findLatestStable,\n getAuthHeaders,\n getRegistryRepository,\n gitRefLabel,\n imageUrlLabel,\n isDockerHost,\n sourceLabel,\n sourceLabels,\n} from './common.ts';\nimport { DockerHubCache } from './dockerhub-cache.ts';\nimport { ecrPublicRegex, ecrRegex, isECRMaxResultsError } from './ecr.ts';\nimport type {\n DistributionManifest,\n Manifest,\n OciImageManifest,\n} from './schema.ts';\nimport {\n DockerHubTagsPage,\n ManifestJson,\n OciHelmConfig,\n OciImageConfig,\n QuayTagsResponse,\n RegistryTagsList,\n} from './schema.ts';\n\nconst defaultConfig = {\n commitMessageTopic: '{{{depName}}} Docker tag',\n commitMessageExtra:\n 'to {{#if isPinDigest}}{{{newDigestShort}}}{{else}}{{#if isMajor}}{{{prettyNewMajor}}}{{else}}{{{prettyNewVersion}}}{{/if}}{{/if}}',\n digest: {\n branchTopic: '{{{depNameSanitized}}}-{{{currentValue}}}',\n commitMessageExtra: 'to {{newDigestShort}}',\n commitMessageTopic:\n '{{{depName}}}{{#if currentValue}}:{{{currentValue}}}{{/if}} Docker digest',\n group: {\n commitMessageTopic: '{{{groupName}}}',\n commitMessageExtra: '',\n },\n },\n pin: {\n commitMessageExtra: '',\n groupName: 'Docker digests',\n group: {\n commitMessageTopic: '{{{groupName}}}',\n branchTopic: 'digests-pin',\n },\n },\n};\n\nexport class DockerDatasource extends Datasource {\n static readonly id = dockerDatasourceId;\n\n override readonly defaultVersioning = dockerVersioningId;\n\n override getDefaultRegistryUrls(_packageName: string): string[] {\n return [DOCKER_HUB];\n }\n\n override readonly defaultConfig = defaultConfig;\n\n override readonly releaseTimestampSupport = true;\n override readonly releaseTimestampNote =\n 'Only supported on Docker Hub: The release timestamp is determined from the `tag_last_pushed` field in the results. **NOTE**: Currently, digests will receive the same release timestamp as the `tag_last_pushed`, which means that digests may appear newer than they are - see https://github.com/renovatebot/renovate/issues/38659';\n override readonly sourceUrlSupport = 'package';\n override readonly sourceUrlNote =\n 'The source URL is determined from the `org.opencontainers.image.source` and `org.label-schema.vcs-url` labels present in the metadata of the **latest stable** image found on the Docker registry.';\n\n constructor() {\n super(DockerDatasource.id);\n }\n\n // TODO: debug why quay throws errors (#9612)\n private async getManifestResponse(\n registryHost: string,\n dockerRepository: string,\n tag: string,\n mode: 'head' | 'getText' = 'getText',\n ): Promise<HttpResponse | null> {\n logger.debug(\n `getManifestResponse(${registryHost}, ${dockerRepository}, ${tag}, ${mode})`,\n );\n try {\n const headers = await getAuthHeaders(\n this.http,\n registryHost,\n dockerRepository,\n );\n if (!headers) {\n logger.warn('No docker auth found - returning');\n return null;\n }\n headers.accept = [\n 'application/vnd.docker.distribution.manifest.list.v2+json',\n 'application/vnd.docker.distribution.manifest.v2+json',\n 'application/vnd.oci.image.manifest.v1+json',\n 'application/vnd.oci.image.index.v1+json',\n ].join(', ');\n const url = `${registryHost}/v2/${dockerRepository}/manifests/${tag}`;\n const manifestResponse = await this.http[mode](url, {\n headers,\n noAuth: true,\n cacheProvider: memCacheProvider,\n });\n return manifestResponse;\n } catch (err) /* istanbul ignore next */ {\n if (err instanceof ExternalHostError) {\n throw err;\n }\n if (err.statusCode === 401) {\n logger.debug(\n { registryHost, dockerRepository },\n 'Unauthorized docker lookup',\n );\n logger.debug({ err });\n return null;\n }\n if (err.statusCode === 404) {\n logger.debug(\n {\n err,\n registryHost,\n dockerRepository,\n tag,\n },\n 'Docker Manifest is unknown',\n );\n return null;\n }\n if (err.statusCode === 429 && isDockerHost(registryHost)) {\n throw new ExternalHostError(err);\n }\n if (err.statusCode >= 500 && err.statusCode < 600) {\n throw new ExternalHostError(err);\n }\n if (err.code === 'ETIMEDOUT') {\n logger.debug(\n { registryHost },\n 'Timeout when attempting to connect to docker registry',\n );\n logger.debug({ err });\n return null;\n }\n logger.debug(\n {\n err,\n registryHost,\n dockerRepository,\n tag,\n },\n 'Unknown Error looking up docker manifest',\n );\n return null;\n }\n }\n\n private async _getImageConfig(\n registryHost: string,\n dockerRepository: string,\n configDigest: string,\n ): Promise<HttpResponse<OciImageConfig> | undefined> {\n logger.trace(\n `getImageConfig(${registryHost}, ${dockerRepository}, ${configDigest})`,\n );\n\n const headers = await getAuthHeaders(\n this.http,\n registryHost,\n dockerRepository,\n );\n /* v8 ignore next -- should never happen */\n if (!headers) {\n logger.warn('No docker auth found - returning');\n return undefined;\n }\n const url = joinUrlParts(\n registryHost,\n 'v2',\n dockerRepository,\n 'blobs',\n configDigest,\n );\n return await this.http.getJson(\n url,\n {\n headers,\n noAuth: true,\n },\n OciImageConfig,\n );\n }\n\n getImageConfig(\n registryHost: string,\n dockerRepository: string,\n configDigest: string,\n ): Promise<HttpResponse<OciImageConfig> | undefined> {\n return withCache(\n {\n namespace: 'datasource-docker-imageconfig',\n key: `${registryHost}:${dockerRepository}@${configDigest}`,\n ttlMinutes: 1440 * 28,\n },\n () => this._getImageConfig(registryHost, dockerRepository, configDigest),\n );\n }\n\n private async _getHelmConfig(\n registryHost: string,\n dockerRepository: string,\n configDigest: string,\n ): Promise<HttpResponse<OciHelmConfig> | undefined> {\n logger.trace(\n `getImageConfig(${registryHost}, ${dockerRepository}, ${configDigest})`,\n );\n\n const headers = await getAuthHeaders(\n this.http,\n registryHost,\n dockerRepository,\n );\n /* v8 ignore next -- should never happen */\n if (!headers) {\n logger.warn('No docker auth found - returning');\n return undefined;\n }\n const url = joinUrlParts(\n registryHost,\n 'v2',\n dockerRepository,\n 'blobs',\n configDigest,\n );\n return await this.http.getJson(\n url,\n {\n headers,\n noAuth: true,\n },\n OciHelmConfig,\n );\n }\n\n getHelmConfig(\n registryHost: string,\n dockerRepository: string,\n configDigest: string,\n ): Promise<HttpResponse<OciHelmConfig> | undefined> {\n return withCache(\n {\n namespace: 'datasource-docker-imageconfig',\n key: `${registryHost}:${dockerRepository}@${configDigest}`,\n ttlMinutes: 1440 * 28,\n },\n () => this._getHelmConfig(registryHost, dockerRepository, configDigest),\n );\n }\n\n private async getConfigDigest(\n registry: string,\n dockerRepository: string,\n tag: string,\n ): Promise<string | null> {\n return (\n (await this.getManifest(registry, dockerRepository, tag))?.config\n ?.digest ?? null\n );\n }\n\n private async getManifestDocument(\n registry: string,\n dockerRepository: string,\n tag: string,\n ): Promise<Manifest | null> {\n const manifestResponse = await this.getManifestResponse(\n registry,\n dockerRepository,\n tag,\n );\n\n // If getting the manifest fails here, then abort\n // This means that the latest tag doesn't have a manifest, which shouldn't\n // be possible\n /* v8 ignore next -- should never happen */\n if (!manifestResponse) {\n return null;\n }\n\n // Softfail on invalid manifests\n const parsed = ManifestJson.safeParse(manifestResponse.body);\n if (!parsed.success) {\n logger.debug(\n {\n registry,\n dockerRepository,\n tag,\n body: manifestResponse.body,\n headers: manifestResponse.headers,\n err: parsed.error,\n },\n 'Invalid manifest response',\n );\n return null;\n }\n\n return parsed.data;\n }\n\n private async resolveImageManifest(\n registry: string,\n dockerRepository: string,\n tag: string,\n manifest: Manifest,\n ): Promise<OciImageManifest | DistributionManifest | null> {\n switch (manifest.mediaType) {\n case 'application/vnd.docker.distribution.manifest.v2+json':\n case 'application/vnd.oci.image.manifest.v1+json':\n return manifest;\n case 'application/vnd.docker.distribution.manifest.list.v2+json':\n case 'application/vnd.oci.image.index.v1+json':\n if (!manifest.manifests.length) {\n logger.debug(\n { manifest },\n 'Invalid manifest list with no manifests - returning',\n );\n return null;\n }\n logger.trace(\n { registry, dockerRepository, tag },\n 'Found manifest list, using first image',\n );\n return this.getManifest(\n registry,\n dockerRepository,\n manifest.manifests[0].digest,\n );\n // istanbul ignore next: can't happen\n default:\n return null;\n }\n }\n\n private async getManifest(\n registry: string,\n dockerRepository: string,\n tag: string,\n ): Promise<OciImageManifest | DistributionManifest | null> {\n const manifest = await this.getManifestDocument(\n registry,\n dockerRepository,\n tag,\n );\n if (!manifest) {\n return null;\n }\n return this.resolveImageManifest(registry, dockerRepository, tag, manifest);\n }\n\n private async _getImageArchitecture(\n registryHost: string,\n dockerRepository: string,\n currentDigest: string,\n ): Promise<string | null | undefined> {\n try {\n let manifestResponse: HttpResponse | null;\n\n try {\n manifestResponse = await this.getManifestResponse(\n registryHost,\n dockerRepository,\n currentDigest,\n 'head',\n );\n } catch (_err) {\n const err =\n _err instanceof ExternalHostError\n ? _err.err\n : /* istanbul ignore next: can never happen */ _err;\n\n // v8 ignore else -- needs a non-5xx failure from the manifest request\n if (\n typeof err.statusCode === 'number' &&\n err.statusCode >= 500 &&\n err.statusCode < 600\n ) {\n // querying the digest manifest for a non existent image leads to a 500 statusCode\n return null;\n }\n\n /* istanbul ignore next */\n throw _err;\n }\n\n if (\n manifestResponse?.headers['content-type'] !==\n 'application/vnd.docker.distribution.manifest.v2+json' &&\n manifestResponse?.headers['content-type'] !==\n 'application/vnd.oci.image.manifest.v1+json'\n ) {\n return null;\n }\n\n const configDigest = await this.getConfigDigest(\n registryHost,\n dockerRepository,\n currentDigest,\n );\n if (!configDigest) {\n return null;\n }\n\n const configResponse = await this.getImageConfig(\n registryHost,\n dockerRepository,\n configDigest,\n );\n\n // TODO: fix me, architecture is required in spec\n // v8 ignore else -- needs a config blob with neither key\n if (\n configResponse &&\n ('config' in configResponse.body ||\n 'architecture' in configResponse.body)\n ) {\n const architecture = configResponse.body.architecture ?? null;\n logger.debug(\n `Current digest ${currentDigest} relates to architecture ${\n architecture ?? 'null'\n }`,\n );\n\n return architecture;\n }\n } catch (err) /* istanbul ignore next */ {\n if (err.statusCode !== 404 || err.message === PAGE_NOT_FOUND_ERROR) {\n throw err;\n }\n logger.debug(\n { registryHost, dockerRepository, currentDigest, err },\n 'Unknown error getting image architecture',\n );\n }\n\n return undefined;\n }\n\n getImageArchitecture(\n registryHost: string,\n dockerRepository: string,\n currentDigest: string,\n ): Promise<string | null | undefined> {\n return withCache(\n {\n namespace: 'datasource-docker-architecture',\n key: `${registryHost}:${dockerRepository}@${currentDigest}`,\n ttlMinutes: 1440 * 28,\n shouldCacheResult: isNonEmptyString,\n },\n () =>\n this._getImageArchitecture(\n registryHost,\n dockerRepository,\n currentDigest,\n ),\n );\n }\n\n /*\n * docker.getLabels\n *\n * This function will:\n * - Return the labels for the requested image\n */\n private async _getLabels(\n registryHost: string,\n dockerRepository: string,\n tag: string,\n ): Promise<Record<string, string> | undefined> {\n logger.debug(`getLabels(${registryHost}, ${dockerRepository}, ${tag})`);\n // Skip Docker Hub image if RENOVATE_X_DOCKER_HUB_DISABLE_LABEL_LOOKUP is set\n if (\n getEnv().RENOVATE_X_DOCKER_HUB_DISABLE_LABEL_LOOKUP &&\n registryHost === DOCKER_HUB\n ) {\n logger.debug(\n 'Docker Hub image - skipping label lookup due to RENOVATE_X_DOCKER_HUB_DISABLE_LABEL_LOOKUP',\n );\n return {};\n }\n try {\n let labels: Record<string, string> | undefined = {};\n const manifestDocument = await this.getManifestDocument(\n registryHost,\n dockerRepository,\n tag,\n );\n\n if (!manifestDocument) {\n logger.debug(\n { registryHost, dockerRepository, tag },\n 'No manifest found',\n );\n return undefined;\n }\n\n if ('annotations' in manifestDocument && manifestDocument.annotations) {\n labels = manifestDocument.annotations;\n }\n\n if ('manifests' in manifestDocument) {\n const descriptorAnnotations = manifestDocument.manifests\n .map((descriptor) => descriptor.annotations)\n .find(\n (annotations) =>\n isNonEmptyString(annotations?.[sourceLabel]) &&\n isNonEmptyString(annotations?.[gitRefLabel]),\n );\n if (descriptorAnnotations) {\n labels = { ...labels, ...descriptorAnnotations };\n }\n }\n\n if (\n 'manifests' in manifestDocument &&\n labels[sourceLabel] &&\n labels[gitRefLabel]\n ) {\n return labels;\n }\n\n const manifest = await this.resolveImageManifest(\n registryHost,\n dockerRepository,\n tag,\n manifestDocument,\n );\n if (!manifest) {\n return undefined;\n }\n\n if ('annotations' in manifest && manifest.annotations) {\n labels = { ...labels, ...manifest.annotations };\n }\n\n switch (manifest.config.mediaType) {\n case 'application/vnd.cncf.helm.config.v1+json': {\n if (labels[sourceLabel]) {\n // we already have the source url, so no need to pull the config\n return labels;\n }\n const configResponse = await this.getHelmConfig(\n registryHost,\n dockerRepository,\n manifest.config.digest,\n );\n\n // v8 ignore else -- needs the helm config blob request to come back empty\n if (configResponse) {\n // Helm chart\n const url = findHelmSourceUrl(configResponse.body);\n // v8 ignore else -- needs a helm chart with no source url\n if (url) {\n labels[sourceLabel] = url;\n }\n }\n break;\n }\n case 'application/vnd.oci.image.config.v1+json':\n case 'application/vnd.docker.container.image.v1+json': {\n if (labels[sourceLabel] && labels[gitRefLabel]) {\n // we already have the source url, so no need to pull the config\n return labels;\n }\n const configResponse = await this.getImageConfig(\n registryHost,\n dockerRepository,\n manifest.config.digest,\n );\n\n /* v8 ignore next -- should never happen */\n if (!configResponse) {\n return labels;\n }\n\n const body = configResponse.body;\n if (body.config) {\n labels = { ...labels, ...body.config.Labels };\n } else {\n logger.debug(\n { headers: configResponse.headers, body },\n `manifest blob response body missing the \"config\" property`,\n );\n }\n break;\n }\n }\n\n // v8 ignore else -- labels are always set by the branches above\n if (labels) {\n logger.debug(\n {\n labels,\n },\n 'found labels in manifest',\n );\n }\n return labels;\n } catch (err) /* istanbul ignore next: should be tested in future */ {\n if (err instanceof ExternalHostError) {\n throw err;\n }\n if (err.statusCode === 400 || err.statusCode === 401) {\n logger.debug(\n { registryHost, dockerRepository, err },\n 'Unauthorized docker lookup',\n );\n } else if (err.statusCode === 404) {\n logger.warn(\n {\n err,\n registryHost,\n dockerRepository,\n tag,\n },\n 'Config Manifest is unknown',\n );\n } else if (err.statusCode === 429 && isDockerHost(registryHost)) {\n logger.warn({ err }, 'docker registry failure: too many requests');\n } else if (err.statusCode >= 500 && err.statusCode < 600) {\n logger.debug(\n {\n err,\n registryHost,\n dockerRepository,\n tag,\n },\n 'docker registry failure: internal error',\n );\n } else if (\n err.code === 'ERR_TLS_CERT_ALTNAME_INVALID' ||\n err.code === 'ETIMEDOUT'\n ) {\n logger.debug(\n { registryHost, err },\n 'Error connecting to docker registry',\n );\n } else if (registryHost === 'https://quay.io') {\n // istanbul ignore next\n logger.debug(\n 'Ignoring quay.io errors until they fully support v2 schema',\n );\n } else {\n logger.info(\n { registryHost, dockerRepository, tag, err },\n 'Unknown error getting Docker labels',\n );\n }\n return {};\n }\n }\n\n getLabels(\n registryHost: string,\n dockerRepository: string,\n tag: string,\n ): Promise<Record<string, string> | undefined> {\n return withCache(\n {\n namespace: 'datasource-docker-labels',\n key: `${registryHost}:${dockerRepository}:${tag}`,\n ttlMinutes: 24 * 60,\n },\n () => this._getLabels(registryHost, dockerRepository, tag),\n );\n }\n\n private async getTagsQuayRegistry(\n registry: string,\n repository: string,\n ): Promise<string[]> {\n let tags: string[] = [];\n const limit = 100;\n\n function pageUrl(page: number): string {\n return `${registry}/api/v1/repository/${repository}/tag/?limit=${limit}&page=${page}&onlyActiveTags=true`;\n }\n\n let page = 1;\n let url: string | null = pageUrl(page);\n while (url && page <= 20) {\n const res: HttpResponse<QuayTagsResponse> = await this.http.getJson(\n url,\n QuayTagsResponse,\n );\n const pageTags = res.body.tags.map((tag) => tag.name);\n tags = tags.concat(pageTags);\n page += 1;\n url = res.body.has_additional ? pageUrl(page) : null;\n }\n return tags;\n }\n\n private async getDockerApiTags(\n registryHost: string,\n dockerRepository: string,\n ): Promise<string[] | undefined> {\n let tags: string[] = [];\n // AWS ECR limits the maximum number of results to 1000\n // See https://docs.aws.amazon.com/AmazonECR/latest/APIReference/API_DescribeRepositories.html#ECR-DescribeRepositories-request-maxResults\n // See https://docs.aws.amazon.com/AmazonECRPublic/latest/APIReference/API_DescribeRepositories.html#ecrpublic-DescribeRepositories-request-maxResults\n const limit =\n ecrRegex.test(registryHost) || ecrPublicRegex.test(registryHost)\n ? 1000\n : 10000;\n let url: string | null =\n `${registryHost}/${dockerRepository}/tags/list?n=${limit}`;\n url = ensurePathPrefix(url, '/v2');\n const headers = await getAuthHeaders(\n this.http,\n registryHost,\n dockerRepository,\n url,\n );\n if (!headers) {\n logger.debug('Failed to get authHeaders for getTags lookup');\n return undefined;\n }\n let page = 0;\n const hostsNeedingAllPages = [\n 'https://ghcr.io', // GHCR sorts from oldest to newest, so we need to get all pages\n 'https://quay.io', // Quay sorts from oldest to newest, so we need to get all pages\n 'https://cgr.dev', // Chainguard sorts lexically and publishes a tag per build, so current versions sort past the page limit\n 'https://registry.access.redhat.com', // RH catalog; Quay-style lexicographic sort, high tag counts\n 'https://registry.redhat.io', // RH authenticated catalog; same backend\n ];\n const pages = hostsNeedingAllPages.includes(registryHost)\n ? 1000\n : GlobalConfig.get('dockerMaxPages');\n logger.trace({ registryHost, dockerRepository, pages }, 'docker.getTags');\n const allowCrossOrigin = isCrossOriginPaginationAllowed(dockerDatasourceId);\n let foundMaxResultsError = false;\n do {\n let res: HttpResponse<RegistryTagsList>;\n try {\n res = await this.http.getJson(\n url,\n { headers, noAuth: true },\n RegistryTagsList,\n );\n } catch (err) {\n if (\n !foundMaxResultsError &&\n err instanceof HttpError &&\n isECRMaxResultsError(err)\n ) {\n const maxResults = 1000;\n url = `${registryHost}/${dockerRepository}/tags/list?n=${maxResults}`;\n url = ensurePathPrefix(url, '/v2');\n foundMaxResultsError = true;\n continue;\n }\n throw err;\n }\n tags = tags.concat(res.body.tags);\n const linkHeader = parseLinkHeader(res.headers.link);\n if (isArtifactoryServer(res)) {\n // Artifactory bug: next link comes back without virtual-repo prefix (RTFACT-18971)\n if (linkHeader?.next?.last) {\n // parse the current URL, strip any old \"last\" param, then set the new one\n const parsed = parseUrl(url);\n // v8 ignore if: url is always a valid HTTP URL as `ensurePathPrefix`\n if (!parsed) {\n url = null;\n break;\n }\n parsed.searchParams.delete('last');\n parsed.searchParams.set('last', linkHeader.next.last);\n url = parsed.href;\n } else {\n url = null;\n }\n } else if (linkHeader?.next?.url) {\n // Resolve the relative-or-absolute next link, not following cross-origin requests unless explicitly opted in\n const nextUrl = resolvePaginationUrl(\n url,\n linkHeader.next.url,\n allowCrossOrigin,\n );\n if (!nextUrl) {\n // make sure that users are aware if there are any (potentially malicious, or misconfigured) pagination links being returned\n logger.once.warn(\n { registryHost, nextUrl: linkHeader.next.url },\n 'Ignoring cross-origin or invalid Docker registry tags pagination link',\n );\n }\n url = nextUrl;\n } else {\n url = null;\n }\n page += 1;\n } while (url && page < pages);\n return tags;\n }\n\n private async _getTags(\n registryHost: string,\n dockerRepository: string,\n ): Promise<string[] | undefined> {\n try {\n const isQuay = registryHost === 'https://quay.io';\n let tags: string[] | undefined;\n if (isQuay) {\n try {\n // Due to pagination and sorting limits on Quay Docker v2 API implementation we try the Quay v1 API first\n tags = await this.getTagsQuayRegistry(registryHost, dockerRepository);\n } catch (err) {\n // If we get a 401 Unauthorized error (v1 API requires separate auth for private images), fall back to Docker v2 API\n if (err.statusCode === 401) {\n logger.debug(\n { registryHost, dockerRepository },\n 'Quay v1 API unauthorized, falling back to Docker v2 API',\n );\n tags = await this.getDockerApiTags(registryHost, dockerRepository);\n } else {\n throw err;\n }\n }\n } else {\n tags = await this.getDockerApiTags(registryHost, dockerRepository);\n }\n return tags;\n } catch (_err) /* istanbul ignore next */ {\n const err = _err instanceof ExternalHostError ? _err.err : _err;\n\n if (\n (err.statusCode === 404 || err.message === PAGE_NOT_FOUND_ERROR) &&\n !dockerRepository.includes('/')\n ) {\n logger.debug(\n `Retrying Tags for ${registryHost}/${dockerRepository} using library/ prefix`,\n );\n return this.getTags(registryHost, `library/${dockerRepository}`);\n }\n // JFrog Artifactory - Retry handling when resolving Docker Official Images\n // These follow the format of {{registryHost}}{{jFrogRepository}}/library/{{dockerRepository}}\n if (\n (err.statusCode === 404 || err.message === PAGE_NOT_FOUND_ERROR) &&\n isArtifactoryServer(err.response) &&\n dockerRepository.split('/').length === 2\n ) {\n logger.debug(\n `JFrog Artifactory: Retrying Tags for ${registryHost}/${dockerRepository} using library/ path between JFrog virtual repository and image`,\n );\n\n const dockerRepositoryParts = dockerRepository.split('/');\n const jfrogRepository = dockerRepositoryParts[0];\n const dockerImage = dockerRepositoryParts[1];\n\n return this.getTags(\n registryHost,\n `${jfrogRepository}/library/${dockerImage}`,\n );\n }\n if (err.statusCode === 429 && isDockerHost(registryHost)) {\n logger.warn(\n { registryHost, dockerRepository, err },\n 'docker registry failure: too many requests',\n );\n throw new ExternalHostError(err);\n }\n if (err.statusCode >= 500 && err.statusCode < 600) {\n logger.warn(\n { registryHost, dockerRepository, err },\n 'docker registry failure: internal error',\n );\n throw new ExternalHostError(err);\n }\n const errorCodes = ['ECONNRESET', 'ETIMEDOUT'];\n if (errorCodes.includes(err.code)) {\n logger.warn(\n { registryHost, dockerRepository, err },\n 'docker registry connection failure',\n );\n throw new ExternalHostError(err);\n }\n if (isDockerHost(registryHost)) {\n logger.info({ err }, 'Docker Hub lookup failure');\n }\n throw _err;\n }\n }\n\n getTags(\n registryHost: string,\n dockerRepository: string,\n ): Promise<string[] | undefined> {\n return withCache(\n {\n namespace: 'datasource-docker-tags',\n key: `${registryHost}:${dockerRepository}`,\n cacheable: registryHost === DOCKER_HUB,\n },\n () => this._getTags(registryHost, dockerRepository),\n );\n }\n\n /**\n * docker.getDigest\n *\n * The `newValue` supplied here should be a valid tag for the docker image.\n *\n * This function will:\n * - Look up a sha256 digest for a tag on its registry\n * - Return the digest as a string\n */\n private async _getDigest(\n { registryUrl, lookupName, packageName, currentDigest }: DigestConfig,\n newValue?: string,\n ): Promise<string | null> {\n let registryHost: string;\n let dockerRepository: string;\n if (registryUrl && lookupName) {\n // Reuse the resolved values from getReleases()\n registryHost = registryUrl;\n dockerRepository = lookupName;\n } else {\n // Resolve values independently\n ({ registryHost, dockerRepository } = getRegistryRepository(\n packageName,\n registryUrl!,\n ));\n }\n logger.debug(\n // TODO: types (#22198)\n `getDigest(${registryHost}, ${dockerRepository}, ${newValue})`,\n );\n const newTag = isNonEmptyString(newValue) ? newValue : 'latest';\n let digest: string | null = null;\n try {\n let architecture: string | null | undefined = null;\n if (currentDigest && isDockerDigest(currentDigest)) {\n architecture = await this.getImageArchitecture(\n registryHost,\n dockerRepository,\n currentDigest,\n );\n }\n\n let manifestResponse: HttpResponse | null = null;\n if (!architecture) {\n // Reuse the digest cached from the Docker Hub tag API\n if (registryHost === DOCKER_HUB) {\n const cache = await DockerHubCache.init(dockerRepository);\n const cachedDigest = cache.getDigestForTag(newTag);\n if (cachedDigest) {\n return cachedDigest;\n }\n }\n\n manifestResponse = await this.getManifestResponse(\n registryHost,\n dockerRepository,\n newTag,\n 'head',\n );\n\n if (\n manifestResponse &&\n hasKey('docker-content-digest', manifestResponse.headers)\n ) {\n digest =\n (manifestResponse.headers['docker-content-digest'] as string) ||\n null;\n }\n }\n\n if (\n isNonEmptyString(architecture) ||\n (manifestResponse &&\n !hasKey('docker-content-digest', manifestResponse.headers))\n ) {\n // Reuse the per-arch digest cached from the Docker Hub tag API\n if (isNonEmptyString(architecture) && registryHost === DOCKER_HUB) {\n const cache = await DockerHubCache.init(dockerRepository);\n const cachedDigest = cache.getArchDigestForTag(newTag, architecture);\n if (cachedDigest) {\n return cachedDigest;\n }\n }\n\n logger.debug(\n { registryHost, dockerRepository },\n 'Architecture-specific digest or missing docker-content-digest header - pulling full manifest',\n );\n manifestResponse = await this.getManifestResponse(\n registryHost,\n dockerRepository,\n newTag,\n );\n\n if (architecture && manifestResponse) {\n const parsed = ManifestJson.safeParse(manifestResponse.body);\n /* istanbul ignore else: hard to test */\n if (parsed.success) {\n const manifestList = parsed.data;\n if (\n manifestList.mediaType ===\n 'application/vnd.docker.distribution.manifest.list.v2+json' ||\n manifestList.mediaType ===\n 'application/vnd.oci.image.index.v1+json'\n ) {\n for (const manifest of manifestList.manifests) {\n if (manifest.platform?.architecture === architecture) {\n digest = manifest.digest;\n break;\n }\n }\n // TODO: return null if no matching architecture digest found\n // https://github.com/renovatebot/renovate/discussions/22639\n // NOTE: reaching the implicit else needs a manifest list with no\n // digest header. A coverage-ignore hint cannot suppress it on an\n // `else if`.\n } else if (\n hasKey('docker-content-digest', manifestResponse.headers)\n ) {\n // TODO: return null if no matching architecture, requires to fetch the config manifest\n // https://github.com/renovatebot/renovate/discussions/22639\n digest = manifestResponse.headers[\n 'docker-content-digest'\n ] as string;\n }\n } else {\n logger.debug(\n {\n registryHost,\n dockerRepository,\n newTag,\n body: manifestResponse.body,\n headers: manifestResponse.headers,\n err: parsed.error,\n },\n 'Failed to parse manifest response',\n );\n }\n }\n\n if (!digest) {\n logger.debug(\n { registryHost, dockerRepository, newTag },\n 'Extraction digest from manifest response body is deprecated',\n );\n digest = extractDigestFromResponseBody(manifestResponse!);\n }\n }\n\n if (\n !manifestResponse &&\n !dockerRepository.includes('/') &&\n !packageName.includes('/')\n ) {\n logger.debug(\n `Retrying Digest for ${registryHost}/${dockerRepository} using library/ prefix`,\n );\n return this.getDigest(\n {\n registryUrl,\n packageName: `library/${packageName}`,\n currentDigest,\n },\n newValue,\n );\n }\n\n if (manifestResponse) {\n // TODO: fix types (#22198)\n logger.debug(`Got docker digest ${digest!}`);\n }\n } catch (err) /* istanbul ignore next */ {\n if (err instanceof ExternalHostError) {\n throw err;\n }\n logger.debug(\n {\n err,\n packageName,\n newTag,\n },\n 'Unknown Error looking up docker image digest',\n );\n }\n return digest;\n }\n\n override getDigest(\n config: DigestConfig,\n newValue?: string,\n ): Promise<string | null> {\n const newTag = newValue ?? 'latest';\n const { registryHost, dockerRepository } = getRegistryRepository(\n config.packageName,\n config.registryUrl!,\n );\n const digest = config.currentDigest ? `@${config.currentDigest}` : '';\n return withCache(\n {\n namespace: 'datasource-docker-digest',\n key: `${registryHost}:${dockerRepository}:${newTag}${digest}`,\n fallback: true,\n shouldCacheResult: isNonEmptyString,\n },\n () => this._getDigest(config, newValue),\n );\n }\n\n private async _getDockerHubTags(\n dockerRepository: string,\n ): Promise<Release[] | null> {\n let url = `https://hub.docker.com/v2/repositories/${dockerRepository}/tags?page_size=1000&ordering=last_updated`;\n\n const cache = await DockerHubCache.init(dockerRepository);\n const maxPages = GlobalConfig.get('dockerMaxPages');\n const allowCrossOrigin = isCrossOriginPaginationAllowed(dockerDatasourceId);\n let page = 0,\n needNextPage = true;\n while (needNextPage && page < maxPages) {\n const { val, err } = await this.http\n .getJsonSafe(url, DockerHubTagsPage)\n .unwrap();\n\n if (err) {\n logger.debug({ err }, `Docker: error fetching data from DockerHub`);\n return null;\n }\n page++;\n const { results, next, count } = val;\n\n needNextPage = cache.reconcile(results, count);\n\n if (!next) {\n break;\n }\n\n // Only follow the `next` link when it's on the same origin, unless explicitly opted in\n const nextUrl = resolvePaginationUrl(url, next, allowCrossOrigin);\n if (!nextUrl) {\n logger.once.warn(\n { dockerRepository, nextUrl: next },\n 'Ignoring cross-origin or invalid Docker Hub tags pagination link',\n );\n break;\n }\n\n url = nextUrl;\n }\n\n await cache.save();\n\n const items = cache.getItems();\n return items.map(({ name: version, tag_last_pushed }) => {\n const release: Release = { version };\n\n const releaseTimestamp = asTimestamp(tag_last_pushed);\n if (releaseTimestamp) {\n release.releaseTimestamp = releaseTimestamp;\n }\n\n // Digest is intentionally not propagated — the Docker Hub tag API\n // returns the manifest-list digest, which would bypass arch-aware\n // resolution in `getDigest()`. `getDigest()` consults the same cache\n // as a shortcut when no arch resolution is needed.\n return release;\n });\n }\n\n getDockerHubTags(dockerRepository: string): Promise<Release[] | null> {\n return withCache(\n {\n namespace: 'datasource-docker-hub-tags',\n key: `${dockerRepository}`,\n },\n () => this._getDockerHubTags(dockerRepository),\n );\n }\n\n /**\n * docker.getReleases\n *\n * A docker image usually looks something like this: somehost.io/owner/repo:8.1.0-alpine\n * In the above:\n * - 'somehost.io' is the registry\n * - 'owner/repo' is the package name\n * - '8.1.0-alpine' is the tag\n *\n * This function will filter only tags that contain a semver version\n */\n private async _getReleases({\n packageName,\n registryUrl,\n }: GetReleasesConfig): Promise<ReleaseResult | null> {\n const { registryHost, dockerRepository } = getRegistryRepository(\n packageName,\n registryUrl!,\n );\n\n type TagsResultType = AsyncResult<\n Release[],\n NonNullable<Error | 'tags-error' | 'dockerhub-error'>\n >;\n\n const getTags = (): TagsResultType =>\n Result.wrapNullable(\n this.getTags(registryHost, dockerRepository),\n 'tags-error' as const,\n ).transform((tags) => tags.map((version) => ({ version })));\n\n const getDockerHubTags = (): TagsResultType =>\n Result.wrapNullable(\n this.getDockerHubTags(dockerRepository),\n 'dockerhub-error' as const,\n ).catch(getTags);\n\n const tagsResult =\n registryHost === DOCKER_HUB &&\n !getEnv().RENOVATE_X_DOCKER_HUB_TAGS_DISABLE\n ? getDockerHubTags()\n : getTags();\n\n const { val: releases, err } = await tagsResult.unwrap();\n if (err instanceof Error) {\n throw err;\n } else if (err) {\n return null;\n }\n\n const ret: ReleaseResult = {\n registryUrl: registryHost,\n releases,\n };\n if (dockerRepository !== packageName) {\n // This will be reused later if a getDigest() call is made\n ret.lookupName = dockerRepository;\n }\n\n const tags = releases.map((release) => release.version);\n const latestTag = tags.includes('latest')\n ? 'latest'\n : (findLatestStable(tags) ?? tags.at(-1));\n\n /* v8 ignore next -- TODO: add test */\n if (!latestTag) {\n return ret;\n }\n const labels = await this.getLabels(\n registryHost,\n dockerRepository,\n latestTag,\n );\n if (labels) {\n if (isNonEmptyString(labels[gitRefLabel])) {\n ret.gitRef = labels[gitRefLabel];\n }\n for (const label of sourceLabels) {\n if (isNonEmptyString(labels[label])) {\n ret.sourceUrl = labels[label];\n break;\n }\n }\n if (isNonEmptyString(labels[imageUrlLabel])) {\n ret.homepage = labels[imageUrlLabel];\n }\n }\n return ret;\n }\n\n getReleases(config: GetReleasesConfig): Promise<ReleaseResult | null> {\n const { registryHost, dockerRepository } = getRegistryRepository(\n config.packageName,\n config.registryUrl!,\n );\n return withCache(\n {\n namespace: 'datasource-docker-releases-v2',\n key: `${registryHost}:${dockerRepository}`,\n cacheable: registryHost === DOCKER_HUB,\n fallback: true,\n },\n () => this._getReleases(config),\n );\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["dockerVersioningId","HttpError"],"sources":["../../../../lib/modules/datasource/docker/index.ts"],"sourcesContent":["import { isNonEmptyString } from '@sindresorhus/is';\nimport { GlobalConfig } from '../../../config/global.ts';\nimport { PAGE_NOT_FOUND_ERROR } from '../../../constants/error-messages.ts';\nimport { logger } from '../../../logger/index.ts';\nimport { ExternalHostError } from '../../../types/errors/external-host-error.ts';\nimport { buildCacheKey } from '../../../util/cache/package/key.ts';\nimport { withCache } from '../../../util/cache/package/with-cache.ts';\nimport { getEnv } from '../../../util/env.ts';\nimport { memCacheProvider } from '../../../util/http/cache/memory-http-cache-provider.ts';\nimport { HttpError } from '../../../util/http/index.ts';\nimport type { HttpResponse } from '../../../util/http/types.ts';\nimport { hasKey } from '../../../util/object.ts';\nimport { type AsyncResult, Result } from '../../../util/result.ts';\nimport { isDockerDigest } from '../../../util/string-match.ts';\nimport { asTimestamp } from '../../../util/timestamp.ts';\nimport {\n ensurePathPrefix,\n joinUrlParts,\n parseLinkHeader,\n parseUrl,\n} from '../../../util/url.ts';\nimport { id as dockerVersioningId } from '../../versioning/docker/index.ts';\nimport { Datasource } from '../datasource.ts';\nimport type {\n DigestConfig,\n GetReleasesConfig,\n Release,\n ReleaseResult,\n} from '../types.ts';\nimport {\n isArtifactoryServer,\n isCrossOriginPaginationAllowed,\n resolvePaginationUrl,\n} from '../util.ts';\nimport {\n DOCKER_HUB,\n dockerDatasourceId,\n extractDigestFromResponseBody,\n findHelmSourceUrl,\n findLatestStable,\n getAuthHeaders,\n getRegistryRepository,\n gitRefLabel,\n imageUrlLabel,\n isDockerHost,\n sourceLabel,\n sourceLabels,\n} from './common.ts';\nimport { DockerHubCache } from './dockerhub-cache.ts';\nimport { ecrPublicRegex, ecrRegex, isECRMaxResultsError } from './ecr.ts';\nimport type {\n DistributionManifest,\n Manifest,\n OciImageManifest,\n} from './schema.ts';\nimport {\n DockerHubTagsPage,\n ManifestJson,\n OciHelmConfig,\n OciImageConfig,\n QuayTagsResponse,\n RegistryTagsList,\n} from './schema.ts';\n\nconst defaultConfig = {\n commitMessageTopic: '{{{depName}}} Docker tag',\n commitMessageExtra:\n 'to {{#if isPinDigest}}{{{newDigestShort}}}{{else}}{{#if isMajor}}{{{prettyNewMajor}}}{{else}}{{{prettyNewVersion}}}{{/if}}{{/if}}',\n digest: {\n branchTopic: '{{{depNameSanitized}}}-{{{currentValue}}}',\n commitMessageExtra: 'to {{newDigestShort}}',\n commitMessageTopic:\n '{{{depName}}}{{#if currentValue}}:{{{currentValue}}}{{/if}} Docker digest',\n group: {\n commitMessageTopic: '{{{groupName}}}',\n commitMessageExtra: '',\n },\n },\n pin: {\n commitMessageExtra: '',\n groupName: 'Docker digests',\n group: {\n commitMessageTopic: '{{{groupName}}}',\n branchTopic: 'digests-pin',\n },\n },\n};\n\nexport class DockerDatasource extends Datasource {\n static readonly id = dockerDatasourceId;\n\n override readonly defaultVersioning = dockerVersioningId;\n\n override getDefaultRegistryUrls(_packageName: string): string[] {\n return [DOCKER_HUB];\n }\n\n override readonly defaultConfig = defaultConfig;\n\n override readonly releaseTimestampSupport = true;\n override readonly releaseTimestampNote =\n 'Only supported on Docker Hub: The release timestamp is determined from the `tag_last_pushed` field in the results. **NOTE**: Currently, digests will receive the same release timestamp as the `tag_last_pushed`, which means that digests may appear newer than they are - see https://github.com/renovatebot/renovate/issues/38659';\n override readonly sourceUrlSupport = 'package';\n override readonly sourceUrlNote =\n 'The source URL is determined from the `org.opencontainers.image.source` and `org.label-schema.vcs-url` labels present in the metadata of the **latest stable** image found on the Docker registry.';\n\n constructor() {\n super(DockerDatasource.id);\n }\n\n // TODO: debug why quay throws errors (#9612)\n private async getManifestResponse(\n registryHost: string,\n dockerRepository: string,\n tag: string,\n mode: 'head' | 'getText' = 'getText',\n ): Promise<HttpResponse | null> {\n logger.debug(\n `getManifestResponse(${registryHost}, ${dockerRepository}, ${tag}, ${mode})`,\n );\n try {\n const headers = await getAuthHeaders(\n this.http,\n registryHost,\n dockerRepository,\n );\n if (!headers) {\n logger.warn('No docker auth found - returning');\n return null;\n }\n headers.accept = [\n 'application/vnd.docker.distribution.manifest.list.v2+json',\n 'application/vnd.docker.distribution.manifest.v2+json',\n 'application/vnd.oci.image.manifest.v1+json',\n 'application/vnd.oci.image.index.v1+json',\n ].join(', ');\n const url = `${registryHost}/v2/${dockerRepository}/manifests/${tag}`;\n const manifestResponse = await this.http[mode](url, {\n headers,\n noAuth: true,\n cacheProvider: memCacheProvider,\n });\n return manifestResponse;\n } catch (err) /* istanbul ignore next */ {\n if (err instanceof ExternalHostError) {\n throw err;\n }\n if (err.statusCode === 401) {\n logger.debug(\n { registryHost, dockerRepository },\n 'Unauthorized docker lookup',\n );\n logger.debug({ err });\n return null;\n }\n if (err.statusCode === 404) {\n logger.debug(\n {\n err,\n registryHost,\n dockerRepository,\n tag,\n },\n 'Docker Manifest is unknown',\n );\n return null;\n }\n if (err.statusCode === 429 && isDockerHost(registryHost)) {\n throw new ExternalHostError(err);\n }\n if (err.statusCode >= 500 && err.statusCode < 600) {\n throw new ExternalHostError(err);\n }\n if (err.code === 'ETIMEDOUT') {\n logger.debug(\n { registryHost },\n 'Timeout when attempting to connect to docker registry',\n );\n logger.debug({ err });\n return null;\n }\n logger.debug(\n {\n err,\n registryHost,\n dockerRepository,\n tag,\n },\n 'Unknown Error looking up docker manifest',\n );\n return null;\n }\n }\n\n private async _getImageConfig(\n registryHost: string,\n dockerRepository: string,\n configDigest: string,\n ): Promise<HttpResponse<OciImageConfig> | undefined> {\n logger.trace(\n `getImageConfig(${registryHost}, ${dockerRepository}, ${configDigest})`,\n );\n\n const headers = await getAuthHeaders(\n this.http,\n registryHost,\n dockerRepository,\n );\n /* v8 ignore next -- should never happen */\n if (!headers) {\n logger.warn('No docker auth found - returning');\n return undefined;\n }\n const url = joinUrlParts(\n registryHost,\n 'v2',\n dockerRepository,\n 'blobs',\n configDigest,\n );\n return await this.http.getJson(\n url,\n {\n headers,\n noAuth: true,\n },\n OciImageConfig,\n );\n }\n\n getImageConfig(\n registryHost: string,\n dockerRepository: string,\n configDigest: string,\n ): Promise<HttpResponse<OciImageConfig> | undefined> {\n return withCache(\n {\n namespace: 'datasource-docker-imageconfig',\n key: buildCacheKey(registryHost, dockerRepository, configDigest),\n ttlMinutes: 1440 * 28,\n },\n () => this._getImageConfig(registryHost, dockerRepository, configDigest),\n );\n }\n\n private async _getHelmConfig(\n registryHost: string,\n dockerRepository: string,\n configDigest: string,\n ): Promise<HttpResponse<OciHelmConfig> | undefined> {\n logger.trace(\n `getImageConfig(${registryHost}, ${dockerRepository}, ${configDigest})`,\n );\n\n const headers = await getAuthHeaders(\n this.http,\n registryHost,\n dockerRepository,\n );\n /* v8 ignore next -- should never happen */\n if (!headers) {\n logger.warn('No docker auth found - returning');\n return undefined;\n }\n const url = joinUrlParts(\n registryHost,\n 'v2',\n dockerRepository,\n 'blobs',\n configDigest,\n );\n return await this.http.getJson(\n url,\n {\n headers,\n noAuth: true,\n },\n OciHelmConfig,\n );\n }\n\n getHelmConfig(\n registryHost: string,\n dockerRepository: string,\n configDigest: string,\n ): Promise<HttpResponse<OciHelmConfig> | undefined> {\n return withCache(\n {\n namespace: 'datasource-docker-imageconfig',\n key: buildCacheKey(registryHost, dockerRepository, configDigest),\n ttlMinutes: 1440 * 28,\n },\n () => this._getHelmConfig(registryHost, dockerRepository, configDigest),\n );\n }\n\n private async getConfigDigest(\n registry: string,\n dockerRepository: string,\n tag: string,\n ): Promise<string | null> {\n return (\n (await this.getManifest(registry, dockerRepository, tag))?.config\n ?.digest ?? null\n );\n }\n\n private async getManifestDocument(\n registry: string,\n dockerRepository: string,\n tag: string,\n ): Promise<Manifest | null> {\n const manifestResponse = await this.getManifestResponse(\n registry,\n dockerRepository,\n tag,\n );\n\n // If getting the manifest fails here, then abort\n // This means that the latest tag doesn't have a manifest, which shouldn't\n // be possible\n /* v8 ignore next -- should never happen */\n if (!manifestResponse) {\n return null;\n }\n\n // Softfail on invalid manifests\n const parsed = ManifestJson.safeParse(manifestResponse.body);\n if (!parsed.success) {\n logger.debug(\n {\n registry,\n dockerRepository,\n tag,\n body: manifestResponse.body,\n headers: manifestResponse.headers,\n err: parsed.error,\n },\n 'Invalid manifest response',\n );\n return null;\n }\n\n return parsed.data;\n }\n\n private async resolveImageManifest(\n registry: string,\n dockerRepository: string,\n tag: string,\n manifest: Manifest,\n ): Promise<OciImageManifest | DistributionManifest | null> {\n switch (manifest.mediaType) {\n case 'application/vnd.docker.distribution.manifest.v2+json':\n case 'application/vnd.oci.image.manifest.v1+json':\n return manifest;\n case 'application/vnd.docker.distribution.manifest.list.v2+json':\n case 'application/vnd.oci.image.index.v1+json':\n if (!manifest.manifests.length) {\n logger.debug(\n { manifest },\n 'Invalid manifest list with no manifests - returning',\n );\n return null;\n }\n logger.trace(\n { registry, dockerRepository, tag },\n 'Found manifest list, using first image',\n );\n return this.getManifest(\n registry,\n dockerRepository,\n manifest.manifests[0].digest,\n );\n // istanbul ignore next: can't happen\n default:\n return null;\n }\n }\n\n private async getManifest(\n registry: string,\n dockerRepository: string,\n tag: string,\n ): Promise<OciImageManifest | DistributionManifest | null> {\n const manifest = await this.getManifestDocument(\n registry,\n dockerRepository,\n tag,\n );\n if (!manifest) {\n return null;\n }\n return this.resolveImageManifest(registry, dockerRepository, tag, manifest);\n }\n\n private async _getImageArchitecture(\n registryHost: string,\n dockerRepository: string,\n currentDigest: string,\n ): Promise<string | null | undefined> {\n try {\n let manifestResponse: HttpResponse | null;\n\n try {\n manifestResponse = await this.getManifestResponse(\n registryHost,\n dockerRepository,\n currentDigest,\n 'head',\n );\n } catch (_err) {\n const err =\n _err instanceof ExternalHostError\n ? _err.err\n : /* istanbul ignore next: can never happen */ _err;\n\n // v8 ignore else -- needs a non-5xx failure from the manifest request\n if (\n typeof err.statusCode === 'number' &&\n err.statusCode >= 500 &&\n err.statusCode < 600\n ) {\n // querying the digest manifest for a non existent image leads to a 500 statusCode\n return null;\n }\n\n /* istanbul ignore next */\n throw _err;\n }\n\n if (\n manifestResponse?.headers['content-type'] !==\n 'application/vnd.docker.distribution.manifest.v2+json' &&\n manifestResponse?.headers['content-type'] !==\n 'application/vnd.oci.image.manifest.v1+json'\n ) {\n return null;\n }\n\n const configDigest = await this.getConfigDigest(\n registryHost,\n dockerRepository,\n currentDigest,\n );\n if (!configDigest) {\n return null;\n }\n\n const configResponse = await this.getImageConfig(\n registryHost,\n dockerRepository,\n configDigest,\n );\n\n // TODO: fix me, architecture is required in spec\n // v8 ignore else -- needs a config blob with neither key\n if (\n configResponse &&\n ('config' in configResponse.body ||\n 'architecture' in configResponse.body)\n ) {\n const architecture = configResponse.body.architecture ?? null;\n logger.debug(\n `Current digest ${currentDigest} relates to architecture ${\n architecture ?? 'null'\n }`,\n );\n\n return architecture;\n }\n } catch (err) /* istanbul ignore next */ {\n if (err.statusCode !== 404 || err.message === PAGE_NOT_FOUND_ERROR) {\n throw err;\n }\n logger.debug(\n { registryHost, dockerRepository, currentDigest, err },\n 'Unknown error getting image architecture',\n );\n }\n\n return undefined;\n }\n\n getImageArchitecture(\n registryHost: string,\n dockerRepository: string,\n currentDigest: string,\n ): Promise<string | null | undefined> {\n return withCache(\n {\n namespace: 'datasource-docker-architecture',\n key: buildCacheKey(registryHost, dockerRepository, currentDigest),\n ttlMinutes: 1440 * 28,\n shouldCacheResult: isNonEmptyString,\n },\n () =>\n this._getImageArchitecture(\n registryHost,\n dockerRepository,\n currentDigest,\n ),\n );\n }\n\n /*\n * docker.getLabels\n *\n * This function will:\n * - Return the labels for the requested image\n */\n private async _getLabels(\n registryHost: string,\n dockerRepository: string,\n tag: string,\n ): Promise<Record<string, string> | undefined> {\n logger.debug(`getLabels(${registryHost}, ${dockerRepository}, ${tag})`);\n // Skip Docker Hub image if RENOVATE_X_DOCKER_HUB_DISABLE_LABEL_LOOKUP is set\n if (\n getEnv().RENOVATE_X_DOCKER_HUB_DISABLE_LABEL_LOOKUP &&\n registryHost === DOCKER_HUB\n ) {\n logger.debug(\n 'Docker Hub image - skipping label lookup due to RENOVATE_X_DOCKER_HUB_DISABLE_LABEL_LOOKUP',\n );\n return {};\n }\n try {\n let labels: Record<string, string> | undefined = {};\n const manifestDocument = await this.getManifestDocument(\n registryHost,\n dockerRepository,\n tag,\n );\n\n if (!manifestDocument) {\n logger.debug(\n { registryHost, dockerRepository, tag },\n 'No manifest found',\n );\n return undefined;\n }\n\n if ('annotations' in manifestDocument && manifestDocument.annotations) {\n labels = manifestDocument.annotations;\n }\n\n if ('manifests' in manifestDocument) {\n const descriptorAnnotations = manifestDocument.manifests\n .map((descriptor) => descriptor.annotations)\n .find(\n (annotations) =>\n isNonEmptyString(annotations?.[sourceLabel]) &&\n isNonEmptyString(annotations?.[gitRefLabel]),\n );\n if (descriptorAnnotations) {\n labels = { ...labels, ...descriptorAnnotations };\n }\n }\n\n if (\n 'manifests' in manifestDocument &&\n labels[sourceLabel] &&\n labels[gitRefLabel]\n ) {\n return labels;\n }\n\n const manifest = await this.resolveImageManifest(\n registryHost,\n dockerRepository,\n tag,\n manifestDocument,\n );\n if (!manifest) {\n return undefined;\n }\n\n if ('annotations' in manifest && manifest.annotations) {\n labels = { ...labels, ...manifest.annotations };\n }\n\n switch (manifest.config.mediaType) {\n case 'application/vnd.cncf.helm.config.v1+json': {\n if (labels[sourceLabel]) {\n // we already have the source url, so no need to pull the config\n return labels;\n }\n const configResponse = await this.getHelmConfig(\n registryHost,\n dockerRepository,\n manifest.config.digest,\n );\n\n // v8 ignore else -- needs the helm config blob request to come back empty\n if (configResponse) {\n // Helm chart\n const url = findHelmSourceUrl(configResponse.body);\n // v8 ignore else -- needs a helm chart with no source url\n if (url) {\n labels[sourceLabel] = url;\n }\n }\n break;\n }\n case 'application/vnd.oci.image.config.v1+json':\n case 'application/vnd.docker.container.image.v1+json': {\n if (labels[sourceLabel] && labels[gitRefLabel]) {\n // we already have the source url, so no need to pull the config\n return labels;\n }\n const configResponse = await this.getImageConfig(\n registryHost,\n dockerRepository,\n manifest.config.digest,\n );\n\n /* v8 ignore next -- should never happen */\n if (!configResponse) {\n return labels;\n }\n\n const body = configResponse.body;\n if (body.config) {\n labels = { ...labels, ...body.config.Labels };\n } else {\n logger.debug(\n { headers: configResponse.headers, body },\n `manifest blob response body missing the \"config\" property`,\n );\n }\n break;\n }\n }\n\n // v8 ignore else -- labels are always set by the branches above\n if (labels) {\n logger.debug(\n {\n labels,\n },\n 'found labels in manifest',\n );\n }\n return labels;\n } catch (err) /* istanbul ignore next: should be tested in future */ {\n if (err instanceof ExternalHostError) {\n throw err;\n }\n if (err.statusCode === 400 || err.statusCode === 401) {\n logger.debug(\n { registryHost, dockerRepository, err },\n 'Unauthorized docker lookup',\n );\n } else if (err.statusCode === 404) {\n logger.warn(\n {\n err,\n registryHost,\n dockerRepository,\n tag,\n },\n 'Config Manifest is unknown',\n );\n } else if (err.statusCode === 429 && isDockerHost(registryHost)) {\n logger.warn({ err }, 'docker registry failure: too many requests');\n } else if (err.statusCode >= 500 && err.statusCode < 600) {\n logger.debug(\n {\n err,\n registryHost,\n dockerRepository,\n tag,\n },\n 'docker registry failure: internal error',\n );\n } else if (\n err.code === 'ERR_TLS_CERT_ALTNAME_INVALID' ||\n err.code === 'ETIMEDOUT'\n ) {\n logger.debug(\n { registryHost, err },\n 'Error connecting to docker registry',\n );\n } else if (registryHost === 'https://quay.io') {\n // istanbul ignore next\n logger.debug(\n 'Ignoring quay.io errors until they fully support v2 schema',\n );\n } else {\n logger.info(\n { registryHost, dockerRepository, tag, err },\n 'Unknown error getting Docker labels',\n );\n }\n return {};\n }\n }\n\n getLabels(\n registryHost: string,\n dockerRepository: string,\n tag: string,\n ): Promise<Record<string, string> | undefined> {\n return withCache(\n {\n namespace: 'datasource-docker-labels',\n key: buildCacheKey(registryHost, dockerRepository, tag),\n ttlMinutes: 24 * 60,\n },\n () => this._getLabels(registryHost, dockerRepository, tag),\n );\n }\n\n private async getTagsQuayRegistry(\n registry: string,\n repository: string,\n ): Promise<string[]> {\n let tags: string[] = [];\n const limit = 100;\n\n function pageUrl(page: number): string {\n return `${registry}/api/v1/repository/${repository}/tag/?limit=${limit}&page=${page}&onlyActiveTags=true`;\n }\n\n let page = 1;\n let url: string | null = pageUrl(page);\n while (url && page <= 20) {\n const res: HttpResponse<QuayTagsResponse> = await this.http.getJson(\n url,\n QuayTagsResponse,\n );\n const pageTags = res.body.tags.map((tag) => tag.name);\n tags = tags.concat(pageTags);\n page += 1;\n url = res.body.has_additional ? pageUrl(page) : null;\n }\n return tags;\n }\n\n private async getDockerApiTags(\n registryHost: string,\n dockerRepository: string,\n ): Promise<string[] | undefined> {\n let tags: string[] = [];\n // AWS ECR limits the maximum number of results to 1000\n // See https://docs.aws.amazon.com/AmazonECR/latest/APIReference/API_DescribeRepositories.html#ECR-DescribeRepositories-request-maxResults\n // See https://docs.aws.amazon.com/AmazonECRPublic/latest/APIReference/API_DescribeRepositories.html#ecrpublic-DescribeRepositories-request-maxResults\n const limit =\n ecrRegex.test(registryHost) || ecrPublicRegex.test(registryHost)\n ? 1000\n : 10000;\n let url: string | null =\n `${registryHost}/${dockerRepository}/tags/list?n=${limit}`;\n url = ensurePathPrefix(url, '/v2');\n const headers = await getAuthHeaders(\n this.http,\n registryHost,\n dockerRepository,\n url,\n );\n if (!headers) {\n logger.debug('Failed to get authHeaders for getTags lookup');\n return undefined;\n }\n let page = 0;\n const hostsNeedingAllPages = [\n 'https://ghcr.io', // GHCR sorts from oldest to newest, so we need to get all pages\n 'https://quay.io', // Quay sorts from oldest to newest, so we need to get all pages\n 'https://cgr.dev', // Chainguard sorts lexically and publishes a tag per build, so current versions sort past the page limit\n 'https://registry.access.redhat.com', // RH catalog; Quay-style lexicographic sort, high tag counts\n 'https://registry.redhat.io', // RH authenticated catalog; same backend\n ];\n const pages = hostsNeedingAllPages.includes(registryHost)\n ? 1000\n : GlobalConfig.get('dockerMaxPages');\n logger.trace({ registryHost, dockerRepository, pages }, 'docker.getTags');\n const allowCrossOrigin = isCrossOriginPaginationAllowed(dockerDatasourceId);\n let foundMaxResultsError = false;\n do {\n let res: HttpResponse<RegistryTagsList>;\n try {\n res = await this.http.getJson(\n url,\n { headers, noAuth: true },\n RegistryTagsList,\n );\n } catch (err) {\n if (\n !foundMaxResultsError &&\n err instanceof HttpError &&\n isECRMaxResultsError(err)\n ) {\n const maxResults = 1000;\n url = `${registryHost}/${dockerRepository}/tags/list?n=${maxResults}`;\n url = ensurePathPrefix(url, '/v2');\n foundMaxResultsError = true;\n continue;\n }\n throw err;\n }\n tags = tags.concat(res.body.tags);\n const linkHeader = parseLinkHeader(res.headers.link);\n if (isArtifactoryServer(res)) {\n // Artifactory bug: next link comes back without virtual-repo prefix (RTFACT-18971)\n if (linkHeader?.next?.last) {\n // parse the current URL, strip any old \"last\" param, then set the new one\n const parsed = parseUrl(url);\n // v8 ignore if: url is always a valid HTTP URL as `ensurePathPrefix`\n if (!parsed) {\n url = null;\n break;\n }\n parsed.searchParams.delete('last');\n parsed.searchParams.set('last', linkHeader.next.last);\n url = parsed.href;\n } else {\n url = null;\n }\n } else if (linkHeader?.next?.url) {\n // Resolve the relative-or-absolute next link, not following cross-origin requests unless explicitly opted in\n const nextUrl = resolvePaginationUrl(\n url,\n linkHeader.next.url,\n allowCrossOrigin,\n );\n if (!nextUrl) {\n // make sure that users are aware if there are any (potentially malicious, or misconfigured) pagination links being returned\n logger.once.warn(\n { registryHost, nextUrl: linkHeader.next.url },\n 'Ignoring cross-origin or invalid Docker registry tags pagination link',\n );\n }\n url = nextUrl;\n } else {\n url = null;\n }\n page += 1;\n } while (url && page < pages);\n return tags;\n }\n\n private async _getTags(\n registryHost: string,\n dockerRepository: string,\n ): Promise<string[] | undefined> {\n try {\n const isQuay = registryHost === 'https://quay.io';\n let tags: string[] | undefined;\n if (isQuay) {\n try {\n // Due to pagination and sorting limits on Quay Docker v2 API implementation we try the Quay v1 API first\n tags = await this.getTagsQuayRegistry(registryHost, dockerRepository);\n } catch (err) {\n // If we get a 401 Unauthorized error (v1 API requires separate auth for private images), fall back to Docker v2 API\n if (err.statusCode === 401) {\n logger.debug(\n { registryHost, dockerRepository },\n 'Quay v1 API unauthorized, falling back to Docker v2 API',\n );\n tags = await this.getDockerApiTags(registryHost, dockerRepository);\n } else {\n throw err;\n }\n }\n } else {\n tags = await this.getDockerApiTags(registryHost, dockerRepository);\n }\n return tags;\n } catch (_err) /* istanbul ignore next */ {\n const err = _err instanceof ExternalHostError ? _err.err : _err;\n\n if (\n (err.statusCode === 404 || err.message === PAGE_NOT_FOUND_ERROR) &&\n !dockerRepository.includes('/')\n ) {\n logger.debug(\n `Retrying Tags for ${registryHost}/${dockerRepository} using library/ prefix`,\n );\n return this.getTags(registryHost, `library/${dockerRepository}`);\n }\n // JFrog Artifactory - Retry handling when resolving Docker Official Images\n // These follow the format of {{registryHost}}{{jFrogRepository}}/library/{{dockerRepository}}\n if (\n (err.statusCode === 404 || err.message === PAGE_NOT_FOUND_ERROR) &&\n isArtifactoryServer(err.response) &&\n dockerRepository.split('/').length === 2\n ) {\n logger.debug(\n `JFrog Artifactory: Retrying Tags for ${registryHost}/${dockerRepository} using library/ path between JFrog virtual repository and image`,\n );\n\n const dockerRepositoryParts = dockerRepository.split('/');\n const jfrogRepository = dockerRepositoryParts[0];\n const dockerImage = dockerRepositoryParts[1];\n\n return this.getTags(\n registryHost,\n `${jfrogRepository}/library/${dockerImage}`,\n );\n }\n if (err.statusCode === 429 && isDockerHost(registryHost)) {\n logger.warn(\n { registryHost, dockerRepository, err },\n 'docker registry failure: too many requests',\n );\n throw new ExternalHostError(err);\n }\n if (err.statusCode >= 500 && err.statusCode < 600) {\n logger.warn(\n { registryHost, dockerRepository, err },\n 'docker registry failure: internal error',\n );\n throw new ExternalHostError(err);\n }\n const errorCodes = ['ECONNRESET', 'ETIMEDOUT'];\n if (errorCodes.includes(err.code)) {\n logger.warn(\n { registryHost, dockerRepository, err },\n 'docker registry connection failure',\n );\n throw new ExternalHostError(err);\n }\n if (isDockerHost(registryHost)) {\n logger.info({ err }, 'Docker Hub lookup failure');\n }\n throw _err;\n }\n }\n\n getTags(\n registryHost: string,\n dockerRepository: string,\n ): Promise<string[] | undefined> {\n return withCache(\n {\n namespace: 'datasource-docker-tags',\n key: buildCacheKey(registryHost, dockerRepository),\n cacheable: registryHost === DOCKER_HUB,\n },\n () => this._getTags(registryHost, dockerRepository),\n );\n }\n\n /**\n * docker.getDigest\n *\n * The `newValue` supplied here should be a valid tag for the docker image.\n *\n * This function will:\n * - Look up a sha256 digest for a tag on its registry\n * - Return the digest as a string\n */\n private async _getDigest(\n { registryUrl, lookupName, packageName, currentDigest }: DigestConfig,\n newValue?: string,\n ): Promise<string | null> {\n let registryHost: string;\n let dockerRepository: string;\n if (registryUrl && lookupName) {\n // Reuse the resolved values from getReleases()\n registryHost = registryUrl;\n dockerRepository = lookupName;\n } else {\n // Resolve values independently\n ({ registryHost, dockerRepository } = getRegistryRepository(\n packageName,\n registryUrl!,\n ));\n }\n logger.debug(\n // TODO: types (#22198)\n `getDigest(${registryHost}, ${dockerRepository}, ${newValue})`,\n );\n const newTag = isNonEmptyString(newValue) ? newValue : 'latest';\n let digest: string | null = null;\n try {\n let architecture: string | null | undefined = null;\n if (currentDigest && isDockerDigest(currentDigest)) {\n architecture = await this.getImageArchitecture(\n registryHost,\n dockerRepository,\n currentDigest,\n );\n }\n\n let manifestResponse: HttpResponse | null = null;\n if (!architecture) {\n // Reuse the digest cached from the Docker Hub tag API\n if (registryHost === DOCKER_HUB) {\n const cache = await DockerHubCache.init(dockerRepository);\n const cachedDigest = cache.getDigestForTag(newTag);\n if (cachedDigest) {\n return cachedDigest;\n }\n }\n\n manifestResponse = await this.getManifestResponse(\n registryHost,\n dockerRepository,\n newTag,\n 'head',\n );\n\n if (\n manifestResponse &&\n hasKey('docker-content-digest', manifestResponse.headers)\n ) {\n digest =\n (manifestResponse.headers['docker-content-digest'] as string) ||\n null;\n }\n }\n\n if (\n isNonEmptyString(architecture) ||\n (manifestResponse &&\n !hasKey('docker-content-digest', manifestResponse.headers))\n ) {\n // Reuse the per-arch digest cached from the Docker Hub tag API\n if (isNonEmptyString(architecture) && registryHost === DOCKER_HUB) {\n const cache = await DockerHubCache.init(dockerRepository);\n const cachedDigest = cache.getArchDigestForTag(newTag, architecture);\n if (cachedDigest) {\n return cachedDigest;\n }\n }\n\n logger.debug(\n { registryHost, dockerRepository },\n 'Architecture-specific digest or missing docker-content-digest header - pulling full manifest',\n );\n manifestResponse = await this.getManifestResponse(\n registryHost,\n dockerRepository,\n newTag,\n );\n\n if (architecture && manifestResponse) {\n const parsed = ManifestJson.safeParse(manifestResponse.body);\n /* istanbul ignore else: hard to test */\n if (parsed.success) {\n const manifestList = parsed.data;\n if (\n manifestList.mediaType ===\n 'application/vnd.docker.distribution.manifest.list.v2+json' ||\n manifestList.mediaType ===\n 'application/vnd.oci.image.index.v1+json'\n ) {\n for (const manifest of manifestList.manifests) {\n if (manifest.platform?.architecture === architecture) {\n digest = manifest.digest;\n break;\n }\n }\n // TODO: return null if no matching architecture digest found\n // https://github.com/renovatebot/renovate/discussions/22639\n // NOTE: reaching the implicit else needs a manifest list with no\n // digest header. A coverage-ignore hint cannot suppress it on an\n // `else if`.\n } else if (\n hasKey('docker-content-digest', manifestResponse.headers)\n ) {\n // TODO: return null if no matching architecture, requires to fetch the config manifest\n // https://github.com/renovatebot/renovate/discussions/22639\n digest = manifestResponse.headers[\n 'docker-content-digest'\n ] as string;\n }\n } else {\n logger.debug(\n {\n registryHost,\n dockerRepository,\n newTag,\n body: manifestResponse.body,\n headers: manifestResponse.headers,\n err: parsed.error,\n },\n 'Failed to parse manifest response',\n );\n }\n }\n\n if (!digest) {\n logger.debug(\n { registryHost, dockerRepository, newTag },\n 'Extraction digest from manifest response body is deprecated',\n );\n digest = extractDigestFromResponseBody(manifestResponse!);\n }\n }\n\n if (\n !manifestResponse &&\n !dockerRepository.includes('/') &&\n !packageName.includes('/')\n ) {\n logger.debug(\n `Retrying Digest for ${registryHost}/${dockerRepository} using library/ prefix`,\n );\n return this.getDigest(\n {\n registryUrl,\n packageName: `library/${packageName}`,\n currentDigest,\n },\n newValue,\n );\n }\n\n if (manifestResponse) {\n // TODO: fix types (#22198)\n logger.debug(`Got docker digest ${digest!}`);\n }\n } catch (err) /* istanbul ignore next */ {\n if (err instanceof ExternalHostError) {\n throw err;\n }\n logger.debug(\n {\n err,\n packageName,\n newTag,\n },\n 'Unknown Error looking up docker image digest',\n );\n }\n return digest;\n }\n\n override getDigest(\n config: DigestConfig,\n newValue?: string,\n ): Promise<string | null> {\n const newTag = newValue ?? 'latest';\n const { registryHost, dockerRepository } = getRegistryRepository(\n config.packageName,\n config.registryUrl!,\n );\n return withCache(\n {\n namespace: 'datasource-docker-digest',\n key: buildCacheKey(\n registryHost,\n dockerRepository,\n newTag,\n config.currentDigest,\n ),\n fallback: true,\n shouldCacheResult: isNonEmptyString,\n },\n () => this._getDigest(config, newValue),\n );\n }\n\n private async _getDockerHubTags(\n dockerRepository: string,\n ): Promise<Release[] | null> {\n let url = `https://hub.docker.com/v2/repositories/${dockerRepository}/tags?page_size=1000&ordering=last_updated`;\n\n const cache = await DockerHubCache.init(dockerRepository);\n const maxPages = GlobalConfig.get('dockerMaxPages');\n const allowCrossOrigin = isCrossOriginPaginationAllowed(dockerDatasourceId);\n let page = 0,\n needNextPage = true;\n while (needNextPage && page < maxPages) {\n const { val, err } = await this.http\n .getJsonSafe(url, DockerHubTagsPage)\n .unwrap();\n\n if (err) {\n logger.debug({ err }, `Docker: error fetching data from DockerHub`);\n return null;\n }\n page++;\n const { results, next, count } = val;\n\n needNextPage = cache.reconcile(results, count);\n\n if (!next) {\n break;\n }\n\n // Only follow the `next` link when it's on the same origin, unless explicitly opted in\n const nextUrl = resolvePaginationUrl(url, next, allowCrossOrigin);\n if (!nextUrl) {\n logger.once.warn(\n { dockerRepository, nextUrl: next },\n 'Ignoring cross-origin or invalid Docker Hub tags pagination link',\n );\n break;\n }\n\n url = nextUrl;\n }\n\n await cache.save();\n\n const items = cache.getItems();\n return items.map(({ name: version, tag_last_pushed }) => {\n const release: Release = { version };\n\n const releaseTimestamp = asTimestamp(tag_last_pushed);\n if (releaseTimestamp) {\n release.releaseTimestamp = releaseTimestamp;\n }\n\n // Digest is intentionally not propagated — the Docker Hub tag API\n // returns the manifest-list digest, which would bypass arch-aware\n // resolution in `getDigest()`. `getDigest()` consults the same cache\n // as a shortcut when no arch resolution is needed.\n return release;\n });\n }\n\n getDockerHubTags(dockerRepository: string): Promise<Release[] | null> {\n return withCache(\n {\n namespace: 'datasource-docker-hub-tags',\n key: dockerRepository,\n },\n () => this._getDockerHubTags(dockerRepository),\n );\n }\n\n /**\n * docker.getReleases\n *\n * A docker image usually looks something like this: somehost.io/owner/repo:8.1.0-alpine\n * In the above:\n * - 'somehost.io' is the registry\n * - 'owner/repo' is the package name\n * - '8.1.0-alpine' is the tag\n *\n * This function will filter only tags that contain a semver version\n */\n private async _getReleases({\n packageName,\n registryUrl,\n }: GetReleasesConfig): Promise<ReleaseResult | null> {\n const { registryHost, dockerRepository } = getRegistryRepository(\n packageName,\n registryUrl!,\n );\n\n type TagsResultType = AsyncResult<\n Release[],\n NonNullable<Error | 'tags-error' | 'dockerhub-error'>\n >;\n\n const getTags = (): TagsResultType =>\n Result.wrapNullable(\n this.getTags(registryHost, dockerRepository),\n 'tags-error' as const,\n ).transform((tags) => tags.map((version) => ({ version })));\n\n const getDockerHubTags = (): TagsResultType =>\n Result.wrapNullable(\n this.getDockerHubTags(dockerRepository),\n 'dockerhub-error' as const,\n ).catch(getTags);\n\n const tagsResult =\n registryHost === DOCKER_HUB &&\n !getEnv().RENOVATE_X_DOCKER_HUB_TAGS_DISABLE\n ? getDockerHubTags()\n : getTags();\n\n const { val: releases, err } = await tagsResult.unwrap();\n if (err instanceof Error) {\n throw err;\n } else if (err) {\n return null;\n }\n\n const ret: ReleaseResult = {\n registryUrl: registryHost,\n releases,\n };\n if (dockerRepository !== packageName) {\n // This will be reused later if a getDigest() call is made\n ret.lookupName = dockerRepository;\n }\n\n const tags = releases.map((release) => release.version);\n const latestTag = tags.includes('latest')\n ? 'latest'\n : (findLatestStable(tags) ?? tags.at(-1));\n\n /* v8 ignore next -- TODO: add test */\n if (!latestTag) {\n return ret;\n }\n const labels = await this.getLabels(\n registryHost,\n dockerRepository,\n latestTag,\n );\n if (labels) {\n if (isNonEmptyString(labels[gitRefLabel])) {\n ret.gitRef = labels[gitRefLabel];\n }\n for (const label of sourceLabels) {\n if (isNonEmptyString(labels[label])) {\n ret.sourceUrl = labels[label];\n break;\n }\n }\n if (isNonEmptyString(labels[imageUrlLabel])) {\n ret.homepage = labels[imageUrlLabel];\n }\n }\n return ret;\n }\n\n getReleases(config: GetReleasesConfig): Promise<ReleaseResult | null> {\n const { registryHost, dockerRepository } = getRegistryRepository(\n config.packageName,\n config.registryUrl!,\n );\n return withCache(\n {\n namespace: 'datasource-docker-releases-v2',\n key: buildCacheKey(registryHost, dockerRepository),\n cacheable: registryHost === DOCKER_HUB,\n fallback: true,\n },\n () => this._getReleases(config),\n );\n }\n}\n"],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import { buildCacheKey } from "../../../util/cache/package/key.js";
1
2
  import { Datasource } from "../datasource.js";
2
3
  import { map } from "../../../util/promises.js";
3
4
  import { DotnetRuntimeReleases, DotnetSdkReleases, ReleasesIndex } from "./schema.js";
@@ -47,7 +48,7 @@ var DotnetVersionDatasource = class DotnetVersionDatasource extends Datasource {
47
48
  }
48
49
  getChannelReleases(releaseUrl, packageName) {
49
50
  return this.cached({
50
- key: `${releaseUrl}:${packageName}`,
51
+ key: buildCacheKey(releaseUrl, packageName),
51
52
  ttlMinutes: 1440,
52
53
  cacheable: true
53
54
  }, () => this.fetchChannelReleases(releaseUrl, packageName));
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["p.map"],"sources":["../../../../lib/modules/datasource/dotnet-version/index.ts"],"sourcesContent":["import * as p from '../../../util/promises.ts';\nimport { Datasource } from '../datasource.ts';\nimport type { GetReleasesConfig, Release, ReleaseResult } from '../types.ts';\nimport {\n DotnetRuntimeReleases,\n DotnetSdkReleases,\n ReleasesIndex,\n} from './schema.ts';\n\nexport class DotnetVersionDatasource extends Datasource {\n static readonly id = 'dotnet-version';\n\n constructor() {\n super(DotnetVersionDatasource.id);\n }\n\n override supportsCustomRegistry(_packageName: string): boolean {\n return false;\n }\n\n override getDefaultRegistryUrls(_packageName: string): string[] {\n return [\n 'https://dotnetcli.blob.core.windows.net/dotnet/release-metadata/releases-index.json',\n ];\n }\n\n override releaseTimestampSupport = true;\n override releaseTimestampNote =\n 'The release timestamp is determined from the `release-date` field in the results.';\n override readonly sourceUrlSupport = 'package';\n override readonly sourceUrlNote =\n 'We use the URL https://github.com/dotnet/sdk for the `dotnet-sdk` package and, the https://github.com/dotnet/runtime URL for the `dotnet-runtime` package.';\n\n private async fetchReleases({\n packageName,\n }: GetReleasesConfig): Promise<ReleaseResult | null> {\n if (!(packageName === 'dotnet-sdk' || packageName === 'dotnet-runtime')) {\n return null;\n }\n\n try {\n const registryUrl = this.getDefaultRegistryUrls('')[0];\n const { body: urls } = await this.http.getJson(\n registryUrl,\n ReleasesIndex,\n );\n\n const channelReleases = await p.map(\n urls,\n (url) => this.getChannelReleases(url, packageName),\n { concurrency: 1, stopOnError: true },\n );\n const releases = channelReleases.flat();\n\n const sourceUrl =\n packageName === 'dotnet-sdk'\n ? 'https://github.com/dotnet/sdk'\n : 'https://github.com/dotnet/runtime';\n\n return { releases, sourceUrl };\n } catch (err) {\n this.handleGenericErrors(err);\n }\n }\n\n getReleases(config: GetReleasesConfig): Promise<ReleaseResult | null> {\n return this.cached(\n {\n key: config.packageName,\n ttlMinutes: 1440,\n fallback: true,\n cacheable: true,\n },\n () => this.fetchReleases(config),\n );\n }\n\n private async fetchChannelReleases(\n releaseUrl: string,\n packageName: string,\n ): Promise<Release[]> {\n const schema =\n packageName === 'dotnet-sdk' ? DotnetSdkReleases : DotnetRuntimeReleases;\n return this.fetchJson(releaseUrl, schema);\n }\n\n getChannelReleases(\n releaseUrl: string,\n packageName: string,\n ): Promise<Release[]> {\n return this.cached(\n {\n key: `${releaseUrl}:${packageName}`,\n ttlMinutes: 1440,\n cacheable: true,\n },\n () => this.fetchChannelReleases(releaseUrl, packageName),\n );\n }\n}\n"],"mappings":";;;;AASA,IAAa,0BAAb,MAAa,gCAAgC,WAAW;CACtD,OAAgB,KAAK;CAErB,cAAc;EACZ,MAAM,wBAAwB,EAAE;CAClC;CAEA,uBAAgC,cAA+B;EAC7D,OAAO;CACT;CAEA,uBAAgC,cAAgC;EAC9D,OAAO,CACL,qFACF;CACF;CAEA,0BAAmC;CACnC,uBACE;CACF,mBAAqC;CACrC,gBACE;CAEF,MAAc,cAAc,EAC1B,eACmD;EACnD,IAAI,EAAE,gBAAgB,gBAAgB,gBAAgB,mBACpD,OAAO;EAGT,IAAI;GACF,MAAM,cAAc,KAAK,uBAAuB,EAAE,CAAC,CAAC;GACpD,MAAM,EAAE,MAAM,SAAS,MAAM,KAAK,KAAK,QACrC,aACA,aACF;GAcA,OAAO;IAAE,WAPQ,MALaA,IAC5B,OACC,QAAQ,KAAK,mBAAmB,KAAK,WAAW,GACjD;KAAE,aAAa;KAAG,aAAa;IAAK,CACtC,EAAA,CACiC,KAOjB;IAAG,WAJjB,gBAAgB,eACZ,kCACA;GAEuB;EAC/B,SAAS,KAAK;GACZ,KAAK,oBAAoB,GAAG;EAC9B;CACF;CAEA,YAAY,QAA0D;EACpE,OAAO,KAAK,OACV;GACE,KAAK,OAAO;GACZ,YAAY;GACZ,UAAU;GACV,WAAW;EACb,SACM,KAAK,cAAc,MAAM,CACjC;CACF;CAEA,MAAc,qBACZ,YACA,aACoB;EACpB,MAAM,SACJ,gBAAgB,eAAe,oBAAoB;EACrD,OAAO,KAAK,UAAU,YAAY,MAAM;CAC1C;CAEA,mBACE,YACA,aACoB;EACpB,OAAO,KAAK,OACV;GACE,KAAK,GAAG,WAAW,GAAG;GACtB,YAAY;GACZ,WAAW;EACb,SACM,KAAK,qBAAqB,YAAY,WAAW,CACzD;CACF;AACF"}
1
+ {"version":3,"file":"index.js","names":["p.map"],"sources":["../../../../lib/modules/datasource/dotnet-version/index.ts"],"sourcesContent":["import { buildCacheKey } from '../../../util/cache/package/key.ts';\nimport * as p from '../../../util/promises.ts';\nimport { Datasource } from '../datasource.ts';\nimport type { GetReleasesConfig, Release, ReleaseResult } from '../types.ts';\nimport {\n DotnetRuntimeReleases,\n DotnetSdkReleases,\n ReleasesIndex,\n} from './schema.ts';\n\nexport class DotnetVersionDatasource extends Datasource {\n static readonly id = 'dotnet-version';\n\n constructor() {\n super(DotnetVersionDatasource.id);\n }\n\n override supportsCustomRegistry(_packageName: string): boolean {\n return false;\n }\n\n override getDefaultRegistryUrls(_packageName: string): string[] {\n return [\n 'https://dotnetcli.blob.core.windows.net/dotnet/release-metadata/releases-index.json',\n ];\n }\n\n override releaseTimestampSupport = true;\n override releaseTimestampNote =\n 'The release timestamp is determined from the `release-date` field in the results.';\n override readonly sourceUrlSupport = 'package';\n override readonly sourceUrlNote =\n 'We use the URL https://github.com/dotnet/sdk for the `dotnet-sdk` package and, the https://github.com/dotnet/runtime URL for the `dotnet-runtime` package.';\n\n private async fetchReleases({\n packageName,\n }: GetReleasesConfig): Promise<ReleaseResult | null> {\n if (!(packageName === 'dotnet-sdk' || packageName === 'dotnet-runtime')) {\n return null;\n }\n\n try {\n const registryUrl = this.getDefaultRegistryUrls('')[0];\n const { body: urls } = await this.http.getJson(\n registryUrl,\n ReleasesIndex,\n );\n\n const channelReleases = await p.map(\n urls,\n (url) => this.getChannelReleases(url, packageName),\n { concurrency: 1, stopOnError: true },\n );\n const releases = channelReleases.flat();\n\n const sourceUrl =\n packageName === 'dotnet-sdk'\n ? 'https://github.com/dotnet/sdk'\n : 'https://github.com/dotnet/runtime';\n\n return { releases, sourceUrl };\n } catch (err) {\n this.handleGenericErrors(err);\n }\n }\n\n getReleases(config: GetReleasesConfig): Promise<ReleaseResult | null> {\n return this.cached(\n {\n key: config.packageName,\n ttlMinutes: 1440,\n fallback: true,\n cacheable: true,\n },\n () => this.fetchReleases(config),\n );\n }\n\n private async fetchChannelReleases(\n releaseUrl: string,\n packageName: string,\n ): Promise<Release[]> {\n const schema =\n packageName === 'dotnet-sdk' ? DotnetSdkReleases : DotnetRuntimeReleases;\n return this.fetchJson(releaseUrl, schema);\n }\n\n getChannelReleases(\n releaseUrl: string,\n packageName: string,\n ): Promise<Release[]> {\n return this.cached(\n {\n key: buildCacheKey(releaseUrl, packageName),\n ttlMinutes: 1440,\n cacheable: true,\n },\n () => this.fetchChannelReleases(releaseUrl, packageName),\n );\n }\n}\n"],"mappings":";;;;;AAUA,IAAa,0BAAb,MAAa,gCAAgC,WAAW;CACtD,OAAgB,KAAK;CAErB,cAAc;EACZ,MAAM,wBAAwB,EAAE;CAClC;CAEA,uBAAgC,cAA+B;EAC7D,OAAO;CACT;CAEA,uBAAgC,cAAgC;EAC9D,OAAO,CACL,qFACF;CACF;CAEA,0BAAmC;CACnC,uBACE;CACF,mBAAqC;CACrC,gBACE;CAEF,MAAc,cAAc,EAC1B,eACmD;EACnD,IAAI,EAAE,gBAAgB,gBAAgB,gBAAgB,mBACpD,OAAO;EAGT,IAAI;GACF,MAAM,cAAc,KAAK,uBAAuB,EAAE,CAAC,CAAC;GACpD,MAAM,EAAE,MAAM,SAAS,MAAM,KAAK,KAAK,QACrC,aACA,aACF;GAcA,OAAO;IAAE,WAPQ,MALaA,IAC5B,OACC,QAAQ,KAAK,mBAAmB,KAAK,WAAW,GACjD;KAAE,aAAa;KAAG,aAAa;IAAK,CACtC,EAAA,CACiC,KAOjB;IAAG,WAJjB,gBAAgB,eACZ,kCACA;GAEuB;EAC/B,SAAS,KAAK;GACZ,KAAK,oBAAoB,GAAG;EAC9B;CACF;CAEA,YAAY,QAA0D;EACpE,OAAO,KAAK,OACV;GACE,KAAK,OAAO;GACZ,YAAY;GACZ,UAAU;GACV,WAAW;EACb,SACM,KAAK,cAAc,MAAM,CACjC;CACF;CAEA,MAAc,qBACZ,YACA,aACoB;EACpB,MAAM,SACJ,gBAAgB,eAAe,oBAAoB;EACrD,OAAO,KAAK,UAAU,YAAY,MAAM;CAC1C;CAEA,mBACE,YACA,aACoB;EACpB,OAAO,KAAK,OACV;GACE,KAAK,cAAc,YAAY,WAAW;GAC1C,YAAY;GACZ,WAAW;EACb,SACM,KAAK,qBAAqB,YAAY,WAAW,CACzD;CACF;AACF"}
@@ -1,4 +1,5 @@
1
1
  import { joinUrlParts } from "../../../util/url.js";
2
+ import { buildCacheKey } from "../../../util/cache/package/key.js";
2
3
  import "../../versioning/elm/index.js";
3
4
  import { withCache } from "../../../util/cache/package/with-cache.js";
4
5
  import { Datasource } from "../datasource.js";
@@ -32,7 +33,7 @@ var ElmPackageDatasource = class ElmPackageDatasource extends Datasource {
32
33
  getReleases(config) {
33
34
  return withCache({
34
35
  namespace: `datasource-${ElmPackageDatasource.id}`,
35
- key: `${config.registryUrl}:${config.packageName}`,
36
+ key: buildCacheKey(config.registryUrl, config.packageName),
36
37
  fallback: true,
37
38
  cacheable: true
38
39
  }, () => this._getReleases(config));
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["baseUrl"],"sources":["../../../../lib/modules/datasource/elm-package/index.ts"],"sourcesContent":["import { withCache } from '../../../util/cache/package/with-cache.ts';\nimport { joinUrlParts } from '../../../util/url.ts';\nimport * as elmVersioning from '../../versioning/elm/index.ts';\nimport { Datasource } from '../datasource.ts';\nimport type { GetReleasesConfig, ReleaseResult } from '../types.ts';\nimport { ElmPackageReleases } from './schema.ts';\n\nexport class ElmPackageDatasource extends Datasource {\n static readonly id = 'elm-package';\n\n constructor() {\n super(ElmPackageDatasource.id);\n }\n\n override supportsCustomRegistry(_packageName: string): boolean {\n return false;\n }\n\n override getDefaultRegistryUrls(_packageName: string): string[] {\n return ['https://package.elm-lang.org'];\n }\n\n override readonly defaultVersioning = elmVersioning.id;\n\n override readonly releaseTimestampSupport = true;\n override readonly releaseTimestampNote =\n 'The release timestamp is determined from the Unix timestamp in the results.';\n\n override readonly sourceUrlSupport = 'package';\n override readonly sourceUrlNote =\n 'The source URL is determined from the package name using the GitHub pattern.';\n\n async _getReleases({\n packageName,\n registryUrl,\n }: GetReleasesConfig): Promise<ReleaseResult | null> {\n /* v8 ignore if -- should never happen */\n if (!registryUrl) {\n return null;\n }\n const baseUrl = registryUrl;\n const pkgUrl = joinUrlParts(\n baseUrl,\n 'packages',\n packageName,\n 'releases.json',\n );\n\n const result = await this.fetchJsonOrNull(pkgUrl, ElmPackageReleases);\n if (!result) {\n return null;\n }\n\n // Elm packages must be published from GitHub - the package name IS the GitHub repo path\n // (e.g., \"elm/core\" is published from github.com/elm/core)\n // This is enforced by the `elm publish` command\n if (packageName.includes('/')) {\n result.sourceUrl = `https://github.com/${packageName}`;\n }\n\n return result;\n }\n\n getReleases(config: GetReleasesConfig): Promise<ReleaseResult | null> {\n return withCache(\n {\n namespace: `datasource-${ElmPackageDatasource.id}`,\n key: `${config.registryUrl}:${config.packageName}`,\n fallback: true,\n cacheable: true,\n },\n () => this._getReleases(config),\n );\n }\n}\n"],"mappings":";;;;;;AAOA,IAAa,uBAAb,MAAa,6BAA6B,WAAW;CACnD,OAAgB,KAAK;CAErB,cAAc;EACZ,MAAM,qBAAqB,EAAE;CAC/B;CAEA,uBAAgC,cAA+B;EAC7D,OAAO;CACT;CAEA,uBAAgC,cAAgC;EAC9D,OAAO,CAAC,8BAA8B;CACxC;CAEA,oBAAsC;CAEtC,0BAA4C;CAC5C,uBACE;CAEF,mBAAqC;CACrC,gBACE;CAEF,MAAM,aAAa,EACjB,aACA,eACmD;;EAEnD,IAAI,CAAC,aACH,OAAO;EAGT,MAAM,SAAS,aACbA,aACA,YACA,aACA,eACF;EAEA,MAAM,SAAS,MAAM,KAAK,gBAAgB,QAAQ,kBAAkB;EACpE,IAAI,CAAC,QACH,OAAO;EAMT,IAAI,YAAY,SAAS,GAAG,GAC1B,OAAO,YAAY,sBAAsB;EAG3C,OAAO;CACT;CAEA,YAAY,QAA0D;EACpE,OAAO,UACL;GACE,WAAW,cAAc,qBAAqB;GAC9C,KAAK,GAAG,OAAO,YAAY,GAAG,OAAO;GACrC,UAAU;GACV,WAAW;EACb,SACM,KAAK,aAAa,MAAM,CAChC;CACF;AACF"}
1
+ {"version":3,"file":"index.js","names":["baseUrl"],"sources":["../../../../lib/modules/datasource/elm-package/index.ts"],"sourcesContent":["import { buildCacheKey } from '../../../util/cache/package/key.ts';\nimport { withCache } from '../../../util/cache/package/with-cache.ts';\nimport { joinUrlParts } from '../../../util/url.ts';\nimport * as elmVersioning from '../../versioning/elm/index.ts';\nimport { Datasource } from '../datasource.ts';\nimport type { GetReleasesConfig, ReleaseResult } from '../types.ts';\nimport { ElmPackageReleases } from './schema.ts';\n\nexport class ElmPackageDatasource extends Datasource {\n static readonly id = 'elm-package';\n\n constructor() {\n super(ElmPackageDatasource.id);\n }\n\n override supportsCustomRegistry(_packageName: string): boolean {\n return false;\n }\n\n override getDefaultRegistryUrls(_packageName: string): string[] {\n return ['https://package.elm-lang.org'];\n }\n\n override readonly defaultVersioning = elmVersioning.id;\n\n override readonly releaseTimestampSupport = true;\n override readonly releaseTimestampNote =\n 'The release timestamp is determined from the Unix timestamp in the results.';\n\n override readonly sourceUrlSupport = 'package';\n override readonly sourceUrlNote =\n 'The source URL is determined from the package name using the GitHub pattern.';\n\n async _getReleases({\n packageName,\n registryUrl,\n }: GetReleasesConfig): Promise<ReleaseResult | null> {\n /* v8 ignore if -- should never happen */\n if (!registryUrl) {\n return null;\n }\n const baseUrl = registryUrl;\n const pkgUrl = joinUrlParts(\n baseUrl,\n 'packages',\n packageName,\n 'releases.json',\n );\n\n const result = await this.fetchJsonOrNull(pkgUrl, ElmPackageReleases);\n if (!result) {\n return null;\n }\n\n // Elm packages must be published from GitHub - the package name IS the GitHub repo path\n // (e.g., \"elm/core\" is published from github.com/elm/core)\n // This is enforced by the `elm publish` command\n if (packageName.includes('/')) {\n result.sourceUrl = `https://github.com/${packageName}`;\n }\n\n return result;\n }\n\n getReleases(config: GetReleasesConfig): Promise<ReleaseResult | null> {\n return withCache(\n {\n namespace: `datasource-${ElmPackageDatasource.id}`,\n key: buildCacheKey(config.registryUrl, config.packageName),\n fallback: true,\n cacheable: true,\n },\n () => this._getReleases(config),\n );\n }\n}\n"],"mappings":";;;;;;;AAQA,IAAa,uBAAb,MAAa,6BAA6B,WAAW;CACnD,OAAgB,KAAK;CAErB,cAAc;EACZ,MAAM,qBAAqB,EAAE;CAC/B;CAEA,uBAAgC,cAA+B;EAC7D,OAAO;CACT;CAEA,uBAAgC,cAAgC;EAC9D,OAAO,CAAC,8BAA8B;CACxC;CAEA,oBAAsC;CAEtC,0BAA4C;CAC5C,uBACE;CAEF,mBAAqC;CACrC,gBACE;CAEF,MAAM,aAAa,EACjB,aACA,eACmD;;EAEnD,IAAI,CAAC,aACH,OAAO;EAGT,MAAM,SAAS,aACbA,aACA,YACA,aACA,eACF;EAEA,MAAM,SAAS,MAAM,KAAK,gBAAgB,QAAQ,kBAAkB;EACpE,IAAI,CAAC,QACH,OAAO;EAMT,IAAI,YAAY,SAAS,GAAG,GAC1B,OAAO,YAAY,sBAAsB;EAG3C,OAAO;CACT;CAEA,YAAY,QAA0D;EACpE,OAAO,UACL;GACE,WAAW,cAAc,qBAAqB;GAC9C,KAAK,cAAc,OAAO,aAAa,OAAO,WAAW;GACzD,UAAU;GACV,WAAW;EACb,SACM,KAAK,aAAa,MAAM,CAChC;CACF;AACF"}
@@ -1,5 +1,6 @@
1
1
  import { logger } from "../../../logger/index.js";
2
2
  import { joinUrlParts } from "../../../util/url.js";
3
+ import { buildCacheKey } from "../../../util/cache/package/key.js";
3
4
  import { Datasource } from "../datasource.js";
4
5
  import { datasource, registryUrl } from "./common.js";
5
6
  import { EndoflifeDateVersions } from "./schema.js";
@@ -27,7 +28,7 @@ var EndoflifeDateDatasource = class EndoflifeDateDatasource extends Datasource {
27
28
  }
28
29
  getReleases(config) {
29
30
  return this.cached({
30
- key: `${config.registryUrl}:${config.packageName}`,
31
+ key: buildCacheKey(config.registryUrl, config.packageName),
31
32
  fallback: true
32
33
  }, () => this.fetchReleases(config));
33
34
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../../lib/modules/datasource/endoflife-date/index.ts"],"sourcesContent":["import { isNonEmptyString } from '@sindresorhus/is';\nimport { logger } from '../../../logger/index.ts';\nimport { joinUrlParts } from '../../../util/url.ts';\nimport { Datasource } from '../datasource.ts';\nimport type { GetReleasesConfig, ReleaseResult } from '../types.ts';\nimport { datasource, registryUrl } from './common.ts';\nimport { EndoflifeDateVersions } from './schema.ts';\n\nexport class EndoflifeDateDatasource extends Datasource {\n static readonly id = datasource;\n\n override getDefaultRegistryUrls(_packageName: string): string[] {\n return [registryUrl];\n }\n override readonly defaultVersioning = 'loose';\n\n override readonly releaseTimestampSupport = true;\n override readonly releaseTimestampNote =\n 'The release timestamp is determined from the `releaseDate` field in the results.';\n\n constructor() {\n super(EndoflifeDateDatasource.id);\n }\n\n private async fetchReleases({\n registryUrl,\n packageName,\n }: GetReleasesConfig): Promise<ReleaseResult | null> {\n if (!isNonEmptyString(registryUrl)) {\n return null;\n }\n\n logger.trace(`${datasource}.getReleases(${registryUrl}, ${packageName})`);\n\n const result: ReleaseResult = {\n releases: [],\n };\n\n const url = joinUrlParts(registryUrl, `${packageName}.json`);\n\n const body = await this.fetchJson(url, EndoflifeDateVersions);\n\n result.releases.push(...body);\n\n return result.releases.length ? result : null;\n }\n\n getReleases(config: GetReleasesConfig): Promise<ReleaseResult | null> {\n return this.cached(\n {\n // TODO: types (#22198)\n key: `${config.registryUrl!}:${config.packageName}`,\n fallback: true,\n },\n () => this.fetchReleases(config),\n );\n }\n}\n"],"mappings":";;;;;;;AAQA,IAAa,0BAAb,MAAa,gCAAgC,WAAW;CACtD,OAAgB,KAAK;CAErB,uBAAgC,cAAgC;EAC9D,OAAO,CAAC,WAAW;CACrB;CACA,oBAAsC;CAEtC,0BAA4C;CAC5C,uBACE;CAEF,cAAc;EACZ,MAAM,wBAAwB,EAAE;CAClC;CAEA,MAAc,cAAc,EAC1B,aACA,eACmD;EACnD,IAAI,CAAC,iBAAiB,WAAW,GAC/B,OAAO;EAGT,OAAO,MAAM,GAAG,WAAW,eAAe,YAAY,IAAI,YAAY,EAAE;EAExE,MAAM,SAAwB,EAC5B,UAAU,CAAC,EACb;EAEA,MAAM,MAAM,aAAa,aAAa,GAAG,YAAY,MAAM;EAE3D,MAAM,OAAO,MAAM,KAAK,UAAU,KAAK,qBAAqB;EAE5D,OAAO,SAAS,KAAK,GAAG,IAAI;EAE5B,OAAO,OAAO,SAAS,SAAS,SAAS;CAC3C;CAEA,YAAY,QAA0D;EACpE,OAAO,KAAK,OACV;GAEE,KAAK,GAAG,OAAO,YAAa,GAAG,OAAO;GACtC,UAAU;EACZ,SACM,KAAK,cAAc,MAAM,CACjC;CACF;AACF"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../../lib/modules/datasource/endoflife-date/index.ts"],"sourcesContent":["import { isNonEmptyString } from '@sindresorhus/is';\nimport { logger } from '../../../logger/index.ts';\nimport { buildCacheKey } from '../../../util/cache/package/key.ts';\nimport { joinUrlParts } from '../../../util/url.ts';\nimport { Datasource } from '../datasource.ts';\nimport type { GetReleasesConfig, ReleaseResult } from '../types.ts';\nimport { datasource, registryUrl } from './common.ts';\nimport { EndoflifeDateVersions } from './schema.ts';\n\nexport class EndoflifeDateDatasource extends Datasource {\n static readonly id = datasource;\n\n override getDefaultRegistryUrls(_packageName: string): string[] {\n return [registryUrl];\n }\n override readonly defaultVersioning = 'loose';\n\n override readonly releaseTimestampSupport = true;\n override readonly releaseTimestampNote =\n 'The release timestamp is determined from the `releaseDate` field in the results.';\n\n constructor() {\n super(EndoflifeDateDatasource.id);\n }\n\n private async fetchReleases({\n registryUrl,\n packageName,\n }: GetReleasesConfig): Promise<ReleaseResult | null> {\n if (!isNonEmptyString(registryUrl)) {\n return null;\n }\n\n logger.trace(`${datasource}.getReleases(${registryUrl}, ${packageName})`);\n\n const result: ReleaseResult = {\n releases: [],\n };\n\n const url = joinUrlParts(registryUrl, `${packageName}.json`);\n\n const body = await this.fetchJson(url, EndoflifeDateVersions);\n\n result.releases.push(...body);\n\n return result.releases.length ? result : null;\n }\n\n getReleases(config: GetReleasesConfig): Promise<ReleaseResult | null> {\n return this.cached(\n {\n key: buildCacheKey(config.registryUrl, config.packageName),\n fallback: true,\n },\n () => this.fetchReleases(config),\n );\n }\n}\n"],"mappings":";;;;;;;;AASA,IAAa,0BAAb,MAAa,gCAAgC,WAAW;CACtD,OAAgB,KAAK;CAErB,uBAAgC,cAAgC;EAC9D,OAAO,CAAC,WAAW;CACrB;CACA,oBAAsC;CAEtC,0BAA4C;CAC5C,uBACE;CAEF,cAAc;EACZ,MAAM,wBAAwB,EAAE;CAClC;CAEA,MAAc,cAAc,EAC1B,aACA,eACmD;EACnD,IAAI,CAAC,iBAAiB,WAAW,GAC/B,OAAO;EAGT,OAAO,MAAM,GAAG,WAAW,eAAe,YAAY,IAAI,YAAY,EAAE;EAExE,MAAM,SAAwB,EAC5B,UAAU,CAAC,EACb;EAEA,MAAM,MAAM,aAAa,aAAa,GAAG,YAAY,MAAM;EAE3D,MAAM,OAAO,MAAM,KAAK,UAAU,KAAK,qBAAqB;EAE5D,OAAO,SAAS,KAAK,GAAG,IAAI;EAE5B,OAAO,OAAO,SAAS,SAAS,SAAS;CAC3C;CAEA,YAAY,QAA0D;EACpE,OAAO,KAAK,OACV;GACE,KAAK,cAAc,OAAO,aAAa,OAAO,WAAW;GACzD,UAAU;EACZ,SACM,KAAK,cAAc,MAAM,CACjC;CACF;AACF"}
@@ -1,5 +1,6 @@
1
1
  import { regEx } from "../../../util/regex.js";
2
2
  import { ensureTrailingSlash, joinUrlParts } from "../../../util/url.js";
3
+ import { buildCacheKey } from "../../../util/cache/package/key.js";
3
4
  import { id } from "../../versioning/pep440/index.js";
4
5
  import { Datasource } from "../datasource.js";
5
6
  import { map } from "../../../util/promises.js";
@@ -46,7 +47,7 @@ var GalaxyCollectionDatasource = class GalaxyCollectionDatasource extends Dataso
46
47
  }
47
48
  getReleases(config) {
48
49
  return this.cached({
49
- key: `getReleases:${config.registryUrl}:${config.packageName}`,
50
+ key: buildCacheKey("getReleases", config.registryUrl, config.packageName),
50
51
  fallback: true
51
52
  }, () => this.fetchReleases(config));
52
53
  }
@@ -66,7 +67,7 @@ var GalaxyCollectionDatasource = class GalaxyCollectionDatasource extends Dataso
66
67
  }
67
68
  getVersionDetails(versionsUrl, basicRelease) {
68
69
  return this.cached({
69
- key: `getVersionDetails:${versionsUrl}:${basicRelease.version}`,
70
+ key: buildCacheKey("getVersionDetails", versionsUrl, basicRelease.version),
70
71
  ttlMinutes: 10080
71
72
  }, () => this.fetchVersionDetails(versionsUrl, basicRelease));
72
73
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["pep440Versioning.id","p.map"],"sources":["../../../../lib/modules/datasource/galaxy-collection/index.ts"],"sourcesContent":["import { isTruthy } from '@sindresorhus/is';\nimport * as p from '../../../util/promises.ts';\nimport { regEx } from '../../../util/regex.ts';\nimport { ensureTrailingSlash, joinUrlParts } from '../../../util/url.ts';\nimport * as pep440Versioning from '../../versioning/pep440/index.ts';\nimport { Datasource } from '../datasource.ts';\nimport type { GetReleasesConfig, Release, ReleaseResult } from '../types.ts';\nimport {\n GalaxyV3,\n GalaxyV3DetailedVersion,\n GalaxyV3Versions,\n} from './schema.ts';\n\nconst ansibleProtocolRegex = regEx(/^\\S+\\/api\\/ansible\\/.+/);\nconst repositoryRegex = regEx(\n /^\\S+\\/api\\/galaxy\\/content\\/(?<repository>[^/]+)/,\n);\n\nexport class GalaxyCollectionDatasource extends Datasource {\n static readonly id = 'galaxy-collection';\n\n constructor() {\n super(GalaxyCollectionDatasource.id);\n }\n\n override supportsCustomRegistry(_packageName: string): boolean {\n return true;\n }\n\n override readonly registryStrategy = 'hunt';\n\n override getDefaultRegistryUrls(_packageName: string): string[] {\n return ['https://galaxy.ansible.com/api/'];\n }\n\n override readonly defaultVersioning = pep440Versioning.id;\n\n override readonly releaseTimestampSupport = true;\n override releaseTimestampNote =\n 'The release timestamp is determined from the `created_at` field in the results.';\n // sourceUrl is returned in each release as well as the ReleaseResult\n // the one present in release result is the sourceUrl of the latest release\n override readonly sourceUrlSupport = 'release';\n override readonly sourceUrlNote =\n 'The `sourceUrl` is determined from the `repository` field in the results.';\n\n private async fetchReleases({\n packageName,\n registryUrl,\n }: GetReleasesConfig): Promise<ReleaseResult | null> {\n const baseUrl = this.constructBaseUrl(registryUrl!, packageName);\n\n const baseProject = await this.fetchJsonOrNull(baseUrl, GalaxyV3);\n if (!baseProject) {\n return null;\n }\n\n const versionsUrl = ensureTrailingSlash(joinUrlParts(baseUrl, 'versions'));\n\n const rawReleases = await this.fetchJsonOrNull(\n versionsUrl,\n GalaxyV3Versions,\n );\n if (!rawReleases) {\n return null;\n }\n\n const releases = rawReleases.map((value) => {\n return {\n ...value,\n isDeprecated: baseProject.deprecated,\n };\n });\n\n // asynchronously get release details\n const enrichedReleases = await p.map(\n releases,\n (release) => this.getVersionDetails(versionsUrl, release),\n { concurrency: 4 },\n );\n\n // filter failed versions\n const filteredReleases = enrichedReleases.filter(isTruthy);\n // extract base information which are only provided on the release from the newest release\n\n // Find the source URL of the highest version release\n const sourceUrlOfHighestRelease = enrichedReleases.find(\n (release) => baseProject.highest_version.version === release.version,\n )?.sourceUrl;\n\n return {\n releases: filteredReleases,\n sourceUrl: sourceUrlOfHighestRelease,\n };\n }\n\n getReleases(config: GetReleasesConfig): Promise<ReleaseResult | null> {\n return this.cached(\n {\n key: `getReleases:${config.registryUrl}:${config.packageName}`,\n fallback: true,\n },\n () => this.fetchReleases(config),\n );\n }\n\n constructBaseUrl(registryUrl: string, packageName: string): string {\n const [namespace, projectName] = packageName.split('.');\n if (ansibleProtocolRegex.test(registryUrl)) {\n return ensureTrailingSlash(\n joinUrlParts(registryUrl, 'api/v3/collections', namespace, projectName),\n );\n }\n const repository =\n repositoryRegex.exec(registryUrl)?.groups?.repository ?? 'published';\n return ensureTrailingSlash(\n joinUrlParts(\n registryUrl,\n 'v3/plugin/ansible/content',\n repository,\n 'collections/index',\n namespace,\n projectName,\n ),\n );\n }\n\n private async fetchVersionDetails(\n versionsUrl: string,\n basicRelease: Release,\n ): Promise<Release> {\n const detailedVersionUrl = ensureTrailingSlash(\n joinUrlParts(versionsUrl, basicRelease.version),\n );\n const rawDetailedVersion = await this.fetchJson(\n detailedVersionUrl,\n GalaxyV3DetailedVersion,\n );\n\n return {\n ...rawDetailedVersion,\n isDeprecated: basicRelease.isDeprecated,\n releaseTimestamp: basicRelease.releaseTimestamp,\n };\n }\n\n getVersionDetails(\n versionsUrl: string,\n basicRelease: Release,\n ): Promise<Release> {\n return this.cached(\n {\n key: `getVersionDetails:${versionsUrl}:${basicRelease.version}`,\n ttlMinutes: 10080, // 1 week\n },\n () => this.fetchVersionDetails(versionsUrl, basicRelease),\n );\n }\n}\n"],"mappings":";;;;;;;;AAaA,MAAM,uBAAuB,MAAM,wBAAwB;AAC3D,MAAM,kBAAkB,MACtB,kDACF;AAEA,IAAa,6BAAb,MAAa,mCAAmC,WAAW;CACzD,OAAgB,KAAK;CAErB,cAAc;EACZ,MAAM,2BAA2B,EAAE;CACrC;CAEA,uBAAgC,cAA+B;EAC7D,OAAO;CACT;CAEA,mBAAqC;CAErC,uBAAgC,cAAgC;EAC9D,OAAO,CAAC,iCAAiC;CAC3C;CAEA,oBAAsCA;CAEtC,0BAA4C;CAC5C,uBACE;CAGF,mBAAqC;CACrC,gBACE;CAEF,MAAc,cAAc,EAC1B,aACA,eACmD;EACnD,MAAM,UAAU,KAAK,iBAAiB,aAAc,WAAW;EAE/D,MAAM,cAAc,MAAM,KAAK,gBAAgB,SAAS,QAAQ;EAChE,IAAI,CAAC,aACH,OAAO;EAGT,MAAM,cAAc,oBAAoB,aAAa,SAAS,UAAU,CAAC;EAEzE,MAAM,cAAc,MAAM,KAAK,gBAC7B,aACA,gBACF;EACA,IAAI,CAAC,aACH,OAAO;EAGT,MAAM,WAAW,YAAY,KAAK,UAAU;GAC1C,OAAO;IACL,GAAG;IACH,cAAc,YAAY;GAC5B;EACF,CAAC;EAGD,MAAM,mBAAmB,MAAMC,IAC7B,WACC,YAAY,KAAK,kBAAkB,aAAa,OAAO,GACxD,EAAE,aAAa,EAAE,CACnB;EAWA,OAAO;GACL,UATuB,iBAAiB,OAAO,QAStB;GACzB,WANgC,iBAAiB,MAChD,YAAY,YAAY,gBAAgB,YAAY,QAAQ,OAC/D,CAAC,EAAE;EAKH;CACF;CAEA,YAAY,QAA0D;EACpE,OAAO,KAAK,OACV;GACE,KAAK,eAAe,OAAO,YAAY,GAAG,OAAO;GACjD,UAAU;EACZ,SACM,KAAK,cAAc,MAAM,CACjC;CACF;CAEA,iBAAiB,aAAqB,aAA6B;EACjE,MAAM,CAAC,WAAW,eAAe,YAAY,MAAM,GAAG;EACtD,IAAI,qBAAqB,KAAK,WAAW,GACvC,OAAO,oBACL,aAAa,aAAa,sBAAsB,WAAW,WAAW,CACxE;EAEF,MAAM,aACJ,gBAAgB,KAAK,WAAW,CAAC,EAAE,QAAQ,cAAc;EAC3D,OAAO,oBACL,aACE,aACA,6BACA,YACA,qBACA,WACA,WACF,CACF;CACF;CAEA,MAAc,oBACZ,aACA,cACkB;EAClB,MAAM,qBAAqB,oBACzB,aAAa,aAAa,aAAa,OAAO,CAChD;EAMA,OAAO;GACL,GAAG,MAN4B,KAAK,UACpC,oBACA,uBACF;GAIE,cAAc,aAAa;GAC3B,kBAAkB,aAAa;EACjC;CACF;CAEA,kBACE,aACA,cACkB;EAClB,OAAO,KAAK,OACV;GACE,KAAK,qBAAqB,YAAY,GAAG,aAAa;GACtD,YAAY;EACd,SACM,KAAK,oBAAoB,aAAa,YAAY,CAC1D;CACF;AACF"}
1
+ {"version":3,"file":"index.js","names":["pep440Versioning.id","p.map"],"sources":["../../../../lib/modules/datasource/galaxy-collection/index.ts"],"sourcesContent":["import { isTruthy } from '@sindresorhus/is';\nimport { buildCacheKey } from '../../../util/cache/package/key.ts';\nimport * as p from '../../../util/promises.ts';\nimport { regEx } from '../../../util/regex.ts';\nimport { ensureTrailingSlash, joinUrlParts } from '../../../util/url.ts';\nimport * as pep440Versioning from '../../versioning/pep440/index.ts';\nimport { Datasource } from '../datasource.ts';\nimport type { GetReleasesConfig, Release, ReleaseResult } from '../types.ts';\nimport {\n GalaxyV3,\n GalaxyV3DetailedVersion,\n GalaxyV3Versions,\n} from './schema.ts';\n\nconst ansibleProtocolRegex = regEx(/^\\S+\\/api\\/ansible\\/.+/);\nconst repositoryRegex = regEx(\n /^\\S+\\/api\\/galaxy\\/content\\/(?<repository>[^/]+)/,\n);\n\nexport class GalaxyCollectionDatasource extends Datasource {\n static readonly id = 'galaxy-collection';\n\n constructor() {\n super(GalaxyCollectionDatasource.id);\n }\n\n override supportsCustomRegistry(_packageName: string): boolean {\n return true;\n }\n\n override readonly registryStrategy = 'hunt';\n\n override getDefaultRegistryUrls(_packageName: string): string[] {\n return ['https://galaxy.ansible.com/api/'];\n }\n\n override readonly defaultVersioning = pep440Versioning.id;\n\n override readonly releaseTimestampSupport = true;\n override releaseTimestampNote =\n 'The release timestamp is determined from the `created_at` field in the results.';\n // sourceUrl is returned in each release as well as the ReleaseResult\n // the one present in release result is the sourceUrl of the latest release\n override readonly sourceUrlSupport = 'release';\n override readonly sourceUrlNote =\n 'The `sourceUrl` is determined from the `repository` field in the results.';\n\n private async fetchReleases({\n packageName,\n registryUrl,\n }: GetReleasesConfig): Promise<ReleaseResult | null> {\n const baseUrl = this.constructBaseUrl(registryUrl!, packageName);\n\n const baseProject = await this.fetchJsonOrNull(baseUrl, GalaxyV3);\n if (!baseProject) {\n return null;\n }\n\n const versionsUrl = ensureTrailingSlash(joinUrlParts(baseUrl, 'versions'));\n\n const rawReleases = await this.fetchJsonOrNull(\n versionsUrl,\n GalaxyV3Versions,\n );\n if (!rawReleases) {\n return null;\n }\n\n const releases = rawReleases.map((value) => {\n return {\n ...value,\n isDeprecated: baseProject.deprecated,\n };\n });\n\n // asynchronously get release details\n const enrichedReleases = await p.map(\n releases,\n (release) => this.getVersionDetails(versionsUrl, release),\n { concurrency: 4 },\n );\n\n // filter failed versions\n const filteredReleases = enrichedReleases.filter(isTruthy);\n // extract base information which are only provided on the release from the newest release\n\n // Find the source URL of the highest version release\n const sourceUrlOfHighestRelease = enrichedReleases.find(\n (release) => baseProject.highest_version.version === release.version,\n )?.sourceUrl;\n\n return {\n releases: filteredReleases,\n sourceUrl: sourceUrlOfHighestRelease,\n };\n }\n\n getReleases(config: GetReleasesConfig): Promise<ReleaseResult | null> {\n return this.cached(\n {\n key: buildCacheKey(\n 'getReleases',\n config.registryUrl,\n config.packageName,\n ),\n fallback: true,\n },\n () => this.fetchReleases(config),\n );\n }\n\n constructBaseUrl(registryUrl: string, packageName: string): string {\n const [namespace, projectName] = packageName.split('.');\n if (ansibleProtocolRegex.test(registryUrl)) {\n return ensureTrailingSlash(\n joinUrlParts(registryUrl, 'api/v3/collections', namespace, projectName),\n );\n }\n const repository =\n repositoryRegex.exec(registryUrl)?.groups?.repository ?? 'published';\n return ensureTrailingSlash(\n joinUrlParts(\n registryUrl,\n 'v3/plugin/ansible/content',\n repository,\n 'collections/index',\n namespace,\n projectName,\n ),\n );\n }\n\n private async fetchVersionDetails(\n versionsUrl: string,\n basicRelease: Release,\n ): Promise<Release> {\n const detailedVersionUrl = ensureTrailingSlash(\n joinUrlParts(versionsUrl, basicRelease.version),\n );\n const rawDetailedVersion = await this.fetchJson(\n detailedVersionUrl,\n GalaxyV3DetailedVersion,\n );\n\n return {\n ...rawDetailedVersion,\n isDeprecated: basicRelease.isDeprecated,\n releaseTimestamp: basicRelease.releaseTimestamp,\n };\n }\n\n getVersionDetails(\n versionsUrl: string,\n basicRelease: Release,\n ): Promise<Release> {\n return this.cached(\n {\n key: buildCacheKey(\n 'getVersionDetails',\n versionsUrl,\n basicRelease.version,\n ),\n ttlMinutes: 10080, // 1 week\n },\n () => this.fetchVersionDetails(versionsUrl, basicRelease),\n );\n }\n}\n"],"mappings":";;;;;;;;;AAcA,MAAM,uBAAuB,MAAM,wBAAwB;AAC3D,MAAM,kBAAkB,MACtB,kDACF;AAEA,IAAa,6BAAb,MAAa,mCAAmC,WAAW;CACzD,OAAgB,KAAK;CAErB,cAAc;EACZ,MAAM,2BAA2B,EAAE;CACrC;CAEA,uBAAgC,cAA+B;EAC7D,OAAO;CACT;CAEA,mBAAqC;CAErC,uBAAgC,cAAgC;EAC9D,OAAO,CAAC,iCAAiC;CAC3C;CAEA,oBAAsCA;CAEtC,0BAA4C;CAC5C,uBACE;CAGF,mBAAqC;CACrC,gBACE;CAEF,MAAc,cAAc,EAC1B,aACA,eACmD;EACnD,MAAM,UAAU,KAAK,iBAAiB,aAAc,WAAW;EAE/D,MAAM,cAAc,MAAM,KAAK,gBAAgB,SAAS,QAAQ;EAChE,IAAI,CAAC,aACH,OAAO;EAGT,MAAM,cAAc,oBAAoB,aAAa,SAAS,UAAU,CAAC;EAEzE,MAAM,cAAc,MAAM,KAAK,gBAC7B,aACA,gBACF;EACA,IAAI,CAAC,aACH,OAAO;EAGT,MAAM,WAAW,YAAY,KAAK,UAAU;GAC1C,OAAO;IACL,GAAG;IACH,cAAc,YAAY;GAC5B;EACF,CAAC;EAGD,MAAM,mBAAmB,MAAMC,IAC7B,WACC,YAAY,KAAK,kBAAkB,aAAa,OAAO,GACxD,EAAE,aAAa,EAAE,CACnB;EAWA,OAAO;GACL,UATuB,iBAAiB,OAAO,QAStB;GACzB,WANgC,iBAAiB,MAChD,YAAY,YAAY,gBAAgB,YAAY,QAAQ,OAC/D,CAAC,EAAE;EAKH;CACF;CAEA,YAAY,QAA0D;EACpE,OAAO,KAAK,OACV;GACE,KAAK,cACH,eACA,OAAO,aACP,OAAO,WACT;GACA,UAAU;EACZ,SACM,KAAK,cAAc,MAAM,CACjC;CACF;CAEA,iBAAiB,aAAqB,aAA6B;EACjE,MAAM,CAAC,WAAW,eAAe,YAAY,MAAM,GAAG;EACtD,IAAI,qBAAqB,KAAK,WAAW,GACvC,OAAO,oBACL,aAAa,aAAa,sBAAsB,WAAW,WAAW,CACxE;EAEF,MAAM,aACJ,gBAAgB,KAAK,WAAW,CAAC,EAAE,QAAQ,cAAc;EAC3D,OAAO,oBACL,aACE,aACA,6BACA,YACA,qBACA,WACA,WACF,CACF;CACF;CAEA,MAAc,oBACZ,aACA,cACkB;EAClB,MAAM,qBAAqB,oBACzB,aAAa,aAAa,aAAa,OAAO,CAChD;EAMA,OAAO;GACL,GAAG,MAN4B,KAAK,UACpC,oBACA,uBACF;GAIE,cAAc,aAAa;GAC3B,kBAAkB,aAAa;EACjC;CACF;CAEA,kBACE,aACA,cACkB;EAClB,OAAO,KAAK,OACV;GACE,KAAK,cACH,qBACA,aACA,aAAa,OACf;GACA,YAAY;EACd,SACM,KAAK,oBAAoB,aAAa,YAAY,CAC1D;CACF;AACF"}
@@ -1,9 +1,10 @@
1
+ import { buildCacheKey } from "../../util/cache/package/key.js";
1
2
  import { Datasource } from "./datasource.js";
2
3
  //#region lib/modules/datasource/git-host-tags.ts
3
4
  /**
4
5
  * Base class for the `*-tags` datasources of git hosting providers.
5
6
  *
6
- * It owns the package cache wrappers and the `<registryUrl>:<repo>:<type>`
7
+ * It owns the package cache wrappers and the `<registryUrl>:<repo>:<type>:<tag>`
7
8
  * cache key convention shared by all of them, so that subclasses only have to
8
9
  * implement the provider specific API calls.
9
10
  *
@@ -11,8 +12,8 @@ import { Datasource } from "./datasource.js";
11
12
  * {@link GitHostTagsDigestDatasource} instead.
12
13
  */
13
14
  var GitHostTagsDatasource = class extends Datasource {
14
- getCacheKey(registryUrl, repo, type) {
15
- return `${this.getRegistryUrl(registryUrl)}:${repo}:${type}`;
15
+ getCacheKey(registryUrl, repo, type, tag) {
16
+ return buildCacheKey(this.getRegistryUrl(registryUrl), repo, type, tag);
16
17
  }
17
18
  getReleases(config) {
18
19
  return this.cached({
@@ -41,11 +42,11 @@ var GitHostTagsDatasource = class extends Datasource {
41
42
  */
42
43
  var GitHostTagsDigestDatasource = class extends GitHostTagsDatasource {
43
44
  getTagCommit(registryUrl, repo, tag) {
44
- return this.cached({ key: this.getCacheKey(registryUrl, repo, `tag-${tag}`) }, () => this.fetchTagCommit(registryUrl, repo, tag));
45
+ return this.cached({ key: this.getCacheKey(registryUrl, repo, "tag", tag) }, () => this.fetchTagCommit(registryUrl, repo, tag));
45
46
  }
46
47
  getDigest(config, newValue) {
47
48
  return this.cached({
48
- key: this.getCacheKey(config.registryUrl, config.packageName, "digest"),
49
+ key: this.getCacheKey(config.registryUrl, config.packageName, "digest", newValue),
49
50
  fallback: true
50
51
  }, () => this.fetchDigest(config, newValue));
51
52
  }
@@ -1 +1 @@
1
- {"version":3,"file":"git-host-tags.js","names":[],"sources":["../../../lib/modules/datasource/git-host-tags.ts"],"sourcesContent":["import type { Http } from '../../util/http/index.ts';\nimport { Datasource } from './datasource.ts';\nimport type {\n DigestConfig,\n GetReleasesConfig,\n GitHostTag,\n ReleaseResult,\n} from './types.ts';\n\n/**\n * Base class for the `*-tags` datasources of git hosting providers.\n *\n * It owns the package cache wrappers and the `<registryUrl>:<repo>:<type>`\n * cache key convention shared by all of them, so that subclasses only have to\n * implement the provider specific API calls.\n *\n * Subclasses that also support digest lookups should extend\n * {@link GitHostTagsDigestDatasource} instead.\n */\nexport abstract class GitHostTagsDatasource<\n H extends Http = Http,\n> extends Datasource<H> {\n /**\n * Normalizes the registry URL, applying the datasource default and stripping\n * any API path suffix.\n */\n protected abstract getRegistryUrl(registryUrl?: string): string;\n\n /** Browser URL of the repository. */\n protected abstract getSourceUrl(\n packageName: string,\n registryUrl?: string,\n ): string;\n\n /** Fetches the tags of the repository. */\n protected abstract fetchTags(\n config: GetReleasesConfig,\n ): Promise<GitHostTag[] | null>;\n\n protected getCacheKey(\n registryUrl: string | undefined,\n repo: string,\n type: string,\n ): string {\n return `${this.getRegistryUrl(registryUrl)}:${repo}:${type}`;\n }\n\n getReleases(config: GetReleasesConfig): Promise<ReleaseResult | null> {\n return this.cached(\n {\n key: this.getCacheKey(config.registryUrl, config.packageName, 'tags'),\n fallback: true,\n },\n () => this.fetchReleases(config),\n );\n }\n\n protected async fetchReleases(\n config: GetReleasesConfig,\n ): Promise<ReleaseResult | null> {\n const { packageName, registryUrl } = config;\n\n const tags = await this.fetchTags(config);\n if (!tags) {\n return null;\n }\n\n return {\n sourceUrl: this.getSourceUrl(packageName, registryUrl),\n registryUrl: this.getRegistryUrl(registryUrl),\n releases: tags.map((tag) => ({ ...tag, gitRef: tag.version })),\n };\n }\n}\n\n/**\n * Base class for the `*-tags` datasources of git hosting providers which also\n * resolve digests: the commit of the given tag, or the latest commit of the\n * default branch when no tag is given.\n */\nexport abstract class GitHostTagsDigestDatasource<\n H extends Http = Http,\n> extends GitHostTagsDatasource<H> {\n /** Fetches the commit hash the given tag points at. */\n protected abstract fetchTagCommit(\n registryUrl: string | undefined,\n repo: string,\n tag: string,\n ): Promise<string | null>;\n\n /** Fetches the latest commit of the repository default branch. */\n protected abstract fetchLatestCommit(\n registryUrl: string | undefined,\n repo: string,\n ): Promise<string | null>;\n\n protected getTagCommit(\n registryUrl: string | undefined,\n repo: string,\n tag: string,\n ): Promise<string | null> {\n return this.cached(\n { key: this.getCacheKey(registryUrl, repo, `tag-${tag}`) },\n () => this.fetchTagCommit(registryUrl, repo, tag),\n );\n }\n\n override getDigest(\n config: DigestConfig,\n newValue?: string,\n ): Promise<string | null> {\n return this.cached(\n {\n key: this.getCacheKey(config.registryUrl, config.packageName, 'digest'),\n fallback: true,\n },\n () => this.fetchDigest(config, newValue),\n );\n }\n\n protected fetchDigest(\n config: DigestConfig,\n newValue?: string,\n ): Promise<string | null> {\n const { packageName: repo, registryUrl } = config;\n\n if (newValue?.length) {\n return this.getTagCommit(registryUrl, repo, newValue);\n }\n\n return this.fetchLatestCommit(registryUrl, repo);\n }\n}\n"],"mappings":";;;;;;;;;;;;AAmBA,IAAsB,wBAAtB,cAEU,WAAc;CAkBtB,YACE,aACA,MACA,MACQ;EACR,OAAO,GAAG,KAAK,eAAe,WAAW,EAAE,GAAG,KAAK,GAAG;CACxD;CAEA,YAAY,QAA0D;EACpE,OAAO,KAAK,OACV;GACE,KAAK,KAAK,YAAY,OAAO,aAAa,OAAO,aAAa,MAAM;GACpE,UAAU;EACZ,SACM,KAAK,cAAc,MAAM,CACjC;CACF;CAEA,MAAgB,cACd,QAC+B;EAC/B,MAAM,EAAE,aAAa,gBAAgB;EAErC,MAAM,OAAO,MAAM,KAAK,UAAU,MAAM;EACxC,IAAI,CAAC,MACH,OAAO;EAGT,OAAO;GACL,WAAW,KAAK,aAAa,aAAa,WAAW;GACrD,aAAa,KAAK,eAAe,WAAW;GAC5C,UAAU,KAAK,KAAK,SAAS;IAAE,GAAG;IAAK,QAAQ,IAAI;GAAQ,EAAE;EAC/D;CACF;AACF;;;;;;AAOA,IAAsB,8BAAtB,cAEU,sBAAyB;CAcjC,aACE,aACA,MACA,KACwB;EACxB,OAAO,KAAK,OACV,EAAE,KAAK,KAAK,YAAY,aAAa,MAAM,OAAO,KAAK,EAAE,SACnD,KAAK,eAAe,aAAa,MAAM,GAAG,CAClD;CACF;CAEA,UACE,QACA,UACwB;EACxB,OAAO,KAAK,OACV;GACE,KAAK,KAAK,YAAY,OAAO,aAAa,OAAO,aAAa,QAAQ;GACtE,UAAU;EACZ,SACM,KAAK,YAAY,QAAQ,QAAQ,CACzC;CACF;CAEA,YACE,QACA,UACwB;EACxB,MAAM,EAAE,aAAa,MAAM,gBAAgB;EAE3C,IAAI,UAAU,QACZ,OAAO,KAAK,aAAa,aAAa,MAAM,QAAQ;EAGtD,OAAO,KAAK,kBAAkB,aAAa,IAAI;CACjD;AACF"}
1
+ {"version":3,"file":"git-host-tags.js","names":[],"sources":["../../../lib/modules/datasource/git-host-tags.ts"],"sourcesContent":["import { buildCacheKey } from '../../util/cache/package/key.ts';\nimport type { Http } from '../../util/http/index.ts';\nimport { Datasource } from './datasource.ts';\nimport type {\n DigestConfig,\n GetReleasesConfig,\n GitHostTag,\n ReleaseResult,\n} from './types.ts';\n\n/**\n * Base class for the `*-tags` datasources of git hosting providers.\n *\n * It owns the package cache wrappers and the `<registryUrl>:<repo>:<type>:<tag>`\n * cache key convention shared by all of them, so that subclasses only have to\n * implement the provider specific API calls.\n *\n * Subclasses that also support digest lookups should extend\n * {@link GitHostTagsDigestDatasource} instead.\n */\nexport abstract class GitHostTagsDatasource<\n H extends Http = Http,\n> extends Datasource<H> {\n /**\n * Normalizes the registry URL, applying the datasource default and stripping\n * any API path suffix.\n */\n protected abstract getRegistryUrl(registryUrl?: string): string;\n\n /** Browser URL of the repository. */\n protected abstract getSourceUrl(\n packageName: string,\n registryUrl?: string,\n ): string;\n\n /** Fetches the tags of the repository. */\n protected abstract fetchTags(\n config: GetReleasesConfig,\n ): Promise<GitHostTag[] | null>;\n\n protected getCacheKey(\n registryUrl: string | undefined,\n repo: string,\n type: string,\n tag?: string,\n ): string {\n return buildCacheKey(this.getRegistryUrl(registryUrl), repo, type, tag);\n }\n\n getReleases(config: GetReleasesConfig): Promise<ReleaseResult | null> {\n return this.cached(\n {\n key: this.getCacheKey(config.registryUrl, config.packageName, 'tags'),\n fallback: true,\n },\n () => this.fetchReleases(config),\n );\n }\n\n protected async fetchReleases(\n config: GetReleasesConfig,\n ): Promise<ReleaseResult | null> {\n const { packageName, registryUrl } = config;\n\n const tags = await this.fetchTags(config);\n if (!tags) {\n return null;\n }\n\n return {\n sourceUrl: this.getSourceUrl(packageName, registryUrl),\n registryUrl: this.getRegistryUrl(registryUrl),\n releases: tags.map((tag) => ({ ...tag, gitRef: tag.version })),\n };\n }\n}\n\n/**\n * Base class for the `*-tags` datasources of git hosting providers which also\n * resolve digests: the commit of the given tag, or the latest commit of the\n * default branch when no tag is given.\n */\nexport abstract class GitHostTagsDigestDatasource<\n H extends Http = Http,\n> extends GitHostTagsDatasource<H> {\n /** Fetches the commit hash the given tag points at. */\n protected abstract fetchTagCommit(\n registryUrl: string | undefined,\n repo: string,\n tag: string,\n ): Promise<string | null>;\n\n /** Fetches the latest commit of the repository default branch. */\n protected abstract fetchLatestCommit(\n registryUrl: string | undefined,\n repo: string,\n ): Promise<string | null>;\n\n protected getTagCommit(\n registryUrl: string | undefined,\n repo: string,\n tag: string,\n ): Promise<string | null> {\n return this.cached(\n { key: this.getCacheKey(registryUrl, repo, 'tag', tag) },\n () => this.fetchTagCommit(registryUrl, repo, tag),\n );\n }\n\n override getDigest(\n config: DigestConfig,\n newValue?: string,\n ): Promise<string | null> {\n return this.cached(\n {\n key: this.getCacheKey(\n config.registryUrl,\n config.packageName,\n 'digest',\n newValue,\n ),\n fallback: true,\n },\n () => this.fetchDigest(config, newValue),\n );\n }\n\n protected fetchDigest(\n config: DigestConfig,\n newValue?: string,\n ): Promise<string | null> {\n const { packageName: repo, registryUrl } = config;\n\n if (newValue?.length) {\n return this.getTagCommit(registryUrl, repo, newValue);\n }\n\n return this.fetchLatestCommit(registryUrl, repo);\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAoBA,IAAsB,wBAAtB,cAEU,WAAc;CAkBtB,YACE,aACA,MACA,MACA,KACQ;EACR,OAAO,cAAc,KAAK,eAAe,WAAW,GAAG,MAAM,MAAM,GAAG;CACxE;CAEA,YAAY,QAA0D;EACpE,OAAO,KAAK,OACV;GACE,KAAK,KAAK,YAAY,OAAO,aAAa,OAAO,aAAa,MAAM;GACpE,UAAU;EACZ,SACM,KAAK,cAAc,MAAM,CACjC;CACF;CAEA,MAAgB,cACd,QAC+B;EAC/B,MAAM,EAAE,aAAa,gBAAgB;EAErC,MAAM,OAAO,MAAM,KAAK,UAAU,MAAM;EACxC,IAAI,CAAC,MACH,OAAO;EAGT,OAAO;GACL,WAAW,KAAK,aAAa,aAAa,WAAW;GACrD,aAAa,KAAK,eAAe,WAAW;GAC5C,UAAU,KAAK,KAAK,SAAS;IAAE,GAAG;IAAK,QAAQ,IAAI;GAAQ,EAAE;EAC/D;CACF;AACF;;;;;;AAOA,IAAsB,8BAAtB,cAEU,sBAAyB;CAcjC,aACE,aACA,MACA,KACwB;EACxB,OAAO,KAAK,OACV,EAAE,KAAK,KAAK,YAAY,aAAa,MAAM,OAAO,GAAG,EAAE,SACjD,KAAK,eAAe,aAAa,MAAM,GAAG,CAClD;CACF;CAEA,UACE,QACA,UACwB;EACxB,OAAO,KAAK,OACV;GACE,KAAK,KAAK,YACR,OAAO,aACP,OAAO,aACP,UACA,QACF;GACA,UAAU;EACZ,SACM,KAAK,YAAY,QAAQ,QAAQ,CACzC;CACF;CAEA,YACE,QACA,UACwB;EACxB,MAAM,EAAE,aAAa,MAAM,gBAAgB;EAE3C,IAAI,UAAU,QACZ,OAAO,KAAK,aAAa,aAAa,MAAM,QAAQ;EAGtD,OAAO,KAAK,kBAAkB,aAAa,IAAI;CACjD;AACF"}