diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 91db290e6bdfc1..65276cefaf3fd0 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1 +1 @@ -FROM ghcr.io/containerbase/devcontainer:13.5.8 +FROM ghcr.io/containerbase/devcontainer:13.5.11 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index fa4e3a42949ee6..6325ace86b5c3d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -304,7 +304,7 @@ jobs: os: ${{ runner.os }} - name: Lint markdown - uses: DavidAnson/markdownlint-cli2-action@a23dae216ce3fee4db69da41fed90d2a4af801cf # v19.0.0 + uses: DavidAnson/markdownlint-cli2-action@05f32210e84442804257b2a6f20b273450ec8265 # v19.1.0 - name: Lint fenced code blocks run: pnpm doc-fence-check @@ -684,7 +684,7 @@ jobs: show-progress: false - name: docker-config - uses: containerbase/internal-tools@c8f78cbc830d1883e695d06e3028136656e70f5b # v3.5.17 + uses: containerbase/internal-tools@4453842226e67bc5d507c41b21184cc9220f4974 # v3.5.19 with: command: docker-config diff --git a/docs/usage/docker.md b/docs/usage/docker.md index 0667264ac85011..7a3361e99045a6 100644 --- a/docs/usage/docker.md +++ b/docs/usage/docker.md @@ -307,7 +307,7 @@ Renovate will get the credentials with the [`google-auth-library`](https://www.n service_account: ${{ env.SERVICE_ACCOUNT }} - name: renovate - uses: renovatebot/github-action@v41.0.8 + uses: renovatebot/github-action@v41.0.10 env: RENOVATE_HOST_RULES: | [ @@ -478,7 +478,7 @@ Make sure to install the Google Cloud SDK into the custom image, as you need the For example: ```Dockerfile -FROM renovate/renovate:39.104.1 +FROM renovate/renovate:39.117.2 # Include the "Docker tip" which you can find here https://cloud.google.com/sdk/docs/install # under "Installation" for "Debian/Ubuntu" RUN ... diff --git a/docs/usage/examples/self-hosting.md b/docs/usage/examples/self-hosting.md index 9388b091bca91a..f8a6ab005917df 100644 --- a/docs/usage/examples/self-hosting.md +++ b/docs/usage/examples/self-hosting.md @@ -25,8 +25,8 @@ It builds `latest` based on the `main` branch and all SemVer tags are published ```sh title="Example of valid tags" docker run --rm renovate/renovate docker run --rm renovate/renovate:39 -docker run --rm renovate/renovate:39.104 -docker run --rm renovate/renovate:39.104.1 +docker run --rm renovate/renovate:39.117 +docker run --rm renovate/renovate:39.117.2 ``` @@ -62,7 +62,7 @@ spec: - name: renovate # Update this to the latest available and then enable Renovate on # the manifest - image: renovate/renovate:39.104.1 + image: renovate/renovate:39.117.2 args: - user/repo # Environment Variables @@ -121,7 +121,7 @@ spec: template: spec: containers: - - image: renovate/renovate:39.104.1 + - image: renovate/renovate:39.117.2 name: renovate-bot env: # For illustration purposes, please use secrets. - name: RENOVATE_PLATFORM @@ -367,7 +367,7 @@ spec: containers: - name: renovate # Update this to the latest available and then enable Renovate on the manifest - image: renovate/renovate:39.104.1 + image: renovate/renovate:39.117.2 volumeMounts: - name: ssh-key-volume readOnly: true diff --git a/docs/usage/mend-hosted/.pages b/docs/usage/mend-hosted/.pages index fae3c0c0bf42c4..4dda5349d7d4e7 100644 --- a/docs/usage/mend-hosted/.pages +++ b/docs/usage/mend-hosted/.pages @@ -1,6 +1,6 @@ title: Mend-hosted Apps nav: - - 'Overview': 'renovate-plans.md' + - 'Overview': 'overview.md' - 'Configuration': 'hosted-apps-config.md' - 'Credentials': 'credentials.md' - 'Migrating Secrets': 'migrating-secrets.md' diff --git a/docs/usage/mend-hosted/renovate-plans.md b/docs/usage/mend-hosted/overview.md similarity index 88% rename from docs/usage/mend-hosted/renovate-plans.md rename to docs/usage/mend-hosted/overview.md index acea1ced6bd85c..576072aa088234 100644 --- a/docs/usage/mend-hosted/renovate-plans.md +++ b/docs/usage/mend-hosted/overview.md @@ -51,3 +51,9 @@ Details of the Mend Renovate Cloud versions are shown in the table below. **Mend Renovate Community Cloud (Free)** - Available for free for all repositories. **Mend Renovate Enterprise Cloud** - Supported premium version. Contact Mend at [sales@mend.io](mailto:sales@mend.io) for purchase details. + + +!!! note + OSS-licensed orgs can request increased resources on Mend Renovate Community Cloud. + To request increased resources, create a “[Suggest an Idea](/~https://github.com/renovatebot/renovate/discussions/categories/suggest-an-idea)” item on the Renovate discussions board on GitHub. + Acceptance is at the discretion of Mend.io. diff --git a/lib/config/options/index.ts b/lib/config/options/index.ts index b3e4cfa980501b..c2ed4e53a92980 100644 --- a/lib/config/options/index.ts +++ b/lib/config/options/index.ts @@ -516,7 +516,7 @@ const options: RenovateOptions[] = [ description: 'Change this value to override the default Renovate sidecar image.', type: 'string', - default: 'ghcr.io/containerbase/sidecar:13.5.8', + default: 'ghcr.io/containerbase/sidecar:13.5.11', globalOnly: true, }, { diff --git a/lib/config/presets/github/index.ts b/lib/config/presets/github/index.ts index 06cca040ac9483..a9063233107ec3 100644 --- a/lib/config/presets/github/index.ts +++ b/lib/config/presets/github/index.ts @@ -24,7 +24,7 @@ export async function fetchJSONFile( logger.trace({ url }, `Preset URL`); let res: { body: { content: string } }; try { - res = await http.getJson(url); + res = await http.getJsonUnchecked(url); } catch (err) { // istanbul ignore if: not testable with nock if (err instanceof ExternalHostError) { diff --git a/lib/config/presets/gitlab/index.ts b/lib/config/presets/gitlab/index.ts index 300bf3e51ff5ee..2af74c99d094cf 100644 --- a/lib/config/presets/gitlab/index.ts +++ b/lib/config/presets/gitlab/index.ts @@ -14,7 +14,7 @@ async function getDefaultBranchName( urlEncodedPkgName: string, endpoint: string, ): Promise { - const res = await gitlabApi.getJson( + const res = await gitlabApi.getJsonUnchecked( `${endpoint}projects/${urlEncodedPkgName}`, ); return res.body.default_branch ?? 'master'; // should never happen, but we keep this to ensure the current behavior diff --git a/lib/config/presets/npm/index.ts b/lib/config/presets/npm/index.ts index c01c5c70e0f173..e50201915c0812 100644 --- a/lib/config/presets/npm/index.ts +++ b/lib/config/presets/npm/index.ts @@ -31,7 +31,7 @@ export async function getPreset({ 'Using npm packages for Renovate presets is now deprecated. Please migrate to repository-based presets instead.', ); const packageUrl = resolvePackageUrl(registryUrl, pkg); - const body = (await http.getJson(packageUrl)).body; + const body = (await http.getJsonUnchecked(packageUrl)).body; // TODO: check null #22198 dep = body.versions![body['dist-tags']!.latest]; } catch { diff --git a/lib/config/types.ts b/lib/config/types.ts index 0798f99d7ca662..7bf0bcaf0237f2 100644 --- a/lib/config/types.ts +++ b/lib/config/types.ts @@ -309,6 +309,7 @@ export interface RenovateConfig branchTopic?: string; additionalBranchPrefix?: string; + sharedVariableName?: string; } const CustomDatasourceFormats = ['json', 'plain', 'yaml', 'html'] as const; diff --git a/lib/data/monorepo.json b/lib/data/monorepo.json index 1d0437dbc8db72..39cf0003ec7979 100644 --- a/lib/data/monorepo.json +++ b/lib/data/monorepo.json @@ -459,6 +459,7 @@ "prisma": "/~https://github.com/prisma/prisma", "prometheus-net": "/~https://github.com/prometheus-net/prometheus-net", "promster": "/~https://github.com/tdeekens/promster", + "protobuf": "/~https://github.com/protocolbuffers/protobuf", "quartznet": "/~https://github.com/quartznet/quartznet", "radix-ui-primitives": "/~https://github.com/radix-ui/primitives", "reach-ui": "/~https://github.com/reach/reach-ui", diff --git a/lib/modules/datasource/artifactory/index.ts b/lib/modules/datasource/artifactory/index.ts index 77eff31975492b..54657508be9b5d 100644 --- a/lib/modules/datasource/artifactory/index.ts +++ b/lib/modules/datasource/artifactory/index.ts @@ -3,6 +3,7 @@ import { cache } from '../../../util/cache/package/decorator'; import { parse } from '../../../util/html'; import { HttpError } from '../../../util/http'; import { regEx } from '../../../util/regex'; +import { asTimestamp } from '../../../util/timestamp'; import { joinUrlParts } from '../../../util/url'; import { Datasource } from '../datasource'; import type { GetReleasesConfig, Release, ReleaseResult } from '../types'; @@ -72,13 +73,13 @@ export class ArtifactoryDatasource extends Datasource { ? node.innerHTML.slice(0, -1) : node.innerHTML; - const published = ArtifactoryDatasource.parseReleaseTimestamp( - node.nextSibling!.text, // TODO: can be null (#22198) + const releaseTimestamp = asTimestamp( + node.nextSibling?.text?.trimStart()?.split(regEx(/\s{2,}/))?.[0], ); const thisRelease: Release = { version, - releaseTimestamp: published, + releaseTimestamp, }; result.releases.push(thisRelease); @@ -112,11 +113,4 @@ export class ArtifactoryDatasource extends Datasource { return result.releases.length ? result : null; } - - private static parseReleaseTimestamp(rawText: string): string { - return ( - rawText.split(regEx(/\s{2,}/)).filter((e) => !isNaN(Date.parse(e)))[0] + - 'Z' - ); - } } diff --git a/lib/modules/datasource/bitbucket-tags/index.ts b/lib/modules/datasource/bitbucket-tags/index.ts index f8b59d23196bf3..1ca5ddf1689513 100644 --- a/lib/modules/datasource/bitbucket-tags/index.ts +++ b/lib/modules/datasource/bitbucket-tags/index.ts @@ -65,9 +65,12 @@ export class BitbucketTagsDatasource extends Datasource { }: GetReleasesConfig): Promise { const url = `/2.0/repositories/${repo}/refs/tags`; const bitbucketTags = ( - await this.bitbucketHttp.getJson>(url, { - paginate: true, - }) + await this.bitbucketHttp.getJsonUnchecked>( + url, + { + paginate: true, + }, + ) ).body.values; const dependency: ReleaseResult = { @@ -96,8 +99,9 @@ export class BitbucketTagsDatasource extends Datasource { ): Promise { const url = `/2.0/repositories/${repo}/refs/tags/${tag}`; - const bitbucketTag = (await this.bitbucketHttp.getJson(url)) - .body; + const bitbucketTag = ( + await this.bitbucketHttp.getJsonUnchecked(url) + ).body; return bitbucketTag.target?.hash ?? null; } @@ -136,7 +140,9 @@ export class BitbucketTagsDatasource extends Datasource { const url = `/2.0/repositories/${repo}/commits/${mainBranch}`; const bitbucketCommits = ( - await this.bitbucketHttp.getJson>(url) + await this.bitbucketHttp.getJsonUnchecked>( + url, + ) ).body; if (bitbucketCommits.values.length === 0) { diff --git a/lib/modules/datasource/conan/index.ts b/lib/modules/datasource/conan/index.ts index 0319d16719bc94..079600bd4df9e8 100644 --- a/lib/modules/datasource/conan/index.ts +++ b/lib/modules/datasource/conan/index.ts @@ -126,7 +126,7 @@ export class ConanDatasource extends Datasource { ); try { - const rep = await this.http.getJson(lookupUrl); + const rep = await this.http.getJsonUnchecked(lookupUrl); const conanJson = ConanJSON.parse(rep.body); if (conanJson) { logger.trace({ lookupUrl }, 'Got conan api result'); diff --git a/lib/modules/datasource/conda/index.ts b/lib/modules/datasource/conda/index.ts index 980eb8de9be103..6985d4d4cde7db 100644 --- a/lib/modules/datasource/conda/index.ts +++ b/lib/modules/datasource/conda/index.ts @@ -52,7 +52,7 @@ export class CondaDatasource extends Datasource { let response: { body: CondaPackage }; try { - response = await this.http.getJson(url); + response = await this.http.getJsonUnchecked(url); result.homepage = response.body.html_url; result.sourceUrl = response.body.dev_url; diff --git a/lib/modules/datasource/crate/index.ts b/lib/modules/datasource/crate/index.ts index 29eb0b84985f23..7e0be2656c71eb 100644 --- a/lib/modules/datasource/crate/index.ts +++ b/lib/modules/datasource/crate/index.ts @@ -156,7 +156,7 @@ export class CrateDatasource extends Datasource { try { type Response = { crate: CrateMetadata }; - const response = await this.http.getJson(crateUrl); + const response = await this.http.getJsonUnchecked(crateUrl); return response.body.crate; } catch (err) { logger.warn( diff --git a/lib/modules/datasource/custom/formats/json.ts b/lib/modules/datasource/custom/formats/json.ts index ead333419bbd91..63b7fb70ad4223 100644 --- a/lib/modules/datasource/custom/formats/json.ts +++ b/lib/modules/datasource/custom/formats/json.ts @@ -4,7 +4,7 @@ import type { CustomDatasourceFetcher } from './types'; export class JSONFetcher implements CustomDatasourceFetcher { async fetch(http: Http, registryURL: string): Promise { - const response = await http.getJson(registryURL); + const response = await http.getJsonUnchecked(registryURL); return response.body; } diff --git a/lib/modules/datasource/dart-version/index.ts b/lib/modules/datasource/dart-version/index.ts index 23f95ccab89124..06b5440f8fbb7d 100644 --- a/lib/modules/datasource/dart-version/index.ts +++ b/lib/modules/datasource/dart-version/index.ts @@ -41,7 +41,7 @@ export class DartVersionDatasource extends Datasource { try { for (const channel of this.channels) { const resp = ( - await this.http.getJson( + await this.http.getJsonUnchecked( `${registryUrl}/storage/v1/b/dart-archive/o?delimiter=%2F&prefix=channels%2F${channel}%2Frelease%2F&alt=json`, ) ).body; diff --git a/lib/modules/datasource/dart/index.ts b/lib/modules/datasource/dart/index.ts index 88e549cfeb8903..80ea1cf8e3a2b4 100644 --- a/lib/modules/datasource/dart/index.ts +++ b/lib/modules/datasource/dart/index.ts @@ -37,7 +37,7 @@ export class DartDatasource extends Datasource { let raw: HttpResponse | null = null; try { - raw = await this.http.getJson(pkgUrl); + raw = await this.http.getJsonUnchecked(pkgUrl); } catch (err) { this.handleGenericErrors(err); } diff --git a/lib/modules/datasource/docker/common.ts b/lib/modules/datasource/docker/common.ts index 1ccc12c66a648d..b838b25d8898e5 100644 --- a/lib/modules/datasource/docker/common.ts +++ b/lib/modules/datasource/docker/common.ts @@ -63,7 +63,7 @@ export async function getAuthHeaders( ? await http.get(apiCheckUrl, options) : // use json request, as this will be cached for tags, so it returns json // TODO: add cache test - await http.getJson(apiCheckUrl, options); + await http.getJsonUnchecked(apiCheckUrl, options); if (apiCheckResponse.statusCode === 200) { logger.debug(`No registry auth required for ${apiCheckUrl}`); @@ -193,7 +193,7 @@ export async function getAuthHeaders( ); opts.noAuth = true; const authResponse = ( - await http.getJson<{ token?: string; access_token?: string }>( + await http.getJsonUnchecked<{ token?: string; access_token?: string }>( authUrl.href, opts, ) diff --git a/lib/modules/datasource/docker/index.ts b/lib/modules/datasource/docker/index.ts index 3e4339d0fa2b25..dec17989b8ff5b 100644 --- a/lib/modules/datasource/docker/index.ts +++ b/lib/modules/datasource/docker/index.ts @@ -629,7 +629,7 @@ export class DockerDatasource extends Datasource { // typescript issue :-/ // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion - const res = (await this.http.getJson( + const res = (await this.http.getJsonUnchecked( url, )) as HttpResponse; const pageTags = res.body.tags.map((tag) => tag.name); @@ -671,7 +671,7 @@ export class DockerDatasource extends Datasource { do { let res: HttpResponse<{ tags: string[] }>; try { - res = await this.http.getJson<{ tags: string[] }>(url, { + res = await this.http.getJsonUnchecked<{ tags: string[] }>(url, { headers, noAuth: true, }); diff --git a/lib/modules/datasource/flutter-version/index.ts b/lib/modules/datasource/flutter-version/index.ts index 46dd2ce47e8d44..5069f9779ecc85 100644 --- a/lib/modules/datasource/flutter-version/index.ts +++ b/lib/modules/datasource/flutter-version/index.ts @@ -43,7 +43,7 @@ export class FlutterVersionDatasource extends Datasource { }; try { const resp = ( - await this.http.getJson( + await this.http.getJsonUnchecked( `${registryUrl}/flutter_infra_release/releases/releases_linux.json`, ) ).body; diff --git a/lib/modules/datasource/galaxy/index.ts b/lib/modules/datasource/galaxy/index.ts index d855a1d4b6225a..cae51402213a80 100644 --- a/lib/modules/datasource/galaxy/index.ts +++ b/lib/modules/datasource/galaxy/index.ts @@ -63,9 +63,8 @@ export class GalaxyDatasource extends Datasource { } } if (body.results.length === 0) { - logger.info( - { dependency: packageName }, - `Received no results from ${galaxyAPIUrl}`, + logger.debug( + `Received no results for ${packageName} from ${galaxyAPIUrl} `, ); return null; } diff --git a/lib/modules/datasource/github-release-attachments/index.ts b/lib/modules/datasource/github-release-attachments/index.ts index 14caabb969ce1d..2b95ca53fea59b 100644 --- a/lib/modules/datasource/github-release-attachments/index.ts +++ b/lib/modules/datasource/github-release-attachments/index.ts @@ -210,9 +210,10 @@ export class GithubReleaseAttachmentsDatasource extends Datasource { } const apiBaseUrl = getApiBaseUrl(registryUrl); - const { body: currentRelease } = await this.http.getJson( - `${apiBaseUrl}repos/${repo}/releases/tags/${currentValue}`, - ); + const { body: currentRelease } = + await this.http.getJsonUnchecked( + `${apiBaseUrl}repos/${repo}/releases/tags/${currentValue}`, + ); const digestAsset = await this.findDigestAsset( currentRelease, currentDigest, @@ -221,9 +222,10 @@ export class GithubReleaseAttachmentsDatasource extends Datasource { if (!digestAsset || newValue === currentValue) { newDigest = currentDigest; } else { - const { body: newRelease } = await this.http.getJson( - `${apiBaseUrl}repos/${repo}/releases/tags/${newValue}`, - ); + const { body: newRelease } = + await this.http.getJsonUnchecked( + `${apiBaseUrl}repos/${repo}/releases/tags/${newValue}`, + ); newDigest = await this.mapDigestAssetToRelease(digestAsset, newRelease); } return newDigest; diff --git a/lib/modules/datasource/github-tags/index.ts b/lib/modules/datasource/github-tags/index.ts index 0fdca9b6b3020d..38871793034609 100644 --- a/lib/modules/datasource/github-tags/index.ts +++ b/lib/modules/datasource/github-tags/index.ts @@ -43,7 +43,7 @@ export class GithubTagsDatasource extends Datasource { let digest: string | null = null; try { const url = `${apiBaseUrl}repos/${githubRepo}/commits?per_page=1`; - const res = await this.http.getJson<{ sha: string }[]>(url); + const res = await this.http.getJsonUnchecked<{ sha: string }[]>(url); digest = res.body[0].sha; } catch (err) { logger.debug( diff --git a/lib/modules/datasource/gitlab-packages/index.ts b/lib/modules/datasource/gitlab-packages/index.ts index 28d0483aae5069..651fb6d0141f16 100644 --- a/lib/modules/datasource/gitlab-packages/index.ts +++ b/lib/modules/datasource/gitlab-packages/index.ts @@ -74,7 +74,9 @@ export class GitlabPackagesDatasource extends Datasource { let response: GitlabPackage[]; try { response = ( - await this.http.getJson(apiUrl, { paginate: true }) + await this.http.getJsonUnchecked(apiUrl, { + paginate: true, + }) ).body; result.releases = response diff --git a/lib/modules/datasource/gitlab-releases/index.ts b/lib/modules/datasource/gitlab-releases/index.ts index 54ba562796a795..f82a5eb68bb50f 100644 --- a/lib/modules/datasource/gitlab-releases/index.ts +++ b/lib/modules/datasource/gitlab-releases/index.ts @@ -43,7 +43,7 @@ export class GitlabReleasesDatasource extends Datasource { try { const gitlabReleasesResponse = ( - await this.http.getJson(apiUrl) + await this.http.getJsonUnchecked(apiUrl) ).body; return { diff --git a/lib/modules/datasource/gitlab-tags/index.ts b/lib/modules/datasource/gitlab-tags/index.ts index 89ba14da0dc5f6..77690fcce59942 100644 --- a/lib/modules/datasource/gitlab-tags/index.ts +++ b/lib/modules/datasource/gitlab-tags/index.ts @@ -48,7 +48,7 @@ export class GitlabTagsDatasource extends Datasource { ); const gitlabTags = ( - await this.http.getJson(url, { + await this.http.getJsonUnchecked(url, { paginate: true, }) ).body; @@ -94,7 +94,8 @@ export class GitlabTagsDatasource extends Datasource { `repository/commits/`, newValue, ); - const gitlabCommits = await this.http.getJson(url); + const gitlabCommits = + await this.http.getJsonUnchecked(url); digest = gitlabCommits.body.id; } else { const url = joinUrlParts( @@ -103,7 +104,8 @@ export class GitlabTagsDatasource extends Datasource { urlEncodedRepo, `repository/commits?per_page=1`, ); - const gitlabCommits = await this.http.getJson(url); + const gitlabCommits = + await this.http.getJsonUnchecked(url); digest = gitlabCommits.body[0].id; } } catch (err) { diff --git a/lib/modules/datasource/go/releases-goproxy.ts b/lib/modules/datasource/go/releases-goproxy.ts index 1a2a9d301cbf1e..4464a2e33b6a57 100644 --- a/lib/modules/datasource/go/releases-goproxy.ts +++ b/lib/modules/datasource/go/releases-goproxy.ts @@ -164,7 +164,7 @@ export class GoProxyDatasource extends Datasource { '@v', `${version}.info`, ); - const res = await this.http.getJson(url); + const res = await this.http.getJsonUnchecked(url); const result: Release = { version: res.body.Version, @@ -187,7 +187,7 @@ export class GoProxyDatasource extends Datasource { this.encodeCase(packageName), '@latest', ); - const res = await this.http.getJson(url); + const res = await this.http.getJsonUnchecked(url); return res.body.Version; } catch (err) { logger.trace({ err }, 'Failed to get latest version'); diff --git a/lib/modules/datasource/gradle-version/index.ts b/lib/modules/datasource/gradle-version/index.ts index bb6368e19803f1..4667b6891955ca 100644 --- a/lib/modules/datasource/gradle-version/index.ts +++ b/lib/modules/datasource/gradle-version/index.ts @@ -46,7 +46,8 @@ export class GradleVersionDatasource extends Datasource { let releases: Release[]; try { - const response = await this.http.getJson(registryUrl); + const response = + await this.http.getJsonUnchecked(registryUrl); releases = response.body .filter((release) => !release.snapshot && !release.nightly) .map((release) => { diff --git a/lib/modules/datasource/helm/common.spec.ts b/lib/modules/datasource/helm/common.spec.ts deleted file mode 100644 index 84b88120db135a..00000000000000 --- a/lib/modules/datasource/helm/common.spec.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Fixtures } from '../../../../test/fixtures'; -import { parseSingleYaml } from '../../../util/yaml'; -import { findSourceUrl } from './common'; -import type { HelmRepository } from './types'; - -// Truncated index.yaml file -const repo = parseSingleYaml(Fixtures.get('sample.yaml')); - -describe('modules/datasource/helm/common', () => { - describe('findSourceUrl', () => { - it.each` - input | output - ${'airflow'} | ${'/~https://github.com/bitnami/charts/tree/master/bitnami/airflow'} - ${'coredns'} | ${'/~https://github.com/coredns/helm'} - ${'pgadmin4'} | ${'/~https://github.com/rowanruseler/helm-charts'} - ${'private-chart-github'} | ${'https://github.example.com/some-org/charts/tree/master/private-chart'} - ${'private-chart-gitlab'} | ${'https://gitlab.example.com/some/group/charts/-/tree/master/private-chart'} - ${'dummy'} | ${null} - `( - '$input -> $output', - ({ input, output }: { input: string; output: string }) => { - expect(findSourceUrl(repo.entries[input][0])).toEqual(output); - }, - ); - }); -}); diff --git a/lib/modules/datasource/helm/common.ts b/lib/modules/datasource/helm/common.ts deleted file mode 100644 index 0b32a3c33fa971..00000000000000 --- a/lib/modules/datasource/helm/common.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { detectPlatform } from '../../../util/common'; -import { parseGitUrl } from '../../../util/git/url'; -import { regEx } from '../../../util/regex'; -import type { HelmRelease } from './types'; - -const chartRepo = regEx(/charts?|helm|helm-charts/i); -const githubRelease = regEx( - /^(https:\/\/github\.com\/[^/]+\/[^/]+)\/releases\//, -); - -function isPossibleChartRepo(url: string): boolean { - if (detectPlatform(url) === null) { - return false; - } - - const parsed = parseGitUrl(url); - return chartRepo.test(parsed.name); -} - -export function findSourceUrl(release: HelmRelease): string | null { - // it's a github release :) - const releaseMatch = githubRelease.exec(release.urls[0]); - if (releaseMatch) { - return releaseMatch[1]; - } - - if (release.home && isPossibleChartRepo(release.home)) { - return release.home; - } - - if (!release.sources?.length) { - return null; - } - - for (const url of release.sources) { - if (isPossibleChartRepo(url)) { - return url; - } - } - - // fallback - return release.sources[0]; -} diff --git a/lib/modules/datasource/helm/index.ts b/lib/modules/datasource/helm/index.ts index 6ca3681c98103e..506b6a46904271 100644 --- a/lib/modules/datasource/helm/index.ts +++ b/lib/modules/datasource/helm/index.ts @@ -1,14 +1,11 @@ -import is from '@sindresorhus/is'; import { logger } from '../../../logger'; import { cache } from '../../../util/cache/package/decorator'; -import type { HttpResponse } from '../../../util/http/types'; import { ensureTrailingSlash } from '../../../util/url'; -import { parseSingleYaml } from '../../../util/yaml'; import * as helmVersioning from '../../versioning/helm'; import { Datasource } from '../datasource'; import type { GetReleasesConfig, ReleaseResult } from '../types'; -import { findSourceUrl } from './common'; -import type { HelmRepository, HelmRepositoryData } from './types'; +import type { HelmRepositoryData } from './schema'; +import { HelmRepositorySchema } from './schema'; export class HelmDatasource extends Datasource { static readonly id = 'helm'; @@ -34,63 +31,22 @@ export class HelmDatasource extends Datasource { @cache({ namespace: `datasource-${HelmDatasource.id}`, - key: (helmRepository: string) => helmRepository, + key: (helmRepository: string) => `repository-data:${helmRepository}`, }) - async getRepositoryData( - helmRepository: string, - ): Promise { - let res: HttpResponse; - try { - res = await this.http.get('index.yaml', { - baseUrl: ensureTrailingSlash(helmRepository), - }); - if (!res?.body) { - logger.warn( - { helmRepository }, - `Received invalid response from helm repository`, - ); - return null; - } - } catch (err) { + async getRepositoryData(helmRepository: string): Promise { + const { val, err } = await this.http + .getYamlSafe( + 'index.yaml', + { baseUrl: ensureTrailingSlash(helmRepository) }, + HelmRepositorySchema, + ) + .unwrap(); + + if (err) { this.handleGenericErrors(err); } - try { - // TODO: use schema (#9610) - const doc = parseSingleYaml(res.body); - if (!is.plainObject(doc)) { - logger.warn( - { helmRepository }, - `Failed to parse index.yaml from helm repository`, - ); - return null; - } - const result: HelmRepositoryData = {}; - for (const [name, releases] of Object.entries(doc.entries)) { - if (releases.length === 0) { - continue; - } - const latestRelease = releases[0]; - const sourceUrl = findSourceUrl(latestRelease); - result[name] = { - homepage: latestRelease.home, - sourceUrl, - releases: releases.map((release) => ({ - version: release.version, - releaseTimestamp: release.created ?? null, - // The Helm repository at Gitlab does not include a digest (#24280) - newDigest: release.digest ?? undefined, - })), - }; - } - return result; - } catch (err) { - logger.debug( - { helmRepository, err }, - `Failed to parse index.yaml from helm repository`, - ); - return null; - } + return val; } async getReleases({ @@ -103,10 +59,6 @@ export class HelmDatasource extends Datasource { } const repositoryData = await this.getRepositoryData(helmRepository); - if (!repositoryData) { - logger.debug(`Missing repo data from ${helmRepository}`); - return null; - } const releases = repositoryData[packageName]; if (!releases) { logger.debug( diff --git a/lib/modules/datasource/helm/schema.spec.ts b/lib/modules/datasource/helm/schema.spec.ts new file mode 100644 index 00000000000000..52f10871fb436f --- /dev/null +++ b/lib/modules/datasource/helm/schema.spec.ts @@ -0,0 +1,41 @@ +import { Fixtures } from '../../../../test/fixtures'; +import { Yaml } from '../../../util/schema-utils'; +import { HelmRepositorySchema } from './schema'; + +describe('modules/datasource/helm/schema', () => { + describe('sourceUrl', () => { + it('works', () => { + const repo = Yaml.pipe(HelmRepositorySchema).parse( + Fixtures.get('sample.yaml'), + ); + expect(repo).toMatchObject({ + airflow: { + homepage: + '/~https://github.com/bitnami/charts/tree/master/bitnami/airflow', + sourceUrl: + '/~https://github.com/bitnami/charts/tree/master/bitnami/airflow', + }, + coredns: { + homepage: 'https://coredns.io', + sourceUrl: '/~https://github.com/coredns/helm', + }, + pgadmin4: { + homepage: 'https://www.pgadmin.org/', + sourceUrl: '/~https://github.com/rowanruseler/helm-charts', + }, + 'private-chart-github': { + homepage: + 'https://github.example.com/some-org/charts/tree/master/private-chart', + sourceUrl: + 'https://github.example.com/some-org/charts/tree/master/private-chart', + }, + 'private-chart-gitlab': { + homepage: + 'https://gitlab.example.com/some/group/charts/-/tree/master/private-chart', + sourceUrl: + 'https://gitlab.example.com/some/group/charts/-/tree/master/private-chart', + }, + }); + }); + }); +}); diff --git a/lib/modules/datasource/helm/schema.ts b/lib/modules/datasource/helm/schema.ts new file mode 100644 index 00000000000000..d10d90120b86ab --- /dev/null +++ b/lib/modules/datasource/helm/schema.ts @@ -0,0 +1,82 @@ +import { z } from 'zod'; +import { detectPlatform } from '../../../util/common'; +import { parseGitUrl } from '../../../util/git/url'; +import { regEx } from '../../../util/regex'; +import { LooseRecord } from '../../../util/schema-utils'; +import type { Release } from '../types'; + +const HelmReleaseSchema = z.object({ + version: z.string(), + created: z.string().nullable().catch(null), + digest: z.string().optional().catch(undefined), + home: z.string().optional().catch(undefined), + sources: z.array(z.string()).catch([]), + urls: z.array(z.string()).catch([]), +}); +type HelmRelease = z.infer; + +const chartRepo = regEx(/charts?|helm|helm-charts/i); + +function isPossibleChartRepo(url: string): boolean { + if (detectPlatform(url) === null) { + return false; + } + + const parsed = parseGitUrl(url); + return chartRepo.test(parsed.name); +} + +const githubRelease = regEx( + /^(https:\/\/github\.com\/[^/]+\/[^/]+)\/releases\//, +); + +function getSourceUrl(release: HelmRelease): string | undefined { + // it's a github release :) + const [githubUrl] = release.urls; + const releaseMatch = githubRelease.exec(githubUrl); + if (releaseMatch) { + return releaseMatch[1]; + } + + if (release.home && isPossibleChartRepo(release.home)) { + return release.home; + } + + for (const url of release.sources) { + if (isPossibleChartRepo(url)) { + return url; + } + } + + // fallback + return release.sources[0]; +} + +export const HelmRepositorySchema = z + .object({ + entries: LooseRecord( + z.string(), + HelmReleaseSchema.array() + .min(1) + .transform((helmReleases) => { + const latestRelease = helmReleases[0]; + const homepage = latestRelease.home; + const sourceUrl = getSourceUrl(latestRelease); + const releases = helmReleases.map( + ({ + version, + created: releaseTimestamp, + digest: newDigest, + }): Release => ({ + version, + releaseTimestamp, + newDigest, + }), + ); + return { homepage, sourceUrl, releases }; + }), + ), + }) + .transform(({ entries }) => entries); + +export type HelmRepositoryData = z.infer; diff --git a/lib/modules/datasource/helm/types.ts b/lib/modules/datasource/helm/types.ts deleted file mode 100644 index 3c89e124e6f589..00000000000000 --- a/lib/modules/datasource/helm/types.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { ReleaseResult } from '../types'; - -export interface HelmRelease { - home?: string; - sources?: string[]; - version: string; - created: string; - digest: string | null; - urls: string[]; -} - -export interface HelmRepository { - entries: Record; -} - -export type HelmRepositoryData = Record; diff --git a/lib/modules/datasource/hermit/index.ts b/lib/modules/datasource/hermit/index.ts index 5e6b53bd4bcd2e..8a920b3c3d6758 100644 --- a/lib/modules/datasource/hermit/index.ts +++ b/lib/modules/datasource/hermit/index.ts @@ -125,7 +125,7 @@ export class HermitDatasource extends Datasource { const apiBaseUrl = getApiBaseUrl(`https://${host}`); - const indexRelease = await this.http.getJson( + const indexRelease = await this.http.getJsonUnchecked( `${apiBaseUrl}repos/${owner}/${repo}/releases/tags/index`, ); diff --git a/lib/modules/datasource/java-version/index.ts b/lib/modules/datasource/java-version/index.ts index 1e1d68d4a2d7e9..4924b0c8ffb317 100644 --- a/lib/modules/datasource/java-version/index.ts +++ b/lib/modules/datasource/java-version/index.ts @@ -31,7 +31,8 @@ export class JavaVersionDatasource extends Datasource { ): Promise { const pgUrl = `${url}&page=${page}`; try { - const pgRes = await this.http.getJson(pgUrl); + const pgRes = + await this.http.getJsonUnchecked(pgUrl); return ( pgRes?.body?.versions?.map(({ semver }) => ({ version: semver, diff --git a/lib/modules/datasource/jenkins-plugins/index.ts b/lib/modules/datasource/jenkins-plugins/index.ts index db434ba666c26c..1f846c1c240e02 100644 --- a/lib/modules/datasource/jenkins-plugins/index.ts +++ b/lib/modules/datasource/jenkins-plugins/index.ts @@ -117,7 +117,7 @@ export class JenkinsPluginsDatasource extends Datasource { try { logger.debug(`jenkins-plugins: Fetching Jenkins plugins from ${url}`); const startTime = Date.now(); - response = (await this.http.getJson(url)).body; + response = (await this.http.getJsonUnchecked(url)).body; const durationMs = Math.round(Date.now() - startTime); logger.debug( { durationMs }, diff --git a/lib/modules/datasource/maven/index.spec.ts b/lib/modules/datasource/maven/index.spec.ts index 4a87d5323f416e..d8d903184d6816 100644 --- a/lib/modules/datasource/maven/index.spec.ts +++ b/lib/modules/datasource/maven/index.spec.ts @@ -1,5 +1,6 @@ import { HeadObjectCommand, S3Client } from '@aws-sdk/client-s3'; import { mockClient } from 'aws-sdk-client-mock'; +import { codeBlock } from 'common-tags'; import { GoogleAuth as _googleAuth } from 'google-auth-library'; import { DateTime } from 'luxon'; import type { Release, ReleaseResult } from '..'; @@ -315,6 +316,72 @@ describe('modules/datasource/maven/index', () => { expect(res?.sourceUrl).toBe('/~https://github.com/example/test'); }); + describe('supports relocation', () => { + it('with only groupId present', async () => { + const pom = codeBlock` + + + + io.example + + + + `; + mockGenericPackage({ pom }); + + const res = await get(); + + expect(res).toMatchObject({ + replacementName: 'io.example:package', + replacementVersion: '2.0.0', + }); + }); + + it('with only artifactId present', async () => { + const pom = codeBlock` + + + + foo + + + + `; + mockGenericPackage({ pom }); + + const res = await get(); + + expect(res).toMatchObject({ + replacementName: 'org.example:foo', + replacementVersion: '2.0.0', + }); + }); + + it('with all elments present', async () => { + const pom = codeBlock` + + + + io.example + foo + 1.2.3 + test relocation + + + + `; + mockGenericPackage({ pom }); + + const res = await get(); + + expect(res).toMatchObject({ + replacementName: 'io.example:foo', + replacementVersion: '1.2.3', + deprecationMessage: 'test relocation', + }); + }); + }); + it('removes authentication header after redirect', async () => { const frontendHost = 'frontend_for_private_s3_repository'; const frontendUrl = `https://${frontendHost}/maven2`; diff --git a/lib/modules/datasource/maven/types.ts b/lib/modules/datasource/maven/types.ts index 853326887eaadc..f367802cd21735 100644 --- a/lib/modules/datasource/maven/types.ts +++ b/lib/modules/datasource/maven/types.ts @@ -18,7 +18,12 @@ export type HttpResourceCheckResult = 'found' | 'not-found' | 'error' | Date; export type DependencyInfo = Pick< ReleaseResult, - 'homepage' | 'sourceUrl' | 'packageScope' + | 'homepage' + | 'sourceUrl' + | 'packageScope' + | 'replacementName' + | 'replacementVersion' + | 'deprecationMessage' >; export interface MavenFetchSuccess { diff --git a/lib/modules/datasource/maven/util.ts b/lib/modules/datasource/maven/util.ts index dd6fd41961fd7d..696836fd41f913 100644 --- a/lib/modules/datasource/maven/util.ts +++ b/lib/modules/datasource/maven/util.ts @@ -543,6 +543,23 @@ export async function getDependencyInfo( } } + const relocation = pomContent.descendantWithPath( + 'distributionManagement.relocation', + ); + if (relocation) { + const relocationGroup = + relocation.valueWithPath('groupId') ?? dependency.group; + const relocationName = + relocation.valueWithPath('artifactId') ?? dependency.name; + result.replacementName = `${relocationGroup}:${relocationName}`; + const relocationVersion = relocation.valueWithPath('version'); + result.replacementVersion = relocationVersion ?? version; + const relocationMessage = relocation.valueWithPath('message'); + if (relocationMessage) { + result.deprecationMessage = relocationMessage; + } + } + const groupId = pomContent.valueWithPath('groupId'); if (groupId) { result.packageScope = groupId; diff --git a/lib/modules/datasource/node-version/index.ts b/lib/modules/datasource/node-version/index.ts index c37c707c32cabf..aba6bd7da83e63 100644 --- a/lib/modules/datasource/node-version/index.ts +++ b/lib/modules/datasource/node-version/index.ts @@ -46,7 +46,7 @@ export class NodeVersionDatasource extends Datasource { }; try { const resp = ( - await this.http.getJson( + await this.http.getJsonUnchecked( joinUrlParts(registryUrl, 'index.json'), ) ).body; diff --git a/lib/modules/datasource/npm/get.ts b/lib/modules/datasource/npm/get.ts index cd8ea585ec259f..ec6cc4e5576055 100644 --- a/lib/modules/datasource/npm/get.ts +++ b/lib/modules/datasource/npm/get.ts @@ -144,7 +144,7 @@ export async function getDependency( }); } - const raw = await http.getJson(packageUrl, options); + const raw = await http.getJsonUnchecked(packageUrl, options); if (cachedResult?.cacheData && raw.statusCode === 304) { logger.trace(`Cached npm result for ${packageName} is revalidated`); HttpCacheStats.incRemoteHits(packageUrl); diff --git a/lib/modules/datasource/nuget/v3.ts b/lib/modules/datasource/nuget/v3.ts index 2e6e289bf0478a..b773b5865f7660 100644 --- a/lib/modules/datasource/nuget/v3.ts +++ b/lib/modules/datasource/nuget/v3.ts @@ -52,7 +52,8 @@ export class NugetV3Api { ); // istanbul ignore else: currently not testable if (!servicesIndexRaw) { - servicesIndexRaw = (await http.getJson(url)).body; + servicesIndexRaw = (await http.getJsonUnchecked(url)) + .body; await packageCache.set( NugetV3Api.cacheNamespace, responseCacheKey, @@ -132,7 +133,7 @@ export class NugetV3Api { let items = catalogPage.items; if (!items) { const url = catalogPage['@id']; - const catalogPageFull = await http.getJson(url); + const catalogPageFull = await http.getJsonUnchecked(url); items = catalogPageFull.body.items; } return items.map(({ catalogEntry }) => catalogEntry); @@ -146,7 +147,8 @@ export class NugetV3Api { ): Promise { const baseUrl = feedUrl.replace(regEx(/\/*$/), ''); const url = `${baseUrl}/${pkgName.toLowerCase()}/index.json`; - const packageRegistration = await http.getJson(url); + const packageRegistration = + await http.getJsonUnchecked(url); const catalogPages = packageRegistration.body.items || []; const catalogPagesQueue = catalogPages.map( (page) => (): Promise => this.getCatalogEntry(http, page), diff --git a/lib/modules/datasource/packagist/index.ts b/lib/modules/datasource/packagist/index.ts index 1284745a7efdfa..da8573de0bfcd5 100644 --- a/lib/modules/datasource/packagist/index.ts +++ b/lib/modules/datasource/packagist/index.ts @@ -49,13 +49,13 @@ export class PackagistDatasource extends Datasource { return username && password ? { username, password } : {}; } - private async getJson>( + private async getJson>( url: string, - schema: U, - ): Promise> { + schema: Schema, + ): Promise> { const opts = PackagistDatasource.getHostOpts(url); - const { body } = await this.http.getJson(url, opts); - return schema.parse(body); + const { body } = await this.http.getJson(url, opts, schema); + return body; } @cache({ diff --git a/lib/modules/datasource/pod/index.ts b/lib/modules/datasource/pod/index.ts index 86aa0449081bf1..ca728d3955cb69 100644 --- a/lib/modules/datasource/pod/index.ts +++ b/lib/modules/datasource/pod/index.ts @@ -125,7 +125,7 @@ export class PodDatasource extends Datasource { packageName: string, ): Promise { try { - const resp = await this.githubHttp.getJson(url); + const resp = await this.githubHttp.getJsonUnchecked(url); if (resp?.body) { return resp.body; } diff --git a/lib/modules/datasource/puppet-forge/index.ts b/lib/modules/datasource/puppet-forge/index.ts index f656f4d5faad79..9bed72a5444d84 100644 --- a/lib/modules/datasource/puppet-forge/index.ts +++ b/lib/modules/datasource/puppet-forge/index.ts @@ -28,7 +28,7 @@ export class PuppetForgeDatasource extends Datasource { let module: PuppetModule; try { - const response = await this.http.getJson(url); + const response = await this.http.getJsonUnchecked(url); module = response.body; } catch (err) { this.handleGenericErrors(err); diff --git a/lib/modules/datasource/pypi/index.ts b/lib/modules/datasource/pypi/index.ts index 3e8812116e0555..16bcb1bcc9fc77 100644 --- a/lib/modules/datasource/pypi/index.ts +++ b/lib/modules/datasource/pypi/index.ts @@ -110,7 +110,9 @@ export class PypiDatasource extends Datasource { const dependency: ReleaseResult = { releases: [] }; logger.trace({ lookupUrl }, 'Pypi api got lookup'); const headers = await this.getAuthHeaders(lookupUrl); - const rep = await this.http.getJson(lookupUrl, { headers }); + const rep = await this.http.getJsonUnchecked(lookupUrl, { + headers, + }); const dep = rep?.body; if (!dep) { logger.trace({ dependency: packageName }, 'pip package not found'); diff --git a/lib/modules/datasource/repology/index.ts b/lib/modules/datasource/repology/index.ts index 987a2c20eac197..45295b7ae785bd 100644 --- a/lib/modules/datasource/repology/index.ts +++ b/lib/modules/datasource/repology/index.ts @@ -56,7 +56,7 @@ export class RepologyDatasource extends Datasource { private async queryPackages(url: string): Promise { try { - const res = await this.http.getJson(url); + const res = await this.http.getJsonUnchecked(url); return res.body; } catch (err) { if (err.statusCode === 404) { diff --git a/lib/modules/datasource/terraform-module/base.ts b/lib/modules/datasource/terraform-module/base.ts index 24f6a62493e949..e2c8aba86f56e6 100644 --- a/lib/modules/datasource/terraform-module/base.ts +++ b/lib/modules/datasource/terraform-module/base.ts @@ -22,7 +22,7 @@ export abstract class TerraformDatasource extends Datasource { ): Promise { const discoveryURL = TerraformDatasource.getDiscoveryUrl(registryUrl); const serviceDiscovery = ( - await this.http.getJson(discoveryURL) + await this.http.getJsonUnchecked(discoveryURL) ).body; return serviceDiscovery; } diff --git a/lib/modules/datasource/terraform-module/index.ts b/lib/modules/datasource/terraform-module/index.ts index 4e3b25e4bfd3ec..05ff6d5e972141 100644 --- a/lib/modules/datasource/terraform-module/index.ts +++ b/lib/modules/datasource/terraform-module/index.ts @@ -103,7 +103,7 @@ export class TerraformModuleDatasource extends TerraformDatasource { serviceDiscovery, repository, ); - res = (await this.http.getJson(pkgUrl)).body; + res = (await this.http.getJsonUnchecked(pkgUrl)).body; const returnedName = res.namespace + '/' + res.name + '/' + res.provider; if (returnedName !== repository) { logger.warn({ pkgUrl }, 'Terraform registry result mismatch'); @@ -152,7 +152,8 @@ export class TerraformModuleDatasource extends TerraformDatasource { serviceDiscovery, `${repository}/versions`, ); - res = (await this.http.getJson(pkgUrl)).body; + res = (await this.http.getJsonUnchecked(pkgUrl)) + .body; if (res.modules.length < 1) { logger.warn({ pkgUrl }, 'Terraform registry result mismatch'); return null; diff --git a/lib/modules/datasource/terraform-provider/index.ts b/lib/modules/datasource/terraform-provider/index.ts index b960f8cf424803..81f7de33cf51a2 100644 --- a/lib/modules/datasource/terraform-provider/index.ts +++ b/lib/modules/datasource/terraform-provider/index.ts @@ -113,7 +113,9 @@ export class TerraformProviderDatasource extends TerraformDatasource { serviceDiscovery, repository, ); - const res = (await this.http.getJson(backendURL)).body; + const res = ( + await this.http.getJsonUnchecked(backendURL) + ).body; const dep: ReleaseResult = { releases: res.versions.map((version) => ({ version, @@ -149,8 +151,9 @@ export class TerraformProviderDatasource extends TerraformDatasource { serviceDiscovery, `${repository}/versions`, ); - const res = (await this.http.getJson(backendURL)) - .body; + const res = ( + await this.http.getJsonUnchecked(backendURL) + ).body; const dep: ReleaseResult = { releases: res.versions.map(({ version }) => ({ version, @@ -171,7 +174,9 @@ export class TerraformProviderDatasource extends TerraformDatasource { `index.json`, ); const res = ( - await this.http.getJson(backendURL) + await this.http.getJsonUnchecked( + backendURL, + ) ).body; const dep: ReleaseResult = { @@ -240,7 +245,7 @@ export class TerraformProviderDatasource extends TerraformDatasource { repository, ); const versionsResponse = ( - await this.http.getJson( + await this.http.getJsonUnchecked( `${backendURL}/versions`, ) ).body; @@ -263,7 +268,9 @@ export class TerraformProviderDatasource extends TerraformDatasource { const buildURL = `${backendURL}/${version}/download/${platform.os}/${platform.arch}`; try { const res = ( - await this.http.getJson(buildURL) + await this.http.getJsonUnchecked( + buildURL, + ) ).body; const newBuild: TerraformBuild = { name: repository, @@ -325,7 +332,7 @@ export class TerraformProviderDatasource extends TerraformDatasource { version: string, ): Promise { return ( - await this.http.getJson( + await this.http.getJsonUnchecked( `${TerraformProviderDatasource.defaultRegistryUrls[1]}/${backendLookUpName}/${version}/index.json`, ) ).body; diff --git a/lib/modules/manager/azure-pipelines/readme.md b/lib/modules/manager/azure-pipelines/readme.md index 47d9fe7058aacf..ddf32fdbce8e32 100644 --- a/lib/modules/manager/azure-pipelines/readme.md +++ b/lib/modules/manager/azure-pipelines/readme.md @@ -44,7 +44,7 @@ resources: - container: linux image: ubuntu:24.04 - container: python - image: python:3.13@sha256:cea505b81701dd9e46b8dde96eaa8054c4bd2035dbb660edeb7af947ed38a0ad + image: python:3.13@sha256:d57ec66c94b9497b9f3c66f6cdddc1e4e0bad4c584397e0b57a721baef0e6fdc stages: - stage: StageOne diff --git a/lib/modules/manager/cocoapods/extract.ts b/lib/modules/manager/cocoapods/extract.ts index 041c2a8a0aace5..50faed7450ac8b 100644 --- a/lib/modules/manager/cocoapods/extract.ts +++ b/lib/modules/manager/cocoapods/extract.ts @@ -36,12 +36,12 @@ export function parseLine(line: string): ParsedLine { const depName = result.subspec ? `${result.spec}/${result.subspec}` : result.spec; - const groupName = result.spec; + const specName = result.spec; if (depName) { result.depName = depName; } - if (groupName) { - result.groupName = groupName; + if (specName) { + result.specName = specName; } delete result.spec; delete result.subspec; @@ -96,7 +96,7 @@ export async function extractPackageFile( const parsedLine = parseLine(line); const { depName, - groupName, + specName, currentValue, git, tag, @@ -112,14 +112,14 @@ export async function extractPackageFile( const managerData = { lineNumber }; let dep: PackageDependency = { depName, - groupName, + sharedVariableName: specName, skipReason: 'unspecified-version', }; if (currentValue) { dep = { depName, - groupName, + sharedVariableName: specName, datasource: PodDatasource.id, currentValue, managerData, @@ -131,14 +131,14 @@ export async function extractPackageFile( } else { dep = { depName, - groupName, + sharedVariableName: specName, skipReason: 'git-dependency', }; } } else if (path) { dep = { depName, - groupName, + sharedVariableName: specName, skipReason: 'path-dependency', }; } diff --git a/lib/modules/manager/cocoapods/types.ts b/lib/modules/manager/cocoapods/types.ts index 74fef13b828c8f..311fb8d867ca32 100644 --- a/lib/modules/manager/cocoapods/types.ts +++ b/lib/modules/manager/cocoapods/types.ts @@ -1,6 +1,6 @@ export interface ParsedLine { depName?: string; - groupName?: string; + specName?: string; spec?: string; subspec?: string; currentValue?: string; diff --git a/lib/modules/manager/flux/__fixtures__/multidoc.yaml b/lib/modules/manager/flux/__fixtures__/multidoc.yaml index 675feac3fc5860..9fdea372428dd6 100644 --- a/lib/modules/manager/flux/__fixtures__/multidoc.yaml +++ b/lib/modules/manager/flux/__fixtures__/multidoc.yaml @@ -13,6 +13,10 @@ spec: name: external-dns version: "1.7.0" interval: 1h0m0s + values: + image: + repository: k8s.gcr.io/external-dns/external-dns + tag: v0.13.4 --- apiVersion: source.toolkit.fluxcd.io/v1beta1 kind: HelmRepository diff --git a/lib/modules/manager/flux/extract.spec.ts b/lib/modules/manager/flux/extract.spec.ts index 739fb6d26e8715..c3c13cca81f565 100644 --- a/lib/modules/manager/flux/extract.spec.ts +++ b/lib/modules/manager/flux/extract.spec.ts @@ -37,6 +37,16 @@ describe('modules/manager/flux/extract', () => { depName: 'external-dns', registryUrls: ['https://kubernetes-sigs.github.io/external-dns/'], }, + { + autoReplaceStringTemplate: + '{{newValue}}{{#if newDigest}}@{{newDigest}}{{/if}}', + currentDigest: undefined, + currentValue: 'v0.13.4', + datasource: DockerDatasource.id, + depName: 'k8s.gcr.io/external-dns/external-dns', + replaceString: 'v0.13.4', + versioning: DockerDatasource.id, + }, { currentValue: 'v11.35.4', datasource: GithubTagsDatasource.id, diff --git a/lib/modules/manager/flux/extract.ts b/lib/modules/manager/flux/extract.ts index c99728199bc8c0..a8483bb358668d 100644 --- a/lib/modules/manager/flux/extract.ts +++ b/lib/modules/manager/flux/extract.ts @@ -13,6 +13,7 @@ import { GithubTagsDatasource } from '../../datasource/github-tags'; import { GitlabTagsDatasource } from '../../datasource/gitlab-tags'; import { HelmDatasource } from '../../datasource/helm'; import { getDep } from '../dockerfile/extract'; +import { findDependencies } from '../helm-values/extract'; import { isOCIRegistry, removeOCIPrefix } from '../helmv3/oci'; import { extractImage } from '../kustomize/extract'; import type { @@ -198,6 +199,10 @@ function resolveResourceManifest( ); resolveHelmRepository(dep, matchingRepositories, registryAliases); deps.push(dep); + + if (resource.spec.values) { + deps.push(...findDependencies(resource.spec.values, registryAliases)); + } break; } diff --git a/lib/modules/manager/flux/readme.md b/lib/modules/manager/flux/readme.md index d7a950582917ad..bf23458a8401bc 100644 --- a/lib/modules/manager/flux/readme.md +++ b/lib/modules/manager/flux/readme.md @@ -24,6 +24,8 @@ Namespaces will not be inferred from the context (e.g. from the parent `Kustomiz Renovate updates `HelmRelease` resources coming from `GitRepository` by updating the `GitRepository` resource. +Renovate updates Docker dependencies inside `HelmRelease` `values` like the [`helm-values`](../helm-values/index.md) manager. + ### GitRepository support Renovate can update `git` references from `GitRepository` resources. diff --git a/lib/modules/manager/flux/schema.ts b/lib/modules/manager/flux/schema.ts index b62413b88b073c..87535be5255133 100644 --- a/lib/modules/manager/flux/schema.ts +++ b/lib/modules/manager/flux/schema.ts @@ -38,6 +38,7 @@ export const HelmRelease = KubernetesResource.extend({ namespace: z.string().optional(), }) .optional(), + values: z.record(z.unknown()).optional(), }), }); export type HelmRelease = z.infer; diff --git a/lib/modules/manager/git-submodules/artifacts.ts b/lib/modules/manager/git-submodules/artifacts.ts index 531588df13c5f0..c8f6c334771c2b 100644 --- a/lib/modules/manager/git-submodules/artifacts.ts +++ b/lib/modules/manager/git-submodules/artifacts.ts @@ -7,7 +7,7 @@ export default function updateArtifacts({ const res: UpdateArtifactsResult[] = []; updatedDeps.forEach((dep) => { // TODO: types (#22198) - logger.info(`Updating submodule ${dep.depName}`); + logger.debug(`Updating submodule ${dep.depName}`); res.push({ file: { type: 'addition', path: dep.depName!, contents: '' }, }); diff --git a/lib/modules/manager/gradle/extract.spec.ts b/lib/modules/manager/gradle/extract.spec.ts index bd11d3a32ac66c..25c24846e3805c 100644 --- a/lib/modules/manager/gradle/extract.spec.ts +++ b/lib/modules/manager/gradle/extract.spec.ts @@ -188,27 +188,27 @@ describe('modules/manager/gradle/extract', () => { { depName: 'javax.cache:cache-api', currentValue: '1.1.0', - groupName: 'Libraries.jCache', + sharedVariableName: 'Libraries.jCache', }, { depName: 'com.android.tools.build:gradle', currentValue: '4.1.2', - groupName: 'Libraries.Android.Tools.version', + sharedVariableName: 'Libraries.Android.Tools.version', }, { depName: 'androidx.test:core', currentValue: '1.3.0-rc01', - groupName: 'Libraries.Test.version', + sharedVariableName: 'Libraries.Test.version', }, { depName: 'androidx.test.espresso:espresso-core', currentValue: '3.3.0-rc01', - groupName: 'Libraries.Test.Espresso.version', + sharedVariableName: 'Libraries.Test.Espresso.version', }, { depName: 'androidx.test:core-ktx', currentValue: '1.3.0-rc01', - groupName: 'Libraries.Test.version', + sharedVariableName: 'Libraries.Test.version', }, ], }, @@ -218,7 +218,7 @@ describe('modules/manager/gradle/extract', () => { { depName: 'org.jetbrains.kotlin:kotlin-stdlib', currentValue: '1.8.10', - groupName: 'GradleDeps.Kotlin.version', + sharedVariableName: 'GradleDeps.Kotlin.version', }, ], }, @@ -228,12 +228,12 @@ describe('modules/manager/gradle/extract', () => { { depName: 'com.fasterxml.jackson.core:jackson-annotations', currentValue: '2.9.10', - groupName: 'Versions.jackson', + sharedVariableName: 'Versions.jackson', }, { depName: 'io.reactivex.rxjava2:rxjava', currentValue: '1.2.3', - groupName: 'Versions.rxjava', + sharedVariableName: 'Versions.rxjava', }, ], }, @@ -513,7 +513,7 @@ describe('modules/manager/gradle/extract', () => { deps: [ { depName: 'io.gitlab.arturbosch.detekt:detekt-formatting', - groupName: 'detekt', + sharedVariableName: 'detekt', currentValue: '1.17.0', managerData: { fileReplacePosition: 21, @@ -522,7 +522,7 @@ describe('modules/manager/gradle/extract', () => { }, { depName: 'io.kotest:kotest-assertions-core-jvm', - groupName: 'kotest', + sharedVariableName: 'kotest', currentValue: '4.6.0', managerData: { fileReplacePosition: 51, @@ -531,7 +531,7 @@ describe('modules/manager/gradle/extract', () => { }, { depName: 'io.kotest:kotest-runner-junit5', - groupName: 'kotest', + sharedVariableName: 'kotest', currentValue: '4.6.0', managerData: { fileReplacePosition: 51, @@ -627,6 +627,58 @@ describe('modules/manager/gradle/extract', () => { ), ).toBeNull(); }); + + it('deletes commit message for plugins with version reference', async () => { + const fsMock = { + 'gradle/libs.versions.toml': codeBlock` + [versions] + detekt = "1.18.1" + + [plugins] + detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" } + + [libraries] + detekt-formatting = { module = "io.gitlab.arturbosch.detekt:detekt-formatting", version.ref = "detekt" } + `, + }; + mockFs(fsMock); + + const res = await extractAllPackageFiles( + partial(), + Object.keys(fsMock), + ); + expect(res).toMatchObject([ + { + packageFile: 'gradle/libs.versions.toml', + deps: [ + { + depName: 'io.gitlab.arturbosch.detekt:detekt-formatting', + sharedVariableName: 'detekt', + currentValue: '1.18.1', + managerData: { + fileReplacePosition: 21, + packageFile: 'gradle/libs.versions.toml', + }, + fileReplacePosition: 21, + }, + { + depType: 'plugin', + depName: 'io.gitlab.arturbosch.detekt', + packageName: + 'io.gitlab.arturbosch.detekt:io.gitlab.arturbosch.detekt.gradle.plugin', + registryUrls: ['https://plugins.gradle.org/m2/'], + currentValue: '1.18.1', + managerData: { + fileReplacePosition: 21, + packageFile: 'gradle/libs.versions.toml', + }, + sharedVariableName: 'detekt', + fileReplacePosition: 21, + }, + ], + }, + ]); + }); }); describe('apply from', () => { @@ -817,7 +869,7 @@ describe('modules/manager/gradle/extract', () => { depName: 'org.apache.lucene:lucene-core', depType: 'dependencies', fileReplacePosition: 22, - groupName: 'org.apache.lucene:*', + sharedVariableName: 'org.apache.lucene:*', lockedVersion: '1.2.3', managerData: { fileReplacePosition: 22, @@ -828,7 +880,7 @@ describe('modules/manager/gradle/extract', () => { depName: 'org.apache.lucene:lucene-codecs', depType: 'dependencies', fileReplacePosition: 22, - groupName: 'org.apache.lucene:*', + sharedVariableName: 'org.apache.lucene:*', lockedVersion: '1.2.3', managerData: { fileReplacePosition: 22, @@ -869,5 +921,117 @@ describe('modules/manager/gradle/extract', () => { ); expect(res).toBeNull(); }); + + it('supports multiple levels of glob', async () => { + const fsMock = { + 'versions.props': codeBlock` + org.apache.* = 4 + org.apache.lucene:* = 3 + org.apache.lucene:a.* = 2 + org.apache.lucene:a.b = 1 + org.apache.foo*:* = 5 + `, + 'versions.lock': codeBlock` + # Run ./gradlew --write-locks to regenerate this file + org.apache.solr:x.y:1 (10 constraints: 95be0c15) + org.apache.lucene:a.b:1 (10 constraints: 95be0c15) + org.apache.lucene:a.c:1 (10 constraints: 95be0c15) + org.apache.lucene:a.d:1 (10 constraints: 95be0c15) + org.apache.lucene:d:1 (10 constraints: 95be0c15) + org.apache.lucene:e.f:1 (10 constraints: 95be0c15) + org.apache.foo-bar:a:1 (10 constraints: 95be0c15) + `, + }; + mockFs(fsMock); + + const res = await extractAllPackageFiles( + partial(), + Object.keys(fsMock), + ); + + // Each lock dep is only present once, with highest prio for exact prop match, then globs from longest to shortest + expect(res).toMatchObject([ + { + packageFile: 'versions.lock', + deps: [], + }, + { + packageFile: 'versions.props', + deps: [ + { + managerData: { + packageFile: 'versions.props', + fileReplacePosition: 91, + }, + depName: 'org.apache.lucene:a.b', + currentValue: '1', + lockedVersion: '1', + fileReplacePosition: 91, + depType: 'dependencies', + }, + { + managerData: { + packageFile: 'versions.props', + fileReplacePosition: 65, + }, + depName: 'org.apache.lucene:a.c', + currentValue: '2', + lockedVersion: '1', + sharedVariableName: 'org.apache.lucene:a.*', + fileReplacePosition: 65, + depType: 'dependencies', + }, + { + managerData: { + packageFile: 'versions.props', + fileReplacePosition: 65, + }, + depName: 'org.apache.lucene:a.d', + currentValue: '2', + lockedVersion: '1', + sharedVariableName: 'org.apache.lucene:a.*', + fileReplacePosition: 65, + depType: 'dependencies', + }, + { + managerData: { + packageFile: 'versions.props', + fileReplacePosition: 39, + }, + depName: 'org.apache.lucene:d', + currentValue: '3', + lockedVersion: '1', + sharedVariableName: 'org.apache.lucene:*', + fileReplacePosition: 39, + depType: 'dependencies', + }, + { + managerData: { + packageFile: 'versions.props', + fileReplacePosition: 39, + }, + depName: 'org.apache.lucene:e.f', + currentValue: '3', + lockedVersion: '1', + sharedVariableName: 'org.apache.lucene:*', + fileReplacePosition: 39, + depType: 'dependencies', + }, + { + managerData: { + fileReplacePosition: 113, + packageFile: 'versions.props', + }, + depName: 'org.apache.foo-bar:a', + currentValue: '5', + lockedVersion: '1', + sharedVariableName: 'org.apache.foo*:*', + fileReplacePosition: 113, + depType: 'dependencies', + }, + ], + }, + ]); + }); }); }); diff --git a/lib/modules/manager/gradle/extract/catalog.spec.ts b/lib/modules/manager/gradle/extract/catalog.spec.ts index f1dc53281634a5..6f470a04b77c07 100644 --- a/lib/modules/manager/gradle/extract/catalog.spec.ts +++ b/lib/modules/manager/gradle/extract/catalog.spec.ts @@ -50,7 +50,7 @@ describe('modules/manager/gradle/extract/catalog', () => { }, { depName: 'com.squareup.retrofit2:retrofit', - groupName: 'retro.fit', + sharedVariableName: 'retro.fit', currentValue: '2.8.2', managerData: { fileReplacePosition: 42, @@ -94,7 +94,7 @@ describe('modules/manager/gradle/extract/catalog', () => { depName: 'org.jetbrains.kotlin.plugin.serialization', depType: 'plugin', currentValue: '1.5.21', - groupName: 'kotlin', + sharedVariableName: 'kotlin', packageName: 'org.jetbrains.kotlin.plugin.serialization:org.jetbrains.kotlin.plugin.serialization.gradle.plugin', managerData: { @@ -133,7 +133,7 @@ describe('modules/manager/gradle/extract/catalog', () => { expect(res).toStrictEqual([ { depName: 'io.gitlab.arturbosch.detekt:detekt-formatting', - groupName: 'detekt', + sharedVariableName: 'detekt', currentValue: '1.18.1', managerData: { fileReplacePosition: 21, @@ -150,7 +150,7 @@ describe('modules/manager/gradle/extract/catalog', () => { fileReplacePosition: 21, packageFile: 'gradle/libs.versions.toml', }, - groupName: 'detekt', + sharedVariableName: 'detekt', }, ]); }); @@ -173,7 +173,7 @@ describe('modules/manager/gradle/extract/catalog', () => { expect(res).toStrictEqual([ { depName: 'junit:junit', - groupName: 'junit', + sharedVariableName: 'junit', currentValue: '1.4.9', managerData: { fileReplacePosition: 124, @@ -182,7 +182,7 @@ describe('modules/manager/gradle/extract/catalog', () => { }, { depName: 'mocha-junit:mocha-junit', - groupName: 'mocha.junit.reporter', + sharedVariableName: 'mocha.junit.reporter', currentValue: '2.0.2', managerData: { fileReplacePosition: 82, diff --git a/lib/modules/manager/gradle/extract/catalog.ts b/lib/modules/manager/gradle/extract/catalog.ts index e4ed8d634266a6..36a21a5b80639e 100644 --- a/lib/modules/manager/gradle/extract/catalog.ts +++ b/lib/modules/manager/gradle/extract/catalog.ts @@ -188,7 +188,7 @@ function extractDependency({ versionSubContent: string; }): PackageDependency { if (is.string(descriptor)) { - const [groupName, name, currentValue] = descriptor.split(':'); + const [group, name, currentValue] = descriptor.split(':'); if (!currentValue) { return { depName, @@ -196,7 +196,7 @@ function extractDependency({ }; } return { - depName: `${groupName}:${name}`, + depName: `${group}:${name}`, currentValue, managerData: { fileReplacePosition: @@ -236,7 +236,7 @@ function extractDependency({ } if (isVersionPointer(descriptor.version)) { - dependency.groupName = normalizeAlias(descriptor.version.ref); + dependency.sharedVariableName = normalizeAlias(descriptor.version.ref); } return dependency; @@ -298,7 +298,7 @@ export function parseCatalog( dependency.skipReason = skipReason; } if (isVersionPointer(version) && dependency.commitMessageTopic) { - dependency.groupName = normalizeAlias(version.ref); + dependency.sharedVariableName = normalizeAlias(version.ref); delete dependency.commitMessageTopic; } diff --git a/lib/modules/manager/gradle/extract/consistent-versions-plugin.spec.ts b/lib/modules/manager/gradle/extract/consistent-versions-plugin.spec.ts index fdde721e725453..850031576ba663 100644 --- a/lib/modules/manager/gradle/extract/consistent-versions-plugin.spec.ts +++ b/lib/modules/manager/gradle/extract/consistent-versions-plugin.spec.ts @@ -136,7 +136,7 @@ describe('modules/manager/gradle/extract/consistent-versions-plugin', () => { depName: 'org.apache.lucene:a.c', currentValue: '2', lockedVersion: '1', - groupName: 'org.apache.lucene:a.*', + sharedVariableName: 'org.apache.lucene:a.*', depType: 'dependencies', }, { @@ -147,7 +147,7 @@ describe('modules/manager/gradle/extract/consistent-versions-plugin', () => { depName: 'org.apache.lucene:a.d', currentValue: '2', lockedVersion: '1', - groupName: 'org.apache.lucene:a.*', + sharedVariableName: 'org.apache.lucene:a.*', depType: 'dependencies', }, { @@ -158,7 +158,7 @@ describe('modules/manager/gradle/extract/consistent-versions-plugin', () => { depName: 'org.apache.lucene:d', currentValue: '3', lockedVersion: '1', - groupName: 'org.apache.lucene:*', + sharedVariableName: 'org.apache.lucene:*', depType: 'dependencies', }, { @@ -169,7 +169,7 @@ describe('modules/manager/gradle/extract/consistent-versions-plugin', () => { depName: 'org.apache.lucene:e.f', currentValue: '3', lockedVersion: '1', - groupName: 'org.apache.lucene:*', + sharedVariableName: 'org.apache.lucene:*', depType: 'dependencies', }, { @@ -180,7 +180,7 @@ describe('modules/manager/gradle/extract/consistent-versions-plugin', () => { depName: 'org.apache.foo-bar:a', currentValue: '5', lockedVersion: '1', - groupName: 'org.apache.foo*:*', + sharedVariableName: 'org.apache.foo*:*', depType: 'dependencies', }, ]); diff --git a/lib/modules/manager/gradle/extract/consistent-versions-plugin.ts b/lib/modules/manager/gradle/extract/consistent-versions-plugin.ts index 4feeb371208802..22ec356576adbe 100644 --- a/lib/modules/manager/gradle/extract/consistent-versions-plugin.ts +++ b/lib/modules/manager/gradle/extract/consistent-versions-plugin.ts @@ -102,7 +102,7 @@ export function parseGcv( currentValue: propVerAndPos.version, lockedVersion: lockVersionAndDepType.version, depType: lockVersionAndDepType.depType, - groupName: propDepGlob, + sharedVariableName: propDepGlob, } satisfies PackageDependency; extractedDeps.push(newDep); // Remove from the lockfile map so the same lib will not be included in more generic globs later diff --git a/lib/modules/manager/gradle/parser.spec.ts b/lib/modules/manager/gradle/parser.spec.ts index 6e835a56d6be00..037799c81c6e3b 100644 --- a/lib/modules/manager/gradle/parser.spec.ts +++ b/lib/modules/manager/gradle/parser.spec.ts @@ -179,32 +179,32 @@ describe('modules/manager/gradle/parser', () => { expect(deps).toMatchObject([ { depName: 'org.slf4j:jcl-over-slf4j', - groupName: 'slfj4Version', + sharedVariableName: 'slfj4Version', currentValue: '2.0.0', }, { depName: 'org.jetbrains.kotlinx:kotlinx-coroutines-core', - groupName: 'libraries.releaseCoroutines', + sharedVariableName: 'libraries.releaseCoroutines', currentValue: '0.26.1-eap13', }, { depName: 'org.slf4j:slf4j-api', - groupName: 'slfj4Version', + sharedVariableName: 'slfj4Version', currentValue: '2.0.0', }, { depName: 'androidx.lifecycle:lifecycle-runtime-ktx', - groupName: 'lifecycle_version', + sharedVariableName: 'lifecycle_version', currentValue: '2.5.1', }, { depName: 'androidx.lifecycle:lifecycle-viewmodel-ktx', - groupName: 'lifecycle_version', + sharedVariableName: 'lifecycle_version', currentValue: '2.5.1', }, { depName: 'org.slf4j:slf4j-ext', - groupName: 'slfj4Version', + sharedVariableName: 'slfj4Version', currentValue: '2.0.0', }, ]); @@ -333,17 +333,17 @@ describe('modules/manager/gradle/parser', () => { expect(deps).toMatchObject([ { depName: 'org.slf4j:jcl-over-slf4j', - groupName: 'slfj4Version', + sharedVariableName: 'slfj4Version', currentValue: '2.0.0', }, { depName: 'org.jetbrains.kotlinx:kotlinx-coroutines-core', - groupName: 'libraries.releaseCoroutines', + sharedVariableName: 'libraries.releaseCoroutines', currentValue: '0.26.1-eap13', }, { depName: 'org.slf4j:slf4j-api', - groupName: 'slfj4Version', + sharedVariableName: 'slfj4Version', currentValue: '2.0.0', }, ]); @@ -372,18 +372,18 @@ describe('modules/manager/gradle/parser', () => { ${'foo = "1.2.3"'} | ${'"foo:bar:$foo@@@"'} | ${null} ${''} | ${'"foo:bar:$baz"'} | ${null} ${'foo = "1"; bar = "2"; baz = "3"'} | ${'"foo:bar:$foo.$bar.$baz"'} | ${{ depName: 'foo:bar', currentValue: '1.2.3', skipReason: 'contains-variable' }} - ${'baz = "1.2.3"'} | ${'"foo:bar:$baz"'} | ${{ depName: 'foo:bar', currentValue: '1.2.3', groupName: 'baz' }} - ${'foo.bar = "1.2.3"'} | ${'"foo:bar:$foo.bar"'} | ${{ depName: 'foo:bar', currentValue: '1.2.3', groupName: 'foo.bar' }} + ${'baz = "1.2.3"'} | ${'"foo:bar:$baz"'} | ${{ depName: 'foo:bar', currentValue: '1.2.3', sharedVariableName: 'baz' }} + ${'foo.bar = "1.2.3"'} | ${'"foo:bar:$foo.bar"'} | ${{ depName: 'foo:bar', currentValue: '1.2.3', sharedVariableName: 'foo.bar' }} ${'foo = "1.2.3"'} | ${'"foo:bar_$foo:4.5.6"'} | ${{ depName: 'foo:bar_1.2.3', managerData: { fileReplacePosition: 28 } }} ${'foo = "bar"'} | ${'"foo:${foo}1:1"'} | ${{ depName: 'foo:bar1', currentValue: '1', managerData: { fileReplacePosition: 25 } }} ${'bar = "bar:1.2.3"'} | ${'"foo:$bar"'} | ${{ depName: 'foo:bar', currentValue: '1.2.3', skipReason: 'contains-variable' }} - ${'baz = "1.2.3"'} | ${'foobar = "foo:bar:$baz"'} | ${{ depName: 'foo:bar', currentValue: '1.2.3', groupName: 'baz' }} + ${'baz = "1.2.3"'} | ${'foobar = "foo:bar:$baz"'} | ${{ depName: 'foo:bar', currentValue: '1.2.3', sharedVariableName: 'baz' }} ${'foo = "${bar}"; baz = "1.2.3"'} | ${'"foo:bar:${baz}"'} | ${{ depName: 'foo:bar', currentValue: '1.2.3' }} - ${'baz = "1.2.3"'} | ${'"foo:bar:${ext[\'baz\']}"'} | ${{ depName: 'foo:bar', currentValue: '1.2.3', groupName: 'baz' }} - ${'baz = "1.2.3"'} | ${'"foo:bar:${ext.baz}"'} | ${{ depName: 'foo:bar', currentValue: '1.2.3', groupName: 'baz' }} - ${'baz = "1.2.3"'} | ${'"foo:bar:${project.ext[\'baz\']}"'} | ${{ depName: 'foo:bar', currentValue: '1.2.3', groupName: 'baz' }} - ${'a = "foo"; b = "bar"; c="1.2.3"'} | ${'"${a}:${b}:${property("c")}"'} | ${{ depName: 'foo:bar', currentValue: '1.2.3', groupName: 'c' }} - ${'a = "foo"; b = "bar"; c="1.2.3"'} | ${'"${a}:${b}:${properties["c"]}"'} | ${{ depName: 'foo:bar', currentValue: '1.2.3', groupName: 'c' }} + ${'baz = "1.2.3"'} | ${'"foo:bar:${ext[\'baz\']}"'} | ${{ depName: 'foo:bar', currentValue: '1.2.3', sharedVariableName: 'baz' }} + ${'baz = "1.2.3"'} | ${'"foo:bar:${ext.baz}"'} | ${{ depName: 'foo:bar', currentValue: '1.2.3', sharedVariableName: 'baz' }} + ${'baz = "1.2.3"'} | ${'"foo:bar:${project.ext[\'baz\']}"'} | ${{ depName: 'foo:bar', currentValue: '1.2.3', sharedVariableName: 'baz' }} + ${'a = "foo"; b = "bar"; c="1.2.3"'} | ${'"${a}:${b}:${property("c")}"'} | ${{ depName: 'foo:bar', currentValue: '1.2.3', sharedVariableName: 'c' }} + ${'a = "foo"; b = "bar"; c="1.2.3"'} | ${'"${a}:${b}:${properties["c"]}"'} | ${{ depName: 'foo:bar', currentValue: '1.2.3', sharedVariableName: 'c' }} `('$def | $str', ({ def, str, output }) => { const { deps } = parseGradle([def, str].join('\n')); expect(deps).toMatchObject([output].filter(is.truthy)); @@ -434,7 +434,11 @@ describe('modules/manager/gradle/parser', () => { `; const { deps } = parseGradle(input); expect(deps).toMatchObject([ - { depName: 'foo:bar', currentValue: '1.2.3', groupName: 'baz' }, + { + depName: 'foo:bar', + currentValue: '1.2.3', + sharedVariableName: 'baz', + }, ]); }); }); @@ -452,7 +456,7 @@ describe('modules/manager/gradle/parser', () => { ${''} | ${'kotlin("foo", version = "1.2.3")'} | ${output} ${'some = "foo"'} | ${'kotlin(some, version = "1.2.3")'} | ${output} ${'some = "foo"'} | ${'kotlin("${some}", "1.2.3")'} | ${output} - ${'baz = "1.2.3"'} | ${'kotlin("foo", baz)'} | ${{ ...output, groupName: 'baz' }} + ${'baz = "1.2.3"'} | ${'kotlin("foo", baz)'} | ${{ ...output, sharedVariableName: 'baz' }} ${'baz = "1.2.3"'} | ${'kotlin("foo", version = baz)'} | ${output} ${'baz = "1.2.3"'} | ${'kotlin("foo", property("baz"))'} | ${output} ${'baz = "1.2.3"'} | ${'kotlin("foo", "${baz}456")'} | ${{ skipReason: 'unspecified-version' }} @@ -473,21 +477,21 @@ describe('modules/manager/gradle/parser', () => { ${''} | ${'group: "foo", name: "bar", version: "1.2.3"'} | ${{ depName: 'foo:bar', currentValue: '1.2.3' }} ${''} | ${'group: "foo", name: "bar", version: baz'} | ${null} ${''} | ${'group: "foo", name: "bar", version: "1.2.3@@@"'} | ${null} - ${'baz = "1.2.3"'} | ${'group: "foo", name: "bar", version: baz'} | ${{ depName: 'foo:bar', currentValue: '1.2.3', groupName: 'baz' }} + ${'baz = "1.2.3"'} | ${'group: "foo", name: "bar", version: baz'} | ${{ depName: 'foo:bar', currentValue: '1.2.3', sharedVariableName: 'baz' }} ${'some = "foo"'} | ${'group: property("some"), name: property("some"), version: "1.2.3"'} | ${{ depName: 'foo:foo', currentValue: '1.2.3' }} ${'some = "foo"'} | ${'group: some, name: some, version: "1.2.3"'} | ${{ depName: 'foo:foo', currentValue: '1.2.3' }} ${'some = "foo"'} | ${'group: "${some}", name: "${some}", version: "1.2.3"'} | ${{ depName: 'foo:foo', currentValue: '1.2.3' }} - ${'baz = "1.2.3"'} | ${'group: "foo", name: "bar", version: "${baz}"'} | ${{ depName: 'foo:bar', currentValue: '1.2.3', groupName: 'baz' }} + ${'baz = "1.2.3"'} | ${'group: "foo", name: "bar", version: "${baz}"'} | ${{ depName: 'foo:bar', currentValue: '1.2.3', sharedVariableName: 'baz' }} ${'baz = "1.2.3"'} | ${'group: "foo", name: "bar", version: "${baz}456"'} | ${{ depName: 'foo:bar', skipReason: 'unspecified-version' }} ${''} | ${'(group: "foo", name: "bar", version: "1.2.3", classifier: "sources")'} | ${{ depName: 'foo:bar', currentValue: '1.2.3' }} ${''} | ${'(group: "foo", name: "bar", version: "1.2.3") {exclude module: "spring-jcl"}'} | ${{ depName: 'foo:bar', currentValue: '1.2.3' }} ${''} | ${"implementation platform(group: 'foo', name: 'bar', version: '1.2.3')"} | ${{ depName: 'foo:bar', currentValue: '1.2.3' }} ${''} | ${'(group = "foo", name = "bar", version = "1.2.3")'} | ${{ depName: 'foo:bar', currentValue: '1.2.3' }} - ${'baz = "1.2.3"'} | ${'(group = "foo", name = "bar", version = baz)'} | ${{ depName: 'foo:bar', currentValue: '1.2.3', groupName: 'baz' }} + ${'baz = "1.2.3"'} | ${'(group = "foo", name = "bar", version = baz)'} | ${{ depName: 'foo:bar', currentValue: '1.2.3', sharedVariableName: 'baz' }} ${'some = "foo"'} | ${'(group = some, name = some, version = "1.2.3")'} | ${{ depName: 'foo:foo', currentValue: '1.2.3' }} ${'some = "foo"'} | ${'(group = "${some}", name = "${some}", version = "1.2.3")'} | ${{ depName: 'foo:foo', currentValue: '1.2.3' }} ${'some = "foo"'} | ${'(group = "${some}" + some, name = some + "bar" + some, version = "1.2.3")'} | ${{ depName: 'foofoo:foobarfoo', currentValue: '1.2.3' }} - ${'baz = "1.2.3"'} | ${'(group = "foo", name = "bar", version = "${baz}")'} | ${{ depName: 'foo:bar', currentValue: '1.2.3', groupName: 'baz' }} + ${'baz = "1.2.3"'} | ${'(group = "foo", name = "bar", version = "${baz}")'} | ${{ depName: 'foo:bar', currentValue: '1.2.3', sharedVariableName: 'baz' }} ${'baz = "1.2.3"'} | ${'(group = "foo", name = "bar", version = "${baz}456")'} | ${{ depName: 'foo:bar', currentValue: '1.2.3456', skipReason: 'unspecified-version' }} ${'baz = "1.2.3"'} | ${'(group = "foo", name = "bar", version = baz + "456")'} | ${{ depName: 'foo:bar', currentValue: '1.2.3456', skipReason: 'unspecified-version' }} ${''} | ${'(group = "foo", name = "bar", version = "1.2.3", changing: true)'} | ${{ depName: 'foo:bar', currentValue: '1.2.3' }} @@ -515,17 +519,17 @@ describe('modules/manager/gradle/parser', () => { { depName: 'org.apache.activemq:activemq-broker', currentValue: '5.8.0', - groupName: 'activemq_version', + sharedVariableName: 'activemq_version', }, { depName: 'org.apache.activemq:activemq-kahadb-store', currentValue: '5.8.0', - groupName: 'activemq_version', + sharedVariableName: 'activemq_version', }, { depName: 'org.apache.activemq:activemq-stomp', currentValue: '5.8.0', - groupName: 'activemq_version', + sharedVariableName: 'activemq_version', }, ]); }); @@ -535,16 +539,16 @@ describe('modules/manager/gradle/parser', () => { { depName: 'foo:bar1', currentValue: '1.2.3', - groupName: 'foo:1.2.3', + sharedVariableName: 'foo:1.2.3', }, { depName: 'foo:bar2', currentValue: '1.2.3', - groupName: 'foo:1.2.3', + sharedVariableName: 'foo:1.2.3', }, ]; const validOutput1 = validOutput.map((dep) => { - return { ...dep, groupName: 'baz' }; + return { ...dep, sharedVariableName: 'baz' }; }); it.each` @@ -584,7 +588,7 @@ describe('modules/manager/gradle/parser', () => { ${''} | ${'id("foo.bar") version("1.2.3")'} | ${{ depName: 'foo.bar', packageName: 'foo.bar:foo.bar.gradle.plugin', currentValue: '1.2.3' }} ${''} | ${'id("foo.bar") version "1.2.3"'} | ${{ depName: 'foo.bar', packageName: 'foo.bar:foo.bar.gradle.plugin', currentValue: '1.2.3' }} ${''} | ${'id "foo.bar" version "$baz"'} | ${{ depName: 'foo.bar', skipReason: 'unspecified-version', currentValue: 'baz' }} - ${'baz = "1.2.3"'} | ${'id "foo.bar" version "$baz"'} | ${{ depName: 'foo.bar', packageName: 'foo.bar:foo.bar.gradle.plugin', currentValue: '1.2.3', groupName: 'baz' }} + ${'baz = "1.2.3"'} | ${'id "foo.bar" version "$baz"'} | ${{ depName: 'foo.bar', packageName: 'foo.bar:foo.bar.gradle.plugin', currentValue: '1.2.3', sharedVariableName: 'baz' }} ${'baz = "1.2.3"'} | ${'id("foo.bar") version "$baz"'} | ${{ depName: 'foo.bar', packageName: 'foo.bar:foo.bar.gradle.plugin', currentValue: '1.2.3' }} ${''} | ${'id "foo.bar" version "x${ab}cd"'} | ${{ depName: 'foo.bar', skipReason: 'unspecified-version' }} ${''} | ${'id("foo.bar") version "$baz"'} | ${{ depName: 'foo.bar', skipReason: 'unspecified-version', currentValue: 'baz' }} @@ -597,7 +601,7 @@ describe('modules/manager/gradle/parser', () => { ${'baz = "1.2.3"'} | ${'id("foo.bar") version baz'} | ${{ depName: 'foo.bar', packageName: 'foo.bar:foo.bar.gradle.plugin', currentValue: '1.2.3' }} ${'baz = "1.2.3"'} | ${'id("foo.bar").version(baz)'} | ${{ depName: 'foo.bar', packageName: 'foo.bar:foo.bar.gradle.plugin', currentValue: '1.2.3' }} ${''} | ${'kotlin("jvm") version "1.3.71"'} | ${{ depName: 'org.jetbrains.kotlin.jvm', packageName: 'org.jetbrains.kotlin.jvm:org.jetbrains.kotlin.jvm.gradle.plugin', currentValue: '1.3.71' }} - ${'baz = "1.3.71"'} | ${'kotlin("jvm") version baz'} | ${{ depName: 'org.jetbrains.kotlin.jvm', packageName: 'org.jetbrains.kotlin.jvm:org.jetbrains.kotlin.jvm.gradle.plugin', currentValue: '1.3.71', groupName: 'baz' }} + ${'baz = "1.3.71"'} | ${'kotlin("jvm") version baz'} | ${{ depName: 'org.jetbrains.kotlin.jvm', packageName: 'org.jetbrains.kotlin.jvm:org.jetbrains.kotlin.jvm.gradle.plugin', currentValue: '1.3.71', sharedVariableName: 'baz' }} `('$def | $input', ({ def, input, output }) => { const { deps } = parseGradle([def, input].join('\n')); expect(deps).toMatchObject([output].filter(is.truthy)); @@ -735,7 +739,7 @@ describe('modules/manager/gradle/parser', () => { ${'f = "foo"; b = "bar"'} | ${'library("foo.bar", "${f}", "${b}").version("1.2.3")'} | ${{ depName: 'foo:bar', currentValue: '1.2.3' }} ${'f = "foo"; b = "bar"; v = "1.2.3"'} | ${'library("foo.bar", property("f"), "${b}").version(v)'} | ${{ depName: 'foo:bar', currentValue: '1.2.3' }} ${'f = "foo"; b = "bar"'} | ${'library("foo.bar", "${f}" + f, "${b}").version("1.2.3")'} | ${{ depName: 'foofoo:bar', currentValue: '1.2.3' }} - ${'version("baz", "1.2.3")'} | ${'library("foo.bar", "foo", "bar").versionRef("baz")'} | ${{ depName: 'foo:bar', currentValue: '1.2.3', groupName: 'baz' }} + ${'version("baz", "1.2.3")'} | ${'library("foo.bar", "foo", "bar").versionRef("baz")'} | ${{ depName: 'foo:bar', currentValue: '1.2.3', sharedVariableName: 'baz' }} ${'library("foo-bar_baz-qux", "foo", "bar")'} | ${'"${libs.foo.bar.baz.qux}:1.2.3"'} | ${{ depName: 'foo:bar', currentValue: '1.2.3' }} ${''} | ${'library(["foo.bar", "foo", "bar"]).version("1.2.3")'} | ${null} ${''} | ${'library("foo", "bar", "baz", "qux").version("1.2.3")'} | ${null} @@ -807,7 +811,7 @@ describe('modules/manager/gradle/parser', () => { { currentValue: '1.5.2.RELEASE', depName: 'org.springframework.boot:spring-boot-gradle-plugin', - groupName: 'springBootVersion', + sharedVariableName: 'springBootVersion', managerData: { fileReplacePosition: 53, packageFile: 'build.gradle', @@ -1039,7 +1043,7 @@ describe('modules/manager/gradle/parser', () => { ${''} | ${'detekt { toolVersion = "1.2.3" }'} | ${{ depName: 'detekt', packageName: GRADLE_PLUGINS['detekt'][1], currentValue: '1.2.3' }} ${''} | ${'findbugs { toolVersion = "1.2.3" }'} | ${{ depName: 'findbugs', packageName: GRADLE_PLUGINS['findbugs'][1], currentValue: '1.2.3' }} ${''} | ${'googleJavaFormat { toolVersion = "1.2.3" }'} | ${{ depName: 'googleJavaFormat', packageName: GRADLE_PLUGINS['googleJavaFormat'][1], currentValue: '1.2.3' }} - ${'baz = "1.2.3"'} | ${'jacoco { toolVersion = baz }'} | ${{ depName: 'jacoco', packageName: GRADLE_PLUGINS['jacoco'][1], currentValue: '1.2.3', groupName: 'baz' }} + ${'baz = "1.2.3"'} | ${'jacoco { toolVersion = baz }'} | ${{ depName: 'jacoco', packageName: GRADLE_PLUGINS['jacoco'][1], currentValue: '1.2.3', sharedVariableName: 'baz' }} ${'baz = "1.2.3"'} | ${'jacoco { toolVersion = property("baz") }'} | ${{ depName: 'jacoco', packageName: GRADLE_PLUGINS['jacoco'][1], currentValue: '1.2.3' }} ${''} | ${'lombok { version = "1.2.3" }'} | ${{ depName: 'lombok', packageName: GRADLE_PLUGINS['lombok'][1], currentValue: '1.2.3' }} ${''} | ${'lombok { version.set("1.2.3") }'} | ${{ depName: 'lombok', packageName: GRADLE_PLUGINS['lombok'][1], currentValue: '1.2.3' }} @@ -1093,7 +1097,7 @@ describe('modules/manager/gradle/parser', () => { deps: [ { depName: 'org.slf4j:slf4j-api', - groupName: 'Versions.baz', + sharedVariableName: 'Versions.baz', currentValue: '1.2.3', }, { @@ -1102,17 +1106,17 @@ describe('modules/manager/gradle/parser', () => { }, { depName: 'androidx.core:core-ktx', - groupName: 'Versions.baz', + sharedVariableName: 'Versions.baz', currentValue: '1.2.3', }, { depName: 'androidx.webkit:webkit', - groupName: 'Versions.baz', + sharedVariableName: 'Versions.baz', currentValue: '1.2.3', }, { depName: 'foo:bar', - groupName: 'Versions.baz', + sharedVariableName: 'Versions.baz', currentValue: '1.2.3', }, ], @@ -1166,22 +1170,22 @@ describe('modules/manager/gradle/parser', () => { { depName: 'org.jetbrains.kotlin:kotlin-stdlib-jdk7', currentValue: '1.5.31', - groupName: 'Deps.kotlinVersion', + sharedVariableName: 'Deps.kotlinVersion', }, { depName: 'androidx.test:core', currentValue: '1.3.0-rc01', - groupName: 'Deps.Test.version', + sharedVariableName: 'Deps.Test.version', }, { depName: 'androidx.test.espresso:espresso-core', currentValue: '3.3.0-rc01', - groupName: 'Deps.Test.Espresso.Release.version', + sharedVariableName: 'Deps.Test.Espresso.Release.version', }, { depName: 'androidx.test:core-ktx', currentValue: '1.3.0-rc01', - groupName: 'Deps.Test.version', + sharedVariableName: 'Deps.Test.version', }, ], }); @@ -1218,7 +1222,7 @@ describe('modules/manager/gradle/parser', () => { { depName: 'com.h2database:h2', currentValue: '2.0.206', - groupName: 'ModuleConfiguration.Build.Database.h2Version', + sharedVariableName: 'ModuleConfiguration.Build.Database.h2Version', }, ], }); diff --git a/lib/modules/manager/gradle/parser/handlers.ts b/lib/modules/manager/gradle/parser/handlers.ts index 4cb6fe719b1118..5aaba92f773cf7 100644 --- a/lib/modules/manager/gradle/parser/handlers.ts +++ b/lib/modules/manager/gradle/parser/handlers.ts @@ -40,7 +40,7 @@ export function handleAssignment(ctx: Ctx): Ctx { // = string value const dep = parseDependencyString(valTokens[0].value); if (dep) { - dep.groupName = key; + dep.sharedVariableName = key; dep.managerData = { fileReplacePosition: valTokens[0].offset + dep.depName!.length + 1, packageFile: ctx.packageFile, @@ -82,7 +82,7 @@ export function handleDepString(ctx: Ctx): Ctx { fileReplacePosition = varData.fileReplacePosition; if (varData.value === dep.currentValue) { dep.managerData = { fileReplacePosition, packageFile }; - dep.groupName = varData.key; + dep.sharedVariableName = varData.key; } } } @@ -102,7 +102,7 @@ export function handleDepString(ctx: Ctx): Ctx { fileReplacePosition = lastToken.offset + lastToken.value.lastIndexOf(dep.currentValue); } - delete dep.groupName; + delete dep.sharedVariableName; } else { dep.skipReason = 'contains-variable'; } @@ -143,7 +143,7 @@ export function handleKotlinShortNotationDep(ctx: Ctx): Ctx { } else if (versionTokens[0].type === 'symbol') { const varData = findVariable(versionTokens[0].value, ctx); if (varData) { - dep.groupName = varData.key; + dep.sharedVariableName = varData.key; dep.currentValue = varData.value; dep.managerData = { fileReplacePosition: varData.fileReplacePosition, @@ -197,7 +197,7 @@ export function handleLongFormDep(ctx: Ctx): Ctx { } else if (versionTokens[0].type === 'symbol') { const varData = findVariable(versionTokens[0].value, ctx); if (varData) { - dep.groupName = varData.key; + dep.sharedVariableName = varData.key; dep.managerData = { fileReplacePosition: varData.fileReplacePosition, packageFile: varData.packageFile, @@ -206,7 +206,7 @@ export function handleLongFormDep(ctx: Ctx): Ctx { } else { // = string value if (methodName?.[0]?.value === 'dependencySet') { - dep.groupName = `${groupId}:${version}`; + dep.sharedVariableName = `${groupId}:${version}`; } dep.managerData = { fileReplacePosition: versionTokens[0].offset, @@ -247,7 +247,7 @@ export function handlePlugin(ctx: Ctx): Ctx { } else if (pluginVersion[0].type === 'symbol') { const varData = findVariable(pluginVersion[0].value, ctx); if (varData) { - dep.groupName = varData.key; + dep.sharedVariableName = varData.key; dep.currentValue = varData.value; dep.managerData = { fileReplacePosition: varData.fileReplacePosition, @@ -429,7 +429,7 @@ export function handleImplicitGradlePlugin(ctx: Ctx): Ctx { } else if (versionTokens[0].type === 'symbol') { const varData = findVariable(versionTokens[0].value, ctx); if (varData) { - dep.groupName = varData.key; + dep.sharedVariableName = varData.key; dep.currentValue = varData.value; dep.managerData = { fileReplacePosition: varData.fileReplacePosition, diff --git a/lib/modules/manager/gradle/update.spec.ts b/lib/modules/manager/gradle/update.spec.ts index 4d0a77623d5810..cd46e12ca1a167 100644 --- a/lib/modules/manager/gradle/update.spec.ts +++ b/lib/modules/manager/gradle/update.spec.ts @@ -23,7 +23,7 @@ describe('modules/manager/gradle/update', () => { upgrade: { currentValue: '1.2.3', newValue: '1.2.5', - groupName: 'group', + sharedVariableName: 'group', managerData: { fileReplacePosition: 3, }, diff --git a/lib/modules/manager/gradle/update.ts b/lib/modules/manager/gradle/update.ts index 0839c2c7e20bb3..4286535ece0b47 100644 --- a/lib/modules/manager/gradle/update.ts +++ b/lib/modules/manager/gradle/update.ts @@ -23,7 +23,7 @@ export function updateDependency({ if (version === newValue) { return fileContent; } - if (version === currentValue || upgrade.groupName) { + if (version === currentValue || upgrade.sharedVariableName) { // TODO: types (#22198) return `${leftPart}${newValue}${restPart}`; } diff --git a/lib/modules/manager/helm-values/extract.ts b/lib/modules/manager/helm-values/extract.ts index 59e465c0f0000e..2987b3ca1297e3 100644 --- a/lib/modules/manager/helm-values/extract.ts +++ b/lib/modules/manager/helm-values/extract.ts @@ -17,13 +17,9 @@ function getHelmDep( registry: string, repository: string, tag: string, - config: ExtractConfig, + registryAliases: Record | undefined, ): PackageDependency { - const dep = getDep( - `${registry}${repository}:${tag}`, - false, - config.registryAliases, - ); + const dep = getDep(`${registry}${repository}:${tag}`, false, registryAliases); dep.replaceString = tag; dep.versioning = dockerVersioning; dep.autoReplaceStringTemplate = @@ -36,11 +32,17 @@ function getHelmDep( * * @param parsedContent */ -function findDependencies( +export function findDependencies( parsedContent: Record | HelmDockerImageDependency, - packageDependencies: Array, - config: ExtractConfig, -): Array { + registryAliases: Record | undefined, +): PackageDependency[] { + return findDependenciesInternal(parsedContent, [], registryAliases); +} +export function findDependenciesInternal( + parsedContent: Record | HelmDockerImageDependency, + packageDependencies: PackageDependency[], + registryAliases: Record | undefined, +): PackageDependency[] { if (!parsedContent || typeof parsedContent !== 'object') { return packageDependencies; } @@ -53,14 +55,16 @@ function findDependencies( registry = registry ? `${registry}/` : ''; const repository = String(currentItem.repository); const tag = `${currentItem.tag ?? currentItem.version}`; - packageDependencies.push(getHelmDep(registry, repository, tag, config)); + packageDependencies.push( + getHelmDep(registry, repository, tag, registryAliases), + ); } else if (matchesHelmValuesInlineImage(key, value)) { - packageDependencies.push(getDep(value, true, config.registryAliases)); + packageDependencies.push(getDep(value, true, registryAliases)); } else { - findDependencies( + findDependenciesInternal( value as Record, packageDependencies, - config, + registryAliases, ); } }); @@ -86,7 +90,7 @@ export function extractPackageFile( const deps: PackageDependency>[] = []; for (const con of parsedContent) { - deps.push(...findDependencies(con, [], config)); + deps.push(...findDependencies(con, config.registryAliases)); } if (deps.length) { diff --git a/lib/modules/manager/leiningen/__snapshots__/extract.spec.ts.snap b/lib/modules/manager/leiningen/__snapshots__/extract.spec.ts.snap index 53d474d9490a58..147031d8545874 100644 --- a/lib/modules/manager/leiningen/__snapshots__/extract.spec.ts.snap +++ b/lib/modules/manager/leiningen/__snapshots__/extract.spec.ts.snap @@ -116,13 +116,13 @@ exports[`modules/manager/leiningen/extract extractPackageFile 1`] = ` "datasource": "clojure", "depName": "clj-stacktrace:clj-stacktrace", "depType": "dependencies", - "groupName": "clj-stacktrace-version", "registryUrls": [ "https://download.java.net/maven/2", "https://oss.sonatype.org/content/repositories/releases", "https://blueant.com/archiva/snapshots", "https://blueant.com/archiva/internal", ], + "sharedVariableName": "clj-stacktrace-version", }, { "currentValue": "0.12.0", diff --git a/lib/modules/manager/leiningen/extract.spec.ts b/lib/modules/manager/leiningen/extract.spec.ts index 76e3d765e03d4e..867a2a5d964dcd 100644 --- a/lib/modules/manager/leiningen/extract.spec.ts +++ b/lib/modules/manager/leiningen/extract.spec.ts @@ -38,7 +38,7 @@ describe('modules/manager/leiningen/extract', () => { datasource: ClojureDatasource.id, depName: 'foo:bar', currentValue: '1.2.3', - groupName: 'baz', + sharedVariableName: 'baz', }, ]); expect( @@ -86,7 +86,7 @@ describe('modules/manager/leiningen/extract', () => { { depName: 'clj-stacktrace:clj-stacktrace', currentValue: '0.2.4', - groupName: 'clj-stacktrace-version', + sharedVariableName: 'clj-stacktrace-version', }, { depName: 'clj-time:clj-time', diff --git a/lib/modules/manager/leiningen/extract.ts b/lib/modules/manager/leiningen/extract.ts index 680b5f14cb025f..54ede6bd46fe68 100644 --- a/lib/modules/manager/leiningen/extract.ts +++ b/lib/modules/manager/leiningen/extract.ts @@ -58,7 +58,7 @@ export function extractFromVectors( datasource: ClojureDatasource.id, depName, currentValue, - groupName: varName, + sharedVariableName: varName, }); } } else { diff --git a/lib/modules/manager/maven/extract.spec.ts b/lib/modules/manager/maven/extract.spec.ts index 3efc9d99aea9fa..f564c877d543a3 100644 --- a/lib/modules/manager/maven/extract.spec.ts +++ b/lib/modules/manager/maven/extract.spec.ts @@ -476,7 +476,7 @@ describe('modules/manager/maven/extract', () => { depType: 'compile', editFile: 'parent.pom.xml', fileReplacePosition: 470, - groupName: 'quuxVersion', + sharedVariableName: 'quuxVersion', registryUrls: [ 'http://example.com/', 'http://example.com/nexus/xyz', @@ -697,12 +697,12 @@ describe('modules/manager/maven/extract', () => { { depName: 'org.example:quux', currentValue: '1.2.3.4', - groupName: 'quuxVersion', + sharedVariableName: 'quuxVersion', }, { depName: 'org.example:quux-test', currentValue: '1.2.3.4', - groupName: 'quuxVersion', + sharedVariableName: 'quuxVersion', }, { depName: 'org.example:quuz', diff --git a/lib/modules/manager/maven/extract.ts b/lib/modules/manager/maven/extract.ts index ef06fe3911228c..939e31e25c1e8a 100644 --- a/lib/modules/manager/maven/extract.ts +++ b/lib/modules/manager/maven/extract.ts @@ -224,7 +224,7 @@ function applyPropsInternal( let fileReplacePosition = dep.fileReplacePosition; let propSource = dep.propSource; - let groupName: string | null = null; + let sharedVariableName: string | null = null; const currentValue = dep.currentValue!.replace( regEx(/^\${[^}]*?}$/), (substr) => { @@ -232,8 +232,8 @@ function applyPropsInternal( // TODO: wrong types here, props is already `MavenProp` const propValue = (props as any)[propKey] as MavenProp; if (propValue) { - if (!groupName) { - groupName = propKey; + if (!sharedVariableName) { + sharedVariableName = propKey; } fileReplacePosition = propValue.fileReplacePosition; propSource = @@ -261,8 +261,8 @@ function applyPropsInternal( currentValue, }; - if (groupName) { - result.groupName = groupName; + if (sharedVariableName) { + result.sharedVariableName = sharedVariableName; } if (propSource && depPackageFile !== propSource) { diff --git a/lib/modules/manager/maven/update.ts b/lib/modules/manager/maven/update.ts index b22261c0a85162..413892c462cf83 100644 --- a/lib/modules/manager/maven/update.ts +++ b/lib/modules/manager/maven/update.ts @@ -25,7 +25,7 @@ export function updateAtPosition( if (version === newValue) { return fileContent; } - if (version === currentValue || upgrade.groupName) { + if (version === currentValue || upgrade.sharedVariableName) { // TODO: validate newValue (#22198) const replacedPart = versionPart.replace(version, newValue!); return leftPart + replacedPart + restPart; diff --git a/lib/modules/manager/npm/post-update/pnpm.spec.ts b/lib/modules/manager/npm/post-update/pnpm.spec.ts index 6c9d28db1b8a50..41c7e9dffac96c 100644 --- a/lib/modules/manager/npm/post-update/pnpm.spec.ts +++ b/lib/modules/manager/npm/post-update/pnpm.spec.ts @@ -104,13 +104,13 @@ describe('modules/manager/npm/post-update/pnpm', () => { fs.readLocalFile.mockResolvedValue('package-lock-contents'); const res = await pnpmHelper.generateLockFile('some-folder', {}, config, [ { - groupName: 'some-group', + sharedVariableName: 'some-group', packageName: 'some-dep', newVersion: '1.1.0', isLockfileUpdate: true, }, { - groupName: 'some-group', + sharedVariableName: 'some-group', packageName: 'some-other-dep', newVersion: '1.1.0', isLockfileUpdate: false, diff --git a/lib/modules/manager/npm/update/locked-dependency/package-lock/index.ts b/lib/modules/manager/npm/update/locked-dependency/package-lock/index.ts index 5e95a770667f67..b9419d3c63e082 100644 --- a/lib/modules/manager/npm/update/locked-dependency/package-lock/index.ts +++ b/lib/modules/manager/npm/update/locked-dependency/package-lock/index.ts @@ -48,7 +48,7 @@ export async function updateLockedDependency( currentVersion, ); if (lockedDeps.some((dep) => dep.bundled)) { - logger.info( + logger.debug( `Package ${depName}@${currentVersion} is bundled and cannot be updated`, ); return { status: 'update-failed' }; diff --git a/lib/modules/manager/nuget/__snapshots__/extract.spec.ts.snap b/lib/modules/manager/nuget/__snapshots__/extract.spec.ts.snap index a8d2ae43fc717d..60fcf38b3c7145 100644 --- a/lib/modules/manager/nuget/__snapshots__/extract.spec.ts.snap +++ b/lib/modules/manager/nuget/__snapshots__/extract.spec.ts.snap @@ -134,14 +134,14 @@ exports[`modules/manager/nuget/extract extractPackageFile() extracts all depende "datasource": "nuget", "depName": "Autofac.Extensions.DependencyInjection", "depType": "nuget", - "groupName": "AutofacVersion", + "sharedVariableName": "AutofacVersion", }, { "currentValue": "4.5.0", "datasource": "nuget", "depName": "Autofac", "depType": "nuget", - "groupName": "AutofacVersion", + "sharedVariableName": "AutofacVersion", }, ] `; diff --git a/lib/modules/manager/nuget/artifacts.spec.ts b/lib/modules/manager/nuget/artifacts.spec.ts index 4dfbbc4a04de05..33a7465d63028b 100644 --- a/lib/modules/manager/nuget/artifacts.spec.ts +++ b/lib/modules/manager/nuget/artifacts.spec.ts @@ -15,7 +15,7 @@ jest.mock('../../../util/host-rules', () => mockDeep()); jest.mock('../../../util/git'); jest.mock('./util'); -const { getDefaultRegistries } = mocked(util); +const { getDefaultRegistries, findGlobalJson } = mocked(util); process.env.CONTAINERBASE = 'true'; @@ -230,12 +230,14 @@ describe('modules/manager/nuget/artifacts', () => { fs.getLocalFiles.mockResolvedValueOnce({ 'packages.lock.json': 'New packages.lock.json', }); + + findGlobalJson.mockResolvedValueOnce({ sdk: { version: '7.0.100' } }); expect( await nuget.updateArtifacts({ packageFileName: 'project.csproj', updatedDeps: [{ depName: 'dep' }], newPackageFileContent: '{}', - config: { ...config, constraints: { dotnet: '7.0.100' } }, + config, }), ).toEqual([ { diff --git a/lib/modules/manager/nuget/artifacts.ts b/lib/modules/manager/nuget/artifacts.ts index c60e04262e6363..88dcdd92e89471 100644 --- a/lib/modules/manager/nuget/artifacts.ts +++ b/lib/modules/manager/nuget/artifacts.ts @@ -25,7 +25,11 @@ import { NUGET_CENTRAL_FILE, getDependentPackageFiles, } from './package-tree'; -import { getConfiguredRegistries, getDefaultRegistries } from './util'; +import { + findGlobalJson, + getConfiguredRegistries, + getDefaultRegistries, +} from './util'; async function createCachedNuGetConfigFile( nugetCacheDir: string, @@ -55,6 +59,9 @@ async function runDotnetRestore( packageFileName, ); + const dotnetVersion = + config.constraints?.dotnet ?? + (await findGlobalJson(packageFileName))?.sdk?.version; const execOptions: ExecOptions = { docker: {}, userConfiguredEnv: config.env, @@ -62,9 +69,7 @@ async function runDotnetRestore( NUGET_PACKAGES: join(nugetCacheDir, 'packages'), MSBUILDDISABLENODEREUSE: '1', }, - toolConstraints: [ - { toolName: 'dotnet', constraint: config.constraints?.dotnet }, - ], + toolConstraints: [{ toolName: 'dotnet', constraint: dotnetVersion }], }; const cmds = [ diff --git a/lib/modules/manager/nuget/extract.ts b/lib/modules/manager/nuget/extract.ts index 56e832df34ec72..3c9e6d8e9d768f 100644 --- a/lib/modules/manager/nuget/extract.ts +++ b/lib/modules/manager/nuget/extract.ts @@ -80,21 +80,21 @@ function extractDepsFromXml(xmlNode: XmlDocument): NugetPackageDependency[] { dep.skipReason = 'invalid-version'; } - let groupName: string | undefined; + let sharedVariableName: string | undefined; currentValue = currentValue ?.trim() ?.replace(/^\$\((\w+)\)$/, (match, key) => { const val = vars.get(key); if (val) { - groupName = key; + sharedVariableName = key; return val; } return match; }); - if (groupName) { - dep.groupName = groupName; + if (sharedVariableName) { + dep.sharedVariableName = sharedVariableName; } currentValue = checkVersion diff --git a/lib/modules/manager/nuget/extract/global-manifest.ts b/lib/modules/manager/nuget/extract/global-manifest.ts index ae9c6e9f99c042..d7e36b7f66c8ea 100644 --- a/lib/modules/manager/nuget/extract/global-manifest.ts +++ b/lib/modules/manager/nuget/extract/global-manifest.ts @@ -2,11 +2,8 @@ import { logger } from '../../../../logger'; import { DotnetVersionDatasource } from '../../../datasource/dotnet-version'; import { NugetDatasource } from '../../../datasource/nuget'; import type { PackageDependency, PackageFileContent } from '../../types'; -import type { - MsbuildGlobalManifest, - NugetPackageDependency, - Registry, -} from '../types'; +import { GlobalJson } from '../schema'; +import type { NugetPackageDependency, Registry } from '../types'; import { applyRegistries } from '../util'; export function extractMsbuildGlobalManifest( @@ -15,10 +12,10 @@ export function extractMsbuildGlobalManifest( registries: Registry[] | undefined, ): PackageFileContent | null { const deps: PackageDependency[] = []; - let manifest: MsbuildGlobalManifest; + let manifest: GlobalJson; let extractedConstraints: Record | undefined; try { - manifest = JSON.parse(content); + manifest = GlobalJson.parse(content); } catch { logger.debug({ packageFile }, `Invalid JSON`); return null; diff --git a/lib/modules/manager/nuget/schema.ts b/lib/modules/manager/nuget/schema.ts new file mode 100644 index 00000000000000..c71dabc94a1fc1 --- /dev/null +++ b/lib/modules/manager/nuget/schema.ts @@ -0,0 +1,63 @@ +import { z } from 'zod'; +import { Jsonc } from '../../../util/schema-utils'; + +/** + * The roll-forward policy to use when selecting an SDK version, either as a fallback when a specific SDK version is missing or as a directive to use a later version. A version must be specified with a rollForward value, unless you're setting it to latestMajor. The default roll forward behavior is determined by the matching rules. + * + * https://learn.microsoft.com/de-de/dotnet/core/tools/global-json#rollforward + */ +const RollForwardSchema = z.enum([ + 'patch', + 'feature', + 'minor', + 'major', + 'latestPatch', + 'latestFeature', + 'latestMinor', + 'latestMajor', + 'disable', +]); +export type RollForward = z.infer; + +/** + * global.json schema + * + * https://learn.microsoft.com/en-us/dotnet/core/tools/global-json#allowprerelease + */ +export const GlobalJsonSchema = z.object({ + /** + * Specifies information about the .NET SDK to select. + */ + sdk: z + .object({ + /** + * The version of the .NET SDK to use. + * + * https://learn.microsoft.com/de-de/dotnet/core/tools/global-json#version + */ + version: z.string().optional(), + /** + * The roll-forward policy to use when selecting an SDK version, either as a fallback when a specific SDK version is missing or as a directive to use a later version. A version must be specified with a rollForward value, unless you're setting it to latestMajor. The default roll forward behavior is determined by the matching rules. + * + * https://learn.microsoft.com/de-de/dotnet/core/tools/global-json#rollforward + */ + rollForward: RollForwardSchema.optional(), + /** + * Indicates whether the SDK resolver should consider prerelease versions when selecting the SDK version to use. + * + * https://learn.microsoft.com/de-de/dotnet/core/tools/global-json#allowprerelease + */ + allowPrerelease: z.boolean().optional(), + }) + .optional(), + + /** + * Lets you control the project SDK version in one place rather than in each individual project. For more information, see How project SDKs are resolved. + * + * https://learn.microsoft.com/de-de/dotnet/core/tools/global-json#msbuild-sdks + */ + 'msbuild-sdks': z.record(z.string()).optional(), +}); + +export const GlobalJson = Jsonc.pipe(GlobalJsonSchema); +export type GlobalJson = z.infer; diff --git a/lib/modules/manager/nuget/types.ts b/lib/modules/manager/nuget/types.ts index 0eef41beaf9885..9d34b776f14fb8 100644 --- a/lib/modules/manager/nuget/types.ts +++ b/lib/modules/manager/nuget/types.ts @@ -17,17 +17,6 @@ export interface Registry { readonly name?: string; sourceMappedPackagePatterns?: string[]; } - -export interface MsbuildGlobalManifest { - readonly sdk?: MsbuildSdk; - readonly 'msbuild-sdks'?: Record; -} - -export interface MsbuildSdk { - readonly version: string; - readonly rollForward: string; -} - export interface ProjectFile { readonly isLeaf: boolean; readonly name: string; diff --git a/lib/modules/manager/nuget/util.spec.ts b/lib/modules/manager/nuget/util.spec.ts index 0956e2014c0383..a1a01dec1040d1 100644 --- a/lib/modules/manager/nuget/util.spec.ts +++ b/lib/modules/manager/nuget/util.spec.ts @@ -3,7 +3,12 @@ import { XmlDocument } from 'xmldoc'; import { fs } from '../../../../test/util'; import type { Registry } from './types'; import { bumpPackageVersion } from './update'; -import { applyRegistries, findVersion, getConfiguredRegistries } from './util'; +import { + applyRegistries, + findGlobalJson, + findVersion, + getConfiguredRegistries, +} from './util'; jest.mock('../../../util/fs'); @@ -340,4 +345,34 @@ describe('modules/manager/nuget/util', () => { }); }); }); + + describe('findGlobalJson', () => { + it('not found', async () => { + fs.findLocalSiblingOrParent.mockResolvedValueOnce(null); + const globalJson = await findGlobalJson('project.csproj'); + expect(globalJson).toBeNull(); + }); + + it('no content', async () => { + fs.findLocalSiblingOrParent.mockResolvedValueOnce('global.json'); + const globalJson = await findGlobalJson('project.csproj'); + expect(globalJson).toBeNull(); + }); + + it('fails to parse', async () => { + fs.findLocalSiblingOrParent.mockResolvedValueOnce('global.json'); + fs.readLocalFile.mockResolvedValueOnce('{'); + const globalJson = await findGlobalJson('project.csproj'); + expect(globalJson).toBeNull(); + }); + + it('parses', async () => { + fs.findLocalSiblingOrParent.mockResolvedValueOnce('global.json'); + fs.readLocalFile.mockResolvedValueOnce( + '{ /* This is comment */ "sdk": { "version": "5.0.100" }, "some": true }', + ); + const globalJson = await findGlobalJson('project.csproj'); + expect(globalJson).toEqual({ sdk: { version: '5.0.100' } }); + }); + }); }); diff --git a/lib/modules/manager/nuget/util.ts b/lib/modules/manager/nuget/util.ts index dd210357d3a863..3f04f4318e758b 100644 --- a/lib/modules/manager/nuget/util.ts +++ b/lib/modules/manager/nuget/util.ts @@ -2,10 +2,15 @@ import upath from 'upath'; import type { XmlElement } from 'xmldoc'; import { XmlDocument } from 'xmldoc'; import { logger } from '../../../logger'; -import { findUpLocal, readLocalFile } from '../../../util/fs'; +import { + findLocalSiblingOrParent, + findUpLocal, + readLocalFile, +} from '../../../util/fs'; import { minimatch } from '../../../util/minimatch'; import { regEx } from '../../../util/regex'; import { nugetOrg } from '../../datasource/nuget'; +import { GlobalJson } from './schema'; import type { NugetPackageDependency, Registry } from './types'; export async function readFileAsXmlDocument( @@ -207,3 +212,31 @@ function sortPatterns( return a[0].localeCompare(b[0]) * -1; } + +export async function findGlobalJson( + packageFile: string, +): Promise { + const globalJsonPath = await findLocalSiblingOrParent( + packageFile, + 'global.json', + ); + if (!globalJsonPath) { + return null; + } + + const content = await readLocalFile(globalJsonPath, 'utf8'); + if (!content) { + logger.debug({ packageFile, globalJsonPath }, 'Failed to read global.json'); + return null; + } + + const result = await GlobalJson.safeParseAsync(content); + if (!result.success) { + logger.debug( + { packageFile, globalJsonPath, err: result.error }, + 'Failed to parse global.json', + ); + return null; + } + return result.data; +} diff --git a/lib/modules/manager/pep621/utils.spec.ts b/lib/modules/manager/pep621/utils.spec.ts index 4d1e6edbcb0ce2..80d2ca16d8d9f2 100644 --- a/lib/modules/manager/pep621/utils.spec.ts +++ b/lib/modules/manager/pep621/utils.spec.ts @@ -10,6 +10,8 @@ describe('modules/manager/pep621/utils', () => { ${null} | ${false} | ${undefined} | ${undefined} | ${undefined} | ${undefined} ${'blinker'} | ${true} | ${'blinker'} | ${undefined} | ${undefined} | ${undefined} ${'packaging==20.0.0'} | ${true} | ${'packaging'} | ${'==20.0.0'} | ${undefined} | ${undefined} + ${'packaging (==20.0.0)'} | ${true} | ${'packaging'} | ${'==20.0.0'} | ${undefined} | ${undefined} + ${'packaging (==20.0.0); python_version < "3.8"'} | ${true} | ${'packaging'} | ${'==20.0.0'} | ${undefined} | ${'python_version < "3.8"'} ${'packaging>=20.9,!=22.0'} | ${true} | ${'packaging'} | ${'>=20.9,!=22.0'} | ${undefined} | ${undefined} ${'cachecontrol[filecache]>=0.12.11'} | ${true} | ${'cachecontrol'} | ${'>=0.12.11'} | ${['filecache']} | ${undefined} ${'private-depB[extra1, extra2]~=2.4'} | ${true} | ${'private-depB'} | ${'~=2.4'} | ${['extra1', 'extra2']} | ${undefined} diff --git a/lib/modules/manager/pep621/utils.ts b/lib/modules/manager/pep621/utils.ts index 1a396064922174..6df1b79ae4e018 100644 --- a/lib/modules/manager/pep621/utils.ts +++ b/lib/modules/manager/pep621/utils.ts @@ -43,8 +43,16 @@ export function parsePEP508( packageName: regExpExec.groups.packageName, }; if (is.nonEmptyString(regExpExec.groups.currentValue)) { - result.currentValue = regExpExec.groups.currentValue; + if ( + regExpExec.groups.currentValue.startsWith('(') && + regExpExec.groups.currentValue.endsWith(')') + ) { + result.currentValue = regExpExec.groups.currentValue.slice(1, -1).trim(); + } else { + result.currentValue = regExpExec.groups.currentValue; + } } + if (is.nonEmptyString(regExpExec.groups.marker)) { result.marker = regExpExec.groups.marker; } diff --git a/lib/modules/manager/poetry/schema.ts b/lib/modules/manager/poetry/schema.ts index 6e650c21b2d0fc..eb4df77fca1858 100644 --- a/lib/modules/manager/poetry/schema.ts +++ b/lib/modules/manager/poetry/schema.ts @@ -195,9 +195,9 @@ export const PoetryGroupDependencies = LooseRecord( .transform(({ dependencies }) => dependencies), ).transform((record) => { const deps: PackageDependency[] = []; - for (const [groupName, group] of Object.entries(record)) { - for (const dep of Object.values(group)) { - dep.depType = groupName; + for (const [name, val] of Object.entries(record)) { + for (const dep of Object.values(val)) { + dep.depType = name; deps.push(dep); } } diff --git a/lib/modules/manager/sbt/__snapshots__/extract.spec.ts.snap b/lib/modules/manager/sbt/__snapshots__/extract.spec.ts.snap index e369d665da0fc2..87d51705bf4989 100644 --- a/lib/modules/manager/sbt/__snapshots__/extract.spec.ts.snap +++ b/lib/modules/manager/sbt/__snapshots__/extract.spec.ts.snap @@ -22,9 +22,9 @@ exports[`modules/manager/sbt/extract extractPackageFile() extract deps from nati "currentValue": "1.2.3", "datasource": "sbt-package", "depName": "com.abc:abc", - "groupName": "abcVersion", "packageName": "com.abc:abc", "registryUrls": [], + "sharedVariableName": "abcVersion", "variableName": "abcVersion", }, ], @@ -57,36 +57,36 @@ exports[`modules/manager/sbt/extract extractPackageFile() extract deps from nati "currentValue": "1.2.3", "datasource": "sbt-package", "depName": "com.abc:abc", - "groupName": "abcVersion", "packageName": "com.abc:abc", "registryUrls": [], + "sharedVariableName": "abcVersion", "variableName": "abcVersion", }, { "currentValue": "1.2.3", "datasource": "sbt-package", "depName": "com.abc:abc-a", - "groupName": "abcVersion", "packageName": "com.abc:abc-a", "registryUrls": [], + "sharedVariableName": "abcVersion", "variableName": "abcVersion", }, { "currentValue": "1.2.3", "datasource": "sbt-package", "depName": "com.abc:abc-b", - "groupName": "abcVersion", "packageName": "com.abc:abc-b", "registryUrls": [], + "sharedVariableName": "abcVersion", "variableName": "abcVersion", }, { "currentValue": "1.2.3", "datasource": "sbt-package", "depName": "com.abc:abc-c", - "groupName": "abcVersion", "packageName": "com.abc:abc-c", "registryUrls": [], + "sharedVariableName": "abcVersion", "variableName": "abcVersion", }, ], @@ -240,7 +240,6 @@ exports[`modules/manager/sbt/extract extractPackageFile() extracts deps for gene "datasource": "sbt-package", "depName": "org.example:grault", "depType": "Test", - "groupName": "versionExample", "packageName": "org.example:grault", "registryUrls": [ "https://example.com/repos/1/", @@ -249,6 +248,7 @@ exports[`modules/manager/sbt/extract extractPackageFile() extracts deps for gene "https://example.com/repos/4/", "https://example.com/repos/5/", ], + "sharedVariableName": "versionExample", "variableName": "versionExample", }, { @@ -401,7 +401,6 @@ exports[`modules/manager/sbt/extract extractPackageFile() extracts deps when sca "datasource": "sbt-package", "depName": "org.example:grault", "depType": "Test", - "groupName": "versionExample", "packageName": "org.example:grault", "registryUrls": [ "https://example.com/repos/1/", @@ -410,6 +409,7 @@ exports[`modules/manager/sbt/extract extractPackageFile() extracts deps when sca "https://example.com/repos/4/", "https://example.com/repos/5/", ], + "sharedVariableName": "versionExample", "variableName": "versionExample", }, { diff --git a/lib/modules/manager/sbt/extract.spec.ts b/lib/modules/manager/sbt/extract.spec.ts index 7410b282ae382c..03f3cbf232c2f7 100644 --- a/lib/modules/manager/sbt/extract.spec.ts +++ b/lib/modules/manager/sbt/extract.spec.ts @@ -116,7 +116,7 @@ describe('modules/manager/sbt/extract', () => { deps: [ { currentValue: '1.2.3', - groupName: 'version', + sharedVariableName: 'version', }, ], }); @@ -137,7 +137,7 @@ describe('modules/manager/sbt/extract', () => { datasource: 'sbt-plugin', depName: 'com.github.gseitz:sbt-release', depType: 'plugin', - groupName: 'sbtReleaseVersion', + sharedVariableName: 'sbtReleaseVersion', packageName: 'com.github.gseitz:sbt-release', registryUrls: [], variableName: 'sbtReleaseVersion', diff --git a/lib/modules/manager/sbt/extract.ts b/lib/modules/manager/sbt/extract.ts index fd5a9173769dd0..80bfc399ee0acf 100644 --- a/lib/modules/manager/sbt/extract.ts +++ b/lib/modules/manager/sbt/extract.ts @@ -218,7 +218,7 @@ function depHandler(ctx: Ctx): Ctx { } if (variableName) { - dep.groupName = variableName; + dep.sharedVariableName = variableName; dep.variableName = variableName; } diff --git a/lib/modules/manager/types.ts b/lib/modules/manager/types.ts index 7fa394d4ebaa11..6c93b44a19556a 100644 --- a/lib/modules/manager/types.ts +++ b/lib/modules/manager/types.ts @@ -120,7 +120,7 @@ export interface PackageDependency> depName?: string; depType?: string; fileReplacePosition?: number; - groupName?: string; + sharedVariableName?: string; lineNumber?: number; packageName?: string; target?: string; diff --git a/lib/modules/platform/bitbucket-server/index.ts b/lib/modules/platform/bitbucket-server/index.ts index 3c4274f2e95808..7f1b2accebc809 100644 --- a/lib/modules/platform/bitbucket-server/index.ts +++ b/lib/modules/platform/bitbucket-server/index.ts @@ -116,7 +116,7 @@ export async function initPlatform({ bitbucketServerVersion = process.env.RENOVATE_X_PLATFORM_VERSION; } else { const { version } = ( - await bitbucketServerHttp.getJson<{ version: string }>( + await bitbucketServerHttp.getJsonUnchecked<{ version: string }>( `./rest/api/1.0/application-properties`, ) ).body; @@ -199,7 +199,7 @@ export async function getRawFile( const fileUrl = `./rest/api/1.0/projects/${project}/repos/${slug}/browse/${fileName}?limit=20000` + (branchOrTag ? '&at=' + branchOrTag : ''); - const res = await bitbucketServerHttp.getJson(fileUrl); + const res = await bitbucketServerHttp.getJsonUnchecked(fileUrl); const { isLastPage, lines, size } = res.body; if (isLastPage) { return lines.map(({ text }) => text).join('\n'); @@ -245,13 +245,13 @@ export async function initRepo({ try { const info = ( - await bitbucketServerHttp.getJson( + await bitbucketServerHttp.getJsonUnchecked( `./rest/api/1.0/projects/${config.projectKey}/repos/${config.repositorySlug}`, ) ).body; config.owner = info.project.key; logger.debug(`${repository} owner = ${config.owner}`); - const branchRes = await bitbucketServerHttp.getJson( + const branchRes = await bitbucketServerHttp.getJsonUnchecked( `./rest/api/1.0/projects/${config.projectKey}/repos/${config.repositorySlug}/branches/default`, ); @@ -303,7 +303,7 @@ export async function getBranchForceRebase( _branchName: string, ): Promise { // https://docs.atlassian.com/bitbucket-server/rest/7.0.1/bitbucket-rest.html#idp342 - const res = await bitbucketServerHttp.getJson<{ + const res = await bitbucketServerHttp.getJsonUnchecked<{ mergeConfig: { defaultStrategy: { id: string } }; }>( `./rest/api/1.0/projects/${config.projectKey}/repos/${config.repositorySlug}/settings/pull-requests`, @@ -327,7 +327,7 @@ export async function getPr( return null; } - const res = await bitbucketServerHttp.getJson( + const res = await bitbucketServerHttp.getJsonUnchecked( `./rest/api/1.0/projects/${config.projectKey}/repos/${config.repositorySlug}/pull-requests/${prNo}`, { memCache: !refreshCache }, ); @@ -458,7 +458,7 @@ async function getStatus( const branchCommit = git.getBranchCommit(branchName); return ( - await bitbucketServerHttp.getJson( + await bitbucketServerHttp.getJsonUnchecked( // TODO: types (#22198) `./rest/build-status/1.0/commits/stats/${branchCommit!}`, { memCache }, @@ -777,7 +777,7 @@ async function getCommentVersion( ): Promise { // GET /rest/api/1.0/projects/{projectKey}/repos/{repositorySlug}/pull-requests/{pullRequestId}/comments/{commentId} const { version } = ( - await bitbucketServerHttp.getJson<{ version: number }>( + await bitbucketServerHttp.getJsonUnchecked<{ version: number }>( `./rest/api/1.0/projects/${config.projectKey}/repos/${config.repositorySlug}/pull-requests/${prNo}/comments/${commentId}`, ) ).body; @@ -913,13 +913,13 @@ export async function createPr({ if (platformPrOptions?.bbUseDefaultReviewers) { logger.debug(`fetching default reviewers`); const { id } = ( - await bitbucketServerHttp.getJson<{ id: number }>( + await bitbucketServerHttp.getJsonUnchecked<{ id: number }>( `./rest/api/1.0/projects/${config.projectKey}/repos/${config.repositorySlug}`, ) ).body; const defReviewers = ( - await bitbucketServerHttp.getJson<{ name: string }[]>( + await bitbucketServerHttp.getJsonUnchecked<{ name: string }[]>( `./rest/default-reviewers/1.0/projects/${config.projectKey}/repos/${ config.repositorySlug }/reviewers?sourceRefId=refs/heads/${escapeHash( diff --git a/lib/modules/platform/bitbucket-server/utils.ts b/lib/modules/platform/bitbucket-server/utils.ts index 92099dafab02b6..8d51b2607d183d 100644 --- a/lib/modules/platform/bitbucket-server/utils.ts +++ b/lib/modules/platform/bitbucket-server/utils.ts @@ -68,7 +68,7 @@ function callApi( return bitbucketServerHttp.deleteJson(apiUrl, options); case 'get': default: - return bitbucketServerHttp.getJson(apiUrl, options); + return bitbucketServerHttp.getJsonUnchecked(apiUrl, options); } } diff --git a/lib/modules/platform/bitbucket/comments.ts b/lib/modules/platform/bitbucket/comments.ts index 2d91964a30d53f..98cfbf5e2c52bc 100644 --- a/lib/modules/platform/bitbucket/comments.ts +++ b/lib/modules/platform/bitbucket/comments.ts @@ -24,7 +24,7 @@ async function getComments( prNo: number, ): Promise { const comments = ( - await bitbucketHttp.getJson>( + await bitbucketHttp.getJsonUnchecked>( `/2.0/repositories/${config.repository}/pullrequests/${prNo}/comments`, { paginate: true, diff --git a/lib/modules/platform/bitbucket/index.ts b/lib/modules/platform/bitbucket/index.ts index f58265dad7aa8c..0d562c7b5d61f7 100644 --- a/lib/modules/platform/bitbucket/index.ts +++ b/lib/modules/platform/bitbucket/index.ts @@ -93,7 +93,7 @@ export async function initPlatform({ } try { const { uuid } = ( - await bitbucketHttp.getJson('/2.0/user', options) + await bitbucketHttp.getJsonUnchecked('/2.0/user', options) ).body; renovateUserUuid = uuid; } catch (err) { @@ -212,7 +212,7 @@ export async function initRepo({ if (bbUseDevelopmentBranch) { // Fetch Bitbucket development branch const developmentBranch = ( - await bitbucketHttp.getJson( + await bitbucketHttp.getJsonUnchecked( `/2.0/repositories/${repository}/branching-model`, ) ).body.development?.branch?.name; @@ -304,7 +304,7 @@ export async function findPr({ if (includeOtherAuthors) { // PR might have been created by anyone, so don't use the cached Renovate PR list const prs = ( - await bitbucketHttp.getJson>( + await bitbucketHttp.getJsonUnchecked>( `/2.0/repositories/${config.repository}/pullrequests?q=source.branch.name="${branchName}"&state=open`, ) ).body.values; @@ -363,7 +363,7 @@ export async function findPr({ // Gets details for a PR export async function getPr(prNo: number): Promise { const pr = ( - await bitbucketHttp.getJson( + await bitbucketHttp.getJsonUnchecked( `/2.0/repositories/${config.repository}/pullrequests/${prNo}`, ) ).body; @@ -395,7 +395,7 @@ async function getBranchCommit( ): Promise { try { const branch = ( - await bitbucketHttp.getJson( + await bitbucketHttp.getJsonUnchecked( `/2.0/repositories/${config.repository}/refs/branches/${escapeHash( branchName, )}`, @@ -424,7 +424,7 @@ async function getStatus( ): Promise { const sha = await getBranchCommit(branchName); return ( - await bitbucketHttp.getJson>( + await bitbucketHttp.getJsonUnchecked>( `/2.0/repositories/${config.repository}/commit/${sha!}/statuses`, { paginate: true, @@ -531,7 +531,7 @@ async function findOpenIssues(title: string): Promise { const filter = encodeURIComponent(filters.join(' AND ')); return ( ( - await bitbucketHttp.getJson<{ values: BbIssue[] }>( + await bitbucketHttp.getJsonUnchecked<{ values: BbIssue[] }>( `/2.0/repositories/${config.repository}/issues?q=${filter}`, ) ).body.values || /* istanbul ignore next */ [] @@ -677,7 +677,7 @@ export async function getIssueList(): Promise { } const filter = encodeURIComponent(filters.join(' AND ')); const url = `/2.0/repositories/${config.repository}/issues?q=${filter}`; - const res = await bitbucketHttp.getJson<{ values: Issue[] }>(url, { + const res = await bitbucketHttp.getJsonUnchecked<{ values: Issue[] }>(url, { cacheProvider: repoCacheProvider, }); return res.body.values || []; @@ -788,7 +788,7 @@ async function sanitizeReviewers( // Validate that each previous PR reviewer account is still active for (const reviewer of reviewers) { const reviewerUser = ( - await bitbucketHttp.getJson( + await bitbucketHttp.getJsonUnchecked( `/2.0/users/${reviewer.uuid}`, { memCache: true }, ) @@ -881,7 +881,7 @@ export async function createPr({ if (platformPrOptions?.bbUseDefaultReviewers) { const reviewersResponse = ( - await bitbucketHttp.getJson>( + await bitbucketHttp.getJsonUnchecked>( `/2.0/repositories/${config.repository}/effective-default-reviewers`, { paginate: true, @@ -1019,7 +1019,7 @@ export async function updatePr({ logger.debug(`updatePr(${prNo}, ${title}, body)`); // Updating a PR in Bitbucket will clear the reviewers if reviewers is not present const pr = ( - await bitbucketHttp.getJson( + await bitbucketHttp.getJsonUnchecked( `/2.0/repositories/${config.repository}/pullrequests/${prNo}`, ) ).body; diff --git a/lib/modules/platform/bitbucket/pr-cache.ts b/lib/modules/platform/bitbucket/pr-cache.ts index b8e9000e3c3784..84e8fc4a31d3fe 100644 --- a/lib/modules/platform/bitbucket/pr-cache.ts +++ b/lib/modules/platform/bitbucket/pr-cache.ts @@ -147,7 +147,7 @@ export class BitbucketPrCache { pagelen: 50, cacheProvider: repoCacheProvider, }; - const res = await http.getJson>(url, opts); + const res = await http.getJsonUnchecked>(url, opts); const items = res.body.values; logger.debug(`Fetched ${items.length} PRs to sync with cache`); diff --git a/lib/modules/platform/gerrit/client.ts b/lib/modules/platform/gerrit/client.ts index fbc392765b418a..e058f0b703f791 100644 --- a/lib/modules/platform/gerrit/client.ts +++ b/lib/modules/platform/gerrit/client.ts @@ -30,7 +30,7 @@ class GerritClient { private gerritHttp = new GerritHttp(); async getRepos(): Promise { - const res = await this.gerritHttp.getJson( + const res = await this.gerritHttp.getJsonUnchecked( 'a/projects/?type=CODE&state=ACTIVE', {}, ); @@ -38,9 +38,10 @@ class GerritClient { } async getProjectInfo(repository: string): Promise { - const projectInfo = await this.gerritHttp.getJson( - `a/projects/${encodeURIComponent(repository)}`, - ); + const projectInfo = + await this.gerritHttp.getJsonUnchecked( + `a/projects/${encodeURIComponent(repository)}`, + ); if (projectInfo.body.state !== 'ACTIVE') { throw new Error(REPOSITORY_ARCHIVED); } @@ -48,7 +49,7 @@ class GerritClient { } async getBranchInfo(repository: string): Promise { - const branchInfo = await this.gerritHttp.getJson( + const branchInfo = await this.gerritHttp.getJsonUnchecked( `a/projects/${encodeURIComponent(repository)}/branches/HEAD`, ); return branchInfo.body; @@ -60,7 +61,7 @@ class GerritClient { refreshCache?: boolean, ): Promise { const filters = GerritClient.buildSearchFilters(repository, findPRConfig); - const changes = await this.gerritHttp.getJson( + const changes = await this.gerritHttp.getJsonUnchecked( `a/changes/?q=` + filters.join('+') + this.requestDetails.map((det) => `&o=${det}`).join(''), @@ -73,7 +74,7 @@ class GerritClient { } async getChange(changeNumber: number): Promise { - const changes = await this.gerritHttp.getJson( + const changes = await this.gerritHttp.getJsonUnchecked( `a/changes/${changeNumber}?` + this.requestDetails.map((det) => `o=${det}`).join('&'), ); @@ -81,9 +82,10 @@ class GerritClient { } async getMergeableInfo(change: GerritChange): Promise { - const mergeable = await this.gerritHttp.getJson( - `a/changes/${change._number}/revisions/current/mergeable`, - ); + const mergeable = + await this.gerritHttp.getJsonUnchecked( + `a/changes/${change._number}/revisions/current/mergeable`, + ); return mergeable.body; } @@ -99,10 +101,9 @@ class GerritClient { } async getMessages(changeNumber: number): Promise { - const messages = await this.gerritHttp.getJson( - `a/changes/${changeNumber}/messages`, - { memCache: false }, - ); + const messages = await this.gerritHttp.getJsonUnchecked< + GerritChangeMessageInfo[] + >(`a/changes/${changeNumber}/messages`, { memCache: false }); return messages.body; } diff --git a/lib/modules/platform/gitea/gitea-helper.spec.ts b/lib/modules/platform/gitea/gitea-helper.spec.ts index 9f06e6750abf06..e3680f6d11978d 100644 --- a/lib/modules/platform/gitea/gitea-helper.spec.ts +++ b/lib/modules/platform/gitea/gitea-helper.spec.ts @@ -685,37 +685,41 @@ describe('modules/platform/gitea/gitea-helper', () => { }); it('should properly determine worst commit status', async () => { - const statuses: { - status: CommitStatusType; - created_at: string; + const statuses: (Pick & { expected: CommitStatusType; - }[] = [ + })[] = [ { + id: 122, status: 'unknown', created_at: '2020-03-25T01:00:00Z', expected: 'unknown', }, { + id: 124, status: 'pending', created_at: '2020-03-25T03:00:00Z', expected: 'pending', }, { + id: 125, status: 'warning', created_at: '2020-03-25T04:00:00Z', expected: 'warning', }, { + id: 126, status: 'failure', created_at: '2020-03-25T05:00:00Z', expected: 'failure', }, { + id: 123, status: 'success', created_at: '2020-03-25T02:00:00Z', expected: 'failure', }, { + id: 127, status: 'success', created_at: '2020-03-25T06:00:00Z', expected: 'success', @@ -726,13 +730,13 @@ describe('modules/platform/gitea/gitea-helper', () => { { ...mockCommitStatus, status: 'unknown' }, ]; - for (const statusElem of statuses) { - const { status, expected } = statusElem; + for (const { id, status, expected, created_at } of statuses) { // Add current status ot list of commit statuses, then mock the API to return the whole list commitStatuses.push({ ...mockCommitStatus, + id, status, - created_at: statusElem.created_at, + created_at, }); httpMock .scope(baseUrl) diff --git a/lib/modules/platform/gitea/gitea-helper.ts b/lib/modules/platform/gitea/gitea-helper.ts index 2514faf3e74672..53e5a54abf4e0d 100644 --- a/lib/modules/platform/gitea/gitea-helper.ts +++ b/lib/modules/platform/gitea/gitea-helper.ts @@ -46,13 +46,16 @@ export async function getCurrentUser( options?: GiteaHttpOptions, ): Promise { const url = `${API_PATH}/user`; - const res = await giteaHttp.getJson(url, options); + const res = await giteaHttp.getJsonUnchecked(url, options); return res.body; } export async function getVersion(options?: GiteaHttpOptions): Promise { const url = `${API_PATH}/version`; - const res = await giteaHttp.getJson<{ version: string }>(url, options); + const res = await giteaHttp.getJsonUnchecked<{ version: string }>( + url, + options, + ); return res.body.version; } @@ -62,7 +65,7 @@ export async function searchRepos( ): Promise { const query = getQueryString(params); const url = `${API_PATH}/repos/search?${query}`; - const res = await giteaHttp.getJson(url, { + const res = await giteaHttp.getJsonUnchecked(url, { ...options, paginate: true, }); @@ -81,7 +84,7 @@ export async function orgListRepos( options?: GiteaHttpOptions, ): Promise { const url = `${API_PATH}/orgs/${organization}/repos`; - const res = await giteaHttp.getJson(url, { + const res = await giteaHttp.getJsonUnchecked(url, { ...options, paginate: true, }); @@ -94,7 +97,7 @@ export async function getRepo( options?: GiteaHttpOptions, ): Promise { const url = `${API_PATH}/repos/${repoPath}`; - const res = await giteaHttp.getJson(url, options); + const res = await giteaHttp.getJsonUnchecked(url, options); return res.body; } @@ -108,7 +111,7 @@ export async function getRepoContents( const url = `${API_PATH}/repos/${repoPath}/contents/${urlEscape( filePath, )}?${query}`; - const res = await giteaHttp.getJson(url, options); + const res = await giteaHttp.getJsonUnchecked(url, options); if (res.body.content) { res.body.contentString = Buffer.from(res.body.content, 'base64').toString(); @@ -176,7 +179,7 @@ export async function getPR( options?: GiteaHttpOptions, ): Promise { const url = `${API_PATH}/repos/${repoPath}/pulls/${idx}`; - const res = await giteaHttp.getJson(url, options); + const res = await giteaHttp.getJsonUnchecked(url, options); return res.body; } @@ -255,7 +258,7 @@ export async function searchIssues( ): Promise { const query = getQueryString({ ...params, type: 'issues' }); const url = `${API_PATH}/repos/${repoPath}/issues?${query}`; - const res = await giteaHttp.getJson(url, { + const res = await giteaHttp.getJsonUnchecked(url, { ...options, paginate: true, }); @@ -269,7 +272,7 @@ export async function getIssue( options?: GiteaHttpOptions, ): Promise { const url = `${API_PATH}/repos/${repoPath}/issues/${idx}`; - const res = await giteaHttp.getJson(url, options); + const res = await giteaHttp.getJsonUnchecked(url, options); return res.body; } @@ -278,7 +281,7 @@ export async function getRepoLabels( options?: GiteaHttpOptions, ): Promise { const url = `${API_PATH}/repos/${repoPath}/labels`; - const res = await giteaHttp.getJson(url, options); + const res = await giteaHttp.getJsonUnchecked(url, options); return res.body; } @@ -288,7 +291,7 @@ export async function getOrgLabels( options?: GiteaHttpOptions, ): Promise { const url = `${API_PATH}/orgs/${orgName}/labels`; - const res = await giteaHttp.getJson(url, options); + const res = await giteaHttp.getJsonUnchecked(url, options); return res.body; } @@ -350,7 +353,7 @@ export async function getComments( options?: GiteaHttpOptions, ): Promise { const url = `${API_PATH}/repos/${repoPath}/issues/${issue}/comments`; - const res = await giteaHttp.getJson(url, options); + const res = await giteaHttp.getJsonUnchecked(url, options); return res.body; } @@ -394,10 +397,7 @@ export const renovateToGiteaStatusMapping: Record< function filterStatus(data: CommitStatus[]): CommitStatus[] { const ret: Record = {}; for (const i of data) { - if ( - !ret[i.context] || - new Date(ret[i.context].created_at) < new Date(i.created_at) - ) { + if (!ret[i.context] || ret[i.context].id < i.id) { ret[i.context] = i; } } @@ -412,19 +412,20 @@ export async function getCombinedCommitStatus( const url = `${API_PATH}/repos/${repoPath}/commits/${urlEscape( branchName, )}/statuses`; - const res = await giteaHttp.getJson(url, { + const res = await giteaHttp.getJsonUnchecked(url, { ...options, paginate: true, }); let worstState = 0; - for (const cs of filterStatus(res.body)) { + const statuses = filterStatus(res.body); + for (const cs of statuses) { worstState = Math.max(worstState, commitStatusStates.indexOf(cs.status)); } return { worstStatus: commitStatusStates[worstState], - statuses: res.body, + statuses, }; } @@ -434,7 +435,7 @@ export async function getBranch( options?: GiteaHttpOptions, ): Promise { const url = `${API_PATH}/repos/${repoPath}/branches/${urlEscape(branchName)}`; - const res = await giteaHttp.getJson(url, options); + const res = await giteaHttp.getJsonUnchecked(url, options); return res.body; } diff --git a/lib/modules/platform/gitea/index.spec.ts b/lib/modules/platform/gitea/index.spec.ts index 84031f86974876..23494f1ed8f1f9 100644 --- a/lib/modules/platform/gitea/index.spec.ts +++ b/lib/modules/platform/gitea/index.spec.ts @@ -9,6 +9,7 @@ import { REPOSITORY_CHANGED, REPOSITORY_EMPTY, REPOSITORY_MIRRORED, + TEMPORARY_ERROR, } from '../../../constants/error-messages'; import type { logger as _logger } from '../../../logger'; import type * as _git from '../../../util/git'; @@ -1309,6 +1310,18 @@ describe('modules/platform/gitea/index', () => { expect(res).toBeNull(); }); + + it('should throw temporary error for null pull request', async () => { + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get('/repos/some/repo/pulls') + .query({ state: 'all', sort: 'recentupdate' }) + .reply(200, [null]); // TODO: 404 should be handled + await initFakePlatform(scope); + await initFakeRepo(scope); + + await expect(gitea.getPr(42)).rejects.toThrow(TEMPORARY_ERROR); + }); }); describe('findPr', () => { diff --git a/lib/modules/platform/gitea/pr-cache.ts b/lib/modules/platform/gitea/pr-cache.ts index e6f363500dd03e..82d935de312186 100644 --- a/lib/modules/platform/gitea/pr-cache.ts +++ b/lib/modules/platform/gitea/pr-cache.ts @@ -1,5 +1,7 @@ import { dequal } from 'dequal'; import { DateTime } from 'luxon'; +import { TEMPORARY_ERROR } from '../../../constants/error-messages'; +import { logger } from '../../../logger'; import * as memCache from '../../../util/cache/memory'; import { getCache } from '../../../util/cache/repository'; import type { GiteaHttp } from '../../../util/http/gitea'; @@ -83,7 +85,7 @@ export class GiteaPrCache { prCache.setPr(item); } - private reconcile(rawItems: PR[]): boolean { + private reconcile(rawItems: (PR | null)[]): boolean { const { items } = this.cache; let { updated_at } = this.cache; const cacheTime = updated_at ? DateTime.fromISO(updated_at) : null; @@ -91,6 +93,12 @@ export class GiteaPrCache { let needNextPage = true; for (const rawItem of rawItems) { + if (!rawItem) { + logger.warn('Gitea PR is empty, throwing temporary error'); + // Gitea API sometimes returns empty PRs, so we throw a temporary error + // /~https://github.com/go-gitea/gitea/blob/fcd096231ac2deaefbca10a7db1b9b01f1da93d7/services/convert/pull.go#L34-L52 + throw new Error(TEMPORARY_ERROR); + } const id = rawItem.number; const newItem = toRenovatePR(rawItem, this.author); @@ -127,10 +135,14 @@ export class GiteaPrCache { `${API_PATH}/repos/${this.repo}/pulls?${query}`; while (url) { - const res: HttpResponse = await http.getJson(url, { - memCache: false, - paginate: false, - }); + // TODO: use zod, typescript can't infer the type of the response #22198 + const res: HttpResponse<(PR | null)[]> = await http.getJsonUnchecked( + url, + { + memCache: false, + paginate: false, + }, + ); const needNextPage = this.reconcile(res.body); if (!needNextPage) { diff --git a/lib/modules/platform/gitea/types.ts b/lib/modules/platform/gitea/types.ts index cf4fb50b22645b..9a20bad14708fe 100644 --- a/lib/modules/platform/gitea/types.ts +++ b/lib/modules/platform/gitea/types.ts @@ -138,8 +138,8 @@ export interface CommitStatus { id: number; status: CommitStatusType; context: string; - description: string; - target_url: string; + description?: string; + target_url?: string; created_at: string; } diff --git a/lib/modules/platform/github/index.ts b/lib/modules/platform/github/index.ts index 8551653ce0dac3..2ef5eb87dac3f3 100644 --- a/lib/modules/platform/github/index.ts +++ b/lib/modules/platform/github/index.ts @@ -251,7 +251,7 @@ export async function initPlatform({ async function fetchRepositories(): Promise { try { if (isGHApp()) { - const res = await githubApi.getJson<{ + const res = await githubApi.getJsonUnchecked<{ repositories: GhRestRepo[]; }>(`installation/repositories?per_page=100`, { paginationField: 'repositories', @@ -259,7 +259,7 @@ async function fetchRepositories(): Promise { }); return res.body.repositories; } else { - const res = await githubApi.getJson( + const res = await githubApi.getJsonUnchecked( `user/repos?per_page=100`, { paginate: 'all' }, ); @@ -313,7 +313,7 @@ async function getBranchProtection( if (config.parentRepo) { return {}; } - const res = await githubApi.getJson( + const res = await githubApi.getJsonUnchecked( `repos/${config.repository}/branches/${escapeHash(branchName)}/protection`, { cacheProvider: repoCacheProvider }, ); @@ -338,7 +338,10 @@ export async function getRawFile( if (branchOrTag) { url += `?ref=` + branchOrTag; } - const res = await githubApi.getJson<{ content: string }>(url, httpOptions); + const res = await githubApi.getJsonUnchecked<{ content: string }>( + url, + httpOptions, + ); const buf = res.body.content; const str = fromBase64(buf); return str; @@ -361,7 +364,7 @@ export async function listForks( // Get list of existing repos const url = `repos/${repository}/forks?per_page=100`; const repos = ( - await githubApi.getJson(url, { + await githubApi.getJsonUnchecked(url, { token, paginate: true, pageLimit: 100, @@ -792,7 +795,7 @@ function cachePr(pr?: GhPr | null): void { // Fetch fresh Pull Request and cache it when possible async function fetchPr(prNo: number): Promise { try { - const { body: ghRestPr } = await githubApi.getJson( + const { body: ghRestPr } = await githubApi.getJsonUnchecked( `repos/${config.parentRepo ?? config.repository}/pulls/${prNo}`, ); const result = coerceRestPr(ghRestPr); @@ -857,7 +860,7 @@ export async function findPr({ const repo = config.parentRepo ?? config.repository; const org = repo?.split('/')[0]; // PR might have been created by anyone, so don't use the cached Renovate PR list - const { body: prList } = await githubApi.getJson( + const { body: prList } = await githubApi.getJsonUnchecked( `repos/${repo}/pulls?head=${org}:${branchName}&state=open`, { cacheProvider: repoCacheProvider }, ); @@ -996,10 +999,11 @@ async function getStatus( const branch = escapeHash(branchName); const url = `repos/${config.repository}/commits/${branch}/status`; - const { body: status } = await githubApi.getJson(url, { - memCache: useCache, - cacheProvider: repoCacheProvider, - }); + const { body: status } = + await githubApi.getJsonUnchecked(url, { + memCache: useCache, + cacheProvider: repoCacheProvider, + }); return status; } @@ -1053,7 +1057,7 @@ export async function getBranchStatus( paginationField: 'check_runs', }; const checkRunsRaw = ( - await githubApi.getJson<{ + await githubApi.getJsonUnchecked<{ check_runs: { name: string; status: string; conclusion: string }[]; }>(checkRunsUrl, opts) ).body; @@ -1116,7 +1120,9 @@ async function getStatusCheck( const url = `repos/${config.repository}/commits/${branchCommit}/statuses`; return ( - await githubApi.getJson(url, { memCache: useCache }) + await githubApi.getJsonUnchecked(url, { + memCache: useCache, + }) ).body; } @@ -1547,10 +1553,13 @@ async function getComments(issueNo: number): Promise { const repo = config.parentRepo ?? config.repository; const url = `repos/${repo}/issues/${issueNo}/comments?per_page=100`; try { - const { body: comments } = await githubApi.getJson(url, { - paginate: true, - cacheProvider: repoCacheProvider, - }); + const { body: comments } = await githubApi.getJsonUnchecked( + url, + { + paginate: true, + cacheProvider: repoCacheProvider, + }, + ); logger.debug(`Found ${comments.length} comments`); return comments; } catch (err) /* istanbul ignore next */ { diff --git a/lib/modules/platform/github/pr.ts b/lib/modules/platform/github/pr.ts index 66b37aa3426fcc..5e32084ca23592 100644 --- a/lib/modules/platform/github/pr.ts +++ b/lib/modules/platform/github/pr.ts @@ -75,7 +75,7 @@ export async function getPrCache( const perPage = isInitial ? 100 : 20; const urlPath = `repos/${repo}/pulls?per_page=${perPage}&state=all&sort=updated&direction=desc&page=${pageIdx}`; - const res = await http.getJson(urlPath, opts); + const res = await http.getJsonUnchecked(urlPath, opts); apiQuotaAffected = true; requestsTotal += 1; diff --git a/lib/modules/platform/github/user.ts b/lib/modules/platform/github/user.ts index 5fabaedb94d662..c2fced06c02866 100644 --- a/lib/modules/platform/github/user.ts +++ b/lib/modules/platform/github/user.ts @@ -32,12 +32,13 @@ export async function getUserDetails( ): Promise { try { const userData = ( - await githubApi.getJson<{ login: string; name: string; id: number }>( - endpoint + 'user', - { - token, - }, - ) + await githubApi.getJsonUnchecked<{ + login: string; + name: string; + id: number; + }>(endpoint + 'user', { + token, + }) ).body; return { username: userData.login, @@ -56,9 +57,12 @@ export async function getUserEmail( ): Promise { try { const emails = ( - await githubApi.getJson<{ email: string }[]>(endpoint + 'user/emails', { - token, - }) + await githubApi.getJsonUnchecked<{ email: string }[]>( + endpoint + 'user/emails', + { + token, + }, + ) ).body; return emails?.[0].email ?? null; } catch { diff --git a/lib/modules/platform/gitlab/http.ts b/lib/modules/platform/gitlab/http.ts index 51f6fc401f56a5..deb011fc5828cb 100644 --- a/lib/modules/platform/gitlab/http.ts +++ b/lib/modules/platform/gitlab/http.ts @@ -7,7 +7,9 @@ export const gitlabApi = new GitlabHttp(); export async function getUserID(username: string): Promise { const userInfo = ( - await gitlabApi.getJson<{ id: number }[]>(`users?username=${username}`) + await gitlabApi.getJsonUnchecked<{ id: number }[]>( + `users?username=${username}`, + ) ).body; if (is.emptyArray(userInfo)) { @@ -22,7 +24,9 @@ export async function getUserID(username: string): Promise { async function getMembers(group: string): Promise { const groupEncoded = encodeURIComponent(group); return ( - await gitlabApi.getJson(`groups/${groupEncoded}/members`) + await gitlabApi.getJsonUnchecked( + `groups/${groupEncoded}/members`, + ) ).body; } @@ -39,7 +43,8 @@ export async function getMemberUsernames(group: string): Promise { export async function isUserBusy(user: string): Promise { try { const url = `/users/${user}/status`; - const userStatus = (await gitlabApi.getJson(url)).body; + const userStatus = (await gitlabApi.getJsonUnchecked(url)) + .body; return userStatus.availability === 'busy'; } catch (err) { logger.warn({ err }, 'Failed to get user status'); diff --git a/lib/modules/platform/gitlab/index.ts b/lib/modules/platform/gitlab/index.ts index 1010f448cdc7f1..64ed26afd3a3d1 100644 --- a/lib/modules/platform/gitlab/index.ts +++ b/lib/modules/platform/gitlab/index.ts @@ -117,7 +117,7 @@ export async function initPlatform({ try { if (!gitAuthor) { const user = ( - await gitlabApi.getJson<{ + await gitlabApi.getJsonUnchecked<{ email: string; name: string; id: number; @@ -133,7 +133,9 @@ export async function initPlatform({ gitlabVersion = process.env.RENOVATE_X_PLATFORM_VERSION; } else { const version = ( - await gitlabApi.getJson<{ version: string }>('version', { token }) + await gitlabApi.getJsonUnchecked<{ version: string }>('version', { + token, + }) ).body; gitlabVersion = version.version; } @@ -191,7 +193,7 @@ export async function getRepos(config?: AutodiscoverConfig): Promise { await pMap( urls, (url) => - gitlabApi.getJson(url, { + gitlabApi.getJsonUnchecked(url, { paginate: true, }), { @@ -226,7 +228,7 @@ export async function getRawFile( const url = `projects/${repo}/repository/files/${escapedFileName}?ref=` + (branchOrTag ?? `HEAD`); - const res = await gitlabApi.getJson<{ content: string }>(url); + const res = await gitlabApi.getJsonUnchecked<{ content: string }>(url); const buf = res.body.content; const str = Buffer.from(buf, 'base64').toString(); return str; @@ -314,7 +316,7 @@ export async function initRepo({ let res: HttpResponse; try { - res = await gitlabApi.getJson( + res = await gitlabApi.getJsonUnchecked( `projects/${config.repository}`, ); if (res.body.archived) { @@ -433,7 +435,7 @@ async function getStatus( }/repository/commits/${branchSha!}/statuses`; return ( - await gitlabApi.getJson(url, { + await gitlabApi.getJsonUnchecked(url, { paginate: true, memCache: useCache, }) @@ -548,9 +550,12 @@ async function fetchPrList(): Promise { const query = getQueryString(searchParams); const urlString = `projects/${config.repository}/merge_requests?${query}`; try { - const res = await gitlabApi.getJson(urlString, { - paginate: true, - }); + const res = await gitlabApi.getJsonUnchecked( + urlString, + { + paginate: true, + }, + ); return res.body.map((pr) => prInfo(pr)); } catch (err) /* istanbul ignore next */ { logger.debug({ err }, 'Error fetching PR list'); @@ -571,7 +576,7 @@ export async function getPrList(): Promise { async function ignoreApprovals(pr: number): Promise { try { const url = `projects/${config.repository}/merge_requests/${pr}/approval_rules`; - const { body: rules } = await gitlabApi.getJson< + const { body: rules } = await gitlabApi.getJsonUnchecked< { name: string; rule_type: string; @@ -655,7 +660,7 @@ async function tryPrAutomerge( // Check for correct merge request status before setting `merge_when_pipeline_succeeds` to `true`. for (let attempt = 1; attempt <= retryTimes; attempt += 1) { - const { body } = await gitlabApi.getJson<{ + const { body } = await gitlabApi.getJsonUnchecked<{ merge_status: string; detailed_merge_status?: string; pipeline: { @@ -929,7 +934,7 @@ export async function findPr({ if (includeOtherAuthors) { // PR might have been created by anyone, so don't use the cached Renovate MR list - const response = await gitlabApi.getJson( + const response = await gitlabApi.getJsonUnchecked( `projects/${config.repository}/merge_requests?source_branch=${branchName}&state=opened`, ); @@ -1054,7 +1059,7 @@ export async function getIssueList(): Promise { searchParams.scope = 'created_by_me'; } const query = getQueryString(searchParams); - const res = await gitlabApi.getJson< + const res = await gitlabApi.getJsonUnchecked< { iid: number; title: string; labels: string[] }[] >(`projects/${config.repository}/issues?${query}`, { memCache: false, @@ -1080,7 +1085,7 @@ export async function getIssue( ): Promise { try { const issueBody = ( - await gitlabApi.getJson<{ description: string }>( + await gitlabApi.getJsonUnchecked<{ description: string }>( `projects/${config.repository}/issues/${number}`, { memCache: useCache }, ) @@ -1127,7 +1132,7 @@ export async function ensureIssue({ } if (issue) { const existingDescription = ( - await gitlabApi.getJson<{ description: string }>( + await gitlabApi.getJsonUnchecked<{ description: string }>( `projects/${config.repository}/issues/${issue.iid}`, ) ).body.description; @@ -1302,7 +1307,7 @@ async function getComments(issueNo: number): Promise { logger.debug(`Getting comments for #${issueNo}`); const url = `projects/${config.repository}/merge_requests/${issueNo}/notes`; const comments = ( - await gitlabApi.getJson(url, { paginate: true }) + await gitlabApi.getJsonUnchecked(url, { paginate: true }) ).body; logger.debug(`Found ${comments.length} comments`); return comments; diff --git a/lib/modules/platform/gitlab/merge-request.ts b/lib/modules/platform/gitlab/merge-request.ts index 91eb6bf88d1a5d..0a657fa95c970f 100644 --- a/lib/modules/platform/gitlab/merge-request.ts +++ b/lib/modules/platform/gitlab/merge-request.ts @@ -9,7 +9,7 @@ export async function getMR( logger.debug(`getMR(${iid})`); const url = `projects/${repository}/merge_requests/${iid}?include_diverged_commits_count=1`; - return (await gitlabApi.getJson(url)).body; + return (await gitlabApi.getJsonUnchecked(url)).body; } export async function updateMR( diff --git a/lib/modules/versioning/schema.ts b/lib/modules/versioning/schema.ts index 3bf4db93da042a..b7d55562f67278 100644 --- a/lib/modules/versioning/schema.ts +++ b/lib/modules/versioning/schema.ts @@ -12,8 +12,7 @@ export const Versioning = z let versioning = versionings.get(versioningName); if (!versioning) { - logger.info( - { versioning: versioningSpec }, + logger.debug( `Versioning: '${versioningSpec}' not found, falling back to ${defaultVersioning.id}`, ); return defaultVersioning.api; diff --git a/lib/modules/versioning/ubuntu/common.ts b/lib/modules/versioning/ubuntu/common.ts index abcb173c0486ea..0cd4b958c7f392 100644 --- a/lib/modules/versioning/ubuntu/common.ts +++ b/lib/modules/versioning/ubuntu/common.ts @@ -1,11 +1,13 @@ import { regEx } from '../../../util/regex'; +const regex = regEx(/^(?\w+)-(?\d{8})(?\.\d{1,2})?$/); + function isDatedCodeName(input: string): boolean { - return regEx(/^(?\w+)-(?\d{8})$/).test(input); + return regex.test(input); } function getDatedContainerImageCodename(version: string): null | string { - const groups = regEx(/^(?\w+)-(?\d{8})$/).exec(version); + const groups = regex.exec(version); if (!groups?.groups) { return null; } @@ -13,7 +15,7 @@ function getDatedContainerImageCodename(version: string): null | string { } function getDatedContainerImageVersion(version: string): null | number { - const groups = regEx(/^(?\w+)-(?\d{8})$/).exec(version); + const groups = regex.exec(version); if (!groups?.groups) { return null; } @@ -21,8 +23,18 @@ function getDatedContainerImageVersion(version: string): null | number { return parseInt(groups.groups.date, 10); } +function getDatedContainerImageSuffix(version: string): null | string { + const groups = regex.exec(version); + if (!groups?.groups?.suffix) { + return null; + } + + return groups.groups.suffix; +} + export { isDatedCodeName, getDatedContainerImageCodename, getDatedContainerImageVersion, + getDatedContainerImageSuffix, }; diff --git a/lib/modules/versioning/ubuntu/index.spec.ts b/lib/modules/versioning/ubuntu/index.spec.ts index eaa5de4e2842bf..5a60006fa9e83e 100644 --- a/lib/modules/versioning/ubuntu/index.spec.ts +++ b/lib/modules/versioning/ubuntu/index.spec.ts @@ -5,84 +5,88 @@ describe('modules/versioning/ubuntu/index', () => { const dt = DateTime.fromISO('2022-04-20'); it.each` - version | expected - ${undefined} | ${false} - ${null} | ${false} - ${''} | ${false} - ${'xenial'} | ${true} - ${'04.10'} | ${true} - ${'05.04'} | ${true} - ${'05.10'} | ${true} - ${'6.06'} | ${true} - ${'6.10'} | ${true} - ${'7.04'} | ${true} - ${'7.10'} | ${true} - ${'8.04'} | ${true} - ${'8.10'} | ${true} - ${'9.04'} | ${true} - ${'9.10'} | ${true} - ${'10.04.4'} | ${true} - ${'10.10'} | ${true} - ${'11.04'} | ${true} - ${'11.10'} | ${true} - ${'12.04.5'} | ${true} - ${'12.10'} | ${true} - ${'13.04'} | ${true} - ${'13.10'} | ${true} - ${'14.04.6'} | ${true} - ${'14.10'} | ${true} - ${'15.04'} | ${true} - ${'15.10'} | ${true} - ${'16.04.7'} | ${true} - ${'16.10'} | ${true} - ${'17.04'} | ${true} - ${'17.10'} | ${true} - ${'18.04.5'} | ${true} - ${'18.10'} | ${true} - ${'19.04'} | ${true} - ${'19.10'} | ${true} - ${'20.04'} | ${true} - ${'20.10'} | ${true} - ${'2020.04'} | ${false} - ${'xenial'} | ${true} - ${'warty'} | ${true} - ${'hoary'} | ${true} - ${'breezy'} | ${true} - ${'dapper'} | ${true} - ${'edgy'} | ${true} - ${'feisty'} | ${true} - ${'gutsy'} | ${true} - ${'hardy'} | ${true} - ${'intrepid'} | ${true} - ${'jaunty'} | ${true} - ${'karmic'} | ${true} - ${'lucid.4'} | ${false} - ${'maverick'} | ${true} - ${'natty'} | ${true} - ${'oneiric'} | ${true} - ${'precise.5'} | ${false} - ${'quantal'} | ${true} - ${'raring'} | ${true} - ${'saucy'} | ${true} - ${'trusty.6'} | ${false} - ${'utopic'} | ${true} - ${'vivid'} | ${true} - ${'wily'} | ${true} - ${'xenial.7'} | ${false} - ${'yakkety'} | ${true} - ${'zesty'} | ${true} - ${'artful'} | ${true} - ${'bionic.5'} | ${false} - ${'cosmic'} | ${true} - ${'disco'} | ${true} - ${'eoan'} | ${true} - ${'focal'} | ${true} - ${'groovy'} | ${true} - ${'hirsute'} | ${true} - ${'impish'} | ${true} - ${'jammy'} | ${true} - ${'jammy-20230816'} | ${true} - ${'jammy-2023086'} | ${false} + version | expected + ${undefined} | ${false} + ${null} | ${false} + ${''} | ${false} + ${'xenial'} | ${true} + ${'04.10'} | ${true} + ${'05.04'} | ${true} + ${'05.10'} | ${true} + ${'6.06'} | ${true} + ${'6.10'} | ${true} + ${'7.04'} | ${true} + ${'7.10'} | ${true} + ${'8.04'} | ${true} + ${'8.10'} | ${true} + ${'9.04'} | ${true} + ${'9.10'} | ${true} + ${'10.04.4'} | ${true} + ${'10.10'} | ${true} + ${'11.04'} | ${true} + ${'11.10'} | ${true} + ${'12.04.5'} | ${true} + ${'12.10'} | ${true} + ${'13.04'} | ${true} + ${'13.10'} | ${true} + ${'14.04.6'} | ${true} + ${'14.10'} | ${true} + ${'15.04'} | ${true} + ${'15.10'} | ${true} + ${'16.04.7'} | ${true} + ${'16.10'} | ${true} + ${'17.04'} | ${true} + ${'17.10'} | ${true} + ${'18.04.5'} | ${true} + ${'18.10'} | ${true} + ${'19.04'} | ${true} + ${'19.10'} | ${true} + ${'20.04'} | ${true} + ${'20.10'} | ${true} + ${'2020.04'} | ${false} + ${'xenial'} | ${true} + ${'warty'} | ${true} + ${'hoary'} | ${true} + ${'breezy'} | ${true} + ${'dapper'} | ${true} + ${'edgy'} | ${true} + ${'feisty'} | ${true} + ${'gutsy'} | ${true} + ${'hardy'} | ${true} + ${'intrepid'} | ${true} + ${'jaunty'} | ${true} + ${'karmic'} | ${true} + ${'lucid.4'} | ${false} + ${'maverick'} | ${true} + ${'natty'} | ${true} + ${'oneiric'} | ${true} + ${'precise.5'} | ${false} + ${'quantal'} | ${true} + ${'raring'} | ${true} + ${'saucy'} | ${true} + ${'trusty.6'} | ${false} + ${'utopic'} | ${true} + ${'vivid'} | ${true} + ${'wily'} | ${true} + ${'xenial.7'} | ${false} + ${'yakkety'} | ${true} + ${'zesty'} | ${true} + ${'artful'} | ${true} + ${'bionic.5'} | ${false} + ${'cosmic'} | ${true} + ${'disco'} | ${true} + ${'eoan'} | ${true} + ${'focal'} | ${true} + ${'groovy'} | ${true} + ${'hirsute'} | ${true} + ${'impish'} | ${true} + ${'jammy'} | ${true} + ${'jammy-20230816'} | ${true} + ${'jammy-20230816'} | ${true} + ${'yakkety-20160806.1'} | ${true} + ${'utopic-20150228.11'} | ${true} + ${'utopic-20150228.11.1'} | ${false} + ${'oracular-20240811.'} | ${false} `('isValid("$version") === $expected', ({ version, expected }) => { expect(ubuntu.isValid(version)).toBe(expected); }); @@ -272,51 +276,59 @@ describe('modules/versioning/ubuntu/index', () => { ); it.each` - a | b | expected - ${'20.04'} | ${'2020.04'} | ${false} - ${'17.10'} | ${'artful'} | ${true} - ${'xenial'} | ${'artful'} | ${false} - ${'17.04'} | ${'artful'} | ${false} - ${'artful'} | ${'17.10'} | ${true} - ${'16.04'} | ${'xenial'} | ${true} - ${'focal'} | ${'20.04'} | ${true} - ${'20.04'} | ${'focal'} | ${true} - ${'19.10'} | ${'19.10'} | ${true} - ${'jammy'} | ${'jammy-20230816'} | ${false} - ${'jammy-20230816'} | ${'jammy-20230816'} | ${true} - ${'jammy-20230716'} | ${'jammy-20230816'} | ${false} + a | b | expected + ${'20.04'} | ${'2020.04'} | ${false} + ${'17.10'} | ${'artful'} | ${true} + ${'xenial'} | ${'artful'} | ${false} + ${'17.04'} | ${'artful'} | ${false} + ${'artful'} | ${'17.10'} | ${true} + ${'16.04'} | ${'xenial'} | ${true} + ${'focal'} | ${'20.04'} | ${true} + ${'20.04'} | ${'focal'} | ${true} + ${'19.10'} | ${'19.10'} | ${true} + ${'jammy'} | ${'jammy-20230816'} | ${false} + ${'jammy-20230816'} | ${'jammy-20230816'} | ${true} + ${'jammy-20230716'} | ${'jammy-20230816'} | ${false} + ${'jammy-20230716.1'} | ${'jammy-20230716.1'} | ${true} + ${'jammy-20230716.1'} | ${'jammy-20230716.2'} | ${false} + ${'jammy-20230716.1'} | ${'jammy-20230816.11'} | ${false} `('equals($a, $b) === $expected', ({ a, b, expected }) => { expect(ubuntu.equals(a, b)).toBe(expected); }); it.each` - a | b | expected - ${'20.04'} | ${'20.10'} | ${false} - ${'20.10'} | ${'20.04'} | ${true} - ${'19.10'} | ${'20.04'} | ${false} - ${'20.04'} | ${'19.10'} | ${true} - ${'16.04'} | ${'16.04.7'} | ${false} - ${'16.04.7'} | ${'16.04'} | ${true} - ${'16.04.1'} | ${'16.04.7'} | ${false} - ${'16.04.7'} | ${'16.04.1'} | ${true} - ${'19.10.1'} | ${'20.04.1'} | ${false} - ${'20.04.1'} | ${'19.10.1'} | ${true} - ${'xxx'} | ${'yyy'} | ${false} - ${'focal'} | ${'groovy'} | ${false} - ${'groovy'} | ${'focal'} | ${true} - ${'eoan'} | ${'focal'} | ${false} - ${'focal'} | ${'eoan'} | ${true} - ${'vivid'} | ${'saucy'} | ${true} - ${'impish'} | ${'focal'} | ${true} - ${'eoan'} | ${'quantal'} | ${true} - ${'focal'} | ${'lucid'} | ${true} - ${'eoan'} | ${'focal'} | ${false} - ${'focal'} | ${'eoan'} | ${true} - ${'jammy'} | ${'focal'} | ${true} - ${'jammy-20230816'} | ${'focal'} | ${true} - ${'jammy-20230816'} | ${'jammy-20230716'} | ${true} - ${'jammy-20230716'} | ${'jammy-20230816'} | ${false} - ${'focal-20230816'} | ${'jammy-20230716'} | ${false} + a | b | expected + ${'20.04'} | ${'20.10'} | ${false} + ${'20.10'} | ${'20.04'} | ${true} + ${'19.10'} | ${'20.04'} | ${false} + ${'20.04'} | ${'19.10'} | ${true} + ${'16.04'} | ${'16.04.7'} | ${false} + ${'16.04.7'} | ${'16.04'} | ${true} + ${'16.04.1'} | ${'16.04.7'} | ${false} + ${'16.04.7'} | ${'16.04.1'} | ${true} + ${'19.10.1'} | ${'20.04.1'} | ${false} + ${'20.04.1'} | ${'19.10.1'} | ${true} + ${'xxx'} | ${'yyy'} | ${false} + ${'focal'} | ${'groovy'} | ${false} + ${'groovy'} | ${'focal'} | ${true} + ${'eoan'} | ${'focal'} | ${false} + ${'focal'} | ${'eoan'} | ${true} + ${'vivid'} | ${'saucy'} | ${true} + ${'impish'} | ${'focal'} | ${true} + ${'eoan'} | ${'quantal'} | ${true} + ${'focal'} | ${'lucid'} | ${true} + ${'eoan'} | ${'focal'} | ${false} + ${'focal'} | ${'eoan'} | ${true} + ${'jammy'} | ${'focal'} | ${true} + ${'jammy-20230816'} | ${'focal'} | ${true} + ${'jammy-20230816'} | ${'jammy-20230716'} | ${true} + ${'jammy-20230716'} | ${'jammy-20230816'} | ${false} + ${'focal-20230816'} | ${'jammy-20230716'} | ${false} + ${'zesty-20170517.1'} | ${'jammy-20240627.1'} | ${false} + ${'jammy-20240627.3'} | ${'jammy-20240627.1'} | ${true} + ${'jammy-20240627.3'} | ${'jammy-20240627.4'} | ${false} + ${'jammy-20240627.1'} | ${'precise-20150228.11'} | ${true} + ${'jammy-20240627'} | ${'precise-20150228.11'} | ${true} `('isGreaterThan("$a", "$b") === $expected', ({ a, b, expected }) => { expect(ubuntu.isGreaterThan(a, b)).toBe(expected); }); diff --git a/lib/modules/versioning/ubuntu/index.ts b/lib/modules/versioning/ubuntu/index.ts index 338b419ecb18ca..ce41ab1a3a0d80 100644 --- a/lib/modules/versioning/ubuntu/index.ts +++ b/lib/modules/versioning/ubuntu/index.ts @@ -4,6 +4,7 @@ import { DistroInfo } from '../distro'; import type { NewValueConfig, VersioningApi } from '../types'; import { getDatedContainerImageCodename, + getDatedContainerImageSuffix, getDatedContainerImageVersion, isDatedCodeName, } from './common'; @@ -105,6 +106,12 @@ function equals(version: string, other: string): boolean { return false; } + const verSuffix = getDatedContainerImageSuffix(version); + const otherSuffix = getDatedContainerImageSuffix(other); + if (verSuffix !== otherSuffix) { + return false; + } + const ver = getVersionByCodename(version); const otherVer = getVersionByCodename(other); return isVersion(ver) && isVersion(otherVer) && ver === otherVer; @@ -138,6 +145,15 @@ function isGreaterThan(version: string, other: string): boolean { return false; } + const xSuffixVersion = getDatedContainerImageSuffix(version) ?? 0; + const ySuffixVersion = getDatedContainerImageSuffix(other) ?? 0; + if (xSuffixVersion > ySuffixVersion) { + return true; + } + if (xSuffixVersion < ySuffixVersion) { + return false; + } + const xPatch = getPatch(version) ?? 0; const yPatch = getPatch(other) ?? 0; return xPatch > yPatch; diff --git a/lib/util/http/bitbucket.spec.ts b/lib/util/http/bitbucket.spec.ts index 52cc342b7d5761..fbf3a4ee429de8 100644 --- a/lib/util/http/bitbucket.spec.ts +++ b/lib/util/http/bitbucket.spec.ts @@ -78,7 +78,9 @@ describe('util/http/bitbucket', () => { values: valuesPageThree, page: '3', }); - const res = await api.getJson('/some-url?foo=bar', { paginate: true }); + const res = await api.getJsonUnchecked('/some-url?foo=bar', { + paginate: true, + }); expect(res.body).toEqual({ page: '1', pagelen: 210, @@ -112,7 +114,9 @@ describe('util/http/bitbucket', () => { values: valuesPageThree, page: '3', }); - const res = await api.getJson('some-url?pagelen=10', { paginate: true }); + const res = await api.getJsonUnchecked('some-url?pagelen=10', { + paginate: true, + }); expect(res.body).toEqual({ page: '1', pagelen: 21, @@ -146,7 +150,7 @@ describe('util/http/bitbucket', () => { values: valuesPageThree, page: '3', }); - const res = await api.getJson('some-url', { + const res = await api.getJsonUnchecked('some-url', { paginate: true, pagelen: 20, }); diff --git a/lib/util/http/cache/repository-http-cache-provider.spec.ts b/lib/util/http/cache/repository-http-cache-provider.spec.ts index a8acbba4b11786..da8c1806d03cd2 100644 --- a/lib/util/http/cache/repository-http-cache-provider.spec.ts +++ b/lib/util/http/cache/repository-http-cache-provider.spec.ts @@ -17,7 +17,7 @@ describe('util/http/cache/repository-http-cache-provider', () => { const scope = httpMock.scope('https://example.com'); scope.get('/foo/bar').reply(200, { msg: 'Hello, world!' }, { etag: '123' }); - const res1 = await http.getJson('https://example.com/foo/bar'); + const res1 = await http.getJsonUnchecked('https://example.com/foo/bar'); expect(res1).toMatchObject({ statusCode: 200, body: { msg: 'Hello, world!' }, @@ -25,7 +25,7 @@ describe('util/http/cache/repository-http-cache-provider', () => { }); scope.get('/foo/bar').reply(304); - const res2 = await http.getJson('https://example.com/foo/bar'); + const res2 = await http.getJsonUnchecked('https://example.com/foo/bar'); expect(res2).toMatchObject({ statusCode: 200, body: { msg: 'Hello, world!' }, @@ -43,7 +43,7 @@ describe('util/http/cache/repository-http-cache-provider', () => { { msg: 'Hello, world!' }, { 'last-modified': 'Mon, 01 Jan 2000 00:00:00 GMT' }, ); - const res1 = await http.getJson('https://example.com/foo/bar'); + const res1 = await http.getJsonUnchecked('https://example.com/foo/bar'); expect(res1).toMatchObject({ statusCode: 200, body: { msg: 'Hello, world!' }, @@ -51,7 +51,7 @@ describe('util/http/cache/repository-http-cache-provider', () => { }); scope.get('/foo/bar').reply(304); - const res2 = await http.getJson('https://example.com/foo/bar'); + const res2 = await http.getJsonUnchecked('https://example.com/foo/bar'); expect(res2).toMatchObject({ statusCode: 200, body: { msg: 'Hello, world!' }, @@ -71,7 +71,7 @@ describe('util/http/cache/repository-http-cache-provider', () => { }; httpMock.scope('https://example.com').get('/foo/bar').reply(304); - const res = await http.getJson('https://example.com/foo/bar'); + const res = await http.getJsonUnchecked('https://example.com/foo/bar'); expect(res).toMatchObject({ statusCode: 200, @@ -86,7 +86,7 @@ describe('util/http/cache/repository-http-cache-provider', () => { .get('/foo/bar') .reply(200, { msg: 'Hello, world!' }); - await http.getJson('https://example.com/foo/bar'); + await http.getJsonUnchecked('https://example.com/foo/bar'); expect(logger.logger.debug).toHaveBeenCalledWith( 'http cache: failed to persist cache for https://example.com/foo/bar', @@ -97,7 +97,7 @@ describe('util/http/cache/repository-http-cache-provider', () => { const scope = httpMock.scope('https://example.com'); scope.get('/foo/bar').reply(200, { msg: 'Hello, world!' }, { etag: '123' }); - const res1 = await http.getJson('https://example.com/foo/bar'); + const res1 = await http.getJsonUnchecked('https://example.com/foo/bar'); expect(res1).toMatchObject({ statusCode: 200, body: { msg: 'Hello, world!' }, @@ -107,7 +107,7 @@ describe('util/http/cache/repository-http-cache-provider', () => { resetCache(); scope.get('/foo/bar').reply(304); - const res2 = await http.getJson('https://example.com/foo/bar'); + const res2 = await http.getJsonUnchecked('https://example.com/foo/bar'); expect(res2).toMatchObject({ statusCode: 304, authorization: false, @@ -118,7 +118,7 @@ describe('util/http/cache/repository-http-cache-provider', () => { const scope = httpMock.scope('https://example.com'); scope.get('/foo/bar').reply(203); - const res = await http.getJson('https://example.com/foo/bar'); + const res = await http.getJsonUnchecked('https://example.com/foo/bar'); expect(res).toMatchObject({ statusCode: 203, @@ -130,7 +130,7 @@ describe('util/http/cache/repository-http-cache-provider', () => { const scope = httpMock.scope('https://example.com'); scope.get('/foo/bar').reply(200, { msg: 'Hello, world!' }, { etag: '123' }); - const res1 = await http.getJson('https://example.com/foo/bar', { + const res1 = await http.getJsonUnchecked('https://example.com/foo/bar', { headers: { authorization: 'Bearer 123' }, }); expect(res1).toMatchObject({ @@ -140,7 +140,7 @@ describe('util/http/cache/repository-http-cache-provider', () => { }); scope.get('/foo/bar').reply(304); - const res2 = await http.getJson('https://example.com/foo/bar', { + const res2 = await http.getJsonUnchecked('https://example.com/foo/bar', { headers: { authorization: 'Bearer 123' }, }); expect(res2).toMatchObject({ diff --git a/lib/util/http/gerrit.spec.ts b/lib/util/http/gerrit.spec.ts index 7c99f72d5f4f01..7d6563817cf5a8 100644 --- a/lib/util/http/gerrit.spec.ts +++ b/lib/util/http/gerrit.spec.ts @@ -33,7 +33,7 @@ describe('util/http/gerrit', () => { }); const res = await api - .getJson('some-url', { headers: { a: 'b' } }) + .getJsonUnchecked('some-url', { headers: { a: 'b' } }) .then((res) => res.body); return expect(res).toEqual(body); }); diff --git a/lib/util/http/gitea.spec.ts b/lib/util/http/gitea.spec.ts index 666d6f94816155..6342d81027024a 100644 --- a/lib/util/http/gitea.spec.ts +++ b/lib/util/http/gitea.spec.ts @@ -18,7 +18,7 @@ describe('util/http/gitea', () => { .get('/pagination-example-1') .reply(200, { hello: 'world' }); - const res = await giteaHttp.getJson('pagination-example-1', { + const res = await giteaHttp.getJsonUnchecked('pagination-example-1', { paginate: true, }); expect(res.body).toEqual({ hello: 'world' }); @@ -34,9 +34,10 @@ describe('util/http/gitea', () => { .get('/pagination-example-1?page=3') .reply(200, ['mno', 'pqr']); - const res = await giteaHttp.getJson(`${baseUrl}/pagination-example-1`, { - paginate: true, - }); + const res = await giteaHttp.getJsonUnchecked( + `${baseUrl}/pagination-example-1`, + { paginate: true }, + ); expect(res.body).toHaveLength(6); expect(res.body).toEqual(['abc', 'def', 'ghi', 'jkl', 'mno', 'pqr']); @@ -52,7 +53,7 @@ describe('util/http/gitea', () => { .get('/pagination-example-2?page=3') .reply(200, { data: ['mno', 'pqr'] }); - const res = await giteaHttp.getJson<{ data: string[] }>( + const res = await giteaHttp.getJsonUnchecked<{ data: string[] }>( 'pagination-example-2', { paginate: true, @@ -70,7 +71,7 @@ describe('util/http/gitea', () => { .get('/pagination-example-3?page=2') .reply(200, { data: [] }); - const res = await giteaHttp.getJson<{ data: string[] }>( + const res = await giteaHttp.getJsonUnchecked<{ data: string[] }>( 'pagination-example-3', { paginate: true, diff --git a/lib/util/http/github.spec.ts b/lib/util/http/github.spec.ts index 31292e7b3a0487..70dc177f8cf12b 100644 --- a/lib/util/http/github.spec.ts +++ b/lib/util/http/github.spec.ts @@ -107,7 +107,7 @@ describe('util/http/github', () => { }) .get(`${url}&page=3`) .reply(200, ['e']); - const res = await githubApi.getJson(url, { paginate: true }); + const res = await githubApi.getJsonUnchecked(url, { paginate: true }); expect(res.body).toEqual(['a', 'b', 'c', 'd', 'e']); }); @@ -133,7 +133,7 @@ describe('util/http/github', () => { ) .get(`${url}?page=3`) .reply(200, { the_field: ['d'], total: 4 }); - const res: any = await githubApi.getJson('some-url', { + const res = await githubApi.getJsonUnchecked('some-url', { paginate: true, paginationField: 'the_field', }); @@ -169,7 +169,7 @@ describe('util/http/github', () => { }) .get(`${url}&page=3`) .reply(200, ['e']); - const res = await githubApi.getJson(url, { + const res = await githubApi.getJsonUnchecked(url, { paginate: true, repository: 'some/repo', }); @@ -206,7 +206,7 @@ describe('util/http/github', () => { }) .get(`${url}&page=3`) .reply(200, ['e']); - const res = await githubApi.getJson(url, { + const res = await githubApi.getJsonUnchecked(url, { paginate: true, repository: 'some/repo', baseUrl: 'https://github.domain.com', @@ -225,7 +225,9 @@ describe('util/http/github', () => { .reply(200, ['a'], { link: `<${url}?page=34>; rel="last"`, }); - const res = await githubApi.getJson('some-url', { paginate: true }); + const res = await githubApi.getJsonUnchecked('some-url', { + paginate: true, + }); expect(res).toBeDefined(); expect(res.body).toEqual(['a']); }); @@ -253,7 +255,9 @@ describe('util/http/github', () => { }) .get(`${apiUrl}&page=3`) .reply(200, ['e']); - const res = await githubApi.getJson(apiUrl, { paginate: true }); + const res = await githubApi.getJsonUnchecked(apiUrl, { + paginate: true, + }); expect(res.body).toEqual(['a', 'b', 'c', 'd', 'e']); }); @@ -273,7 +277,9 @@ describe('util/http/github', () => { }) .get(`${apiUrl}&page=3`) .reply(200, ['e']); - const res = await githubApi.getJson(apiUrl, { paginate: true }); + const res = await githubApi.getJsonUnchecked(apiUrl, { + paginate: true, + }); expect(res.body).toEqual(['a', 'b', 'c', 'd', 'e']); }); @@ -295,7 +301,9 @@ describe('util/http/github', () => { }) .get(`/${apiUrl}&page=3`) .reply(200, ['e']); - const res = await githubApi.getJson(apiUrl, { paginate: true }); + const res = await githubApi.getJsonUnchecked(apiUrl, { + paginate: true, + }); expect(res.body).toEqual(['a', 'b', 'c', 'd', 'e']); }); @@ -320,13 +328,13 @@ describe('util/http/github', () => { }, headers, ); - await githubApi.getJson(url); + await githubApi.getJsonUnchecked(url); } async function failWithError(error: string | Record) { const url = '/some-url'; httpMock.scope(githubApiHost).get(url).replyWithError(error); - await githubApi.getJson(url); + await githubApi.getJsonUnchecked(url); } it('should throw Not found', async () => { diff --git a/lib/util/http/gitlab.spec.ts b/lib/util/http/gitlab.spec.ts index f3f3363eb64fa6..6ab99079d319a2 100644 --- a/lib/util/http/gitlab.spec.ts +++ b/lib/util/http/gitlab.spec.ts @@ -44,7 +44,9 @@ describe('util/http/gitlab', () => { }) .get('/api/v4/some-url&page=3') .reply(200, ['d']); - const res = await gitlabApi.getJson('some-url', { paginate: true }); + const res = await gitlabApi.getJsonUnchecked('some-url', { + paginate: true, + }); expect(res.body).toHaveLength(4); }); @@ -64,7 +66,9 @@ describe('util/http/gitlab', () => { }) .get('/api/v4/some-url&page=3') .reply(200, ['d']); - const res = await gitlabApi.getJson('some-url', { paginate: true }); + const res = await gitlabApi.getJsonUnchecked('some-url', { + paginate: true, + }); expect(res.body).toHaveLength(4); }); @@ -87,7 +91,9 @@ describe('util/http/gitlab', () => { httpMock.scope(gitlabApiHost).get('/api/v4/some-url').reply(200, ['a'], { link: '; rel="last"', }); - const res = await gitlabApi.getJson('some-url', { paginate: true }); + const res = await gitlabApi.getJsonUnchecked('some-url', { + paginate: true, + }); expect(res.body).toHaveLength(1); }); @@ -140,7 +146,7 @@ describe('util/http/gitlab', () => { it('ParseError', async () => { httpMock.scope(gitlabApiHost).get('/api/v4/some-url').reply(200, '{{'); - await expect(gitlabApi.getJson('some-url')).rejects.toThrow( + await expect(gitlabApi.getJsonUnchecked('some-url')).rejects.toThrow( EXTERNAL_HOST_ERROR, ); }); diff --git a/lib/util/http/index.spec.ts b/lib/util/http/index.spec.ts index 8eda7e35e7e140..57eafc9007c118 100644 --- a/lib/util/http/index.spec.ts +++ b/lib/util/http/index.spec.ts @@ -80,7 +80,7 @@ describe('util/http/index', () => { .get('/') .reply(200, '{ "test": true }', { etag: 'abc123' }); - const res = await http.getJson('http://renovate.com'); + const res = await http.getJsonUnchecked('http://renovate.com'); expect(res).toEqual({ authorization: false, @@ -367,14 +367,37 @@ describe('util/http/index', () => { }); }); - describe('getYaml', () => { + describe('getYamlUnchecked', () => { it('parses yaml response without schema', async () => { httpMock.scope(baseUrl).get('/').reply(200, 'x: 2\ny: 2'); - const res = await http.getYaml('http://renovate.com'); + const res = await http.getYamlUnchecked('http://renovate.com'); + expect(res.body).toEqual({ x: 2, y: 2 }); + }); + + it('parses yaml with options', async () => { + httpMock + .scope(baseUrl) + .get('/') + .matchHeader('custom', 'header') + .reply(200, 'x: 2\ny: 2'); + + const res = await http.getYamlUnchecked('http://renovate.com', { + headers: { custom: 'header' }, + }); expect(res.body).toEqual({ x: 2, y: 2 }); }); + it('throws on invalid yaml', async () => { + httpMock.scope(baseUrl).get('/').reply(200, '!@#$%^'); + + await expect( + http.getYamlUnchecked('http://renovate.com'), + ).rejects.toThrow('Failed to parse YAML file'); + }); + }); + + describe('getYaml', () => { it('parses yaml with schema validation', async () => { httpMock.scope(baseUrl).get('/').reply(200, 'x: 2\ny: 2'); @@ -397,12 +420,6 @@ describe('util/http/index', () => { expect(res.body).toBe('2 + 2 = 4'); }); - it('throws on invalid yaml', async () => { - httpMock.scope(baseUrl).get('/').reply(200, '!@#$%^'); - - await expect(http.getYaml('http://renovate.com')).rejects.toThrow(); - }); - it('throws on schema validation failure', async () => { httpMock.scope(baseUrl).get('/').reply(200, 'foo: bar'); @@ -410,6 +427,14 @@ describe('util/http/index', () => { http.getYaml('http://renovate.com', SomeSchema), ).rejects.toThrow(z.ZodError); }); + + it('throws on invalid yaml', async () => { + httpMock.scope(baseUrl).get('/').reply(200, '!@#$%^'); + + await expect( + http.getYaml('http://renovate.com', SomeSchema), + ).rejects.toThrow('Failed to parse YAML file'); + }); }); describe('getYamlSafe', () => { diff --git a/lib/util/http/index.ts b/lib/util/http/index.ts index b0968a15bb950f..d6fb3e59faadcd 100644 --- a/lib/util/http/index.ts +++ b/lib/util/http/index.ts @@ -329,37 +329,48 @@ export class Http { }); } - async getYaml(url: string, options?: Opts): Promise>; - async getYaml = ZodType>( + /** + * @deprecated use `getYaml` instead + */ + async getYamlUnchecked( + url: string, + options?: Opts, + ): Promise> { + const res = await this.get(url, options); + const body = parseSingleYaml(res.body); + return { ...res, body }; + } + + async getYaml>( url: string, schema: Schema, ): Promise>>; - async getYaml = ZodType>( + async getYaml>( url: string, options: Opts, schema: Schema, ): Promise>>; - async getYaml = ZodType>( + async getYaml>( arg1: string, arg2?: Opts | Schema, arg3?: Schema, - ): Promise> { - const { url, httpOptions, schema } = this.resolveArgs( - arg1, - arg2, - arg3, - ); + ): Promise>> { + const url = arg1; + let schema: Schema; + let httpOptions: Opts | undefined; + if (arg3) { + schema = arg3; + httpOptions = arg2 as Opts; + } else { + schema = arg2 as Schema; + } + const opts: InternalHttpOptions = { ...httpOptions, method: 'get', }; const res = await this.get(url, opts); - if (!schema) { - const body = parseSingleYaml(res.body); - return { ...res, body }; - } - const body = await schema.parseAsync(parseSingleYaml(res.body)); return { ...res, body }; } @@ -396,49 +407,73 @@ export class Http { let res: AsyncResult, SafeJsonError>; if (httpOptions) { - res = Result.wrap(this.getYaml(url, httpOptions, schema)); + res = Result.wrap(this.getYaml(url, httpOptions, schema)); } else { - res = Result.wrap(this.getYaml(url, schema)); + res = Result.wrap(this.getYaml(url, schema)); } return res.transform((response) => Result.ok(response.body)); } - getJson(url: string, options?: Opts): Promise>; - getJson = ZodType>( + /** + * Request JSON and return the response without any validation. + * + * The usage of this method is discouraged, please use `getJson` instead. + * + * If you're new to Zod schema validation library: + * - consult the [documentation of Zod library](/~https://github.com/colinhacks/zod?tab=readme-ov-file#basic-usage) + * - search the Renovate codebase for 'zod' module usage + * - take a look at the `schema-utils.ts` file for Renovate-specific schemas and utilities + */ + getJsonUnchecked( + url: string, + options?: Opts, + ): Promise> { + return this.requestJson('get', { url, httpOptions: options }); + } + + /** + * Request JSON with a Zod schema for the response, + * throwing an error if the response is not valid. + * + * @param url + * @param schema Zod schema for the response + */ + getJson>( url: string, schema: Schema, ): Promise>>; - getJson = ZodType>( + getJson>( url: string, options: Opts, schema: Schema, ): Promise>>; - getJson = ZodType>( + getJson>( arg1: string, arg2?: Opts | Schema, arg3?: Schema, - ): Promise> { - const args = this.resolveArgs(arg1, arg2, arg3); - return this.requestJson('get', args); + ): Promise>> { + const args = this.resolveArgs>(arg1, arg2, arg3); + return this.requestJson>('get', args); } - getJsonSafe< - ResT extends NonNullable, - Schema extends ZodType = ZodType, - >(url: string, schema: Schema): AsyncResult, SafeJsonError>; - getJsonSafe< - ResT extends NonNullable, - Schema extends ZodType = ZodType, - >( + /** + * Request JSON with a Zod schema for the response, + * wrapping response data in a `Result` class. + * + * @param url + * @param schema Zod schema for the response + */ + getJsonSafe, Schema extends ZodType>( + url: string, + schema: Schema, + ): AsyncResult, SafeJsonError>; + getJsonSafe, Schema extends ZodType>( url: string, options: Opts, schema: Schema, ): AsyncResult, SafeJsonError>; - getJsonSafe< - ResT extends NonNullable, - Schema extends ZodType = ZodType, - >( + getJsonSafe, Schema extends ZodType>( arg1: string, arg2?: Opts | Schema, arg3?: Schema, diff --git a/lib/util/merge-confidence/index.ts b/lib/util/merge-confidence/index.ts index 93844cd7b33ecb..8491263c61bf98 100644 --- a/lib/util/merge-confidence/index.ts +++ b/lib/util/merge-confidence/index.ts @@ -168,7 +168,9 @@ async function queryApi( let confidence: MergeConfidence = 'neutral'; try { - const res = (await http.getJson<{ confidence: MergeConfidence }>(url)).body; + const res = ( + await http.getJsonUnchecked<{ confidence: MergeConfidence }>(url) + ).body; if (isMergeConfidence(res.confidence)) { confidence = res.confidence; } diff --git a/lib/util/timestamp.spec.ts b/lib/util/timestamp.spec.ts index c084c062f3025e..1926ea478aed71 100644 --- a/lib/util/timestamp.spec.ts +++ b/lib/util/timestamp.spec.ts @@ -17,6 +17,8 @@ describe('util/timestamp', () => { ${'2021-01-01'} | ${'2021-01-01T00:00:00.000Z'} ${'20210101000000'} | ${'2021-01-01T00:00:00.000Z'} ${'20211231235959'} | ${'2021-12-31T23:59:59.000Z'} + ${'20210101000000+0000'} | ${'2021-01-01T00:00:00.000Z'} + ${'20211231235959+0000'} | ${'2021-12-31T23:59:59.000Z'} ${'Jan 1, 2021'} | ${'2021-01-01T00:00:00.000Z'} ${'2021/01/01'} | ${'2021-01-01T00:00:00.000Z'} ${'2021-01-02T00:00:00+05:30'} | ${'2021-01-01T18:30:00.000Z'} diff --git a/lib/util/timestamp.ts b/lib/util/timestamp.ts index b40fd93ead2d2a..5c0e3d32b9c9c1 100644 --- a/lib/util/timestamp.ts +++ b/lib/util/timestamp.ts @@ -64,6 +64,15 @@ export function asTimestamp(input: unknown): Timestamp | null { return numberLikeDate.toISO() as Timestamp; } + const numberLikeOffsetDate = DateTime.fromFormat( + input, + 'yyyyMMddHHmmssZZZ', + { zone: 'UTC' }, + ); + if (isValid(numberLikeOffsetDate)) { + return numberLikeOffsetDate.toISO() as Timestamp; + } + const fallbackDate = DateTime.fromMillis( Date.parse(input) - timezoneOffset, { zone: 'UTC' }, diff --git a/lib/workers/repository/init/inherited.spec.ts b/lib/workers/repository/init/inherited.spec.ts index e31f5ba2fc32bf..5808c82d5379d0 100644 --- a/lib/workers/repository/init/inherited.spec.ts +++ b/lib/workers/repository/init/inherited.spec.ts @@ -1,4 +1,4 @@ -import { mocked, platform } from '../../../../test/util'; +import { hostRules, mocked, platform } from '../../../../test/util'; import * as presets_ from '../../../config/presets'; import type { RenovateConfig } from '../../../config/types'; import * as validation from '../../../config/validation'; @@ -91,6 +91,27 @@ describe('workers/repository/init/inherited', () => { expect(logger.warn).not.toHaveBeenCalled(); }); + it('should set hostRules from inherited config', async () => { + platform.getRawFile.mockResolvedValue( + `{ + "hostRules": [ + { + "matchHost": "some-host-url", + "token": "some-token" + } + ] + }`, + ); + const res = await mergeInheritedConfig(config); + expect(hostRules.getAll()).toMatchObject([ + { + matchHost: 'some-host-url', + token: 'some-token', + }, + ]); + expect(res.hostRules).toBeUndefined(); + }); + it('should resolve presets found in inherited config', async () => { platform.getRawFile.mockResolvedValue( '{"onboarding":false,"labels":["test"],"extends":[":automergeAll"]}', diff --git a/lib/workers/repository/init/inherited.ts b/lib/workers/repository/init/inherited.ts index d924ff825bd37d..da497ca5aee671 100644 --- a/lib/workers/repository/init/inherited.ts +++ b/lib/workers/repository/init/inherited.ts @@ -12,6 +12,9 @@ import { } from '../../../constants/error-messages'; import { logger } from '../../../logger'; import { platform } from '../../../modules/platform'; +import * as hostRules from '../../../util/host-rules'; +import * as queue from '../../../util/http/queue'; +import * as throttle from '../../../util/http/throttle'; import * as template from '../../../util/template'; export async function mergeInheritedConfig( @@ -102,6 +105,7 @@ export async function mergeInheritedConfig( } if (is.nullOrUndefined(filteredConfig.extends)) { + setInheritedHostRules(filteredConfig); return mergeChildConfig(config, filteredConfig); } @@ -137,5 +141,27 @@ export async function mergeInheritedConfig( ); } + setInheritedHostRules(filteredConfig); return mergeChildConfig(config, filteredConfig); } + +function setInheritedHostRules(config: RenovateConfig): void { + if (config.hostRules) { + logger.debug('Setting hostRules from config'); + for (const rule of config.hostRules) { + try { + hostRules.add(rule); + } catch (err) { + // istanbul ignore next + logger.warn( + { err, config: rule }, + 'Error setting hostRule from config', + ); + } + } + // host rules can change concurrency + queue.clear(); + throttle.clear(); + delete config.hostRules; + } +} diff --git a/lib/workers/repository/process/lookup/index.spec.ts b/lib/workers/repository/process/lookup/index.spec.ts index 986d8bc395d6f4..26e13ba8e45673 100644 --- a/lib/workers/repository/process/lookup/index.spec.ts +++ b/lib/workers/repository/process/lookup/index.spec.ts @@ -4947,6 +4947,29 @@ describe('workers/repository/process/lookup/index', () => { ]); }); + it('handles replacements - from datasource', async () => { + config.currentValue = '2.0.0'; + config.packageName = 'org.example:foo'; + config.datasource = MavenDatasource.id; + getMavenReleases.mockResolvedValueOnce({ + releases: [{ version: '2.0.0' }], + replacementName: 'foo:bar', + replacementVersion: '2.0.0', + }); + + const { updates } = await Result.wrap( + lookup.lookupUpdates(config), + ).unwrapOrThrow(); + + expect(updates).toEqual([ + { + updateType: 'replacement', + newName: 'foo:bar', + newValue: '2.0.0', + }, + ]); + }); + it('rollback for invalid version to last stable version', async () => { config.currentValue = '2.5.17'; config.packageName = 'vue'; diff --git a/lib/workers/repository/process/lookup/index.ts b/lib/workers/repository/process/lookup/index.ts index e481f6b3acbc0d..7c674c80080dd1 100644 --- a/lib/workers/repository/process/lookup/index.ts +++ b/lib/workers/repository/process/lookup/index.ts @@ -571,6 +571,12 @@ export async function lookupUpdates( if (isReplacementRulesConfigured(config)) { addReplacementUpdateIfValid(res.updates, config); + } else if (dependency?.replacementName && dependency.replacementVersion) { + res.updates.push({ + updateType: 'replacement', + newName: dependency.replacementName, + newValue: dependency.replacementVersion, + }); } // Record if the dep is fixed to a version diff --git a/lib/workers/repository/process/vulnerabilities.spec.ts b/lib/workers/repository/process/vulnerabilities.spec.ts index ada896774595a5..8922742ae9def5 100644 --- a/lib/workers/repository/process/vulnerabilities.spec.ts +++ b/lib/workers/repository/process/vulnerabilities.spec.ts @@ -407,7 +407,7 @@ describe('workers/repository/process/vulnerabilities', () => { config, packageFiles, ); - expect(logger.logger.info).toHaveBeenCalledWith( + expect(logger.logger.debug).toHaveBeenCalledWith( 'No fixed version available for vulnerability GHSA-xxxx-yyyy-zzzz in fake 4.17.11', ); }); @@ -449,7 +449,7 @@ describe('workers/repository/process/vulnerabilities', () => { config, packageFiles, ); - expect(logger.logger.info).toHaveBeenCalledWith( + expect(logger.logger.debug).toHaveBeenCalledWith( 'No fixed version available for vulnerability GHSA-xxxx-yyyy-zzzz in fake 1.5.1', ); }); diff --git a/lib/workers/repository/process/vulnerabilities.ts b/lib/workers/repository/process/vulnerabilities.ts index 5a44b9cfde0b68..96e7af3a3fe6ea 100644 --- a/lib/workers/repository/process/vulnerabilities.ts +++ b/lib/workers/repository/process/vulnerabilities.ts @@ -483,7 +483,7 @@ export class Vulnerabilities { packageFileConfig, } = vul; if (is.nullOrUndefined(fixedVersion)) { - logger.info( + logger.debug( `No fixed version available for vulnerability ${vulnerability.id} in ${packageName} ${depVersion}`, ); return null; diff --git a/lib/workers/repository/update/pr/changelog/github/index.ts b/lib/workers/repository/update/pr/changelog/github/index.ts index 89e061532d9252..64d21bd9e3f7c4 100644 --- a/lib/workers/repository/update/pr/changelog/github/index.ts +++ b/lib/workers/repository/update/pr/changelog/github/index.ts @@ -28,11 +28,11 @@ export async function getReleaseNotesMd( logger.trace('github.getReleaseNotesMd()'); const apiPrefix = `${ensureTrailingSlash(apiBaseUrl)}repos/${repository}`; const { default_branch: defaultBranch = 'HEAD' } = ( - await http.getJson<{ default_branch: string }>(apiPrefix) + await http.getJsonUnchecked<{ default_branch: string }>(apiPrefix) ).body; // https://docs.github.com/en/rest/reference/git#get-a-tree - const res = await http.getJson( + const res = await http.getJsonUnchecked( `${apiPrefix}/git/trees/${defaultBranch}${ sourceDirectory ? '?recursive=1' : '' }`, @@ -73,7 +73,7 @@ export async function getReleaseNotesMd( } // https://docs.github.com/en/rest/reference/git#get-a-blob - const fileRes = await http.getJson( + const fileRes = await http.getJsonUnchecked( `${apiPrefix}/git/blobs/${sha}`, ); diff --git a/lib/workers/repository/update/pr/changelog/gitlab/index.ts b/lib/workers/repository/update/pr/changelog/gitlab/index.ts index 8957d154ea81a0..4c17d4bac34fa5 100644 --- a/lib/workers/repository/update/pr/changelog/gitlab/index.ts +++ b/lib/workers/repository/update/pr/changelog/gitlab/index.ts @@ -25,7 +25,7 @@ export async function getReleaseNotesMd( // https://docs.gitlab.com/13.2/ee/api/repositories.html#list-repository-tree const tree = ( - await http.getJson( + await http.getJsonUnchecked( `${apiPrefix}tree?per_page=100${ sourceDirectory ? `&path=${sourceDirectory}` : '' }`, @@ -69,9 +69,12 @@ export async function getReleaseList( const urlEncodedRepo = encodeURIComponent(repository); const apiUrl = `${apiBaseUrl}projects/${urlEncodedRepo}/releases`; - const res = await http.getJson(`${apiUrl}?per_page=100`, { - paginate: true, - }); + const res = await http.getJsonUnchecked( + `${apiUrl}?per_page=100`, + { + paginate: true, + }, + ); return res.body.map((release) => ({ url: `${project.baseUrl}${repository}/-/releases/${release.tag_name}`, notesSourceUrl: apiUrl, diff --git a/lib/workers/repository/updates/branch-name.spec.ts b/lib/workers/repository/updates/branch-name.spec.ts index a4b4dd5993954e..5feb61bb8e0e57 100644 --- a/lib/workers/repository/updates/branch-name.spec.ts +++ b/lib/workers/repository/updates/branch-name.spec.ts @@ -3,9 +3,22 @@ import { generateBranchName } from './branch-name'; describe('workers/repository/updates/branch-name', () => { describe('getBranchName()', () => { - it('uses groupName if no slug defined', () => { + it('falls back to sharedVariableName if no groupName', () => { + const upgrade: RenovateConfig = { + sharedVariableName: 'some variable name', + group: { + branchName: '{{groupSlug}}-{{branchTopic}}', + branchTopic: 'grouptopic', + }, + }; + generateBranchName(upgrade); + expect(upgrade.branchName).toBe('some-variable-name-grouptopic'); + }); + + it('uses groupName if no slug defined, ignores sharedVariableName', () => { const upgrade: RenovateConfig = { groupName: 'some group name', + sharedVariableName: 'some variable name', group: { branchName: '{{groupSlug}}-{{branchTopic}}', branchTopic: 'grouptopic', diff --git a/lib/workers/repository/updates/branch-name.ts b/lib/workers/repository/updates/branch-name.ts index d151c0772b8c24..36f085dd1fe08d 100644 --- a/lib/workers/repository/updates/branch-name.ts +++ b/lib/workers/repository/updates/branch-name.ts @@ -57,6 +57,12 @@ export function generateBranchName(update: RenovateConfig): void { // Check whether to use a group name const newMajor = String(update.newMajor); const newMinor = String(update.newMinor); + if (!update.groupName && update.sharedVariableName) { + logger.debug( + `Using sharedVariableName=${update.sharedVariableName} as groupName for depName=${update.depName}`, + ); + update.groupName = update.sharedVariableName; + } if (update.groupName) { update.groupName = template.compile(update.groupName, update); logger.trace('Using group branchName template'); diff --git a/lib/workers/repository/updates/flatten.spec.ts b/lib/workers/repository/updates/flatten.spec.ts index 42cd3a7b3b6fe7..8561d1a0a1afb0 100644 --- a/lib/workers/repository/updates/flatten.spec.ts +++ b/lib/workers/repository/updates/flatten.spec.ts @@ -1,7 +1,7 @@ import is from '@sindresorhus/is'; import type { RenovateConfig } from '../../../../test/util'; import { getConfig } from '../../../config/defaults'; -import { flattenUpdates } from './flatten'; +import { flattenUpdates, sanitizeDepName } from './flatten'; jest.mock('../../../util/git/semantic'); @@ -14,6 +14,14 @@ beforeEach(() => { }); describe('workers/repository/updates/flatten', () => { + describe('sanitizeDepName()', () => { + it('sanitizes urls', () => { + expect(sanitizeDepName('https://some.host.name/a/path/to.git')).toBe( + 'https-some.host.name-a-path-to.git', + ); + }); + }); + describe('flattenUpdates()', () => { it('flattens', async () => { // TODO #22198 diff --git a/lib/workers/repository/updates/flatten.ts b/lib/workers/repository/updates/flatten.ts index 93b1d51c8556c4..989ff00553864c 100644 --- a/lib/workers/repository/updates/flatten.ts +++ b/lib/workers/repository/updates/flatten.ts @@ -17,12 +17,13 @@ import { generateBranchName } from './branch-name'; const upper = (str: string): string => str.charAt(0).toUpperCase() + str.substring(1); -function sanitizeDepName(depName: string): string { +export function sanitizeDepName(depName: string): string { return depName .replace('@types/', '') .replace('@', '') .replace(regEx(/\//g), '-') .replace(regEx(/\s+/g), '-') + .replace(regEx(/:/g), '-') .replace(regEx(/-+/), '-') .toLowerCase(); } diff --git a/pdm.lock b/pdm.lock index 2a60e46c387dca..2300b1e1502c67 100644 --- a/pdm.lock +++ b/pdm.lock @@ -5,7 +5,7 @@ groups = ["default"] strategy = ["inherit_metadata"] lock_version = "4.5.0" -content_hash = "sha256:389d88fe2eea354363ad2bc3a292f9398c1ab70d41dec7307928a6d5fe1a11c5" +content_hash = "sha256:a03cc9a3cd0c5c98c36b8ea5b28cad01f8fc69178d24ab168005edb15697d803" [[metadata.targets]] requires_python = ">=3.11" @@ -297,7 +297,7 @@ files = [ [[package]] name = "mkdocs-material" -version = "9.5.49" +version = "9.5.50" requires_python = ">=3.8" summary = "Documentation that simply works" groups = ["default"] @@ -315,8 +315,8 @@ dependencies = [ "requests~=2.26", ] files = [ - {file = "mkdocs_material-9.5.49-py3-none-any.whl", hash = "sha256:c3c2d8176b18198435d3a3e119011922f3e11424074645c24019c2dcf08a360e"}, - {file = "mkdocs_material-9.5.49.tar.gz", hash = "sha256:3671bb282b4f53a1c72e08adbe04d2481a98f85fed392530051f80ff94a9621d"}, + {file = "mkdocs_material-9.5.50-py3-none-any.whl", hash = "sha256:f24100f234741f4d423a9d672a909d859668a4f404796be3cf035f10d6050385"}, + {file = "mkdocs_material-9.5.50.tar.gz", hash = "sha256:ae5fe16f3d7c9ccd05bb6916a7da7420cf99a9ce5e33debd9d40403a090d5825"}, ] [[package]] diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 42951809e0fdaa..f3a46994d71097 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1302,8 +1302,8 @@ packages: resolution: {integrity: sha512-9Bb014e+m2TgBeEJGEbdplMVWwPmL1FPtggHQRkV+WVsMggPtEkLKPlcVYm/o8xKLkpJ7B+6N8WfQMtDLX2Dpw==} engines: {node: '>= 18'} - '@octokit/request@9.1.4': - resolution: {integrity: sha512-tMbOwGm6wDII6vygP3wUVqFTw3Aoo0FnVQyhihh8vVq12uO3P+vQZeo2CKMpWtPSogpACD0yyZAlVlQnjW71DA==} + '@octokit/request@9.2.0': + resolution: {integrity: sha512-kXLfcxhC4ozCnAXy2ff+cSxpcF0A1UqxjvYMqNuPIeOAzJbVWQ+dy5G2fTylofB/gTbObT8O6JORab+5XtA1Kw==} engines: {node: '>= 18'} '@octokit/rest@20.1.1': @@ -1329,6 +1329,10 @@ packages: resolution: {integrity: sha512-l1aJ30CXeauVYaI+btiynHpw341LthkMTv3omi1VJDX14werY2Wmv9n1yudMsq9HuY0m8PvXEVX4d8zxEb+WRg==} engines: {node: '>=14'} + '@opentelemetry/api-logs@0.57.1': + resolution: {integrity: sha512-I4PHczeujhQAQv6ZBzqHYEUiggZL4IdSMixtVD3EYqbdrjujE7kRfI5QohjlPoJm8BvenoW5YaTMWRrbpot6tg==} + engines: {node: '>=14'} + '@opentelemetry/api@1.9.0': resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==} engines: {node: '>=8.0.0'} @@ -1660,8 +1664,8 @@ packages: resolution: {integrity: sha512-Igfg8lKu3dRVkTSEm98QpZUvKEOa71jDX4vKRcvJVyRc3UgN3j7vFMf0s7xLQhYmKa8kyJGQgUJDOV5V3neVlQ==} engines: {node: '>=18.0.0'} - '@smithy/core@3.1.0': - resolution: {integrity: sha512-swFv0wQiK7TGHeuAp6lfF5Kw1dHWsTrCuc+yh4Kh05gEShjsE2RUxHucEerR9ih9JITNtaHcSpUThn5Y/vDw0A==} + '@smithy/core@3.1.1': + resolution: {integrity: sha512-hhUZlBWYuh9t6ycAcN90XOyG76C1AzwxZZgaCVPMYpWqqk9uMFo7HGG5Zu2cEhCJn7DdOi5krBmlibWWWPgdsw==} engines: {node: '>=18.0.0'} '@smithy/credential-provider-imds@4.0.1': @@ -1724,12 +1728,12 @@ packages: resolution: {integrity: sha512-OGXo7w5EkB5pPiac7KNzVtfCW2vKBTZNuCctn++TTSOMpe6RZO/n6WEC1AxJINn3+vWLKW49uad3lo/u0WJ9oQ==} engines: {node: '>=18.0.0'} - '@smithy/middleware-endpoint@4.0.1': - resolution: {integrity: sha512-hCCOPu9+sRI7Wj0rZKKnGylKXBEd9cQJetzjQqe8cT4PWvtQAbvNVa6cgAONiZg9m8LaXtP9/waxm3C3eO4hiw==} + '@smithy/middleware-endpoint@4.0.2': + resolution: {integrity: sha512-Z9m67CXizGpj8CF/AW/7uHqYNh1VXXOn9Ap54fenWsCa0HnT4cJuE61zqG3cBkTZJDCy0wHJphilI41co/PE5g==} engines: {node: '>=18.0.0'} - '@smithy/middleware-retry@4.0.1': - resolution: {integrity: sha512-n3g2zZFgOWaz2ZYCy8+4wxSmq+HSTD8QKkRhFDv+nkxY1o7gzyp4PDz/+tOdcNPMPZ/A6Mt4aVECYNjQNiaHJw==} + '@smithy/middleware-retry@4.0.3': + resolution: {integrity: sha512-TiKwwQTwUDeDtwWW8UWURTqu7s6F3wN2pmziLU215u7bqpVT9Mk2oEvURjpRLA+5XeQhM68R5BpAGzVtomsqgA==} engines: {node: '>=18.0.0'} '@smithy/middleware-serde@4.0.1': @@ -1744,8 +1748,8 @@ packages: resolution: {integrity: sha512-8mRTjvCtVET8+rxvmzRNRR0hH2JjV0DFOmwXPrISmTIJEfnCBugpYYGAsCj8t41qd+RB5gbheSQ/6aKZCQvFLQ==} engines: {node: '>=18.0.0'} - '@smithy/node-http-handler@4.0.1': - resolution: {integrity: sha512-ddQc7tvXiVLC5c3QKraGWde761KSk+mboCheZoWtuqnXh5l0WKyFy3NfDIM/dsKrI9HlLVH/21pi9wWK2gUFFA==} + '@smithy/node-http-handler@4.0.2': + resolution: {integrity: sha512-X66H9aah9hisLLSnGuzRYba6vckuFtGE+a5DcHLliI/YlqKrGoxhisD5XbX44KyoeRzoNlGr94eTsMVHFAzPOw==} engines: {node: '>=18.0.0'} '@smithy/property-provider@4.0.1': @@ -1776,8 +1780,8 @@ packages: resolution: {integrity: sha512-nCe6fQ+ppm1bQuw5iKoeJ0MJfz2os7Ic3GBjOkLOPtavbD1ONoyE3ygjBfz2ythFWm4YnRm6OxW+8p/m9uCoIA==} engines: {node: '>=18.0.0'} - '@smithy/smithy-client@4.1.0': - resolution: {integrity: sha512-NiboZnrsrZY+Cy5hQNbYi+nVNssXVi2I+yL4CIKNIanOhH8kpC5PKQ2jx/MQpwVr21a3XcVoQBArlpRF36OeEQ==} + '@smithy/smithy-client@4.1.2': + resolution: {integrity: sha512-0yApeHWBqocelHGK22UivZyShNxFbDNrgREBllGh5Ws0D0rg/yId/CJfeoKKpjbfY2ju8j6WgDUGZHYQmINZ5w==} engines: {node: '>=18.0.0'} '@smithy/types@4.1.0': @@ -1812,12 +1816,12 @@ packages: resolution: {integrity: sha512-L1RBVzLyfE8OXH+1hsJ8p+acNUSirQnWQ6/EgpchV88G6zGBTDPdXiiExei6Z1wR2RxYvxY/XLw6AMNCCt8H3w==} engines: {node: '>=18.0.0'} - '@smithy/util-defaults-mode-browser@4.0.1': - resolution: {integrity: sha512-nkQifWzWUHw/D0aLPgyKut+QnJ5X+5E8wBvGfvrYLLZ86xPfVO6MoqfQo/9s4bF3Xscefua1M6KLZtobHMWrBg==} + '@smithy/util-defaults-mode-browser@4.0.3': + resolution: {integrity: sha512-7c5SF1fVK0EOs+2EOf72/qF199zwJflU1d02AevwKbAUPUZyE9RUZiyJxeUmhVxfKDWdUKaaVojNiaDQgnHL9g==} engines: {node: '>=18.0.0'} - '@smithy/util-defaults-mode-node@4.0.1': - resolution: {integrity: sha512-LeAx2faB83litC9vaOdwFaldtto2gczUHxfFf8yoRwDU3cwL4/pDm7i0hxsuBCRk5mzHsrVGw+3EVCj32UZMdw==} + '@smithy/util-defaults-mode-node@4.0.3': + resolution: {integrity: sha512-CVnD42qYD3JKgDlImZ9+On+MqJHzq9uJgPbMdeBE8c2x8VJ2kf2R3XO/yVFx+30ts5lD/GlL0eFIShY3x9ROgQ==} engines: {node: '>=18.0.0'} '@smithy/util-endpoints@3.0.1': @@ -1836,8 +1840,8 @@ packages: resolution: {integrity: sha512-WmRHqNVwn3kI3rKk1LsKcVgPBG6iLTBGC1iYOV3GQegwJ3E8yjzHytPt26VNzOWr1qu0xE03nK0Ug8S7T7oufw==} engines: {node: '>=18.0.0'} - '@smithy/util-stream@4.0.1': - resolution: {integrity: sha512-Js16gOgU6Qht6qTPfuJgb+1YD4AEO+5Y1UPGWKSp3BNo8ONl/qhXSYDhFKJtwybRJynlCqvP5IeiaBsUmkSPTQ==} + '@smithy/util-stream@4.0.2': + resolution: {integrity: sha512-0eZ4G5fRzIoewtHtwaYyl8g2C+osYOT4KClXgfdNEDAgkbe2TYPqcnw4GAWabqkZCax2ihRGPe9LZnsPdIUIHA==} engines: {node: '>=18.0.0'} '@smithy/util-uri-escape@4.0.0': @@ -2231,6 +2235,10 @@ packages: resolution: {integrity: sha512-60L9KIuN/xgmsINzonOcMDSB8p82h95hoBfSBtXuO4jlR1R9L1xSkmVZKgCPVfavDlXihh4ARNjXhh1gGnLC7Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/scope-manager@8.20.0': + resolution: {integrity: sha512-J7+VkpeGzhOt3FeG1+SzhiMj9NzGD/M6KoGn9f4dbz3YzK9hvbhVTmLj/HiTp9DazIzJ8B4XcM80LrR9Dm1rJw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/type-utils@8.19.1': resolution: {integrity: sha512-Rp7k9lhDKBMRJB/nM9Ksp1zs4796wVNyihG9/TU9R6KCJDNkQbc2EOKjrBtLYh3396ZdpXLtr/MkaSEmNMtykw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2246,6 +2254,10 @@ packages: resolution: {integrity: sha512-JBVHMLj7B1K1v1051ZaMMgLW4Q/jre5qGK0Ew6UgXz1Rqh+/xPzV1aW581OM00X6iOfyr1be+QyW8LOUf19BbA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/types@8.20.0': + resolution: {integrity: sha512-cqaMiY72CkP+2xZRrFt3ExRBu0WmVitN/rYPZErA80mHjHx/Svgp8yfbzkJmDoQ/whcytOPO9/IZXnOc+wigRA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/typescript-estree@5.62.0': resolution: {integrity: sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -2261,6 +2273,12 @@ packages: peerDependencies: typescript: '>=4.8.4 <5.8.0' + '@typescript-eslint/typescript-estree@8.20.0': + resolution: {integrity: sha512-Y7ncuy78bJqHI35NwzWol8E0X7XkRVS4K4P4TCyzWkOJih5NDvtoRDW4Ba9YJJoB2igm9yXDdYI/+fkiiAxPzA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <5.8.0' + '@typescript-eslint/utils@5.62.0': resolution: {integrity: sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -2274,6 +2292,13 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.8.0' + '@typescript-eslint/utils@8.20.0': + resolution: {integrity: sha512-dq70RUw6UK9ei7vxc4KQtBRk7qkHZv447OUZ6RPQMQl71I3NZxQJX/f32Smr+iqWrB02pHKn2yAdHBb0KNrRMA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.8.0' + '@typescript-eslint/visitor-keys@5.62.0': resolution: {integrity: sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -2282,6 +2307,10 @@ packages: resolution: {integrity: sha512-fzmjU8CHK853V/avYZAvuVut3ZTfwN5YtMaoi+X9Y9MA9keaWNHC3zEQ9zvyX/7Hj+5JkNyK1l7TOR2hevHB6Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/visitor-keys@8.20.0': + resolution: {integrity: sha512-v/BpkeeYAsPkKCkR8BDwcno0llhzWVqPOamQrAEMdpZav2Y9OVjd9dwJyBLJWwf335B5DmlifECIkZRJCaGaHA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@ungap/structured-clone@1.2.1': resolution: {integrity: sha512-fEzPV3hSkSMltkw152tJKNARhOupqbH96MZWyRjNaYZOMIzbrTeQDG+MTc6Mr2pgzFQzFxAfmhGDNP5QK++2ZA==} @@ -2634,8 +2663,8 @@ packages: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} - caniuse-lite@1.0.30001692: - resolution: {integrity: sha512-A95VKan0kdtrsnMubMKxEKUKImOPSuCpYgxSQBo036P5YYgVIcOYJEgt/txJWqObiRQeISNCfef9nvlQ0vbV7A==} + caniuse-lite@1.0.30001695: + resolution: {integrity: sha512-vHyLade6wTgI2u1ec3WQBxv+2BrTERV28UXQu9LO6lZ9pYeMk34vjXFLOxo1A4UBA8XTL4njRQZdno/yYaSmWw==} chalk@2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} @@ -3056,8 +3085,8 @@ packages: engines: {node: '>=0.10.0'} hasBin: true - electron-to-chromium@1.5.80: - resolution: {integrity: sha512-LTrKpW0AqIuHwmlVNV+cjFYTnXtM9K37OGhpe0ZI10ScPSxqVSryZHIY3WnCS5NSYbBODRTZyhRMS2h5FAEqAw==} + electron-to-chromium@1.5.83: + resolution: {integrity: sha512-LcUDPqSt+V0QmI47XLzZrz5OqILSMGsPFkDYus22rIbgorSvBYEFqq854ltTmUdHkY92FSdAAvsh4jWEULMdfQ==} email-addresses@5.0.0: resolution: {integrity: sha512-4OIPYlA6JXqtVn8zpHpGiI7vE6EQOAg16aGnDMIAlZVinnoZ8208tW1hAbjWydgN/4PLTT9q+O1K6AH/vALJGw==} @@ -3134,8 +3163,8 @@ packages: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} - es-object-atoms@1.0.0: - resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==} + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} engines: {node: '>= 0.4'} es-set-tostringtag@2.1.0: @@ -4354,8 +4383,8 @@ packages: jws@4.0.0: resolution: {integrity: sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==} - katex@0.16.19: - resolution: {integrity: sha512-3IA6DYVhxhBabjSLTNO9S4+OliA3Qvb8pBQXMfC4WxXJgLwZgnfDl0BmB4z6nBMdznBsZ+CGM8DrGZ5hcguDZg==} + katex@0.16.21: + resolution: {integrity: sha512-XvqR7FgOHtWupfMiigNzmh+MgUVmDGU2kXZm899ZkPfcuoPuFxyHmXsgATDpFZDAXCI8tvinaVcDo8PIIJSo4A==} hasBin: true keybase-ecurve@1.0.1: @@ -4830,8 +4859,8 @@ packages: resolution: {integrity: sha512-o2zOYiCpzRqSzPj0Zt/dQ/DqZeYoaQ7TUonc/xUPjCGl9WeHpNbxgVvOquXYAaJzI0M9BXV3HTzG0p8IUAbBTQ==} engines: {node: '>= 10.13'} - node-abi@3.71.0: - resolution: {integrity: sha512-SZ40vRiy/+wRTf21hxkkEjPJZpARzUMVcJoQse2EF8qkUWbbO2z7vd5oA/H6bVH6SZQ5STGcu0KRDS7biNRfxw==} + node-abi@3.73.0: + resolution: {integrity: sha512-z8iYzQGBu35ZkTQ9mtR8RqugJZ9RCLn8fv3d7LsgDBzOijGQP3RdKTX4LA7LXw03ZhU5z0l4xfhIMgSES31+cg==} engines: {node: '>=10'} node-emoji@2.2.0: @@ -5349,8 +5378,8 @@ packages: resolution: {integrity: sha512-L/e3qq/3m/TrYtINo2aBB98oz6w8VHGyFy+arSKwPMZDUNNw2OaQxYnZO6UIZZw2OnRl2qkxGmuSOEfsuHXJdA==} engines: {node: '>=0.10.0'} - qs@6.13.1: - resolution: {integrity: sha512-EJPeIn0CYrGu+hli1xilKAPXODtJ12T0sP63Ijx2/khC2JtuaN3JyNIpvmnkmaEtha9ocbG4A4cMcr+TvqvwQg==} + qs@6.14.0: + resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} engines: {node: '>=0.6'} queue-microtask@1.2.3: @@ -5718,8 +5747,8 @@ packages: spdx-expression-parse@3.0.1: resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} - spdx-license-ids@3.0.20: - resolution: {integrity: sha512-jg25NiDV/1fLtSgEgyvVyDunvaNHbuwF9lfNV17gSmPFAlYzdfNBlLtLzXTevwkPj7DhGbmN9VnmJIgLnhvaBw==} + spdx-license-ids@3.0.21: + resolution: {integrity: sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==} split2@1.0.0: resolution: {integrity: sha512-NKywug4u4pX/AZBB1FCPzZ6/7O+Xhz1qMVbzTvvKvikjO99oPN87SkK08mEY9P63/5lWjK+wgOOgApnTg5r6qg==} @@ -5855,8 +5884,8 @@ packages: resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} engines: {node: '>=6'} - tar-fs@2.1.1: - resolution: {integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==} + tar-fs@2.1.2: + resolution: {integrity: sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA==} tar-stream@2.2.0: resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} @@ -6489,26 +6518,26 @@ snapshots: '@aws-sdk/util-user-agent-browser': 3.723.0 '@aws-sdk/util-user-agent-node': 3.726.0 '@smithy/config-resolver': 4.0.1 - '@smithy/core': 3.1.0 + '@smithy/core': 3.1.1 '@smithy/fetch-http-handler': 5.0.1 '@smithy/hash-node': 4.0.1 '@smithy/invalid-dependency': 4.0.1 '@smithy/middleware-content-length': 4.0.1 - '@smithy/middleware-endpoint': 4.0.1 - '@smithy/middleware-retry': 4.0.1 + '@smithy/middleware-endpoint': 4.0.2 + '@smithy/middleware-retry': 4.0.3 '@smithy/middleware-serde': 4.0.1 '@smithy/middleware-stack': 4.0.1 '@smithy/node-config-provider': 4.0.1 - '@smithy/node-http-handler': 4.0.1 + '@smithy/node-http-handler': 4.0.2 '@smithy/protocol-http': 5.0.1 - '@smithy/smithy-client': 4.1.0 + '@smithy/smithy-client': 4.1.2 '@smithy/types': 4.1.0 '@smithy/url-parser': 4.0.1 '@smithy/util-base64': 4.0.0 '@smithy/util-body-length-browser': 4.0.0 '@smithy/util-body-length-node': 4.0.0 - '@smithy/util-defaults-mode-browser': 4.0.1 - '@smithy/util-defaults-mode-node': 4.0.1 + '@smithy/util-defaults-mode-browser': 4.0.3 + '@smithy/util-defaults-mode-node': 4.0.3 '@smithy/util-endpoints': 3.0.1 '@smithy/util-middleware': 4.0.1 '@smithy/util-retry': 4.0.1 @@ -6537,26 +6566,26 @@ snapshots: '@aws-sdk/util-user-agent-browser': 3.723.0 '@aws-sdk/util-user-agent-node': 3.726.0 '@smithy/config-resolver': 4.0.1 - '@smithy/core': 3.1.0 + '@smithy/core': 3.1.1 '@smithy/fetch-http-handler': 5.0.1 '@smithy/hash-node': 4.0.1 '@smithy/invalid-dependency': 4.0.1 '@smithy/middleware-content-length': 4.0.1 - '@smithy/middleware-endpoint': 4.0.1 - '@smithy/middleware-retry': 4.0.1 + '@smithy/middleware-endpoint': 4.0.2 + '@smithy/middleware-retry': 4.0.3 '@smithy/middleware-serde': 4.0.1 '@smithy/middleware-stack': 4.0.1 '@smithy/node-config-provider': 4.0.1 - '@smithy/node-http-handler': 4.0.1 + '@smithy/node-http-handler': 4.0.2 '@smithy/protocol-http': 5.0.1 - '@smithy/smithy-client': 4.1.0 + '@smithy/smithy-client': 4.1.2 '@smithy/types': 4.1.0 '@smithy/url-parser': 4.0.1 '@smithy/util-base64': 4.0.0 '@smithy/util-body-length-browser': 4.0.0 '@smithy/util-body-length-node': 4.0.0 - '@smithy/util-defaults-mode-browser': 4.0.1 - '@smithy/util-defaults-mode-node': 4.0.1 + '@smithy/util-defaults-mode-browser': 4.0.3 + '@smithy/util-defaults-mode-node': 4.0.3 '@smithy/util-endpoints': 3.0.1 '@smithy/util-middleware': 4.0.1 '@smithy/util-retry': 4.0.1 @@ -6584,26 +6613,26 @@ snapshots: '@aws-sdk/util-user-agent-browser': 3.723.0 '@aws-sdk/util-user-agent-node': 3.726.0 '@smithy/config-resolver': 4.0.1 - '@smithy/core': 3.1.0 + '@smithy/core': 3.1.1 '@smithy/fetch-http-handler': 5.0.1 '@smithy/hash-node': 4.0.1 '@smithy/invalid-dependency': 4.0.1 '@smithy/middleware-content-length': 4.0.1 - '@smithy/middleware-endpoint': 4.0.1 - '@smithy/middleware-retry': 4.0.1 + '@smithy/middleware-endpoint': 4.0.2 + '@smithy/middleware-retry': 4.0.3 '@smithy/middleware-serde': 4.0.1 '@smithy/middleware-stack': 4.0.1 '@smithy/node-config-provider': 4.0.1 - '@smithy/node-http-handler': 4.0.1 + '@smithy/node-http-handler': 4.0.2 '@smithy/protocol-http': 5.0.1 - '@smithy/smithy-client': 4.1.0 + '@smithy/smithy-client': 4.1.2 '@smithy/types': 4.1.0 '@smithy/url-parser': 4.0.1 '@smithy/util-base64': 4.0.0 '@smithy/util-body-length-browser': 4.0.0 '@smithy/util-body-length-node': 4.0.0 - '@smithy/util-defaults-mode-browser': 4.0.1 - '@smithy/util-defaults-mode-node': 4.0.1 + '@smithy/util-defaults-mode-browser': 4.0.3 + '@smithy/util-defaults-mode-node': 4.0.3 '@smithy/util-endpoints': 3.0.1 '@smithy/util-middleware': 4.0.1 '@smithy/util-retry': 4.0.1 @@ -6633,26 +6662,26 @@ snapshots: '@aws-sdk/util-user-agent-browser': 3.723.0 '@aws-sdk/util-user-agent-node': 3.726.0 '@smithy/config-resolver': 4.0.1 - '@smithy/core': 3.1.0 + '@smithy/core': 3.1.1 '@smithy/fetch-http-handler': 5.0.1 '@smithy/hash-node': 4.0.1 '@smithy/invalid-dependency': 4.0.1 '@smithy/middleware-content-length': 4.0.1 - '@smithy/middleware-endpoint': 4.0.1 - '@smithy/middleware-retry': 4.0.1 + '@smithy/middleware-endpoint': 4.0.2 + '@smithy/middleware-retry': 4.0.3 '@smithy/middleware-serde': 4.0.1 '@smithy/middleware-stack': 4.0.1 '@smithy/node-config-provider': 4.0.1 - '@smithy/node-http-handler': 4.0.1 + '@smithy/node-http-handler': 4.0.2 '@smithy/protocol-http': 5.0.1 - '@smithy/smithy-client': 4.1.0 + '@smithy/smithy-client': 4.1.2 '@smithy/types': 4.1.0 '@smithy/url-parser': 4.0.1 '@smithy/util-base64': 4.0.0 '@smithy/util-body-length-browser': 4.0.0 '@smithy/util-body-length-node': 4.0.0 - '@smithy/util-defaults-mode-browser': 4.0.1 - '@smithy/util-defaults-mode-node': 4.0.1 + '@smithy/util-defaults-mode-browser': 4.0.3 + '@smithy/util-defaults-mode-node': 4.0.3 '@smithy/util-endpoints': 3.0.1 '@smithy/util-middleware': 4.0.1 '@smithy/util-retry': 4.0.1 @@ -6681,26 +6710,26 @@ snapshots: '@aws-sdk/util-user-agent-browser': 3.723.0 '@aws-sdk/util-user-agent-node': 3.726.0 '@smithy/config-resolver': 4.0.1 - '@smithy/core': 3.1.0 + '@smithy/core': 3.1.1 '@smithy/fetch-http-handler': 5.0.1 '@smithy/hash-node': 4.0.1 '@smithy/invalid-dependency': 4.0.1 '@smithy/middleware-content-length': 4.0.1 - '@smithy/middleware-endpoint': 4.0.1 - '@smithy/middleware-retry': 4.0.1 + '@smithy/middleware-endpoint': 4.0.2 + '@smithy/middleware-retry': 4.0.3 '@smithy/middleware-serde': 4.0.1 '@smithy/middleware-stack': 4.0.1 '@smithy/node-config-provider': 4.0.1 - '@smithy/node-http-handler': 4.0.1 + '@smithy/node-http-handler': 4.0.2 '@smithy/protocol-http': 5.0.1 - '@smithy/smithy-client': 4.1.0 + '@smithy/smithy-client': 4.1.2 '@smithy/types': 4.1.0 '@smithy/url-parser': 4.0.1 '@smithy/util-base64': 4.0.0 '@smithy/util-body-length-browser': 4.0.0 '@smithy/util-body-length-node': 4.0.0 - '@smithy/util-defaults-mode-browser': 4.0.1 - '@smithy/util-defaults-mode-node': 4.0.1 + '@smithy/util-defaults-mode-browser': 4.0.3 + '@smithy/util-defaults-mode-node': 4.0.3 '@smithy/util-endpoints': 3.0.1 '@smithy/util-middleware': 4.0.1 '@smithy/util-retry': 4.0.1 @@ -6737,7 +6766,7 @@ snapshots: '@aws-sdk/util-user-agent-node': 3.726.0 '@aws-sdk/xml-builder': 3.723.0 '@smithy/config-resolver': 4.0.1 - '@smithy/core': 3.1.0 + '@smithy/core': 3.1.1 '@smithy/eventstream-serde-browser': 4.0.1 '@smithy/eventstream-serde-config-resolver': 4.0.1 '@smithy/eventstream-serde-node': 4.0.1 @@ -6748,25 +6777,25 @@ snapshots: '@smithy/invalid-dependency': 4.0.1 '@smithy/md5-js': 4.0.1 '@smithy/middleware-content-length': 4.0.1 - '@smithy/middleware-endpoint': 4.0.1 - '@smithy/middleware-retry': 4.0.1 + '@smithy/middleware-endpoint': 4.0.2 + '@smithy/middleware-retry': 4.0.3 '@smithy/middleware-serde': 4.0.1 '@smithy/middleware-stack': 4.0.1 '@smithy/node-config-provider': 4.0.1 - '@smithy/node-http-handler': 4.0.1 + '@smithy/node-http-handler': 4.0.2 '@smithy/protocol-http': 5.0.1 - '@smithy/smithy-client': 4.1.0 + '@smithy/smithy-client': 4.1.2 '@smithy/types': 4.1.0 '@smithy/url-parser': 4.0.1 '@smithy/util-base64': 4.0.0 '@smithy/util-body-length-browser': 4.0.0 '@smithy/util-body-length-node': 4.0.0 - '@smithy/util-defaults-mode-browser': 4.0.1 - '@smithy/util-defaults-mode-node': 4.0.1 + '@smithy/util-defaults-mode-browser': 4.0.3 + '@smithy/util-defaults-mode-node': 4.0.3 '@smithy/util-endpoints': 3.0.1 '@smithy/util-middleware': 4.0.1 '@smithy/util-retry': 4.0.1 - '@smithy/util-stream': 4.0.1 + '@smithy/util-stream': 4.0.2 '@smithy/util-utf8': 4.0.0 '@smithy/util-waiter': 4.0.2 tslib: 2.8.1 @@ -6790,26 +6819,26 @@ snapshots: '@aws-sdk/util-user-agent-browser': 3.723.0 '@aws-sdk/util-user-agent-node': 3.726.0 '@smithy/config-resolver': 4.0.1 - '@smithy/core': 3.1.0 + '@smithy/core': 3.1.1 '@smithy/fetch-http-handler': 5.0.1 '@smithy/hash-node': 4.0.1 '@smithy/invalid-dependency': 4.0.1 '@smithy/middleware-content-length': 4.0.1 - '@smithy/middleware-endpoint': 4.0.1 - '@smithy/middleware-retry': 4.0.1 + '@smithy/middleware-endpoint': 4.0.2 + '@smithy/middleware-retry': 4.0.3 '@smithy/middleware-serde': 4.0.1 '@smithy/middleware-stack': 4.0.1 '@smithy/node-config-provider': 4.0.1 - '@smithy/node-http-handler': 4.0.1 + '@smithy/node-http-handler': 4.0.2 '@smithy/protocol-http': 5.0.1 - '@smithy/smithy-client': 4.1.0 + '@smithy/smithy-client': 4.1.2 '@smithy/types': 4.1.0 '@smithy/url-parser': 4.0.1 '@smithy/util-base64': 4.0.0 '@smithy/util-body-length-browser': 4.0.0 '@smithy/util-body-length-node': 4.0.0 - '@smithy/util-defaults-mode-browser': 4.0.1 - '@smithy/util-defaults-mode-node': 4.0.1 + '@smithy/util-defaults-mode-browser': 4.0.3 + '@smithy/util-defaults-mode-node': 4.0.3 '@smithy/util-endpoints': 3.0.1 '@smithy/util-middleware': 4.0.1 '@smithy/util-retry': 4.0.1 @@ -6833,26 +6862,26 @@ snapshots: '@aws-sdk/util-user-agent-browser': 3.723.0 '@aws-sdk/util-user-agent-node': 3.726.0 '@smithy/config-resolver': 4.0.1 - '@smithy/core': 3.1.0 + '@smithy/core': 3.1.1 '@smithy/fetch-http-handler': 5.0.1 '@smithy/hash-node': 4.0.1 '@smithy/invalid-dependency': 4.0.1 '@smithy/middleware-content-length': 4.0.1 - '@smithy/middleware-endpoint': 4.0.1 - '@smithy/middleware-retry': 4.0.1 + '@smithy/middleware-endpoint': 4.0.2 + '@smithy/middleware-retry': 4.0.3 '@smithy/middleware-serde': 4.0.1 '@smithy/middleware-stack': 4.0.1 '@smithy/node-config-provider': 4.0.1 - '@smithy/node-http-handler': 4.0.1 + '@smithy/node-http-handler': 4.0.2 '@smithy/protocol-http': 5.0.1 - '@smithy/smithy-client': 4.1.0 + '@smithy/smithy-client': 4.1.2 '@smithy/types': 4.1.0 '@smithy/url-parser': 4.0.1 '@smithy/util-base64': 4.0.0 '@smithy/util-body-length-browser': 4.0.0 '@smithy/util-body-length-node': 4.0.0 - '@smithy/util-defaults-mode-browser': 4.0.1 - '@smithy/util-defaults-mode-node': 4.0.1 + '@smithy/util-defaults-mode-browser': 4.0.3 + '@smithy/util-defaults-mode-node': 4.0.3 '@smithy/util-endpoints': 3.0.1 '@smithy/util-middleware': 4.0.1 '@smithy/util-retry': 4.0.1 @@ -6878,26 +6907,26 @@ snapshots: '@aws-sdk/util-user-agent-browser': 3.723.0 '@aws-sdk/util-user-agent-node': 3.726.0 '@smithy/config-resolver': 4.0.1 - '@smithy/core': 3.1.0 + '@smithy/core': 3.1.1 '@smithy/fetch-http-handler': 5.0.1 '@smithy/hash-node': 4.0.1 '@smithy/invalid-dependency': 4.0.1 '@smithy/middleware-content-length': 4.0.1 - '@smithy/middleware-endpoint': 4.0.1 - '@smithy/middleware-retry': 4.0.1 + '@smithy/middleware-endpoint': 4.0.2 + '@smithy/middleware-retry': 4.0.3 '@smithy/middleware-serde': 4.0.1 '@smithy/middleware-stack': 4.0.1 '@smithy/node-config-provider': 4.0.1 - '@smithy/node-http-handler': 4.0.1 + '@smithy/node-http-handler': 4.0.2 '@smithy/protocol-http': 5.0.1 - '@smithy/smithy-client': 4.1.0 + '@smithy/smithy-client': 4.1.2 '@smithy/types': 4.1.0 '@smithy/url-parser': 4.0.1 '@smithy/util-base64': 4.0.0 '@smithy/util-body-length-browser': 4.0.0 '@smithy/util-body-length-node': 4.0.0 - '@smithy/util-defaults-mode-browser': 4.0.1 - '@smithy/util-defaults-mode-node': 4.0.1 + '@smithy/util-defaults-mode-browser': 4.0.3 + '@smithy/util-defaults-mode-node': 4.0.3 '@smithy/util-endpoints': 3.0.1 '@smithy/util-middleware': 4.0.1 '@smithy/util-retry': 4.0.1 @@ -6909,12 +6938,12 @@ snapshots: '@aws-sdk/core@3.723.0': dependencies: '@aws-sdk/types': 3.723.0 - '@smithy/core': 3.1.0 + '@smithy/core': 3.1.1 '@smithy/node-config-provider': 4.0.1 '@smithy/property-provider': 4.0.1 '@smithy/protocol-http': 5.0.1 '@smithy/signature-v4': 5.0.1 - '@smithy/smithy-client': 4.1.0 + '@smithy/smithy-client': 4.1.2 '@smithy/types': 4.1.0 '@smithy/util-middleware': 4.0.1 fast-xml-parser: 4.4.1 @@ -6943,12 +6972,12 @@ snapshots: '@aws-sdk/core': 3.723.0 '@aws-sdk/types': 3.723.0 '@smithy/fetch-http-handler': 5.0.1 - '@smithy/node-http-handler': 4.0.1 + '@smithy/node-http-handler': 4.0.2 '@smithy/property-provider': 4.0.1 '@smithy/protocol-http': 5.0.1 - '@smithy/smithy-client': 4.1.0 + '@smithy/smithy-client': 4.1.2 '@smithy/types': 4.1.0 - '@smithy/util-stream': 4.0.1 + '@smithy/util-stream': 4.0.2 tslib: 2.8.1 '@aws-sdk/credential-provider-ini@3.726.0(@aws-sdk/client-sso-oidc@3.726.0(@aws-sdk/client-sts@3.726.1))(@aws-sdk/client-sts@3.726.1)': @@ -7073,7 +7102,7 @@ snapshots: '@smithy/protocol-http': 5.0.1 '@smithy/types': 4.1.0 '@smithy/util-middleware': 4.0.1 - '@smithy/util-stream': 4.0.1 + '@smithy/util-stream': 4.0.2 '@smithy/util-utf8': 4.0.0 tslib: 2.8.1 @@ -7107,10 +7136,10 @@ snapshots: dependencies: '@aws-sdk/types': 3.723.0 '@aws-sdk/util-format-url': 3.723.0 - '@smithy/middleware-endpoint': 4.0.1 + '@smithy/middleware-endpoint': 4.0.2 '@smithy/protocol-http': 5.0.1 '@smithy/signature-v4': 5.0.1 - '@smithy/smithy-client': 4.1.0 + '@smithy/smithy-client': 4.1.2 '@smithy/types': 4.1.0 tslib: 2.8.1 @@ -7118,7 +7147,7 @@ snapshots: dependencies: '@aws-sdk/types': 3.723.0 '@aws-sdk/util-format-url': 3.723.0 - '@smithy/middleware-endpoint': 4.0.1 + '@smithy/middleware-endpoint': 4.0.2 '@smithy/protocol-http': 5.0.1 '@smithy/signature-v4': 5.0.1 '@smithy/types': 4.1.0 @@ -7129,15 +7158,15 @@ snapshots: '@aws-sdk/core': 3.723.0 '@aws-sdk/types': 3.723.0 '@aws-sdk/util-arn-parser': 3.723.0 - '@smithy/core': 3.1.0 + '@smithy/core': 3.1.1 '@smithy/node-config-provider': 4.0.1 '@smithy/protocol-http': 5.0.1 '@smithy/signature-v4': 5.0.1 - '@smithy/smithy-client': 4.1.0 + '@smithy/smithy-client': 4.1.2 '@smithy/types': 4.1.0 '@smithy/util-config-provider': 4.0.0 '@smithy/util-middleware': 4.0.1 - '@smithy/util-stream': 4.0.1 + '@smithy/util-stream': 4.0.2 '@smithy/util-utf8': 4.0.0 tslib: 2.8.1 @@ -7152,7 +7181,7 @@ snapshots: '@aws-sdk/core': 3.723.0 '@aws-sdk/types': 3.723.0 '@aws-sdk/util-endpoints': 3.726.0 - '@smithy/core': 3.1.0 + '@smithy/core': 3.1.1 '@smithy/protocol-http': 5.0.1 '@smithy/types': 4.1.0 tslib: 2.8.1 @@ -7764,7 +7793,7 @@ snapshots: dependencies: '@octokit/auth-token': 5.1.1 '@octokit/graphql': 8.1.2 - '@octokit/request': 9.1.4 + '@octokit/request': 9.2.0 '@octokit/request-error': 6.1.6 '@octokit/types': 13.7.0 before-after-hook: 3.0.2 @@ -7788,7 +7817,7 @@ snapshots: '@octokit/graphql@8.1.2': dependencies: - '@octokit/request': 9.1.4 + '@octokit/request': 9.2.0 '@octokit/types': 13.7.0 universal-user-agent: 7.0.2 @@ -7843,7 +7872,7 @@ snapshots: '@octokit/types': 13.7.0 universal-user-agent: 6.0.1 - '@octokit/request@9.1.4': + '@octokit/request@9.2.0': dependencies: '@octokit/endpoint': 10.1.2 '@octokit/request-error': 6.1.6 @@ -7872,6 +7901,10 @@ snapshots: dependencies: '@opentelemetry/api': 1.9.0 + '@opentelemetry/api-logs@0.57.1': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/api@1.9.0': {} '@opentelemetry/context-async-hooks@1.30.0(@opentelemetry/api@1.9.0)': @@ -7895,7 +7928,7 @@ snapshots: '@opentelemetry/instrumentation-bunyan@0.45.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/api-logs': 0.57.0 + '@opentelemetry/api-logs': 0.57.1 '@opentelemetry/instrumentation': 0.57.0(@opentelemetry/api@1.9.0) '@types/bunyan': 1.8.9 transitivePeerDependencies: @@ -8294,14 +8327,14 @@ snapshots: '@smithy/util-middleware': 4.0.1 tslib: 2.8.1 - '@smithy/core@3.1.0': + '@smithy/core@3.1.1': dependencies: '@smithy/middleware-serde': 4.0.1 '@smithy/protocol-http': 5.0.1 '@smithy/types': 4.1.0 '@smithy/util-body-length-browser': 4.0.0 '@smithy/util-middleware': 4.0.1 - '@smithy/util-stream': 4.0.1 + '@smithy/util-stream': 4.0.2 '@smithy/util-utf8': 4.0.0 tslib: 2.8.1 @@ -8396,9 +8429,9 @@ snapshots: '@smithy/types': 4.1.0 tslib: 2.8.1 - '@smithy/middleware-endpoint@4.0.1': + '@smithy/middleware-endpoint@4.0.2': dependencies: - '@smithy/core': 3.1.0 + '@smithy/core': 3.1.1 '@smithy/middleware-serde': 4.0.1 '@smithy/node-config-provider': 4.0.1 '@smithy/shared-ini-file-loader': 4.0.1 @@ -8407,12 +8440,12 @@ snapshots: '@smithy/util-middleware': 4.0.1 tslib: 2.8.1 - '@smithy/middleware-retry@4.0.1': + '@smithy/middleware-retry@4.0.3': dependencies: '@smithy/node-config-provider': 4.0.1 '@smithy/protocol-http': 5.0.1 '@smithy/service-error-classification': 4.0.1 - '@smithy/smithy-client': 4.1.0 + '@smithy/smithy-client': 4.1.2 '@smithy/types': 4.1.0 '@smithy/util-middleware': 4.0.1 '@smithy/util-retry': 4.0.1 @@ -8436,7 +8469,7 @@ snapshots: '@smithy/types': 4.1.0 tslib: 2.8.1 - '@smithy/node-http-handler@4.0.1': + '@smithy/node-http-handler@4.0.2': dependencies: '@smithy/abort-controller': 4.0.1 '@smithy/protocol-http': 5.0.1 @@ -8485,14 +8518,14 @@ snapshots: '@smithy/util-utf8': 4.0.0 tslib: 2.8.1 - '@smithy/smithy-client@4.1.0': + '@smithy/smithy-client@4.1.2': dependencies: - '@smithy/core': 3.1.0 - '@smithy/middleware-endpoint': 4.0.1 + '@smithy/core': 3.1.1 + '@smithy/middleware-endpoint': 4.0.2 '@smithy/middleware-stack': 4.0.1 '@smithy/protocol-http': 5.0.1 '@smithy/types': 4.1.0 - '@smithy/util-stream': 4.0.1 + '@smithy/util-stream': 4.0.2 tslib: 2.8.1 '@smithy/types@4.1.0': @@ -8533,21 +8566,21 @@ snapshots: dependencies: tslib: 2.8.1 - '@smithy/util-defaults-mode-browser@4.0.1': + '@smithy/util-defaults-mode-browser@4.0.3': dependencies: '@smithy/property-provider': 4.0.1 - '@smithy/smithy-client': 4.1.0 + '@smithy/smithy-client': 4.1.2 '@smithy/types': 4.1.0 bowser: 2.11.0 tslib: 2.8.1 - '@smithy/util-defaults-mode-node@4.0.1': + '@smithy/util-defaults-mode-node@4.0.3': dependencies: '@smithy/config-resolver': 4.0.1 '@smithy/credential-provider-imds': 4.0.1 '@smithy/node-config-provider': 4.0.1 '@smithy/property-provider': 4.0.1 - '@smithy/smithy-client': 4.1.0 + '@smithy/smithy-client': 4.1.2 '@smithy/types': 4.1.0 tslib: 2.8.1 @@ -8572,10 +8605,10 @@ snapshots: '@smithy/types': 4.1.0 tslib: 2.8.1 - '@smithy/util-stream@4.0.1': + '@smithy/util-stream@4.0.2': dependencies: '@smithy/fetch-http-handler': 5.0.1 - '@smithy/node-http-handler': 4.0.1 + '@smithy/node-http-handler': 4.0.2 '@smithy/types': 4.1.0 '@smithy/util-base64': 4.0.0 '@smithy/util-buffer-from': 4.0.0 @@ -8970,6 +9003,11 @@ snapshots: '@typescript-eslint/types': 8.19.1 '@typescript-eslint/visitor-keys': 8.19.1 + '@typescript-eslint/scope-manager@8.20.0': + dependencies: + '@typescript-eslint/types': 8.20.0 + '@typescript-eslint/visitor-keys': 8.20.0 + '@typescript-eslint/type-utils@8.19.1(eslint@8.57.1)(typescript@5.7.3)': dependencies: '@typescript-eslint/typescript-estree': 8.19.1(typescript@5.7.3) @@ -8985,6 +9023,8 @@ snapshots: '@typescript-eslint/types@8.19.1': {} + '@typescript-eslint/types@8.20.0': {} + '@typescript-eslint/typescript-estree@5.62.0(typescript@5.7.3)': dependencies: '@typescript-eslint/types': 5.62.0 @@ -9013,6 +9053,20 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/typescript-estree@8.20.0(typescript@5.7.3)': + dependencies: + '@typescript-eslint/types': 8.20.0 + '@typescript-eslint/visitor-keys': 8.20.0 + debug: 4.4.0 + fast-glob: 3.3.3 + is-glob: 4.0.3 + minimatch: 9.0.5 + semver: 7.6.3 + ts-api-utils: 2.0.0(typescript@5.7.3) + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/utils@5.62.0(eslint@8.57.1)(typescript@5.7.3)': dependencies: '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1) @@ -9039,6 +9093,17 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/utils@8.20.0(eslint@8.57.1)(typescript@5.7.3)': + dependencies: + '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1) + '@typescript-eslint/scope-manager': 8.20.0 + '@typescript-eslint/types': 8.20.0 + '@typescript-eslint/typescript-estree': 8.20.0(typescript@5.7.3) + eslint: 8.57.1 + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/visitor-keys@5.62.0': dependencies: '@typescript-eslint/types': 5.62.0 @@ -9049,6 +9114,11 @@ snapshots: '@typescript-eslint/types': 8.19.1 eslint-visitor-keys: 4.2.0 + '@typescript-eslint/visitor-keys@8.20.0': + dependencies: + '@typescript-eslint/types': 8.20.0 + eslint-visitor-keys: 4.2.0 + '@ungap/structured-clone@1.2.1': {} '@yarnpkg/core@4.2.0(typanion@3.14.0)': @@ -9211,7 +9281,7 @@ snapshots: call-bind: 1.0.8 define-properties: 1.2.1 es-abstract: 1.23.9 - es-object-atoms: 1.0.0 + es-object-atoms: 1.1.1 get-intrinsic: 1.2.7 is-string: 1.1.1 @@ -9223,7 +9293,7 @@ snapshots: define-properties: 1.2.1 es-abstract: 1.23.9 es-errors: 1.3.0 - es-object-atoms: 1.0.0 + es-object-atoms: 1.1.1 es-shim-unscopables: 1.0.2 array.prototype.flat@1.3.3: @@ -9389,8 +9459,8 @@ snapshots: browserslist@4.24.4: dependencies: - caniuse-lite: 1.0.30001692 - electron-to-chromium: 1.5.80 + caniuse-lite: 1.0.30001695 + electron-to-chromium: 1.5.83 node-releases: 2.0.19 update-browserslist-db: 1.1.2(browserslist@4.24.4) @@ -9499,7 +9569,7 @@ snapshots: camelcase@6.3.0: {} - caniuse-lite@1.0.30001692: {} + caniuse-lite@1.0.30001695: {} chalk@2.4.2: dependencies: @@ -9888,7 +9958,7 @@ snapshots: dependencies: jake: 10.9.2 - electron-to-chromium@1.5.80: {} + electron-to-chromium@1.5.83: {} email-addresses@5.0.0: {} @@ -9954,7 +10024,7 @@ snapshots: data-view-byte-offset: 1.0.1 es-define-property: 1.0.1 es-errors: 1.3.0 - es-object-atoms: 1.0.0 + es-object-atoms: 1.1.1 es-set-tostringtag: 2.1.0 es-to-primitive: 1.3.0 function.prototype.name: 1.1.8 @@ -10000,7 +10070,7 @@ snapshots: es-errors@1.3.0: {} - es-object-atoms@1.0.0: + es-object-atoms@1.1.1: dependencies: es-errors: 1.3.0 @@ -10116,7 +10186,7 @@ snapshots: eslint-plugin-jest@28.10.0(@typescript-eslint/eslint-plugin@8.19.1(@typescript-eslint/parser@8.19.1(eslint@8.57.1)(typescript@5.7.3))(eslint@8.57.1)(typescript@5.7.3))(eslint@8.57.1)(jest@29.7.0(@types/node@22.10.5)(ts-node@10.9.2(@swc/core@1.10.7)(@types/node@22.10.5)(typescript@5.7.3)))(typescript@5.7.3): dependencies: - '@typescript-eslint/utils': 8.19.1(eslint@8.57.1)(typescript@5.7.3) + '@typescript-eslint/utils': 8.20.0(eslint@8.57.1)(typescript@5.7.3) eslint: 8.57.1 optionalDependencies: '@typescript-eslint/eslint-plugin': 8.19.1(@typescript-eslint/parser@8.19.1(eslint@8.57.1)(typescript@5.7.3))(eslint@8.57.1)(typescript@5.7.3) @@ -10482,7 +10552,7 @@ snapshots: call-bind-apply-helpers: 1.0.1 es-define-property: 1.0.1 es-errors: 1.3.0 - es-object-atoms: 1.0.0 + es-object-atoms: 1.1.1 function-bind: 1.1.2 get-proto: 1.0.1 gopd: 1.2.0 @@ -10495,7 +10565,7 @@ snapshots: get-proto@1.0.1: dependencies: dunder-proto: 1.0.1 - es-object-atoms: 1.0.0 + es-object-atoms: 1.1.1 get-stream@5.2.0: dependencies: @@ -11532,7 +11602,7 @@ snapshots: jwa: 2.0.0 safe-buffer: 5.2.1 - katex@0.16.19: + katex@0.16.21: dependencies: commander: 8.3.0 @@ -11869,7 +11939,7 @@ snapshots: dependencies: '@types/katex': 0.16.7 devlop: 1.1.0 - katex: 0.16.19 + katex: 0.16.21 micromark-factory-space: 2.0.1 micromark-util-character: 2.1.1 micromark-util-symbol: 2.0.1 @@ -12140,7 +12210,7 @@ snapshots: transitivePeerDependencies: - supports-color - node-abi@3.71.0: + node-abi@3.73.0: dependencies: semver: 7.6.3 optional: true @@ -12293,7 +12363,7 @@ snapshots: call-bind: 1.0.8 call-bound: 1.0.3 define-properties: 1.2.1 - es-object-atoms: 1.0.0 + es-object-atoms: 1.1.1 has-symbols: 1.1.0 object-keys: 1.1.1 @@ -12302,7 +12372,7 @@ snapshots: call-bind: 1.0.8 define-properties: 1.2.1 es-abstract: 1.23.9 - es-object-atoms: 1.0.0 + es-object-atoms: 1.1.1 object.groupby@1.0.3: dependencies: @@ -12315,7 +12385,7 @@ snapshots: call-bind: 1.0.8 call-bound: 1.0.3 define-properties: 1.2.1 - es-object-atoms: 1.0.0 + es-object-atoms: 1.1.1 once@1.4.0: dependencies: @@ -12557,11 +12627,11 @@ snapshots: minimist: 1.2.8 mkdirp-classic: 0.5.3 napi-build-utils: 1.0.2 - node-abi: 3.71.0 + node-abi: 3.73.0 pump: 3.0.2 rc: 1.2.8 simple-get: 4.0.1 - tar-fs: 2.1.1 + tar-fs: 2.1.2 tunnel-agent: 0.6.0 optional: true @@ -12635,7 +12705,7 @@ snapshots: purepack@1.0.6: {} - qs@6.13.1: + qs@6.14.0: dependencies: side-channel: 1.1.0 @@ -12736,7 +12806,7 @@ snapshots: define-properties: 1.2.1 es-abstract: 1.23.9 es-errors: 1.3.0 - es-object-atoms: 1.0.0 + es-object-atoms: 1.1.1 get-intrinsic: 1.2.7 get-proto: 1.0.1 which-builtin-type: 1.2.1 @@ -12964,7 +13034,7 @@ snapshots: dependencies: dunder-proto: 1.0.1 es-errors: 1.3.0 - es-object-atoms: 1.0.0 + es-object-atoms: 1.1.1 shebang-command@2.0.0: dependencies: @@ -13103,16 +13173,16 @@ snapshots: spdx-correct@3.2.0: dependencies: spdx-expression-parse: 3.0.1 - spdx-license-ids: 3.0.20 + spdx-license-ids: 3.0.21 spdx-exceptions@2.5.0: {} spdx-expression-parse@3.0.1: dependencies: spdx-exceptions: 2.5.0 - spdx-license-ids: 3.0.20 + spdx-license-ids: 3.0.21 - spdx-license-ids@3.0.20: {} + spdx-license-ids@3.0.21: {} split2@1.0.0: dependencies: @@ -13170,7 +13240,7 @@ snapshots: define-data-property: 1.1.4 define-properties: 1.2.1 es-abstract: 1.23.9 - es-object-atoms: 1.0.0 + es-object-atoms: 1.1.1 has-property-descriptors: 1.0.2 string.prototype.trimend@1.0.9: @@ -13178,13 +13248,13 @@ snapshots: call-bind: 1.0.8 call-bound: 1.0.3 define-properties: 1.2.1 - es-object-atoms: 1.0.0 + es-object-atoms: 1.1.1 string.prototype.trimstart@1.0.8: dependencies: call-bind: 1.0.8 define-properties: 1.2.1 - es-object-atoms: 1.0.0 + es-object-atoms: 1.1.1 string_decoder@1.1.1: dependencies: @@ -13250,7 +13320,7 @@ snapshots: tapable@2.2.1: {} - tar-fs@2.1.1: + tar-fs@2.1.2: dependencies: chownr: 1.1.4 mkdirp-classic: 0.5.3 @@ -13511,7 +13581,7 @@ snapshots: dependencies: des.js: 1.1.0 js-md4: 0.3.2 - qs: 6.13.1 + qs: 6.14.0 tunnel: 0.0.6 underscore: 1.13.7 diff --git a/pyproject.toml b/pyproject.toml index 505881c624b713..6f45156ddfa069 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] dependencies = [ - "mkdocs-material==9.5.49", + "mkdocs-material==9.5.50", "mkdocs-awesome-pages-plugin==2.10.1", ] requires-python = ">=3.11" diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile index 6f67a74e29ce02..4d3759fd1feaf0 100644 --- a/tools/docker/Dockerfile +++ b/tools/docker/Dockerfile @@ -5,19 +5,19 @@ ARG BASE_IMAGE_TYPE=slim # -------------------------------------- # slim image # -------------------------------------- -FROM ghcr.io/renovatebot/base-image:9.30.2@sha256:5cd2ac3e6047a2335c55a733648d3add98ad0eb1dca5c3c7ba3814de61665611 AS slim-base +FROM ghcr.io/renovatebot/base-image:9.33.4@sha256:40148df951d4066f5f4aa1e947de6aaca142e6590a89c91e9dcf0b37bcf92733 AS slim-base # -------------------------------------- # full image # -------------------------------------- -FROM ghcr.io/renovatebot/base-image:9.30.2-full@sha256:cf6723892696a8fc3fe6a9df5f639f876335f21d2703fc414afbd18c8249787a AS full-base +FROM ghcr.io/renovatebot/base-image:9.33.4-full@sha256:0625807c6162e85e0f288eb51dd901f99a91a122287a1858b40c0ba43e962a0b AS full-base ENV RENOVATE_BINARY_SOURCE=global # -------------------------------------- # build image # -------------------------------------- -FROM --platform=$BUILDPLATFORM ghcr.io/renovatebot/base-image:9.30.2@sha256:5cd2ac3e6047a2335c55a733648d3add98ad0eb1dca5c3c7ba3814de61665611 AS build +FROM --platform=$BUILDPLATFORM ghcr.io/renovatebot/base-image:9.33.4@sha256:40148df951d4066f5f4aa1e947de6aaca142e6590a89c91e9dcf0b37bcf92733 AS build # We want a specific node version here # renovate: datasource=node-version diff --git a/tools/docs/github-query-items.ts b/tools/docs/github-query-items.ts index 13527c800eca6b..1683158541a861 100644 --- a/tools/docs/github-query-items.ts +++ b/tools/docs/github-query-items.ts @@ -63,7 +63,7 @@ export async function getOpenGitHubItems(): Promise { const per_page = 100; try { const query = getQueryString({ q, per_page }); - const res = await githubApi.getJson( + const res = await githubApi.getJsonUnchecked( gitHubApiUrl + query, { paginationField: 'items',