diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index c184af8ff08f5f..3b08960a3a20ab 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1 +1 @@ -FROM ghcr.io/containerbase/devcontainer:13.5.5 +FROM ghcr.io/containerbase/devcontainer:13.5.10 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f8c3bc859da7ce..fa4e3a42949ee6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -31,7 +31,7 @@ concurrency: env: DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} NODE_VERSION: 22 - PDM_VERSION: 2.22.1 # renovate: datasource=pypi depName=pdm + PDM_VERSION: 2.22.2 # renovate: datasource=pypi depName=pdm DRY_RUN: true TEST_LEGACY_DECRYPTION: true SPARSE_CHECKOUT: |- @@ -304,7 +304,7 @@ jobs: os: ${{ runner.os }} - name: Lint markdown - uses: DavidAnson/markdownlint-cli2-action@eb5ca3ab411449c66620fe7f1b3c9e10547144b0 # v18.0.0 + uses: DavidAnson/markdownlint-cli2-action@a23dae216ce3fee4db69da41fed90d2a4af801cf # v19.0.0 - name: Lint fenced code blocks run: pnpm doc-fence-check @@ -411,7 +411,7 @@ jobs: - name: Save coverage artifacts if: (success() || failure()) && github.event.pull_request.draft != true && matrix.coverage - uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0 + uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 with: name: ${{ matrix.upload-artifact-name }} path: | @@ -567,7 +567,7 @@ jobs: run: pnpm test-e2e:pack - name: Upload - uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0 + uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 with: name: renovate-package path: renovate-0.0.0-semantic-release.tgz @@ -611,7 +611,7 @@ jobs: run: pnpm test:docs - name: Upload - uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0 + uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 with: name: docs path: tmp/docs/ @@ -684,7 +684,7 @@ jobs: show-progress: false - name: docker-config - uses: containerbase/internal-tools@c440de95307545d23ff0e0b57018147e02ae217f # v3.5.15 + uses: containerbase/internal-tools@c8f78cbc830d1883e695d06e3028136656e70f5b # v3.5.17 with: command: docker-config diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index fbcd8f0dd563ad..28e256da7b5452 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -41,7 +41,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@48ab28a6f5dbc2a99bf1e0131198dd8f1df78169 # v3.28.0 + uses: github/codeql-action/init@b6a472f63d85b9c78a3ac5e89422239fc15e9b3c # v3.28.1 with: languages: javascript @@ -51,7 +51,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@48ab28a6f5dbc2a99bf1e0131198dd8f1df78169 # v3.28.0 + uses: github/codeql-action/autobuild@b6a472f63d85b9c78a3ac5e89422239fc15e9b3c # v3.28.1 # ℹī¸ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -65,4 +65,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@48ab28a6f5dbc2a99bf1e0131198dd8f1df78169 # v3.28.0 + uses: github/codeql-action/analyze@b6a472f63d85b9c78a3ac5e89422239fc15e9b3c # v3.28.1 diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index b3cfe0671e90ed..a21f09f3638134 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -43,7 +43,7 @@ jobs: # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF # format to the repository Actions tab. - name: 'Upload artifact' - uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0 + uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 with: name: SARIF file path: results.sarif @@ -51,6 +51,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: 'Upload to code-scanning' - uses: github/codeql-action/upload-sarif@48ab28a6f5dbc2a99bf1e0131198dd8f1df78169 # v3.28.0 + uses: github/codeql-action/upload-sarif@b6a472f63d85b9c78a3ac5e89422239fc15e9b3c # v3.28.1 with: sarif_file: results.sarif diff --git a/.github/workflows/trivy.yml b/.github/workflows/trivy.yml index 4bb06dc0427ed2..9b99d5869217c0 100644 --- a/.github/workflows/trivy.yml +++ b/.github/workflows/trivy.yml @@ -31,7 +31,7 @@ jobs: format: 'sarif' output: 'trivy-results.sarif' - - uses: github/codeql-action/upload-sarif@48ab28a6f5dbc2a99bf1e0131198dd8f1df78169 # v3.28.0 + - uses: github/codeql-action/upload-sarif@b6a472f63d85b9c78a3ac5e89422239fc15e9b3c # v3.28.1 with: sarif_file: trivy-results.sarif category: 'docker-image-${{ matrix.tag }}' diff --git a/.nvmrc b/.nvmrc index 7af24b7ddbde0c..6fa8dec4cd6789 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -22.11.0 +22.13.0 diff --git a/docs/usage/assets/images/portal-sign-in.png b/docs/usage/assets/images/portal-sign-in.png new file mode 100644 index 00000000000000..743a62a05cded9 Binary files /dev/null and b/docs/usage/assets/images/portal-sign-in.png differ diff --git a/docs/usage/bazel.md b/docs/usage/bazel.md index 4a95e19c55e2e1..3ef033f1685ecd 100644 --- a/docs/usage/bazel.md +++ b/docs/usage/bazel.md @@ -145,6 +145,19 @@ archive_override( Renovate ignores [`multiple_version_override`](https://bazel.build/rules/lib/globals/module#multiple_version_override). `multiple_version_override` does not affect the processing of version updates for a module. +### `git_repository` + +If Renovate finds a [`git_repository`](https://bazel.build/rules/lib/repo/git#git_repository), it evaluates the `commit` value at the specified `remote`. +`remote` is limited to github repos: `https://github.com//.git` + +```python +git_repository( + name = "rules_foo", + remote = "https://github.com/fooexample/rules_foo.git", + commit = "8c94e11c2b05b6f25ced5f23cd07d0cfd36edc1a", +) +``` + ## Legacy `WORKSPACE` files Renovate extracts dependencies from the following repository rules: @@ -160,7 +173,7 @@ Renovate extracts dependencies from the following repository rules: It also recognizes when these repository rule names are prefixed with an underscore. For example, `_http_archive` is treated the same as `http_archive`. -### `git_repository` +### `git_repository` (legacy) Renovate updates any `git_repository` declaration that has the following: diff --git a/docs/usage/configuration-options.md b/docs/usage/configuration-options.md index a55d0fa601e80e..e76873af8a49d0 100644 --- a/docs/usage/configuration-options.md +++ b/docs/usage/configuration-options.md @@ -2426,6 +2426,7 @@ Renovate only queries the OSV database for dependencies that use one of these da - [`crate`](./modules/datasource/crate/index.md) - [`go`](./modules/datasource/go/index.md) +- [`hackage`](./modules/datasource/hackage/index.md) - [`hex`](./modules/datasource/hex/index.md) - [`maven`](./modules/datasource/maven/index.md) - [`npm`](./modules/datasource/npm/index.md) @@ -3706,6 +3707,7 @@ This feature works with the following managers: - [`dockerfile`](modules/manager/dockerfile/index.md) - [`droneci`](modules/manager/droneci/index.md) - [`flux`](modules/manager/flux/index.md) +- [`github-actions`](modules/manager/github-actions/index.md) - [`gitlabci`](modules/manager/gitlabci/index.md) - [`helm-requirements`](modules/manager/helm-requirements/index.md) - [`helm-values`](modules/manager/helm-values/index.md) diff --git a/docs/usage/docker.md b/docs/usage/docker.md index b9a5bf9d923484..188c30f0a941de 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.7 + uses: renovatebot/github-action@v41.0.9 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.82.1 +FROM renovate/renovate:39.104.1 # 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/opentelemetry.md b/docs/usage/examples/opentelemetry.md index c007e6bea9f7e2..504a7e0ef92e90 100644 --- a/docs/usage/examples/opentelemetry.md +++ b/docs/usage/examples/opentelemetry.md @@ -14,7 +14,7 @@ name: renovate-otel-demo services: # Jaeger for storing traces jaeger: - image: jaegertracing/jaeger:2.1.0 + image: jaegertracing/jaeger:2.2.0 ports: - '16686:16686' # Web UI - '4317' # OTLP gRPC @@ -22,7 +22,7 @@ services: # Prometheus for storing metrics prometheus: - image: prom/prometheus:v3.0.1 + image: prom/prometheus:v3.1.0 ports: - '9090:9090' # Web UI - '4318' # OTLP HTTP @@ -36,7 +36,7 @@ services: otel-collector: # Using the Contrib version to access the spanmetrics connector. # If you don't need the spanmetrics connector, you can use the standard version - image: otel/opentelemetry-collector-contrib:0.116.1 + image: otel/opentelemetry-collector-contrib:0.117.0 volumes: - ./otel-collector-config.yml:/etc/otelcol-contrib/config.yaml ports: diff --git a/docs/usage/examples/self-hosting.md b/docs/usage/examples/self-hosting.md index a78c38938e0eb1..9388b091bca91a 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.82 -docker run --rm renovate/renovate:39.82.1 +docker run --rm renovate/renovate:39.104 +docker run --rm renovate/renovate:39.104.1 ``` @@ -62,7 +62,7 @@ spec: - name: renovate # Update this to the latest available and then enable Renovate on # the manifest - image: renovate/renovate:39.82.1 + image: renovate/renovate:39.104.1 args: - user/repo # Environment Variables @@ -121,7 +121,7 @@ spec: template: spec: containers: - - image: renovate/renovate:39.82.1 + - image: renovate/renovate:39.104.1 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.82.1 + image: renovate/renovate:39.104.1 volumeMounts: - name: ssh-key-volume readOnly: true diff --git a/docs/usage/mend-hosted/.pages b/docs/usage/mend-hosted/.pages index 01b1b47debd098..4dda5349d7d4e7 100644 --- a/docs/usage/mend-hosted/.pages +++ b/docs/usage/mend-hosted/.pages @@ -1,5 +1,6 @@ title: Mend-hosted Apps nav: + - 'Overview': 'overview.md' - 'Configuration': 'hosted-apps-config.md' - 'Credentials': 'credentials.md' - 'Migrating Secrets': 'migrating-secrets.md' diff --git a/docs/usage/mend-hosted/overview.md b/docs/usage/mend-hosted/overview.md new file mode 100644 index 00000000000000..576072aa088234 --- /dev/null +++ b/docs/usage/mend-hosted/overview.md @@ -0,0 +1,59 @@ +# Mend Renovate Cloud-hosted (Community and Enterprise) + +Mend provides cloud hosting services for running Renovate in free and paid versions: + +- Mend Renovate Community Cloud (Free) +- Mend Renovate Enterprise Cloud + +They are available for Git repositories hosted on the following cloud platforms: + +- GitHub +- Bitbucket Cloud +- Azure DevOps + +Mend Renovate cloud will regularly schedule Renovate jobs against all installed repositories. +It also listens to webhooks and enqueues a Renovate job when relevant changes occur in a repo, or when actions are triggered from the Renovate PRs or Dashboard issue. +There is a web UI with functionality to view and interact with installed repositories, their jobs and job logs. + +## Getting started + +To get started using Mend Renovate Cloud versions, access the Developer Portal at [https://developer.mend.io/](https://developer.mend.io/). + +Developers can log in using the OAuth credentials from their cloud-based Git repository. + +![Developer Portal sign-in screen](../assets/images/portal-sign-in.png) + +Features of the Developer Portal include: + +- Ability to install, uninstall and view installed repositories +- Trigger Renovate jobs to run on demand +- View logs for all Renovate jobs +- Configure settings that apply at the Org-level or Repo-level + +## Resources and Scheduling + +The resources, scheduling and concurrency of Renovate jobs is determined by the version of Mend Renovate used by the Org. +Details of the Mend Renovate Cloud versions are shown in the table below. + +| | Mend Renovate Community Cloud (Free) | Mend Renovate Enterprise Cloud | +| ----------------------------- | ------------------------------------ | ------------------------------ | +| Concurrent jobs per Org | 1 | 16 | +| Job scheduling (active repos) | Every 4 hours | Hourly (\*1) | +| Job runner CPUs | 1 CPU | 2 CPU | +| Job runner Memory | 2Gb | 8Gb | +| Job runner Disk space | 15Gb | 40Gb | +| Job timeout | 30 minutes | 60 minutes | +| Merge Confidence Workflows | Not included | Included | +| Mend.io Helpdesk Support | Not included | Included | + +(1) Bitbucket repositories running Mend Renovate Enterprise are scheduled to run every 4 hours, to avoid hitting rate limits on GitHub APIs. + +**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/docs/usage/self-hosted-experimental.md b/docs/usage/self-hosted-experimental.md index f80219fd96fde9..78ea76a020dba6 100644 --- a/docs/usage/self-hosted-experimental.md +++ b/docs/usage/self-hosted-experimental.md @@ -23,6 +23,13 @@ For more information see [the OpenTelemetry docs](opentelemetry.md). If set to any value, Renovate will always paginate requests to GitHub fully, instead of stopping after 10 pages. +## `RENOVATE_STATIC_REPO_CONFIG` + +If set to a _valid_ `JSON` string containing a _valid_ Renovate configuration, it will be applied to the repository config before resolving the actual configuration file within the repository. + +> [!warning] +> An invalid value will result in the scan being aborted. + ## `RENOVATE_X_DOCKER_HUB_DISABLE_LABEL_LOOKUP` If set to any value, Renovate will skip attempting to get release labels (e.g. gitRef, sourceUrl) from manifest annotations for `https://index.docker.io`. diff --git a/lib/config/decrypt.spec.ts b/lib/config/decrypt.spec.ts index 3a056690dba2eb..3878b86870d4ec 100644 --- a/lib/config/decrypt.spec.ts +++ b/lib/config/decrypt.spec.ts @@ -12,6 +12,7 @@ describe('config/decrypt', () => { beforeEach(() => { config = {}; GlobalConfig.reset(); + delete process.env.MEND_HOSTED; delete process.env.RENOVATE_X_ENCRYPTED_STRICT; }); @@ -34,8 +35,19 @@ describe('config/decrypt', () => { it('throws exception if encrypted found but no privateKey', async () => { config.encrypted = { a: '1' }; + process.env.RENOVATE_X_ENCRYPTED_STRICT = 'true'; + await expect(decryptConfig(config, repository)).rejects.toThrow( + 'config-validation', + ); + }); + + // coverage + it('throws exception if encrypted found but no privateKey- Mend Hosted', async () => { + config.encrypted = { a: '1' }; + process.env.MEND_HOSTED = 'true'; + process.env.RENOVATE_X_ENCRYPTED_STRICT = 'true'; await expect(decryptConfig(config, repository)).rejects.toThrow( 'config-validation', ); diff --git a/lib/config/decrypt.ts b/lib/config/decrypt.ts index 80cddcd490830a..d7f80a1f186a7b 100644 --- a/lib/config/decrypt.ts +++ b/lib/config/decrypt.ts @@ -179,6 +179,12 @@ export async function decryptConfig( error.validationSource = 'config'; error.validationError = 'Encrypted config unsupported'; error.validationMessage = `This config contains an encrypted object at location \`$.${key}\` but no privateKey is configured. To support encrypted config, the Renovate administrator must configure a \`privateKey\` in Global Configuration.`; + if (process.env.MEND_HOSTED === 'true') { + error.validationMessage = `Mend-hosted Renovate Apps no longer support the use of encrypted secrets in Renovate file config (e.g. renovate.json). +Please migrate all secrets to the Developer Portal using the web UI available at https://developer.mend.io/ + +Refer to migration documents here: https://docs.renovatebot.com/mend-hosted/migrating-secrets/`; + } throw error; } else { logger.error('Found encrypted data but no privateKey'); diff --git a/lib/config/options/index.ts b/lib/config/options/index.ts index 409b7474d2ed70..ea5da7747594a5 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.5', + default: 'ghcr.io/containerbase/sidecar:13.5.10', globalOnly: true, }, { diff --git a/lib/config/presets/common.ts b/lib/config/presets/common.ts index d79e996f3a8241..3b613bc4e25463 100644 --- a/lib/config/presets/common.ts +++ b/lib/config/presets/common.ts @@ -74,6 +74,7 @@ const renamedMonorepos: Record = { Steeltoe: 'steeltoe', stryker: 'stryker-js', Swashbuckle: 'swashbuckle-aspnetcore', + nrwl: 'nx', }; for (const [from, to] of Object.entries(renamedMonorepos)) { 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/internal/global.ts b/lib/config/presets/internal/global.ts index aaf331d81e69c5..ce8240fcf131d8 100644 --- a/lib/config/presets/internal/global.ts +++ b/lib/config/presets/internal/global.ts @@ -4,7 +4,7 @@ import type { Preset } from '../types'; export const presets: Record = { safeEnv: { - allowedEnv: ['GO*'], + allowedEnv: ['GO*', 'RUSTC_BOOTSTRAP'], description: 'Hopefully safe environment variables to allow users to configure.', }, diff --git a/lib/config/presets/internal/group.ts b/lib/config/presets/internal/group.ts index 51a13f529b4e61..0e23a4b694df17 100644 --- a/lib/config/presets/internal/group.ts +++ b/lib/config/presets/internal/group.ts @@ -451,7 +451,11 @@ const staticGroups = { packageRules: [ { groupName: 'react monorepo', - matchPackageNames: ['@types/react', '@types/react-dom'], + matchPackageNames: [ + '@types/react', + '@types/react-dom', + '@types/react-is', + ], }, ], }, 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/constants/category.ts b/lib/constants/category.ts index a92c54656eeb56..94c22015c9a5cd 100644 --- a/lib/constants/category.ts +++ b/lib/constants/category.ts @@ -12,6 +12,7 @@ export const Categories = [ 'dotnet', 'elixir', 'golang', + 'haskell', 'helm', 'iac', 'java', diff --git a/lib/data/monorepo.json b/lib/data/monorepo.json index 3b013e219ed302..1d0437dbc8db72 100644 --- a/lib/data/monorepo.json +++ b/lib/data/monorepo.json @@ -55,6 +55,7 @@ "https://github.com/awslabs/aws-sdk-rust" ], "awsappsync": "https://github.com/awslabs/aws-mobile-appsync-sdk-js", + "axum": "https://github.com/tokio-rs/axum", "azure-functions-dotnet-worker": "https://github.com/Azure/azure-functions-dotnet-worker", "azure azure-libraries-for-net": "https://github.com/Azure/azure-libraries-for-net", "azure azure-sdk-for-net": "https://github.com/Azure/azure-sdk-for-net", @@ -435,6 +436,8 @@ "opentelemetry-java-contrib": "https://github.com/open-telemetry/opentelemetry-java-contrib", "opentelemetry-js": "https://github.com/open-telemetry/opentelemetry-js", "opentelemetry-js-contrib": "https://github.com/open-telemetry/opentelemetry-js-contrib", + "opentelemetry-python": "https://github.com/open-telemetry/opentelemetry-python", + "opentelemetry-python-contrib": "https://github.com/open-telemetry/opentelemetry-python-contrib", "opentelemetry-rust": "https://github.com/open-telemetry/opentelemetry-rust", "opentelemetry-rust-contrib": "https://github.com/open-telemetry/opentelemetry-rust-contrib", "orleans": "https://github.com/dotnet/orleans", @@ -502,7 +505,10 @@ "shiki": "https://github.com/shikijs/shiki", "shopify-app-bridge": "https://github.com/Shopify/app-bridge", "sitecore-jss": "https://github.com/Sitecore/jss", - "skiasharp": "https://github.com/mono/SkiaSharp", + "skiasharp": [ + "https://github.com/mono/SkiaSharp", + "https://go.microsoft.com/fwlink/?linkid=868515" + ], "slack-net": "https://github.com/soxtoby/SlackNet", "slf4j": "https://github.com/qos-ch/slf4j", "slim-message-bus": "https://github.com/zarusz/SlimMessageBus", @@ -514,6 +520,7 @@ "strapi": "https://github.com/strapi/strapi", "strum": "https://github.com/Peternator7/strum", "stryker-js": "https://github.com/stryker-mutator/stryker-js", + "stylex-swc": "https://github.com/Dwlad90/stylex-swc-plugin", "surveyjs": "https://github.com/surveyjs/surveyjs", "swashbuckle-aspnetcore": "https://github.com/domaindrivendev/Swashbuckle.AspNetCore", "system.io.abstractions": "https://github.com/System-IO-Abstractions/System.IO.Abstractions/", @@ -584,7 +591,7 @@ "hapijs": "https://github.com/hapijs/", "lodash": "https://github.com/lodash/", "ngrx": "https://github.com/ngrx/", - "nrwl": "https://github.com/nrwl/", + "nx": "https://github.com/nrwl/nx", "octokit": "https://github.com/octokit/", "semantic-release": "https://github.com/semantic-release/", "swc": "https://github.com/swc-project/" diff --git a/lib/logger/utils.ts b/lib/logger/utils.ts index b85f2c44de22e4..e6278f919e2311 100644 --- a/lib/logger/utils.ts +++ b/lib/logger/utils.ts @@ -317,7 +317,7 @@ export function validateLogLevel( }, ], }); - logger.fatal(`${logLevelToCheck} is not a valid log level. terminating...`); + logger.fatal({ logLevel: logLevelToCheck }, 'Invalid log level'); process.exit(1); } diff --git a/lib/modules/datasource/api.ts b/lib/modules/datasource/api.ts index e7284442c0a36b..84ba7fc52c5d2a 100644 --- a/lib/modules/datasource/api.ts +++ b/lib/modules/datasource/api.ts @@ -17,6 +17,7 @@ import { DartDatasource } from './dart'; import { DartVersionDatasource } from './dart-version'; import { DebDatasource } from './deb'; import { DenoDatasource } from './deno'; +import { DevboxDatasource } from './devbox'; import { DockerDatasource } from './docker'; import { DotnetVersionDatasource } from './dotnet-version'; import { EndoflifeDateDatasource } from './endoflife-date'; @@ -88,6 +89,7 @@ api.set(DartDatasource.id, new DartDatasource()); api.set(DartVersionDatasource.id, new DartVersionDatasource()); api.set(DebDatasource.id, new DebDatasource()); api.set(DenoDatasource.id, new DenoDatasource()); +api.set(DevboxDatasource.id, new DevboxDatasource()); api.set(DockerDatasource.id, new DockerDatasource()); api.set(DotnetVersionDatasource.id, new DotnetVersionDatasource()); api.set(EndoflifeDateDatasource.id, new EndoflifeDateDatasource()); diff --git a/lib/modules/datasource/artifactory/__fixtures__/releases-as-files.html b/lib/modules/datasource/artifactory/__fixtures__/releases-as-files.html index 2bdde583999c96..3d5bf59b799634 100644 --- a/lib/modules/datasource/artifactory/__fixtures__/releases-as-files.html +++ b/lib/modules/datasource/artifactory/__fixtures__/releases-as-files.html @@ -11,9 +11,9 @@

Index

          ..
          1.0.0  21-Jul-2021 20:08    -
-         1.0.1  23-Aug-2021 20:03    -
-         1.0.2  21-Jul-2021 20:09    -
-         1.0.3  06-Feb-2021 09:54    -
+         1.0.1  23-Aug-2021 20:03    12 MB
+         1.0.2  21-Jul-2021 20:09    123.45 GB
+         1.0.3  06-Feb-2021 09:54    9.0 KB
        

Artifactory Port 8080
diff --git a/lib/modules/datasource/artifactory/index.ts b/lib/modules/datasource/artifactory/index.ts index e66ffb4ebaac59..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,8 +113,4 @@ export class ArtifactoryDatasource extends Datasource { return result.releases.length ? result : null; } - - private static parseReleaseTimestamp(rawText: string): string { - return rawText.trim().replace(regEx(/ ?-$/), '') + 'Z'; - } } diff --git a/lib/modules/datasource/azure-pipelines-tasks/__fixtures__/tasks.json b/lib/modules/datasource/azure-pipelines-tasks/__fixtures__/tasks.json new file mode 100644 index 00000000000000..df4a3ea7a7e5da --- /dev/null +++ b/lib/modules/datasource/azure-pipelines-tasks/__fixtures__/tasks.json @@ -0,0 +1,575 @@ +{ + "count": 3, + "value": [ + { + "visibility": [ + "Build", + "Release" + ], + "runsOn": [ + "Agent", + "DeploymentGroup" + ], + "id": "e213ff0f-5d5c-4791-802d-52ea3e7be1f1", + "name": "PowerShell", + "version": { + "major": 2, + "minor": 247, + "patch": 1, + "isTest": false + }, + "serverOwned": true, + "contentsUploaded": true, + "iconUrl": "https://dev.azure.com/test_organization/_apis/distributedtask/tasks/e213ff0f-5d5c-4791-802d-52ea3e7be1f1/2.247.1/icon", + "minimumAgentVersion": "2.115.0", + "friendlyName": "PowerShell", + "description": "Run a PowerShell script on Linux, macOS, or Windows", + "category": "Utility", + "helpMarkDown": "[Learn more about this task](https://go.microsoft.com/fwlink/?LinkID=613736)", + "helpUrl": "https://docs.microsoft.com/azure/devops/pipelines/tasks/utility/powershell", + "releaseNotes": "Script task consistency. Added support for macOS and Linux.", + "definitionType": "task", + "showEnvironmentVariables": true, + "author": "Microsoft Corporation", + "demands": [], + "groups": [ + { + "name": "preferenceVariables", + "displayName": "Preference Variables", + "isExpanded": false + }, + { + "name": "advanced", + "displayName": "Advanced", + "isExpanded": false + } + ], + "inputs": [ + { + "options": { + "filePath": "File Path", + "inline": "Inline" + }, + "name": "targetType", + "label": "Type", + "defaultValue": "filePath", + "type": "radio", + "helpMarkDown": "Target script type: File Path or Inline" + }, + { + "name": "filePath", + "label": "Script Path", + "defaultValue": "", + "required": true, + "type": "filePath", + "helpMarkDown": "Path of the script to execute. Must be a fully qualified path or relative to $(System.DefaultWorkingDirectory).", + "visibleRule": "targetType = filePath" + }, + { + "name": "arguments", + "label": "Arguments", + "defaultValue": "", + "type": "string", + "helpMarkDown": "Arguments passed to the PowerShell script. Either ordinal parameters or named parameters.", + "visibleRule": "targetType = filePath" + }, + { + "properties": { + "resizable": "true", + "rows": "10", + "maxLength": "20000" + }, + "name": "script", + "label": "Script", + "defaultValue": "# Write your PowerShell commands here.\n\nWrite-Host \"Hello World\"\n", + "required": true, + "type": "multiLine", + "helpMarkDown": "", + "visibleRule": "targetType = inline" + }, + { + "options": { + "default": "Default", + "stop": "Stop", + "continue": "Continue", + "silentlyContinue": "SilentlyContinue" + }, + "name": "errorActionPreference", + "label": "ErrorActionPreference", + "defaultValue": "stop", + "type": "pickList", + "helpMarkDown": "When not `Default`, prepends the line `$ErrorActionPreference = 'VALUE'` at the top of your script.", + "groupName": "preferenceVariables" + }, + { + "options": { + "default": "Default", + "stop": "Stop", + "continue": "Continue", + "silentlyContinue": "SilentlyContinue" + }, + "name": "warningPreference", + "label": "WarningPreference", + "defaultValue": "default", + "type": "pickList", + "helpMarkDown": "When not `Default`, prepends the line `$WarningPreference = 'VALUE'` at the top of your script.", + "groupName": "preferenceVariables" + }, + { + "options": { + "default": "Default", + "stop": "Stop", + "continue": "Continue", + "silentlyContinue": "SilentlyContinue" + }, + "name": "informationPreference", + "label": "InformationPreference", + "defaultValue": "default", + "type": "pickList", + "helpMarkDown": "When not `Default`, prepends the line `$InformationPreference = 'VALUE'` at the top of your script.", + "groupName": "preferenceVariables" + }, + { + "options": { + "default": "Default", + "stop": "Stop", + "continue": "Continue", + "silentlyContinue": "SilentlyContinue" + }, + "name": "verbosePreference", + "label": "VerbosePreference", + "defaultValue": "default", + "type": "pickList", + "helpMarkDown": "When not `Default`, prepends the line `$VerbosePreference = 'VALUE'` at the top of your script.", + "groupName": "preferenceVariables" + }, + { + "options": { + "default": "Default", + "stop": "Stop", + "continue": "Continue", + "silentlyContinue": "SilentlyContinue" + }, + "name": "debugPreference", + "label": "DebugPreference", + "defaultValue": "default", + "type": "pickList", + "helpMarkDown": "When not `Default`, prepends the line `$DebugPreference = 'VALUE'` at the top of your script.", + "groupName": "preferenceVariables" + }, + { + "options": { + "default": "Default", + "stop": "Stop", + "continue": "Continue", + "silentlyContinue": "SilentlyContinue" + }, + "name": "progressPreference", + "label": "ProgressPreference", + "defaultValue": "silentlyContinue", + "type": "pickList", + "helpMarkDown": "When not `Default`, prepends the line `$ProgressPreference = 'VALUE'` at the top of your script.", + "groupName": "preferenceVariables" + }, + { + "name": "failOnStderr", + "label": "Fail on Standard Error", + "defaultValue": "false", + "type": "boolean", + "helpMarkDown": "If this is true, this task will fail if any errors are written to the error pipeline, or if any data is written to the Standard Error stream. Otherwise the task will rely on the exit code to determine failure.", + "groupName": "advanced" + }, + { + "name": "showWarnings", + "label": "Show warnings as Azure DevOps warnings", + "defaultValue": "false", + "type": "boolean", + "helpMarkDown": "If this is true, and your script writes a warnings - they are shown as warnings also in pipeline logs", + "groupName": "advanced" + }, + { + "name": "ignoreLASTEXITCODE", + "label": "Ignore $LASTEXITCODE", + "defaultValue": "false", + "type": "boolean", + "helpMarkDown": "If this is false, the line `if ((Test-Path -LiteralPath variable:\\LASTEXITCODE)) { exit $LASTEXITCODE }` is appended to the end of your script. This will cause the last exit code from an external command to be propagated as the exit code of powershell. Otherwise the line is not appended to the end of your script.", + "groupName": "advanced" + }, + { + "name": "pwsh", + "label": "Use PowerShell Core", + "defaultValue": "false", + "type": "boolean", + "helpMarkDown": "If this is true, then on Windows the task will use pwsh.exe from your PATH instead of powershell.exe.", + "groupName": "advanced" + }, + { + "name": "workingDirectory", + "label": "Working Directory", + "defaultValue": "", + "type": "filePath", + "helpMarkDown": "Working directory where the script is run.", + "groupName": "advanced" + }, + { + "name": "runScriptInSeparateScope", + "label": "Run script in the separate scope", + "defaultValue": "false", + "type": "boolean", + "helpMarkDown": "This input allows executing PowerShell scripts using '&' operator instead of the default '.'. If this input set to the true script will be executed in separate scope and globally scoped PowerShell variables won't be updated", + "groupName": "advanced" + } + ], + "satisfies": [], + "sourceDefinitions": [], + "dataSourceBindings": [], + "instanceNameFormat": "PowerShell Script", + "preJobExecution": {}, + "execution": { + "PowerShell3": { + "target": "powershell.ps1", + "platforms": [ + "windows" + ] + }, + "Node10": { + "target": "powershell.js", + "argumentFormat": "" + }, + "Node16": { + "target": "powershell.js", + "argumentFormat": "" + }, + "Node20_1": { + "target": "powershell.js", + "argumentFormat": "" + } + }, + "postJobExecution": {}, + "_buildConfigMapping": { + "Default": "2.247.0", + "Node20-225": "2.247.1" + } + }, + { + "visibility": [ + "Build", + "Release" + ], + "runsOn": [ + "Agent", + "DeploymentGroup" + ], + "id": "e213ff0f-5d5c-4791-802d-52ea3e7be1f1", + "name": "PowerShell", + "deprecated": true, + "version": { + "major": 1, + "minor": 2, + "patch": 3, + "isTest": false + }, + "serverOwned": true, + "contentsUploaded": true, + "iconUrl": "https://dev.azure.com/test_organization/_apis/distributedtask/tasks/e213ff0f-5d5c-4791-802d-52ea3e7be1f1/1.2.3/icon", + "minimumAgentVersion": "1.102", + "friendlyName": "PowerShell", + "description": "Run a PowerShell script", + "category": "Utility", + "helpMarkDown": "[More Information](https://go.microsoft.com/fwlink/?LinkID=613736)", + "definitionType": "task", + "author": "Microsoft Corporation", + "demands": [ + "DotNetFramework" + ], + "groups": [ + { + "name": "advanced", + "displayName": "Advanced", + "isExpanded": false + } + ], + "inputs": [ + { + "options": { + "inlineScript": "Inline Script", + "filePath": "File Path" + }, + "name": "scriptType", + "label": "Type", + "defaultValue": "filePath", + "required": true, + "type": "pickList", + "helpMarkDown": "Type of the script: File Path or Inline Script" + }, + { + "name": "scriptName", + "label": "Script Path", + "defaultValue": "", + "required": true, + "type": "filePath", + "helpMarkDown": "Path of the script to execute. Should be fully qualified path or relative to the default working directory.", + "visibleRule": "scriptType = filePath" + }, + { + "name": "arguments", + "label": "Arguments", + "defaultValue": "", + "type": "string", + "helpMarkDown": "Arguments passed to the PowerShell script. Either ordinal parameters or named parameters" + }, + { + "name": "workingFolder", + "label": "Working folder", + "defaultValue": "", + "type": "filePath", + "helpMarkDown": "Current working directory when script is run. Defaults to the folder where the script is located.", + "groupName": "advanced" + }, + { + "properties": { + "resizable": "true", + "rows": "10", + "maxLength": "500" + }, + "name": "inlineScript", + "label": "Inline Script", + "defaultValue": "# You can write your powershell scripts inline here. \n# You can also pass predefined and custom variables to this scripts using arguments\n\n Write-Host \"Hello World\"", + "required": true, + "type": "multiLine", + "helpMarkDown": "", + "visibleRule": "scriptType = inlineScript" + }, + { + "name": "failOnStandardError", + "label": "Fail on Standard Error", + "defaultValue": "true", + "type": "boolean", + "helpMarkDown": "If this is true, this task will fail if any errors are written to the error pipeline, or if any data is written to the Standard Error stream. Otherwise the task will rely solely on $LASTEXITCODE and the exit code to determine failure.", + "groupName": "advanced" + } + ], + "satisfies": [], + "sourceDefinitions": [], + "dataSourceBindings": [], + "instanceNameFormat": "PowerShell Script", + "preJobExecution": {}, + "execution": { + "PowerShellExe": { + "target": "$(scriptName)", + "argumentFormat": "$(arguments)", + "workingDirectory": "$(workingFolder)", + "inlineScript": "$(inlineScript)", + "scriptType": "$(scriptType)", + "failOnStandardError": "$(failOnStandardError)" + } + }, + "postJobExecution": {}, + "_buildConfigMapping": {} + }, + { + "visibility": [ + "Build", + "Release" + ], + "runsOn": [ + "Agent", + "DeploymentGroup" + ], + "id": "72a1931b-effb-4d2e-8fd8-f8472a07cb62", + "name": "AzurePowerShell", + "version": { + "major": 5, + "minor": 248, + "patch": 3, + "isTest": false + }, + "serverOwned": true, + "contentsUploaded": true, + "iconUrl": "https://dev.azure.com/test_organization/_apis/distributedtask/tasks/72a1931b-effb-4d2e-8fd8-f8472a07cb62/5.248.3/icon", + "minimumAgentVersion": "2.115.0", + "friendlyName": "Azure PowerShell", + "description": "Run a PowerShell script within an Azure environment", + "category": "Deploy", + "helpMarkDown": "[Learn more about this task](https://go.microsoft.com/fwlink/?LinkID=613749)", + "helpUrl": "https://aka.ms/azurepowershelltroubleshooting", + "releaseNotes": "Added support for Az Module and cross platform agents.", + "definitionType": "task", + "author": "Microsoft Corporation", + "demands": [], + "groups": [ + { + "name": "AzurePowerShellVersionOptions", + "displayName": "Azure PowerShell version options", + "isExpanded": true + }, + { + "name": "advanced", + "displayName": "Advanced", + "isExpanded": false + } + ], + "inputs": [ + { + "aliases": [ + "azureSubscription" + ], + "properties": { + "EndpointFilterRule": "ScopeLevel != AzureMLWorkspace" + }, + "name": "ConnectedServiceNameARM", + "label": "Azure Subscription", + "defaultValue": "", + "required": true, + "type": "connectedService:AzureRM", + "helpMarkDown": "Azure Resource Manager subscription to configure before running PowerShell" + }, + { + "options": { + "FilePath": "Script File Path", + "InlineScript": "Inline Script" + }, + "name": "ScriptType", + "label": "Script Type", + "defaultValue": "FilePath", + "type": "radio", + "helpMarkDown": "Type of the script: File Path or Inline Script" + }, + { + "name": "ScriptPath", + "label": "Script Path", + "defaultValue": "", + "type": "filePath", + "helpMarkDown": "Path of the script. Should be fully qualified path or relative to the default working directory.", + "visibleRule": "ScriptType = FilePath" + }, + { + "properties": { + "resizable": "true", + "rows": "10", + "maxLength": "5000" + }, + "name": "Inline", + "label": "Inline Script", + "defaultValue": "# You can write your azure powershell scripts inline here. \n# You can also pass predefined and custom variables to this script using arguments", + "type": "multiLine", + "helpMarkDown": "Enter the script to execute.", + "visibleRule": "ScriptType = InlineScript" + }, + { + "properties": { + "editorExtension": "ms.vss-services-azure.parameters-grid" + }, + "name": "ScriptArguments", + "label": "Script Arguments", + "defaultValue": "", + "type": "string", + "helpMarkDown": "Additional parameters to pass to PowerShell. Can be either ordinal or named parameters.", + "visibleRule": "ScriptType = FilePath" + }, + { + "options": { + "stop": "Stop", + "continue": "Continue", + "silentlyContinue": "SilentlyContinue" + }, + "name": "errorActionPreference", + "label": "ErrorActionPreference", + "defaultValue": "stop", + "type": "pickList", + "helpMarkDown": "Select the value of the ErrorActionPreference variable for executing the script." + }, + { + "name": "FailOnStandardError", + "label": "Fail on Standard Error", + "defaultValue": "false", + "type": "boolean", + "helpMarkDown": "If this is true, this task will fail if any errors are written to the error pipeline, or if any data is written to the Standard Error stream." + }, + { + "aliases": [ + "azurePowerShellVersion" + ], + "options": { + "LatestVersion": "Latest installed version", + "OtherVersion": "Specify other version" + }, + "name": "TargetAzurePs", + "label": "Azure PowerShell Version", + "defaultValue": "OtherVersion", + "type": "radio", + "helpMarkDown": "In case of hosted agents, the supported Azure PowerShell Version is: 1.0.0, 1.6.0, 2.3.2, 2.6.0, 3.1.0 (Hosted VS2017 Queue).\nTo pick the latest version available on the agent, select \"Latest installed version\".\n\nFor private agents you can specify preferred version of Azure PowerShell using \"Specify version\"", + "groupName": "AzurePowerShellVersionOptions" + }, + { + "aliases": [ + "preferredAzurePowerShellVersion" + ], + "name": "CustomTargetAzurePs", + "label": "Preferred Azure PowerShell Version", + "defaultValue": "", + "required": true, + "type": "string", + "helpMarkDown": "Preferred Azure PowerShell Version needs to be a proper semantic version eg. 1.2.3. Regex like 2.\\*,2.3.\\* is not supported. The Hosted VS2017 Pool currently supports Az module version: 1.0.0, 1.6.0, 2.3.2, 2.6.0, 3.1.0", + "visibleRule": "TargetAzurePs = OtherVersion", + "groupName": "AzurePowerShellVersionOptions" + }, + { + "name": "pwsh", + "label": "Use PowerShell Core", + "defaultValue": "false", + "type": "boolean", + "helpMarkDown": "If this is true, then on Windows the task will use pwsh.exe from your PATH instead of powershell.exe.", + "groupName": "advanced" + }, + { + "name": "validateScriptSignature", + "label": "Validate script signature", + "defaultValue": "false", + "type": "boolean", + "helpMarkDown": "If this is true, then the task will first check to make sure specified script is signed and valid before executing it.", + "visibleRule": "ScriptType = FilePath", + "groupName": "advanced" + }, + { + "name": "workingDirectory", + "label": "Working Directory", + "defaultValue": "", + "type": "filePath", + "helpMarkDown": "Working directory where the script is run.", + "groupName": "advanced" + } + ], + "satisfies": [], + "sourceDefinitions": [], + "dataSourceBindings": [], + "instanceNameFormat": "Azure PowerShell script: $(ScriptType)", + "preJobExecution": {}, + "execution": { + "PowerShell3": { + "target": "azurepowershell.ps1", + "platforms": [ + "windows" + ] + }, + "Node16": { + "target": "azurepowershell.js", + "argumentFormat": "" + }, + "Node10": { + "target": "azurepowershell.js", + "argumentFormat": "" + }, + "Node20_1": { + "target": "azurepowershell.js", + "argumentFormat": "" + } + }, + "postJobExecution": {}, + "_buildConfigMapping": { + "Default": "5.248.2", + "Node20_229_2": "5.248.3" + } + } + ] +} \ No newline at end of file diff --git a/lib/modules/datasource/azure-pipelines-tasks/index.spec.ts b/lib/modules/datasource/azure-pipelines-tasks/index.spec.ts index 94d15fcec1f583..94d73d131bfe46 100644 --- a/lib/modules/datasource/azure-pipelines-tasks/index.spec.ts +++ b/lib/modules/datasource/azure-pipelines-tasks/index.spec.ts @@ -1,5 +1,9 @@ import { getPkgReleases } from '..'; +import { Fixtures } from '../../../../test/fixtures'; import * as httpMock from '../../../../test/http-mock'; +import { GlobalConfig } from '../../../config/global'; +import * as hostRules from '../../../util/host-rules'; +import { AzurePipelinesTask } from './schema'; import { AzurePipelinesTasksDatasource } from '.'; const gitHubHost = 'https://raw.githubusercontent.com'; @@ -9,6 +13,11 @@ const marketplaceTasksPath = '/renovatebot/azure-devops-marketplace/main/azure-pipelines-marketplace-tasks.json'; describe('modules/datasource/azure-pipelines-tasks/index', () => { + beforeEach(() => { + GlobalConfig.reset(); + hostRules.clear(); + }); + it('returns null for unknown task', async () => { httpMock .scope(gitHubHost) @@ -64,4 +73,103 @@ describe('modules/datasource/azure-pipelines-tasks/index', () => { }), ).toEqual({ releases: [{ version: '0.171.0' }, { version: '0.198.0' }] }); }); + + it('returns organization task with single version', async () => { + GlobalConfig.set({ + platform: 'azure', + endpoint: 'https://my.custom.domain', + }); + + hostRules.add({ + hostType: AzurePipelinesTasksDatasource.id, + matchHost: 'my.custom.domain', + token: '123test', + }); + + httpMock + .scope('https://my.custom.domain') + .get('/_apis/distributedtask/tasks/') + .reply(200, Fixtures.get('tasks.json')); + + expect( + await getPkgReleases({ + datasource: AzurePipelinesTasksDatasource.id, + packageName: 'AzurePowerShell', + }), + ).toEqual({ releases: [{ version: '5.248.3' }] }); + }); + + it('returns organization task with multiple versions', async () => { + GlobalConfig.set({ + platform: 'azure', + endpoint: 'https://my.custom.domain', + }); + + hostRules.add({ + hostType: AzurePipelinesTasksDatasource.id, + matchHost: 'my.custom.domain', + token: '123test', + }); + + httpMock + .scope('https://my.custom.domain') + .get('/_apis/distributedtask/tasks/') + .reply(200, Fixtures.get('tasks.json')); + + expect( + await getPkgReleases({ + datasource: AzurePipelinesTasksDatasource.id, + packageName: 'PowerShell', + }), + ).toEqual({ + releases: [ + { isDeprecated: true, version: '1.2.3' }, + { isDeprecated: undefined, version: '2.247.1' }, + ], + }); + }); + + describe('compare semver', () => { + it.each` + a | exp + ${[]} | ${[]} + ${['']} | ${['']} + ${['', '']} | ${['', '']} + ${['1.0.0']} | ${['1.0.0']} + ${['1.0.1', '1.1.0', '1.0.0']} | ${['1.0.0', '1.0.1', '1.1.0']} + `('when versions is $a', ({ a, exp }) => { + const azureVersions = a.map((x: string) => { + const splitted = x.split('.'); + + const version = + splitted.length === 3 + ? { + major: Number(splitted[0]), + minor: Number(splitted[1]), + patch: Number(splitted[2]), + } + : null; + + return AzurePipelinesTask.parse({ + name: '', + deprecated: false, + version, + }); + }); + + const azureSortedVersions = azureVersions.sort( + AzurePipelinesTasksDatasource.compareSemanticVersions('version'), + ); + + expect( + azureSortedVersions.map((x: any) => { + const data = AzurePipelinesTask.parse(x); + + return data.version === null + ? '' + : `${data.version.major}.${data.version.minor}.${data.version.patch}`; + }), + ).toStrictEqual(exp); + }); + }); }); diff --git a/lib/modules/datasource/azure-pipelines-tasks/index.ts b/lib/modules/datasource/azure-pipelines-tasks/index.ts index db9bf125aff6ef..d7c81d19e960ea 100644 --- a/lib/modules/datasource/azure-pipelines-tasks/index.ts +++ b/lib/modules/datasource/azure-pipelines-tasks/index.ts @@ -1,7 +1,16 @@ +import type { TypeOf, ZodType } from 'zod'; +import { GlobalConfig } from '../../../config/global'; import { cache } from '../../../util/cache/package/decorator'; +import * as hostRules from '../../../util/host-rules'; +import type { HttpOptions } from '../../../util/http/types'; import { id as versioning } from '../../versioning/loose'; import { Datasource } from '../datasource'; import type { GetReleasesConfig, ReleaseResult } from '../types'; +import { + AzurePipelinesFallbackTasks, + AzurePipelinesJSON, + AzurePipelinesTaskVersion, +} from './schema'; const TASKS_URL_BASE = 'https://raw.githubusercontent.com/renovatebot/azure-devops-marketplace/main'; @@ -22,13 +31,58 @@ export class AzurePipelinesTasksDatasource extends Datasource { async getReleases({ packageName, }: GetReleasesConfig): Promise { - const versions = - (await this.getTasks(BUILT_IN_TASKS_URL))[packageName.toLowerCase()] ?? - (await this.getTasks(MARKETPLACE_TASKS_URL))[packageName.toLowerCase()]; + const platform = GlobalConfig.get('platform'); + const endpoint = GlobalConfig.get('endpoint'); + const { token } = hostRules.find({ + hostType: AzurePipelinesTasksDatasource.id, + url: endpoint, + }); - if (versions) { - const releases = versions.map((version) => ({ version })); - return { releases }; + if (platform === 'azure' && endpoint && token) { + const auth = Buffer.from(`renovate:${token}`).toString('base64'); + const opts: HttpOptions = { + headers: { authorization: `Basic ${auth}` }, + }; + const results = await this.getTasks( + `${endpoint}/_apis/distributedtask/tasks/`, + opts, + AzurePipelinesJSON, + ); + + const result: ReleaseResult = { releases: [] }; + + results.value + .filter((task) => task.name === packageName) + .sort(AzurePipelinesTasksDatasource.compareSemanticVersions('version')) + .forEach((task) => { + result.releases.push({ + version: `${task.version!.major}.${task.version!.minor}.${task.version!.patch}`, + isDeprecated: task.deprecated, + }); + }); + + return result; + } else { + const versions = + ( + await this.getTasks( + BUILT_IN_TASKS_URL, + {}, + AzurePipelinesFallbackTasks, + ) + )[packageName.toLowerCase()] ?? + ( + await this.getTasks( + MARKETPLACE_TASKS_URL, + {}, + AzurePipelinesFallbackTasks, + ) + )[packageName.toLowerCase()]; + + if (versions) { + const releases = versions.map((version) => ({ version })); + return { releases }; + } } return null; @@ -39,8 +93,39 @@ export class AzurePipelinesTasksDatasource extends Datasource { key: (url: string) => url, ttlMinutes: 24 * 60, }) - async getTasks(url: string): Promise> { - const { body } = await this.http.getJson>(url); + async getTasks( + url: string, + opts: HttpOptions, + schema: Schema, + ): Promise> { + const { body } = await this.http.getJson(url, opts, schema); return body; } + + static compareSemanticVersions = (key: string) => (a: any, b: any) => { + const a1Version = AzurePipelinesTaskVersion.safeParse(a[key]).data; + const b1Version = AzurePipelinesTaskVersion.safeParse(b[key]).data; + + const a1 = + a1Version === undefined + ? '' + : `${a1Version.major}.${a1Version.minor}.${a1Version.patch}`; + const b1 = + b1Version === undefined + ? '' + : `${b1Version.major}.${b1Version.minor}.${b1Version.patch}`; + + const len = Math.min(a1.length, b1.length); + + for (let i = 0; i < len; i++) { + const a2 = +a1[i] || 0; + const b2 = +b1[i] || 0; + + if (a2 !== b2) { + return a2 > b2 ? 1 : -1; + } + } + + return b1.length - a1.length; + }; } diff --git a/lib/modules/datasource/azure-pipelines-tasks/schema.ts b/lib/modules/datasource/azure-pipelines-tasks/schema.ts new file mode 100644 index 00000000000000..eb20bc97dd0a06 --- /dev/null +++ b/lib/modules/datasource/azure-pipelines-tasks/schema.ts @@ -0,0 +1,19 @@ +import { z } from 'zod'; + +export const AzurePipelinesTaskVersion = z.object({ + major: z.number(), + minor: z.number(), + patch: z.number(), +}); + +export const AzurePipelinesTask = z.object({ + name: z.string(), + deprecated: z.boolean().optional(), + version: AzurePipelinesTaskVersion.nullable(), +}); + +export const AzurePipelinesJSON = z.object({ + value: AzurePipelinesTask.array(), +}); + +export const AzurePipelinesFallbackTasks = z.record(z.string().array()); 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/bitrise/index.ts b/lib/modules/datasource/bitrise/index.ts index f3b2b66b838e14..5b6465797593d2 100644 --- a/lib/modules/datasource/bitrise/index.ts +++ b/lib/modules/datasource/bitrise/index.ts @@ -6,7 +6,6 @@ import { parseGitUrl } from '../../../util/git/url'; import { GithubHttp } from '../../../util/http/github'; import { fromBase64 } from '../../../util/string'; import { joinUrlParts } from '../../../util/url'; -import { parseSingleYaml } from '../../../util/yaml'; import { GithubContentResponse } from '../../platform/github/schema'; import semver from '../../versioning/semver'; import { Datasource } from '../datasource'; @@ -104,16 +103,14 @@ export class BitriseDatasource extends Datasource { } if (body.encoding !== 'base64') { logger.warn( - { data: body, url: stepUrl }, - `Got unexpected encoding for Bitrise step location '${body.encoding}'`, + { encoding: body.encoding, data: body, url: stepUrl }, + `Got unexpected encoding for Bitrise step location`, ); return null; } const content = fromBase64(body.content); - const { published_at, source_code_url } = parseSingleYaml(content, { - customSchema: BitriseStepFile, - }); + const { published_at, source_code_url } = BitriseStepFile.parse(content); result.releases.push({ version: versionDir.name, diff --git a/lib/modules/datasource/bitrise/schema.ts b/lib/modules/datasource/bitrise/schema.ts index b06b5d3c105cd0..064151a45de2cd 100644 --- a/lib/modules/datasource/bitrise/schema.ts +++ b/lib/modules/datasource/bitrise/schema.ts @@ -1,6 +1,9 @@ import { z } from 'zod'; +import { Yaml } from '../../../util/schema-utils'; -export const BitriseStepFile = z.object({ - published_at: z.string(), - source_code_url: z.string().optional(), -}); +export const BitriseStepFile = Yaml.pipe( + z.object({ + published_at: z.string(), + source_code_url: z.string().optional(), + }), +); diff --git a/lib/modules/datasource/conan/common.ts b/lib/modules/datasource/conan/common.ts index bba6a0a0213af2..fce9a20255a83a 100644 --- a/lib/modules/datasource/conan/common.ts +++ b/lib/modules/datasource/conan/common.ts @@ -6,7 +6,7 @@ export const defaultRegistryUrl = 'https://center2.conan.io/'; export const datasource = 'conan'; export const conanDatasourceRegex = regEx( - /(?[a-zA-Z\-_0-9]+)\/(?[^@/\n]+)(?@\S+\/\S+)/gim, + /^(?[a-zA-Z\-_0-9]+)\/(?[^@/\n]+)(?@\S+\/\S+)$/im, ); export function getConanPackage(packageName: string): ConanPackage { diff --git a/lib/modules/datasource/conan/index.spec.ts b/lib/modules/datasource/conan/index.spec.ts index f12ea65847e878..56c7faa5c1db71 100644 --- a/lib/modules/datasource/conan/index.spec.ts +++ b/lib/modules/datasource/conan/index.spec.ts @@ -360,6 +360,7 @@ describe('modules/datasource/conan/index', () => { version: '1.1.1', }, ], + sourceUrl: 'https://fake.conan.url.com', }); }); diff --git a/lib/modules/datasource/conan/index.ts b/lib/modules/datasource/conan/index.ts index 8ecb40124792bb..079600bd4df9e8 100644 --- a/lib/modules/datasource/conan/index.ts +++ b/lib/modules/datasource/conan/index.ts @@ -3,7 +3,6 @@ import { logger } from '../../../logger'; import { cache } from '../../../util/cache/package/decorator'; import { GithubHttp } from '../../../util/http/github'; import { ensureTrailingSlash, joinUrlParts } from '../../../util/url'; -import { parseSingleYaml } from '../../../util/yaml'; import * as allVersioning from '../../versioning'; import { Datasource } from '../datasource'; import type { @@ -13,19 +12,14 @@ import type { ReleaseResult, } from '../types'; import { isArtifactoryServer } from '../util'; +import { datasource, defaultRegistryUrl, getConanPackage } from './common'; import { - conanDatasourceRegex, - datasource, - defaultRegistryUrl, - getConanPackage, -} from './common'; -import type { + ConanCenterReleases, ConanJSON, + ConanLatestRevision, ConanProperties, ConanRevisionJSON, - ConanRevisionsJSON, - ConanYAML, -} from './types'; +} from './schema'; export class ConanDatasource extends Datasource { static readonly id = datasource; @@ -59,16 +53,12 @@ export class ConanDatasource extends Datasource { return null; } const url = `https://api.github.com/repos/conan-io/conan-center-index/contents/recipes/${conanName}/config.yml`; - const res = await this.githubHttp.get(url, { - headers: { accept: 'application/vnd.github.v3.raw' }, - }); - // TODO: use schema (#9610) - const doc = parseSingleYaml(res.body); - return { - releases: Object.keys(doc?.versions ?? {}).map((version) => ({ - version, - })), - }; + const { body: result } = await this.githubHttp.getYaml( + url, + { headers: { accept: 'application/vnd.github.v3.raw' } }, + ConanCenterReleases, + ); + return result; } @cache({ @@ -94,10 +84,11 @@ export class ConanDatasource extends Datasource { conanPackage.userAndChannel, '/revisions', ); - const revisionRep = - await this.http.getJson(revisionLookUp); - const revisions = revisionRep?.body.revisions; - return revisions?.[0].revision ?? null; + const { body: digest } = await this.http.getJson( + revisionLookUp, + ConanLatestRevision, + ); + return digest; } @cache({ @@ -135,25 +126,16 @@ export class ConanDatasource extends Datasource { ); try { - const rep = await this.http.getJson(lookupUrl); - const versions = rep?.body; - if (versions) { + const rep = await this.http.getJsonUnchecked(lookupUrl); + const conanJson = ConanJSON.parse(rep.body); + if (conanJson) { logger.trace({ lookupUrl }, 'Got conan api result'); const dep: ReleaseResult = { releases: [] }; - for (const resultString of Object.values(versions.results ?? {})) { - conanDatasourceRegex.lastIndex = 0; - const fromMatch = conanDatasourceRegex.exec(resultString); - if (fromMatch?.groups?.version && fromMatch?.groups?.userChannel) { - const version = fromMatch.groups.version; - if (fromMatch.groups.userChannel === userAndChannel) { - const result: Release = { - version, - }; - dep.releases.push(result); - } - } - } + const conanJsonReleases: Release[] = conanJson + .filter(({ userChannel }) => userChannel === userAndChannel) + .map(({ version }) => ({ version })); + dep.releases.push(...conanJsonReleases); try { if (isArtifactoryServer(rep)) { @@ -182,25 +164,22 @@ export class ConanDatasource extends Datasource { url, `v2/conans/${conanPackage.conanName}/${latestVersion}/${conanPackage.userAndChannel}/latest`, ); - const revResp = - await this.http.getJson(latestRevisionUrl); - const packageRev = revResp.body.revision; + const { + body: { revision: packageRev }, + } = await this.http.getJson(latestRevisionUrl, ConanRevisionJSON); const [user, channel] = conanPackage.userAndChannel.split('/'); const packageUrl = joinUrlParts( `${groups.host}/artifactory/api/storage/${groups.repo}`, `${user}/${conanPackage.conanName}/${latestVersion}/${channel}/${packageRev}/export/conanfile.py?properties=conan.package.url`, ); - const packageUrlResp = - await this.http.getJson(packageUrl); - - if ( - packageUrlResp.body.properties && - 'conan.package.url' in packageUrlResp.body.properties - ) { - const conanPackageUrl = - packageUrlResp.body.properties['conan.package.url'][0]; - dep.sourceUrl = conanPackageUrl; + const { body: conanProperties } = await this.http.getJson( + packageUrl, + ConanProperties, + ); + const { sourceUrl } = conanProperties; + if (sourceUrl) { + dep.sourceUrl = sourceUrl; } } } catch (err) { diff --git a/lib/modules/datasource/conan/schema.ts b/lib/modules/datasource/conan/schema.ts new file mode 100644 index 00000000000000..c13ec77b8c845f --- /dev/null +++ b/lib/modules/datasource/conan/schema.ts @@ -0,0 +1,65 @@ +import { z } from 'zod'; +import { LooseArray } from '../../../util/schema-utils'; +import type { ReleaseResult } from '../types'; +import { conanDatasourceRegex } from './common'; + +export const ConanCenterReleases = z + .object({ + versions: z.record(z.string(), z.unknown()), + }) + .transform( + ({ versions }): ReleaseResult => ({ + releases: Object.keys(versions).map((version) => ({ version })), + }), + ) + .nullable() + .catch(null); + +export const ConanJSON = z + .object({ + results: z + .string() + .array() + .transform((array) => + array.map((val) => val.match(conanDatasourceRegex)?.groups), + ) + .pipe( + LooseArray( + z.object({ + name: z.string(), + version: z.string(), + userChannel: z.string(), + }), + ), + ), + }) + .transform(({ results }) => results) + .nullable() + .catch(null); + +export const ConanRevisionJSON = z.object({ + revision: z.string(), + time: z.string(), +}); + +export const ConanLatestRevision = z + .object({ revisions: z.unknown().array() }) + .transform(({ revisions }) => revisions[0]) + .pipe(ConanRevisionJSON) + .transform(({ revision }) => revision) + .nullable() + .catch(null); + +export const ConanProperties = z + .object({ + properties: z.object({ + 'conan.package.url': z.union([ + z.string().transform((url) => [url]), + z.string().array(), + ]), + }), + }) + .transform(({ properties }) => { + const sourceUrl = properties['conan.package.url'][0]; + return { sourceUrl }; + }); diff --git a/lib/modules/datasource/conan/types.ts b/lib/modules/datasource/conan/types.ts index bb65481f5015f8..18dda2e72854d1 100644 --- a/lib/modules/datasource/conan/types.ts +++ b/lib/modules/datasource/conan/types.ts @@ -1,35 +1,4 @@ -export interface ConanJSON { - results?: Record; -} - -export interface ConanRevisionJSON { - revision: string; - time: string; -} - -export interface ConanRevisionsJSON { - revisions?: Record; -} - -export interface ConanYAML { - versions?: Record; -} - export interface ConanPackage { conanName: string; userAndChannel: string; } - -export interface ConanRecipeProperties { - 'conan.package.channel': string[]; - 'conan.package.license': string[]; - 'conan.package.name': string[]; - 'conan.package.url': string[]; - 'conan.package.user': string[]; - 'conan.package.version': string[]; -} - -export interface ConanProperties { - properties: ConanRecipeProperties; - uri: string; -} 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/deb/index.ts b/lib/modules/datasource/deb/index.ts index ad29d107df4977..192bc6fdb25910 100644 --- a/lib/modules/datasource/deb/index.ts +++ b/lib/modules/datasource/deb/index.ts @@ -90,13 +90,14 @@ export class DebDatasource extends Datasource { await extract(compressedFile, compression, extractedFile); lastTimestamp = await getFileCreationTime(extractedFile); } catch (error) { - logger.error( + logger.warn( { + compressedFile, componentUrl, compression, error: error.message, }, - `Failed to extract package file from ${compressedFile}`, + 'Failed to extract package file from compressed file', ); } finally { await fs.rmCache(compressedFile); @@ -213,7 +214,8 @@ export class DebDatasource extends Datasource { return response.statusCode !== 304; } catch (error) { logger.warn( - `Could not determine if ${packageUrl} is modified since ${lastDownloadTimestamp.toUTCString()}: ${error.message}`, + { packageUrl, lastDownloadTimestamp, errorMessage: error.message }, + 'Could not determine if package file is modified since last download', ); return true; // Assume it needs to be downloaded if check fails } diff --git a/lib/modules/datasource/deno/index.spec.ts b/lib/modules/datasource/deno/index.spec.ts index a720572b7cf566..9554fc28aa279d 100644 --- a/lib/modules/datasource/deno/index.spec.ts +++ b/lib/modules/datasource/deno/index.spec.ts @@ -66,8 +66,9 @@ describe('modules/datasource/deno/index', () => { expect(logger.logger.warn).toHaveBeenCalledWith( expect.objectContaining({ err: expect.any(ZodError), + version: '0.161.0', }), - `Deno: failed to get version details for 0.161.0`, + 'Deno: failed to get version details', ); }); diff --git a/lib/modules/datasource/deno/index.ts b/lib/modules/datasource/deno/index.ts index e9ca1cca0527e2..c2178451eba9dd 100644 --- a/lib/modules/datasource/deno/index.ts +++ b/lib/modules/datasource/deno/index.ts @@ -102,8 +102,8 @@ export class DenoDatasource extends Datasource { url, DenoAPIModuleVersionResponse.catch(({ error: err }) => { logger.warn( - { err }, - `Deno: failed to get version details for ${version}`, + { err, version }, + 'Deno: failed to get version details', ); return { version }; }), diff --git a/lib/modules/datasource/devbox/common.ts b/lib/modules/datasource/devbox/common.ts new file mode 100644 index 00000000000000..9149c754171e9a --- /dev/null +++ b/lib/modules/datasource/devbox/common.ts @@ -0,0 +1,3 @@ +export const defaultRegistryUrl = 'https://search.devbox.sh/v2/'; + +export const datasource = 'devbox'; diff --git a/lib/modules/datasource/devbox/index.spec.ts b/lib/modules/datasource/devbox/index.spec.ts new file mode 100644 index 00000000000000..5b525a34d9c0b8 --- /dev/null +++ b/lib/modules/datasource/devbox/index.spec.ts @@ -0,0 +1,159 @@ +import { getPkgReleases } from '..'; +import * as httpMock from '../../../../test/http-mock'; +import { EXTERNAL_HOST_ERROR } from '../../../constants/error-messages'; +import { datasource, defaultRegistryUrl } from './common'; + +const packageName = 'nodejs'; + +function getPath(packageName: string): string { + return `/pkg?name=${encodeURIComponent(packageName)}`; +} + +const sampleReleases = [ + { + version: '22.2.0', + last_updated: '2024-05-22T06:18:38Z', + }, + { + version: '22.0.0', + last_updated: '2024-05-12T16:19:40Z', + }, + { + version: '21.7.3', + last_updated: '2024-04-19T21:36:04Z', + }, +]; + +describe('modules/datasource/devbox/index', () => { + describe('getReleases', () => { + it('throws for error', async () => { + httpMock + .scope(defaultRegistryUrl) + .get(getPath(packageName)) + .replyWithError('error'); + await expect( + getPkgReleases({ + datasource, + packageName, + }), + ).rejects.toThrow(EXTERNAL_HOST_ERROR); + }); + }); + + it('returns null for 404', async () => { + httpMock.scope(defaultRegistryUrl).get(getPath(packageName)).reply(404); + expect( + await getPkgReleases({ + datasource, + packageName, + }), + ).toBeNull(); + }); + + it('returns null for empty result', async () => { + httpMock.scope(defaultRegistryUrl).get(getPath(packageName)).reply(200, {}); + expect( + await getPkgReleases({ + datasource, + packageName, + }), + ).toBeNull(); + }); + + it('returns null for empty 200 OK', async () => { + httpMock + .scope(defaultRegistryUrl) + .get(getPath(packageName)) + .reply(200, { versions: [] }); + expect( + await getPkgReleases({ + datasource, + packageName, + }), + ).toBeNull(); + }); + + it('throws for 5xx', async () => { + httpMock.scope(defaultRegistryUrl).get(getPath(packageName)).reply(502); + await expect( + getPkgReleases({ + datasource, + packageName, + }), + ).rejects.toThrow(EXTERNAL_HOST_ERROR); + }); + + it('processes real data', async () => { + httpMock.scope(defaultRegistryUrl).get(getPath(packageName)).reply(200, { + name: 'nodejs', + summary: 'Event-driven I/O framework for the V8 JavaScript engine', + homepage_url: 'https://nodejs.org', + license: 'MIT', + releases: sampleReleases, + }); + const res = await getPkgReleases({ + datasource, + packageName, + }); + expect(res).toEqual({ + homepage: 'https://nodejs.org', + registryUrl: 'https://search.devbox.sh/v2', + releases: [ + { + version: '21.7.3', + releaseTimestamp: '2024-04-19T21:36:04.000Z', + }, + { + version: '22.0.0', + releaseTimestamp: '2024-05-12T16:19:40.000Z', + }, + { + version: '22.2.0', + releaseTimestamp: '2024-05-22T06:18:38.000Z', + }, + ], + }); + }); + + it('processes empty data', async () => { + httpMock.scope(defaultRegistryUrl).get(getPath(packageName)).reply(200, { + name: 'nodejs', + summary: 'Event-driven I/O framework for the V8 JavaScript engine', + homepage_url: 'https://nodejs.org', + license: 'MIT', + releases: [], + }); + const res = await getPkgReleases({ + datasource, + packageName, + }); + expect(res).toBeNull(); + }); + + it('returns null when no body is returned', async () => { + httpMock + .scope(defaultRegistryUrl) + .get(getPath(packageName)) + .reply(200, undefined); + const res = await getPkgReleases({ + datasource, + packageName, + }); + expect(res).toBeNull(); + }); + + it('falls back to a default homepage_url', async () => { + httpMock.scope(defaultRegistryUrl).get(getPath(packageName)).reply(200, { + name: 'nodejs', + summary: 'Event-driven I/O framework for the V8 JavaScript engine', + homepage_url: undefined, + license: 'MIT', + releases: sampleReleases, + }); + const res = await getPkgReleases({ + datasource, + packageName, + }); + expect(res?.homepage).toBeUndefined(); + }); +}); diff --git a/lib/modules/datasource/devbox/index.ts b/lib/modules/datasource/devbox/index.ts new file mode 100644 index 00000000000000..be89dced54ee8f --- /dev/null +++ b/lib/modules/datasource/devbox/index.ts @@ -0,0 +1,57 @@ +import { logger } from '../../../logger'; +import { ExternalHostError } from '../../../types/errors/external-host-error'; +import { HttpError } from '../../../util/http'; +import { joinUrlParts } from '../../../util/url'; +import * as devboxVersioning from '../../versioning/devbox'; +import { Datasource } from '../datasource'; +import type { GetReleasesConfig, ReleaseResult } from '../types'; +import { datasource, defaultRegistryUrl } from './common'; +import { DevboxResponse } from './schema'; + +export class DevboxDatasource extends Datasource { + static readonly id = datasource; + + constructor() { + super(datasource); + } + + override readonly customRegistrySupport = true; + override readonly releaseTimestampSupport = true; + + override readonly registryStrategy = 'first'; + + override readonly defaultVersioning = devboxVersioning.id; + + override readonly defaultRegistryUrls = [defaultRegistryUrl]; + + async getReleases({ + registryUrl, + packageName, + }: GetReleasesConfig): Promise { + const res: ReleaseResult = { + releases: [], + }; + + logger.trace({ registryUrl, packageName }, 'fetching devbox release'); + + const devboxPkgUrl = joinUrlParts( + registryUrl!, + `/pkg?name=${encodeURIComponent(packageName)}`, + ); + + try { + const response = await this.http.getJson(devboxPkgUrl, DevboxResponse); + res.releases = response.body.releases; + res.homepage = response.body.homepage; + } catch (err) { + // istanbul ignore else: not testable with nock + if (err instanceof HttpError) { + if (err.response?.statusCode !== 404) { + throw new ExternalHostError(err); + } + } + this.handleGenericErrors(err); + } + return res.releases.length ? res : null; + } +} diff --git a/lib/modules/datasource/devbox/schema.ts b/lib/modules/datasource/devbox/schema.ts new file mode 100644 index 00000000000000..bc31efae879850 --- /dev/null +++ b/lib/modules/datasource/devbox/schema.ts @@ -0,0 +1,23 @@ +import { z } from 'zod'; + +export const DevboxRelease = z.object({ + version: z.string(), + last_updated: z.string(), +}); + +export const DevboxResponse = z + .object({ + name: z.string(), + summary: z.string().optional(), + homepage_url: z.string().optional(), + license: z.string().optional(), + releases: DevboxRelease.array(), + }) + .transform((response) => ({ + name: response.name, + homepage: response.homepage_url, + releases: response.releases.map((release) => ({ + version: release.version, + releaseTimestamp: release.last_updated, + })), + })); 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.spec.ts b/lib/modules/datasource/docker/index.spec.ts index 68096768f24baf..768dacc88d61b4 100644 --- a/lib/modules/datasource/docker/index.spec.ts +++ b/lib/modules/datasource/docker/index.spec.ts @@ -98,10 +98,13 @@ describe('modules/datasource/docker/index', () => { .reply(200, { token: 'some-token' }); hostRules.find.mockReturnValue({}); - const res = await getDigest({ - datasource: 'docker', - packageName: 'some-dep', - }); + const res = await getDigest( + { + datasource: 'docker', + packageName: 'some-dep', + }, + '', + ); expect(res).toBe('some-digest'); }); diff --git a/lib/modules/datasource/docker/index.ts b/lib/modules/datasource/docker/index.ts index b6082a6455ef31..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, }); @@ -831,7 +831,7 @@ export class DockerDatasource extends Datasource { // TODO: types (#22198) `getDigest(${registryHost}, ${dockerRepository}, ${newValue})`, ); - const newTag = newValue ?? 'latest'; + const newTag = is.nonEmptyString(newValue) ? newValue : 'latest'; let digest: string | null = null; try { let architecture: string | null | undefined = null; 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-collection/index.ts b/lib/modules/datasource/galaxy-collection/index.ts index ffd91268ea96d8..bfafa69db2b63d 100644 --- a/lib/modules/datasource/galaxy-collection/index.ts +++ b/lib/modules/datasource/galaxy-collection/index.ts @@ -65,8 +65,8 @@ export class GalaxyCollectionDatasource extends Datasource { .getJsonSafe(baseUrl, GalaxyV3) .onError((err) => { logger.warn( - { datasource: this.id, packageName, err }, - `Error fetching ${baseUrl}`, + { url: baseUrl, datasource: this.id, packageName, err }, + 'Error fetching from url', ); }) .unwrap(); @@ -80,8 +80,8 @@ export class GalaxyCollectionDatasource extends Datasource { .getJsonSafe(versionsUrl, GalaxyV3Versions) .onError((err) => { logger.warn( - { datasource: this.id, packageName, err }, - `Error fetching ${versionsUrl}`, + { url: versionsUrl, datasource: this.id, packageName, err }, + 'Error fetching from url', ); }) .unwrap(); @@ -136,8 +136,8 @@ export class GalaxyCollectionDatasource extends Datasource { .getJsonSafe(detailedVersionUrl, GalaxyV3DetailedVersion) .onError((err) => { logger.warn( - { datasource: this.id, packageName, err }, - `Error fetching ${versionsUrl}`, + { url: versionsUrl, datasource: this.id, packageName, err }, + 'Error fetching from url', ); }) .unwrap(); diff --git a/lib/modules/datasource/galaxy/index.ts b/lib/modules/datasource/galaxy/index.ts index a0a01011c53241..cae51402213a80 100644 --- a/lib/modules/datasource/galaxy/index.ts +++ b/lib/modules/datasource/galaxy/index.ts @@ -57,15 +57,14 @@ export class GalaxyDatasource extends Datasource { if (!body.results.length) { logger.warn( { dependency: packageName, userName }, - `Multiple results from galaxy for ${packageName}, none match`, + `No matching result from galaxy for package`, ); return null; } } 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/glasskube-packages/index.ts b/lib/modules/datasource/glasskube-packages/index.ts index a289e79682dfa5..f36daeb381bf14 100644 --- a/lib/modules/datasource/glasskube-packages/index.ts +++ b/lib/modules/datasource/glasskube-packages/index.ts @@ -3,11 +3,7 @@ import { joinUrlParts } from '../../../util/url'; import * as glasskubeVersioning from '../../versioning/glasskube'; import { Datasource } from '../datasource'; import type { GetReleasesConfig, ReleaseResult } from '../types'; -import type { GlasskubePackageVersions } from './schema'; -import { - GlasskubePackageManifestYaml, - GlasskubePackageVersionsYaml, -} from './schema'; +import { GlasskubePackageManifest, GlasskubePackageVersions } from './schema'; export class GlasskubePackagesDatasource extends Datasource { static readonly id = 'glasskube-packages'; @@ -33,16 +29,17 @@ export class GlasskubePackagesDatasource extends Datasource { packageName, registryUrl, }: GetReleasesConfig): Promise { - let versions: GlasskubePackageVersions; const result: ReleaseResult = { releases: [] }; - try { - const response = await this.http.get( + const { val: versions, err: versionsErr } = await this.http + .getYamlSafe( joinUrlParts(registryUrl!, packageName, 'versions.yaml'), - ); - versions = GlasskubePackageVersionsYaml.parse(response.body); - } catch (err) { - this.handleGenericErrors(err); + GlasskubePackageVersions, + ) + .unwrap(); + + if (versionsErr) { + this.handleGenericErrors(versionsErr); } result.releases = versions.versions.map((it) => ({ @@ -50,25 +47,28 @@ export class GlasskubePackagesDatasource extends Datasource { })); result.tags = { latest: versions.latestVersion }; - try { - const response = await this.http.get( + const { val: latestManifest, err: latestManifestErr } = await this.http + .getYamlSafe( joinUrlParts( registryUrl!, packageName, versions.latestVersion, 'package.yaml', ), - ); - const latestManifest = GlasskubePackageManifestYaml.parse(response.body); - for (const ref of latestManifest?.references ?? []) { - if (ref.label.toLowerCase() === 'github') { - result.sourceUrl = ref.url; - } else if (ref.label.toLowerCase() === 'website') { - result.homepage = ref.url; - } + GlasskubePackageManifest, + ) + .unwrap(); + + if (latestManifestErr) { + this.handleGenericErrors(latestManifestErr); + } + + for (const ref of latestManifest?.references ?? []) { + if (ref.label.toLowerCase() === 'github') { + result.sourceUrl = ref.url; + } else if (ref.label.toLowerCase() === 'website') { + result.homepage = ref.url; } - } catch (err) { - this.handleGenericErrors(err); } return result; diff --git a/lib/modules/datasource/glasskube-packages/schema.ts b/lib/modules/datasource/glasskube-packages/schema.ts index 5e299304b4104f..e459912c14bfb4 100644 --- a/lib/modules/datasource/glasskube-packages/schema.ts +++ b/lib/modules/datasource/glasskube-packages/schema.ts @@ -1,12 +1,11 @@ import { z } from 'zod'; -import { Yaml } from '../../../util/schema-utils'; -const GlasskubePackageVersions = z.object({ +export const GlasskubePackageVersions = z.object({ latestVersion: z.string(), versions: z.array(z.object({ version: z.string() })), }); -const GlasskubePackageManifest = z.object({ +export const GlasskubePackageManifest = z.object({ references: z.optional( z.array( z.object({ @@ -16,8 +15,3 @@ const GlasskubePackageManifest = z.object({ ), ), }); - -export const GlasskubePackageVersionsYaml = Yaml.pipe(GlasskubePackageVersions); -export const GlasskubePackageManifestYaml = Yaml.pipe(GlasskubePackageManifest); - -export type GlasskubePackageVersions = z.infer; 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/hex/index.ts b/lib/modules/datasource/hex/index.ts index ebf03fbfb47089..35c63c0802f6e2 100644 --- a/lib/modules/datasource/hex/index.ts +++ b/lib/modules/datasource/hex/index.ts @@ -55,7 +55,10 @@ export class HexDatasource extends Datasource { const { val: result, err } = await this.http .getJsonSafe(hexUrl, HexRelease) .onError((err) => { - logger.warn({ datasource: 'hex', packageName, err }, `Error fetching ${hexUrl}`); // prettier-ignore + logger.warn( + { url: hexUrl, datasource: 'hex', packageName, err }, + 'Error fetching from url', + ); }) .unwrap(); diff --git a/lib/modules/datasource/index.ts b/lib/modules/datasource/index.ts index 8fa5355a125ceb..fec86165a9c690 100644 --- a/lib/modules/datasource/index.ts +++ b/lib/modules/datasource/index.ts @@ -287,7 +287,7 @@ async function fetchReleases( let { registryUrls } = config; // istanbul ignore if: need test if (!datasourceName || getDatasourceFor(datasourceName) === undefined) { - logger.warn('Unknown datasource: ' + datasourceName); + logger.warn({ datasource: datasourceName }, 'Unknown datasource'); return null; } if (datasourceName === 'npm') { 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 1edc357068e5cd..696836fd41f913 100644 --- a/lib/modules/datasource/maven/util.ts +++ b/lib/modules/datasource/maven/util.ts @@ -12,8 +12,8 @@ import { Result } from '../../../util/result'; import type { S3UrlParts } from '../../../util/s3'; import { getS3Client, parseS3Url } from '../../../util/s3'; import { streamToString } from '../../../util/streams'; +import { asTimestamp } from '../../../util/timestamp'; import { ensureTrailingSlash, parseUrl } from '../../../util/url'; -import { normalizeDate } from '../metadata'; import { getGoogleAuthToken } from '../util'; import { MAVEN_REPO } from './common'; import type { @@ -83,7 +83,7 @@ export async function downloadHttpProtocol( result.isCacheable = true; } - const lastModified = normalizeDate(res?.headers?.['last-modified']); + const lastModified = asTimestamp(res?.headers?.['last-modified']); if (lastModified) { result.lastModified = lastModified; } @@ -203,7 +203,7 @@ export async function downloadS3Protocol( const data = await streamToString(Body); const result: MavenFetchSuccess = { data }; - const lastModified = normalizeDate(LastModified); + const lastModified = asTimestamp(LastModified); if (lastModified) { result.lastModified = lastModified; } @@ -276,7 +276,7 @@ async function checkHttpResource( const res = await http.head(pkgUrl.toString()); const timestamp = res?.headers?.['last-modified']; if (timestamp) { - const isoTimestamp = normalizeDate(timestamp); + const isoTimestamp = asTimestamp(timestamp); if (isoTimestamp) { const releaseDate = DateTime.fromISO(isoTimestamp, { zone: 'UTC', @@ -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/metadata.spec.ts b/lib/modules/datasource/metadata.spec.ts index 0b49c803ce8db8..645d270f98ae1b 100644 --- a/lib/modules/datasource/metadata.spec.ts +++ b/lib/modules/datasource/metadata.spec.ts @@ -5,7 +5,6 @@ import { addMetaData, massageGithubUrl, massageUrl, - normalizeDate, shouldDeleteHomepage, } from './metadata'; import { NpmDatasource } from './npm'; @@ -521,23 +520,4 @@ describe('modules/datasource/metadata', () => { sourceUrl: 'https://github.com/flyingcircusio/pycountry', }); }); - - describe('normalizeDate()', () => { - it('works for number input', () => { - const now = Date.now(); - expect(normalizeDate(now)).toBe(new Date(now).toISOString()); - }); - - it('works for string input', () => { - expect(normalizeDate('2021-01-01')).toBe( - new Date('2021-01-01').toISOString(), - ); - }); - - it('works for Date instance', () => { - expect(normalizeDate(new Date('2021-01-01'))).toBe( - new Date('2021-01-01').toISOString(), - ); - }); - }); }); diff --git a/lib/modules/datasource/metadata.ts b/lib/modules/datasource/metadata.ts index 8f6fd5fc56f5cf..6fe5efa54a465a 100644 --- a/lib/modules/datasource/metadata.ts +++ b/lib/modules/datasource/metadata.ts @@ -1,10 +1,10 @@ import is from '@sindresorhus/is'; import parse from 'github-url-from-git'; -import { DateTime } from 'luxon'; import { detectPlatform } from '../../util/common'; import { parseGitUrl } from '../../util/git/url'; import * as hostRules from '../../util/host-rules'; import { regEx } from '../../util/regex'; +import { asTimestamp } from '../../util/timestamp'; import { isHttpUrl, parseUrl, trimTrailingSlash } from '../../util/url'; import { manualChangelogUrls, manualSourceUrls } from './metadata-manual'; import type { ReleaseResult } from './types'; @@ -64,56 +64,11 @@ function massageGitAtUrl(url: string): string { return massagedUrl; } -export function normalizeDate(input: any): string | null { - if ( - typeof input === 'number' && - !Number.isNaN(input) && - input > 0 && - input <= Date.now() + 24 * 60 * 60 * 1000 - ) { - return new Date(input).toISOString(); - } - - if (typeof input === 'string') { - // `Date.parse()` is more permissive, but it assumes local time zone - // for inputs like `2021-01-01`. - // - // Here we try to parse with default UTC with fallback to `Date.parse()`. - // - // It allows us not to care about machine timezones so much, though - // some misinterpretation is still possible, but only if both: - // - // 1. Renovate machine is configured for non-UTC zone - // 2. Format of `input` is very exotic - // (from `DateTime.fromISO()` perspective) - // - - let luxonDate = DateTime.fromISO(input, { zone: 'UTC' }); - if (luxonDate.isValid) { - return luxonDate.toISO(); - } - luxonDate = DateTime.fromFormat(input, 'yyyyMMddHHmmss', { - zone: 'UTC', - }); - if (luxonDate.isValid) { - return luxonDate.toISO(); - } - - return normalizeDate(Date.parse(input)); - } - - if (input instanceof Date) { - return input.toISOString(); - } - - return null; -} - function massageTimestamps(dep: ReleaseResult): void { for (const release of dep.releases || []) { let { releaseTimestamp } = release; delete release.releaseTimestamp; - releaseTimestamp = normalizeDate(releaseTimestamp); + releaseTimestamp = asTimestamp(releaseTimestamp); if (releaseTimestamp) { release.releaseTimestamp = releaseTimestamp; } 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/npm/npmrc.ts b/lib/modules/datasource/npm/npmrc.ts index 086bb07338bfe5..5129f50ea82a8d 100644 --- a/lib/modules/datasource/npm/npmrc.ts +++ b/lib/modules/datasource/npm/npmrc.ts @@ -26,7 +26,7 @@ function envReplace(value: any, env = process.env): any { return value.replace(ENV_EXPR, (match, _esc, envVarName) => { if (env[envVarName] === undefined) { - logger.warn('Failed to replace env in config: ' + match); + logger.warn({ match }, 'Failed to replace env in config'); throw new Error('env-replace'); } return env[envVarName]; diff --git a/lib/modules/datasource/nuget/__snapshots__/index.spec.ts.snap b/lib/modules/datasource/nuget/__snapshots__/index.spec.ts.snap index e668b57267e71e..9b1702cc94ed93 100644 --- a/lib/modules/datasource/nuget/__snapshots__/index.spec.ts.snap +++ b/lib/modules/datasource/nuget/__snapshots__/index.spec.ts.snap @@ -34,7 +34,6 @@ exports[`modules/datasource/nuget/index getReleases processes real data (v2) 1`] "version": "2.5.10.11092", }, { - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "2.6.0.12051", }, { @@ -228,7 +227,6 @@ exports[`modules/datasource/nuget/index getReleases processes real data (v3) fee }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "2.6.0.12051", }, { @@ -418,7 +416,6 @@ exports[`modules/datasource/nuget/index getReleases processes real data (v3) fee }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "2.6.0.12051", }, { @@ -604,12 +601,10 @@ exports[`modules/datasource/nuget/index getReleases processes real data (v3) for }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "2.0.1", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "2.0.1.1", }, { @@ -638,7 +633,6 @@ exports[`modules/datasource/nuget/index getReleases processes real data (v3) for }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.0.0-rc", }, { @@ -651,12 +645,10 @@ exports[`modules/datasource/nuget/index getReleases processes real data (v3) for }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.1.0-alpha1", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.1.0-rc1", }, { @@ -665,7 +657,6 @@ exports[`modules/datasource/nuget/index getReleases processes real data (v3) for }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.1.1-rc1", }, { @@ -678,7 +669,6 @@ exports[`modules/datasource/nuget/index getReleases processes real data (v3) for }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.2.0-rc1", }, { @@ -687,7 +677,6 @@ exports[`modules/datasource/nuget/index getReleases processes real data (v3) for }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.2.1-rc1", }, { @@ -704,52 +693,42 @@ exports[`modules/datasource/nuget/index getReleases processes real data (v3) for }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.3.0-alpha1", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.3.0-alpha2", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.3.0-alpha3", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.3.0-alpha4", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.3.0-beta1", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.3.0-beta2", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.3.0-beta3", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.3.0-rc1", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.3.0-rc2", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.3.0-rc3", }, { @@ -758,7 +737,6 @@ exports[`modules/datasource/nuget/index getReleases processes real data (v3) for }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.3.1-rc1", }, { @@ -779,7 +757,6 @@ exports[`modules/datasource/nuget/index getReleases processes real data (v3) for }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.3.5-alpha1", }, { @@ -800,7 +777,6 @@ exports[`modules/datasource/nuget/index getReleases processes real data (v3) for }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.3.9-test-retry-archive", }, { @@ -817,112 +793,90 @@ exports[`modules/datasource/nuget/index getReleases processes real data (v3) for }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.4.0-alpha1", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.4.0-alpha2", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.4.0-alpha3", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.4.0-alpha4", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.4.0-beta-14", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.4.0-beta1", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.4.0-beta10", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.4.0-beta11", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.4.0-beta12", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.4.0-beta13", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.4.0-beta2", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.4.0-beta3", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.4.0-beta4", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.4.0-beta5", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.4.0-beta6", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.4.0-beta7", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.4.0-beta8", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.4.0-beta9", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.4.0-betaV14", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.4.0-betaV15", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.4.0-rc1", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.4.0-rc2", }, { @@ -931,12 +885,10 @@ exports[`modules/datasource/nuget/index getReleases processes real data (v3) for }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.4.1-dev-b4084", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.4.1-dev-b4085", }, { @@ -945,12 +897,10 @@ exports[`modules/datasource/nuget/index getReleases processes real data (v3) for }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.4.2-rc1", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.4.2-rc2", }, { @@ -967,7 +917,6 @@ exports[`modules/datasource/nuget/index getReleases processes real data (v3) for }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.4.5-beta1", }, { @@ -976,22 +925,18 @@ exports[`modules/datasource/nuget/index getReleases processes real data (v3) for }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.4.6-beta1", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.4.6-beta2", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.4.6-beta3", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.4.6-rc1", }, { @@ -1028,97 +973,78 @@ exports[`modules/datasource/nuget/index getReleases processes real data (v3) for }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.5.0-alpha01", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.5.0-alpha02", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.5.0-alpha03", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.5.0-alpha04", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.5.0-beta01", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.5.0-beta02", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.5.0-beta03", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.5.0-beta04", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.5.0-beta05", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.5.0-beta06", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.5.0-beta07", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.5.0-beta08", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.5.0-rc01", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.5.0-rc02", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.5.0-rc03", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.5.0-rc04", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.5.0-rc05", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.5.0-rc06", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.5.0-rc07", }, { @@ -1171,17 +1097,14 @@ exports[`modules/datasource/nuget/index getReleases processes real data (v3) for }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.6.0-rc1", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.6.0-rc2", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.6.0-rc3", }, { @@ -1222,7 +1145,6 @@ exports[`modules/datasource/nuget/index getReleases processes real data (v3) for }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "4.7.0-rc1", }, { @@ -1243,67 +1165,54 @@ exports[`modules/datasource/nuget/index getReleases processes real data (v3) for }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "5.0.0-beta01", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "5.0.0-beta02", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "5.0.0-beta03", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "5.0.0-beta03-tryoutMutex", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "5.0.0-beta04", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "5.0.0-beta05", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "5.0.0-beta05-test", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "5.0.0-beta06", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "5.0.0-beta07", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "5.0.0-beta08", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "5.0.0-beta09", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "5.0.0-beta10", }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "5.0.0-beta11", }, ], @@ -1329,7 +1238,6 @@ exports[`modules/datasource/nuget/index getReleases processes real data (v3) nus }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "2.6.0.12051", }, { @@ -1519,7 +1427,6 @@ exports[`modules/datasource/nuget/index getReleases processes real data (v3) nus }, { "isDeprecated": true, - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "2.6.0.12051", }, { @@ -1868,7 +1775,6 @@ exports[`modules/datasource/nuget/index getReleases returns deduplicated results { "isDeprecated": true, "registryUrl": "https://api.nuget.org/v3/index.json", - "releaseTimestamp": "1900-01-01T00:00:00.000Z", "version": "2.6.0.12051", }, { 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/datasource/util.ts b/lib/modules/datasource/util.ts index b418bb9bb7c560..e53566d786f63f 100644 --- a/lib/modules/datasource/util.ts +++ b/lib/modules/datasource/util.ts @@ -1,6 +1,7 @@ import is from '@sindresorhus/is'; import { GoogleAuth } from 'google-auth-library'; import { logger } from '../../logger'; +import type { HostRule } from '../../types'; import type { HttpResponse } from '../../util/http/types'; import { addSecretForSanitizing } from '../../util/sanitize'; @@ -12,7 +13,7 @@ export function isArtifactoryServer( return is.string(res?.headers[JFROG_ARTIFACTORY_RES_HEADER]); } -export async function getGoogleAuthTokenRaw(): Promise { +export async function getGoogleAuthHostRule(): Promise { try { const googleAuth: GoogleAuth = new GoogleAuth({ scopes: 'https://www.googleapis.com/auth/cloud-platform', @@ -21,7 +22,10 @@ export async function getGoogleAuthTokenRaw(): Promise { if (accessToken) { // sanitize token addSecretForSanitizing(accessToken); - return accessToken; + return { + username: 'oauth2accesstoken', + password: accessToken, + }; } else { logger.warn( 'Could not retrieve access token using google-auth-library getAccessToken', @@ -38,9 +42,13 @@ export async function getGoogleAuthTokenRaw(): Promise { } export async function getGoogleAuthToken(): Promise { - const accessToken = await getGoogleAuthTokenRaw(); - if (accessToken) { - return Buffer.from(`oauth2accesstoken:${accessToken}`).toString('base64'); + const rule = await getGoogleAuthHostRule(); + if (rule) { + const token = Buffer.from(`${rule.username}:${rule.password}`).toString( + 'base64', + ); + addSecretForSanitizing(token); + return token; } return null; } diff --git a/lib/modules/manager/api.ts b/lib/modules/manager/api.ts index e8522f73326a9e..573fcf95375e93 100644 --- a/lib/modules/manager/api.ts +++ b/lib/modules/manager/api.ts @@ -44,6 +44,7 @@ import * as gleam from './gleam'; import * as gomod from './gomod'; import * as gradle from './gradle'; import * as gradleWrapper from './gradle-wrapper'; +import * as haskellCabal from './haskell-cabal'; import * as helmRequirements from './helm-requirements'; import * as helmValues from './helm-values'; import * as helmfile from './helmfile'; @@ -150,6 +151,7 @@ api.set('gleam', gleam); api.set('gomod', gomod); api.set('gradle', gradle); api.set('gradle-wrapper', gradleWrapper); +api.set('haskell-cabal', haskellCabal); api.set('helm-requirements', helmRequirements); api.set('helm-values', helmValues); api.set('helmfile', helmfile); 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/batect/extract.ts b/lib/modules/manager/batect/extract.ts index d7ca1e4e6299f9..4644131b7e8219 100644 --- a/lib/modules/manager/batect/extract.ts +++ b/lib/modules/manager/batect/extract.ts @@ -1,121 +1,9 @@ -import is from '@sindresorhus/is'; import upath from 'upath'; import { logger } from '../../../logger'; import { readLocalFile } from '../../../util/fs'; -import { parseSingleYaml } from '../../../util/yaml'; -import { GitTagsDatasource } from '../../datasource/git-tags'; -import { id as dockerVersioning } from '../../versioning/docker'; -import { id as semverVersioning } from '../../versioning/semver'; -import { getDep } from '../dockerfile/extract'; -import type { ExtractConfig, PackageDependency, PackageFile } from '../types'; -import type { - BatectConfig, - BatectFileInclude, - BatectGitInclude, - BatectInclude, - ExtractionResult, -} from './types'; - -function loadConfig(content: string): BatectConfig { - const config = parseSingleYaml(content); - - if (typeof config !== 'object') { - throw new Error( - `Configuration file does not contain a YAML object (it is ${typeof config}).`, - ); - } - - return config as BatectConfig; -} - -function extractImages(config: BatectConfig): string[] { - if (config.containers === undefined) { - return []; - } - - return Object.values(config.containers) - .map((container) => container.image) - .filter(is.string); -} - -function createImageDependency(tag: string): PackageDependency { - return { - ...getDep(tag), - versioning: dockerVersioning, - }; -} - -function extractImageDependencies(config: BatectConfig): PackageDependency[] { - const images = extractImages(config); - const deps = images.map((image) => createImageDependency(image)); - - logger.trace({ deps }, 'Loaded images from Batect configuration file'); - - return deps; -} - -function includeIsGitInclude( - include: BatectInclude, -): include is BatectGitInclude { - return typeof include === 'object' && include.type === 'git'; -} - -function extractGitBundles(config: BatectConfig): BatectGitInclude[] { - if (config.include === undefined) { - return []; - } - - return config.include.filter(includeIsGitInclude); -} - -function createBundleDependency(bundle: BatectGitInclude): PackageDependency { - return { - depName: bundle.repo, - currentValue: bundle.ref, - versioning: semverVersioning, - datasource: GitTagsDatasource.id, - commitMessageTopic: 'bundle {{depName}}', - }; -} - -function extractBundleDependencies(config: BatectConfig): PackageDependency[] { - const bundles = extractGitBundles(config); - const deps = bundles.map((bundle) => createBundleDependency(bundle)); - - logger.trace({ deps }, 'Loaded bundles from Batect configuration file'); - - return deps; -} - -function includeIsStringFileInclude(include: BatectInclude): include is string { - return typeof include === 'string'; -} - -function includeIsObjectFileInclude( - include: BatectInclude, -): include is BatectFileInclude { - return typeof include === 'object' && include.type === 'file'; -} - -function extractReferencedConfigFiles( - config: BatectConfig, - fileName: string, -): string[] { - if (config.include === undefined) { - return []; - } - - const dirName = upath.dirname(fileName); - - const paths = [ - ...config.include.filter(includeIsStringFileInclude), - ...config.include - .filter(includeIsObjectFileInclude) - .map((include) => include.path), - ].filter((p) => p !== undefined && p !== null); - - return paths.map((p) => upath.join(dirName, p)); -} +import type { ExtractConfig, PackageFile } from '../types'; +import { BatectConfigSchema } from './schema'; +import type { ExtractionResult } from './types'; export function extractPackageFile( content: string, @@ -124,15 +12,13 @@ export function extractPackageFile( logger.trace(`batect.extractPackageFile(${packageFile})`); try { - const config = loadConfig(content); - const deps = [ - ...extractImageDependencies(config), - ...extractBundleDependencies(config), - ]; + const { imageDependencies, bundleDependencies, fileIncludes } = + BatectConfigSchema.parse(content); + const deps = [...imageDependencies, ...bundleDependencies]; - const referencedConfigFiles = extractReferencedConfigFiles( - config, - packageFile, + const dirName = upath.dirname(packageFile); + const referencedConfigFiles = fileIncludes.map((file) => + upath.join(dirName, file), ); return { deps, referencedConfigFiles }; diff --git a/lib/modules/manager/batect/schema.ts b/lib/modules/manager/batect/schema.ts new file mode 100644 index 00000000000000..a463b51a7cb64e --- /dev/null +++ b/lib/modules/manager/batect/schema.ts @@ -0,0 +1,62 @@ +import { z } from 'zod'; +import { LooseArray, LooseRecord, Yaml } from '../../../util/schema-utils'; +import { GitTagsDatasource } from '../../datasource/git-tags'; +import { id as dockerVersioning } from '../../versioning/docker'; +import { id as semverVersioning } from '../../versioning/semver'; +import { getDep } from '../dockerfile/extract'; +import type { PackageDependency } from '../types'; + +export const BatectConfigSchema = Yaml.pipe( + z.object({ + containers: LooseRecord( + z.string(), + z.object({ image: z.string() }).transform(({ image }) => image), + ) + .transform((x) => Object.values(x)) + .catch([]), + include: LooseArray( + z.union([ + z.object({ + type: z.literal('git'), + repo: z.string(), + ref: z.string(), + }), + z.object({ + type: z.literal('file'), + path: z.string(), + }), + z.string().transform((path) => ({ type: 'file' as const, path })), + ]), + ).catch([]), + }), +).transform(({ containers, include }) => { + const imageDependencies = containers.map((image) => ({ + ...getDep(image), + versioning: dockerVersioning, + })); + + const bundleDependencies: PackageDependency[] = []; + const fileIncludes: string[] = []; + + for (const item of include) { + if (item.type === 'git') { + bundleDependencies.push({ + depName: item.repo, + currentValue: item.ref, + versioning: semverVersioning, + datasource: GitTagsDatasource.id, + commitMessageTopic: 'bundle {{depName}}', + }); + } else { + fileIncludes.push(item.path); + } + } + + return { + imageDependencies, + bundleDependencies, + fileIncludes, + }; +}); + +export type BatectConfig = z.infer; diff --git a/lib/modules/manager/batect/types.ts b/lib/modules/manager/batect/types.ts index c5a1765e7060cd..ff439c63266c68 100644 --- a/lib/modules/manager/batect/types.ts +++ b/lib/modules/manager/batect/types.ts @@ -1,27 +1,5 @@ import type { PackageDependency } from '../types'; -export interface BatectConfig { - containers?: Record; - include?: BatectInclude[]; -} - -export interface BatectContainer { - image?: string; -} - -export type BatectInclude = string | BatectFileInclude | BatectGitInclude; - -export interface BatectFileInclude { - type: 'file'; - path: string; -} - -export interface BatectGitInclude { - type: 'git'; - repo: string; - ref: string; -} - export interface ExtractionResult { deps: PackageDependency[]; referencedConfigFiles: string[]; diff --git a/lib/modules/manager/bazel-module/extract.spec.ts b/lib/modules/manager/bazel-module/extract.spec.ts index 336d6172a3ba13..53e5ca47845b30 100644 --- a/lib/modules/manager/bazel-module/extract.spec.ts +++ b/lib/modules/manager/bazel-module/extract.spec.ts @@ -392,5 +392,31 @@ describe('modules/manager/bazel-module/extract', () => { }, ]); }); + + it('returns git_repository dependencies', async () => { + const input = codeBlock` + git_repository( + name = "rules_foo", + commit = "850cb49c8649e463b80ef7984e7c744279746170", + remote = "https://github.com/example/rules_foo.git", + ) + `; + const result = await extractPackageFile(input, 'MODULE.bazel'); + if (!result) { + throw new Error('Expected a result.'); + } + expect(result.deps).toHaveLength(1); + expect(result.deps).toEqual( + expect.arrayContaining([ + { + datasource: GithubTagsDatasource.id, + depType: 'git_repository', + depName: 'rules_foo', + currentDigest: '850cb49c8649e463b80ef7984e7c744279746170', + packageName: 'example/rules_foo', + }, + ]), + ); + }); }); }); diff --git a/lib/modules/manager/bazel-module/extract.ts b/lib/modules/manager/bazel-module/extract.ts index b62bcbccdd983e..8774057c32833f 100644 --- a/lib/modules/manager/bazel-module/extract.ts +++ b/lib/modules/manager/bazel-module/extract.ts @@ -8,7 +8,10 @@ import type { RecordFragment } from './fragments'; import { parse } from './parser'; import { RuleToMavenPackageDep, fillRegistryUrls } from './parser/maven'; import { RuleToDockerPackageDep } from './parser/oci'; -import { RuleToBazelModulePackageDep } from './rules'; +import { + GitRepositoryToPackageDep, + RuleToBazelModulePackageDep, +} from './rules'; import * as rules from './rules'; export async function extractPackageFile( @@ -18,9 +21,14 @@ export async function extractPackageFile( try { const records = parse(content); const pfc = await extractBazelPfc(records, packageFile); + const gitRepositoryDeps = extractGitRepositoryDeps(records); const mavenDeps = extractMavenDeps(records); const dockerDeps = LooseArray(RuleToDockerPackageDep).parse(records); + if (gitRepositoryDeps.length) { + pfc.deps.push(...gitRepositoryDeps); + } + if (mavenDeps.length) { pfc.deps.push(...mavenDeps); } @@ -57,6 +65,12 @@ async function extractBazelPfc( return pfc; } +function extractGitRepositoryDeps( + records: RecordFragment[], +): PackageDependency[] { + return LooseArray(GitRepositoryToPackageDep).parse(records); +} + function extractMavenDeps(records: RecordFragment[]): PackageDependency[] { return LooseArray(RuleToMavenPackageDep) .transform(fillRegistryUrls) diff --git a/lib/modules/manager/bazel-module/parser/index.spec.ts b/lib/modules/manager/bazel-module/parser/index.spec.ts index 26ce0ae5c45e37..f3783f87774f02 100644 --- a/lib/modules/manager/bazel-module/parser/index.spec.ts +++ b/lib/modules/manager/bazel-module/parser/index.spec.ts @@ -315,5 +315,37 @@ describe('modules/manager/bazel-module/parser/index', () => { ), ]); }); + + it('finds the git_repository', () => { + const input = codeBlock` + git_repository( + name = "rules_foo", + remote = "https://github.com/example/rules_foo.git", + commit = "6a2c2e22849b3e6b33d5ea9aa72222d4803a986a", + patches = ["//:rules_foo.patch"], + patch_strip = 1, + ) + `; + const res = parse(input); + expect(res).toEqual([ + fragments.record( + { + rule: fragments.string('git_repository'), + name: fragments.string('rules_foo'), + patches: fragments.array( + [fragments.string('//:rules_foo.patch')], + true, + ), + commit: fragments.string( + '6a2c2e22849b3e6b33d5ea9aa72222d4803a986a', + ), + remote: fragments.string( + 'https://github.com/example/rules_foo.git', + ), + }, + true, + ), + ]); + }); }); }); diff --git a/lib/modules/manager/bazel-module/parser/module.ts b/lib/modules/manager/bazel-module/parser/module.ts index 80371274c029e3..54371e9a7bd25d 100644 --- a/lib/modules/manager/bazel-module/parser/module.ts +++ b/lib/modules/manager/bazel-module/parser/module.ts @@ -9,6 +9,7 @@ const supportedRules = [ 'git_override', 'local_path_override', 'single_version_override', + 'git_repository', ]; const supportedRulesRegex = regEx(`^${supportedRules.join('|')}$`); diff --git a/lib/modules/manager/bazel-module/rules.spec.ts b/lib/modules/manager/bazel-module/rules.spec.ts index 048471c6504d39..c3a8b2a2207cef 100644 --- a/lib/modules/manager/bazel-module/rules.spec.ts +++ b/lib/modules/manager/bazel-module/rules.spec.ts @@ -10,6 +10,7 @@ import type { OverridePackageDep, } from './rules'; import { + GitRepositoryToPackageDep, RuleToBazelModulePackageDep, bazelModulePackageDepToPackageDependency, processModulePkgDeps, @@ -72,6 +73,19 @@ const singleVersionOverrideWithoutVersionAndRegistryPkgDep: BasePackageDep = { depName: 'rules_foo', skipReason: 'ignored', }; +const gitRepositoryForGithubPkgDep: BasePackageDep = { + datasource: GithubTagsDatasource.id, + depType: 'git_repository', + depName: 'rules_foo', + packageName: 'example/rules_foo', + currentDigest: '850cb49c8649e463b80ef7984e7c744279746170', +}; +const gitRepositoryForUnsupportedPkgDep: BasePackageDep = { + depType: 'git_repository', + depName: 'rules_foo', + currentDigest: '850cb49c8649e463b80ef7984e7c744279746170', + skipReason: 'unsupported-datasource', +}; describe('modules/manager/bazel-module/rules', () => { describe('RuleToBazelModulePackageDep', () => { @@ -129,6 +143,30 @@ describe('modules/manager/bazel-module/rules', () => { }); }); + describe('GitRepositoryToPackageDep', () => { + const gitRepositoryWithGihubHost = fragments.record({ + rule: fragments.string('git_repository'), + name: fragments.string('rules_foo'), + remote: fragments.string('https://github.com/example/rules_foo.git'), + commit: fragments.string('850cb49c8649e463b80ef7984e7c744279746170'), + }); + const gitRepositoryWithUnsupportedHost = fragments.record({ + rule: fragments.string('git_repository'), + name: fragments.string('rules_foo'), + remote: fragments.string('https://nobuenos.com/example/rules_foo.git'), + commit: fragments.string('850cb49c8649e463b80ef7984e7c744279746170'), + }); + + it.each` + msg | a | exp + ${'git_repository, GitHub host'} | ${gitRepositoryWithGihubHost} | ${gitRepositoryForGithubPkgDep} + ${'git_repository, unsupported host'} | ${gitRepositoryWithUnsupportedHost} | ${gitRepositoryForUnsupportedPkgDep} + `('.parse() with $msg', ({ a, exp }) => { + const pkgDep = GitRepositoryToPackageDep.parse(a); + expect(pkgDep).toEqual(exp); + }); + }); + describe('.toPackageDependencies()', () => { const expectedBazelDepNoOverrides: PackageDependency[] = [bazelDepPkgDep]; const expectedBazelDepAndGitOverride: PackageDependency[] = [ diff --git a/lib/modules/manager/bazel-module/rules.ts b/lib/modules/manager/bazel-module/rules.ts index fda2cf253c0fd0..8f1bb2e626d77a 100644 --- a/lib/modules/manager/bazel-module/rules.ts +++ b/lib/modules/manager/bazel-module/rules.ts @@ -242,3 +242,28 @@ export function toPackageDependencies( ): PackageDependency[] { return collectByModule(packageDeps).map(processModulePkgDeps).flat(); } + +export const GitRepositoryToPackageDep = RecordFragmentSchema.extend({ + children: z.object({ + rule: StringFragmentSchema.extend({ + value: z.literal('git_repository'), + }), + name: StringFragmentSchema, + remote: StringFragmentSchema, + commit: StringFragmentSchema, + }), +}).transform(({ children: { rule, name, remote, commit } }): BasePackageDep => { + const gitRepo: BasePackageDep = { + depType: rule.value, + depName: name.value, + currentDigest: commit.value, + }; + const ghPackageName = githubPackageName(remote.value); + if (is.nonEmptyString(ghPackageName)) { + gitRepo.datasource = GithubTagsDatasource.id; + gitRepo.packageName = ghPackageName; + } else { + gitRepo.skipReason = 'unsupported-datasource'; + } + return gitRepo; +}); diff --git a/lib/modules/manager/bundler/artifacts.spec.ts b/lib/modules/manager/bundler/artifacts.spec.ts index 497d293a06b552..ad0ee829c84efb 100644 --- a/lib/modules/manager/bundler/artifacts.spec.ts +++ b/lib/modules/manager/bundler/artifacts.spec.ts @@ -435,217 +435,6 @@ describe('modules/manager/bundler/artifacts', () => { datasource.getPkgReleases.mockResolvedValueOnce({ releases: [{ version: '1.17.2' }, { version: '2.3.5' }], }); - bundlerHostRules.findAllAuthenticatable.mockReturnValue([ - { - hostType: 'bundler', - matchHost: 'gems.private.com', - resolvedHost: 'gems.private.com', - username: 'some-user', - password: 'some-password', - }, - ]); - bundlerHostRules.getAuthenticationHeaderValue.mockReturnValue( - 'some-user:some-password', - ); - const execSnapshots = mockExecAll(); - git.getRepoStatus.mockResolvedValueOnce( - partial({ - modified: ['Gemfile.lock'], - }), - ); - fs.readLocalFile.mockResolvedValueOnce('Updated Gemfile.lock'); - expect( - await updateArtifacts({ - packageFileName: 'Gemfile', - updatedDeps: [{ depName: 'foo' }, { depName: 'bar' }], - newPackageFileContent: 'Updated Gemfile content', - config, - }), - ).toEqual([updatedGemfileLock]); - expect(execSnapshots).toMatchObject([ - { cmd: 'docker pull ghcr.io/containerbase/sidecar' }, - { cmd: 'docker ps --filter name=renovate_sidecar -aq' }, - { - cmd: - 'docker run --rm --name=renovate_sidecar --label=renovate_child ' + - '-v "/tmp/github/some/repo":"/tmp/github/some/repo" ' + - '-v "/tmp/cache":"/tmp/cache" ' + - '-e BUNDLE_GEMS__PRIVATE__COM ' + - '-e GEM_HOME ' + - '-e CONTAINERBASE_CACHE_DIR ' + - '-w "/tmp/github/some/repo" ' + - 'ghcr.io/containerbase/sidecar' + - ' bash -l -c "' + - 'install-tool ruby 1.2.0' + - ' && ' + - 'install-tool bundler 2.3.5' + - ' && ' + - 'ruby --version' + - ' && ' + - 'bundler lock --update foo bar' + - '"', - }, - ]); - }); - - it('injects bundler host configuration as command with bundler < 2', async () => { - GlobalConfig.set({ ...adminConfig, binarySource: 'docker' }); - fs.readLocalFile.mockResolvedValueOnce('Current Gemfile.lock'); - fs.readLocalFile.mockResolvedValueOnce('1.2.0'); - // ruby - datasource.getPkgReleases.mockResolvedValueOnce({ - releases: [ - { version: '1.0.0' }, - { version: '1.2.0' }, - { version: '1.3.0' }, - ], - }); - bundlerHostRules.findAllAuthenticatable.mockReturnValue([ - { - hostType: 'bundler', - matchHost: 'gems-private.com', - resolvedHost: 'gems-private.com', - username: 'some-user', - password: 'some-password', - }, - ]); - bundlerHostRules.getAuthenticationHeaderValue.mockReturnValue( - 'some-user:some-password', - ); - const execSnapshots = mockExecAll(); - git.getRepoStatus.mockResolvedValueOnce( - partial({ - modified: ['Gemfile.lock'], - }), - ); - fs.readLocalFile.mockResolvedValueOnce('Updated Gemfile.lock'); - expect( - await updateArtifacts({ - packageFileName: 'Gemfile', - updatedDeps: [{ depName: 'foo' }, { depName: 'bar' }], - newPackageFileContent: 'Updated Gemfile content', - config: { - ...config, - constraints: { - bundler: '1.2', - }, - }, - }), - ).toEqual([updatedGemfileLock]); - expect(execSnapshots).toMatchObject([ - { cmd: 'docker pull ghcr.io/containerbase/sidecar' }, - { cmd: 'docker ps --filter name=renovate_sidecar -aq' }, - { - cmd: - 'docker run --rm --name=renovate_sidecar --label=renovate_child ' + - '-v "/tmp/github/some/repo":"/tmp/github/some/repo" ' + - '-v "/tmp/cache":"/tmp/cache" ' + - '-e GEM_HOME ' + - '-e CONTAINERBASE_CACHE_DIR ' + - '-w "/tmp/github/some/repo" ' + - 'ghcr.io/containerbase/sidecar' + - ' bash -l -c "' + - 'install-tool ruby 1.2.0' + - ' && ' + - 'install-tool bundler 1.2' + - ' && ' + - 'ruby --version' + - ' && ' + - 'bundler config --local gems-private.com some-user:some-password' + - ' && ' + - 'bundler lock --update foo bar' + - '"', - }, - ]); - }); - - it('injects bundler host configuration as command with bundler >= 2', async () => { - GlobalConfig.set({ ...adminConfig, binarySource: 'docker' }); - fs.readLocalFile.mockResolvedValueOnce('Current Gemfile.lock'); - fs.readLocalFile.mockResolvedValueOnce('1.2.0'); - // ruby - datasource.getPkgReleases.mockResolvedValueOnce({ - releases: [ - { version: '1.0.0' }, - { version: '1.2.0' }, - { version: '1.3.0' }, - ], - }); - bundlerHostRules.findAllAuthenticatable.mockReturnValue([ - { - hostType: 'bundler', - matchHost: 'gems-private.com', - resolvedHost: 'gems-private.com', - username: 'some-user', - password: 'some-password', - }, - ]); - bundlerHostRules.getAuthenticationHeaderValue.mockReturnValue( - 'some-user:some-password', - ); - const execSnapshots = mockExecAll(); - git.getRepoStatus.mockResolvedValueOnce( - partial({ - modified: ['Gemfile.lock'], - }), - ); - fs.readLocalFile.mockResolvedValueOnce('Updated Gemfile.lock'); - expect( - await updateArtifacts({ - packageFileName: 'Gemfile', - updatedDeps: [{ depName: 'foo' }, { depName: 'bar' }], - newPackageFileContent: 'Updated Gemfile content', - config: { - ...config, - constraints: { - bundler: '2.1', - }, - }, - }), - ).toEqual([updatedGemfileLock]); - expect(execSnapshots).toMatchObject([ - { cmd: 'docker pull ghcr.io/containerbase/sidecar' }, - { cmd: 'docker ps --filter name=renovate_sidecar -aq' }, - { - cmd: - 'docker run --rm --name=renovate_sidecar --label=renovate_child ' + - '-v "/tmp/github/some/repo":"/tmp/github/some/repo" ' + - '-v "/tmp/cache":"/tmp/cache" ' + - '-e GEM_HOME ' + - '-e CONTAINERBASE_CACHE_DIR ' + - '-w "/tmp/github/some/repo" ' + - 'ghcr.io/containerbase/sidecar' + - ' bash -l -c "' + - 'install-tool ruby 1.2.0' + - ' && ' + - 'install-tool bundler 2.1' + - ' && ' + - 'ruby --version' + - ' && ' + - 'bundler config set --local gems-private.com some-user:some-password' + - ' && ' + - 'bundler lock --update foo bar' + - '"', - }, - ]); - }); - - it('injects bundler host configuration as command with bundler == latest', async () => { - GlobalConfig.set({ ...adminConfig, binarySource: 'docker' }); - fs.readLocalFile.mockResolvedValueOnce('Current Gemfile.lock'); - fs.readLocalFile.mockResolvedValueOnce('1.2.0'); - // ruby - datasource.getPkgReleases.mockResolvedValueOnce({ - releases: [ - { version: '1.0.0' }, - { version: '1.2.0' }, - { version: '1.3.0' }, - ], - }); - // bundler - datasource.getPkgReleases.mockResolvedValueOnce({ - releases: [{ version: '1.17.2' }, { version: '2.3.5' }], - }); bundlerHostRules.findAllAuthenticatable.mockReturnValue([ { hostType: 'bundler', @@ -681,6 +470,7 @@ describe('modules/manager/bundler/artifacts', () => { 'docker run --rm --name=renovate_sidecar --label=renovate_child ' + '-v "/tmp/github/some/repo":"/tmp/github/some/repo" ' + '-v "/tmp/cache":"/tmp/cache" ' + + '-e BUNDLE_GEMS___PRIVATE__COM ' + '-e GEM_HOME ' + '-e CONTAINERBASE_CACHE_DIR ' + '-w "/tmp/github/some/repo" ' + @@ -688,12 +478,10 @@ describe('modules/manager/bundler/artifacts', () => { ' bash -l -c "' + 'install-tool ruby 1.2.0' + ' && ' + - 'install-tool bundler 1.3.0' + + 'install-tool bundler 2.3.5' + ' && ' + 'ruby --version' + ' && ' + - 'bundler config set --local gems-private.com some-user:some-password' + - ' && ' + 'bundler lock --update foo bar' + '"', }, diff --git a/lib/modules/manager/bundler/artifacts.ts b/lib/modules/manager/bundler/artifacts.ts index d1dc827f704eb5..071bd1a652c2ce 100644 --- a/lib/modules/manager/bundler/artifacts.ts +++ b/lib/modules/manager/bundler/artifacts.ts @@ -1,4 +1,3 @@ -import { lt } from '@renovatebot/ruby-semver'; import is from '@sindresorhus/is'; import { quote } from 'shlex'; import { @@ -17,7 +16,6 @@ import { } from '../../../util/fs'; import { getRepoStatus } from '../../../util/git'; import { newlineRegex, regEx } from '../../../util/regex'; -import { isValid } from '../../versioning/ruby'; import type { UpdateArtifact, UpdateArtifactsResult } from '../types'; import { getBundlerConstraint, @@ -32,14 +30,17 @@ import { const hostConfigVariablePrefix = 'BUNDLE_'; function buildBundleHostVariable(hostRule: HostRule): Record { - if (!hostRule.resolvedHost || hostRule.resolvedHost.includes('-')) { + // istanbul ignore if: doesn't happen in practice + if (!hostRule.resolvedHost) { return {}; } const varName = hostConfigVariablePrefix.concat( hostRule.resolvedHost + .toUpperCase() .split('.') - .map((term) => term.toUpperCase()) - .join('__'), + .join('__') + .split('-') + .join('___'), ); return { [varName]: `${getAuthenticationHeaderValue(hostRule)}`, @@ -149,47 +150,12 @@ export async function updateArtifacts( {} as Record, ); - // Detect hosts with a hyphen '-' in the url. - // Those cannot be added with environment variables but need to be added - // with the bundler config - const bundlerHostRulesAuthCommands: string[] = bundlerHostRules.reduce( - (authCommands: string[], hostRule) => { - if (hostRule.resolvedHost?.includes('-')) { - // TODO: fix me, hostrules can missing all auth - const creds = getAuthenticationHeaderValue(hostRule); - authCommands.push(`${quote(hostRule.resolvedHost)} ${quote(creds)}`); - } - return authCommands; - }, - [], - ); - const bundler = getBundlerConstraint( updateArtifact, existingLockFileContent, ); const preCommands = ['ruby --version']; - // Bundler < 2 has a different config option syntax than >= 2 - if ( - bundlerHostRulesAuthCommands && - bundler && - isValid(bundler) && - lt(bundler, '2') - ) { - preCommands.push( - ...bundlerHostRulesAuthCommands.map( - (authCommand) => `bundler config --local ${authCommand}`, - ), - ); - } else if (bundlerHostRulesAuthCommands) { - preCommands.push( - ...bundlerHostRulesAuthCommands.map( - (authCommand) => `bundler config set --local ${authCommand}`, - ), - ); - } - const execOptions: ExecOptions = { cwdFile: lockFileName, userConfiguredEnv: config.env, diff --git a/lib/modules/manager/cargo/artifacts.ts b/lib/modules/manager/cargo/artifacts.ts index 8ac570605d2008..4d144f83fb353a 100644 --- a/lib/modules/manager/cargo/artifacts.ts +++ b/lib/modules/manager/cargo/artifacts.ts @@ -135,7 +135,8 @@ async function updateArtifactsImpl( // If there is a dependency without a locked version then log a warning // and perform a regular workspace lockfile update. logger.warn( - `Missing locked version for dependency \`${missingDep.depName}\``, + { dependency: missingDep.depName }, + 'Missing locked version for dependency', ); await cargoUpdate( packageFileName, diff --git a/lib/modules/manager/cargo/extract.ts b/lib/modules/manager/cargo/extract.ts index 3d090e52b7a3e8..35e9d6926bfbad 100644 --- a/lib/modules/manager/cargo/extract.ts +++ b/lib/modules/manager/cargo/extract.ts @@ -134,7 +134,7 @@ function resolveRegistryIndex( `Replacing index of cargo registry ${registryName} with ${replacementName}`, ); if (originalNames.has(replacementName)) { - logger.warn(`${registryName} cargo registry resolves to itself`); + logger.warn({ registryName }, 'cargo registry resolves to itself'); return null; } return resolveRegistryIndex( 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/common.ts b/lib/modules/manager/flux/common.ts index 8fff55a1cf3e42..bafa6285135b0c 100644 --- a/lib/modules/manager/flux/common.ts +++ b/lib/modules/manager/flux/common.ts @@ -1,4 +1,6 @@ import { regEx } from '../../../util/regex'; +import type { HelmRepository } from './schema'; +import type { FluxManifest } from './types'; export const systemManifestFileNameRegex = '(?:^|/)gotk-components\\.ya?ml$'; @@ -8,3 +10,19 @@ export const systemManifestHeaderRegex = export function isSystemManifest(file: string): boolean { return regEx(systemManifestFileNameRegex).test(file); } + +export function collectHelmRepos(manifests: FluxManifest[]): HelmRepository[] { + const helmRepositories: HelmRepository[] = []; + + for (const manifest of manifests) { + if (manifest.kind === 'resource') { + for (const resource of manifest.resources) { + if (resource.kind === 'HelmRepository') { + helmRepositories.push(resource); + } + } + } + } + + return helmRepositories; +} diff --git a/lib/modules/manager/flux/extract.spec.ts b/lib/modules/manager/flux/extract.spec.ts index 134fc4dd6ed73e..70e97ac2746614 100644 --- a/lib/modules/manager/flux/extract.spec.ts +++ b/lib/modules/manager/flux/extract.spec.ts @@ -34,6 +34,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 a592183c303b69..3178c28e989303 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 { @@ -21,7 +22,11 @@ import type { PackageFile, PackageFileContent, } from '../types'; -import { isSystemManifest, systemManifestHeaderRegex } from './common'; +import { + collectHelmRepos, + isSystemManifest, + systemManifestHeaderRegex, +} from './common'; import { FluxResource, type HelmRepository } from './schema'; import type { FluxManagerData, @@ -102,6 +107,39 @@ function resolveGitRepositoryPerSourceTag( } } +function resolveHelmRepository( + dep: PackageDependency, + matchingRepositories: HelmRepository[], + registryAliases: Record | undefined, +): void { + if (matchingRepositories.length) { + dep.registryUrls = matchingRepositories + .map((repo) => { + if (repo.spec.type === 'oci' || isOCIRegistry(repo.spec.url)) { + // Change datasource to Docker + dep.datasource = DockerDatasource.id; + // Ensure the URL is a valid OCI path + dep.packageName = getDep( + `${removeOCIPrefix(repo.spec.url)}/${dep.depName}`, + false, + registryAliases, + ).depName; + return null; + } else { + return repo.spec.url; + } + }) + .filter(is.string); + + // if registryUrls is empty, delete it from dep + if (!dep.registryUrls?.length) { + delete dep.registryUrls; + } + } else { + dep.skipReason = 'unknown-registry'; + } +} + function resolveSystemManifest( manifest: SystemFluxManifest, ): PackageDependency[] { @@ -126,7 +164,8 @@ function resolveResourceManifest( for (const resource of manifest.resources) { switch (resource.kind) { case 'HelmRelease': { - const depName = resource.spec.chart.spec.chart; + const chartSpec = resource.spec.chart.spec; + const depName = chartSpec.chart; const dep: PackageDependency = { depName, currentValue: resource.spec.chart.spec.version, @@ -142,41 +181,17 @@ function resolveResourceManifest( const matchingRepositories = helmRepositories.filter( (rep) => - rep.kind === resource.spec.chart.spec.sourceRef?.kind && - rep.metadata.name === resource.spec.chart.spec.sourceRef.name && + rep.kind === chartSpec.sourceRef?.kind && + rep.metadata.name === chartSpec.sourceRef.name && rep.metadata.namespace === - (resource.spec.chart.spec.sourceRef.namespace ?? - resource.metadata?.namespace), + (chartSpec.sourceRef.namespace ?? resource.metadata?.namespace), ); - if (matchingRepositories.length) { - dep.registryUrls = matchingRepositories - .map((repo) => { - if (repo.spec.type === 'oci' || isOCIRegistry(repo.spec.url)) { - // Change datasource to Docker - dep.datasource = DockerDatasource.id; - // Ensure the URL is a valid OCI path - dep.packageName = getDep( - `${removeOCIPrefix(repo.spec.url)}/${ - resource.spec.chart.spec.chart - }`, - false, - registryAliases, - ).depName; - return null; - } else { - return repo.spec.url; - } - }) - .filter(is.string); + resolveHelmRepository(dep, matchingRepositories, registryAliases); + deps.push(dep); - // if registryUrls is empty, delete it from dep - if (!dep.registryUrls?.length) { - delete dep.registryUrls; - } - } else { - dep.skipReason = 'unknown-registry'; + if (resource.spec.values) { + deps.push(...findDependencies(resource.spec.values, registryAliases)); } - deps.push(dep); break; } case 'GitRepository': { @@ -252,14 +267,7 @@ export function extractPackageFile( if (!manifest) { return null; } - const helmRepositories: HelmRepository[] = []; - if (manifest.kind === 'resource') { - for (const resource of manifest.resources) { - if (resource.kind === 'HelmRepository') { - helmRepositories.push(resource); - } - } - } + const helmRepositories = collectHelmRepos([manifest]); let deps: PackageDependency[] | null = null; switch (manifest.kind) { case 'system': @@ -293,16 +301,7 @@ export async function extractAllPackageFiles( } } - const helmRepositories: HelmRepository[] = []; - for (const manifest of manifests) { - if (manifest.kind === 'resource') { - for (const resource of manifest.resources) { - if (resource.kind === 'HelmRepository') { - helmRepositories.push(resource); - } - } - } - } + const helmRepositories = collectHelmRepos(manifests); for (const manifest of manifests) { let deps: PackageDependency[] | null = null; diff --git a/lib/modules/manager/flux/readme.md b/lib/modules/manager/flux/readme.md index bb1777f3bd8f05..508331962138f0 100644 --- a/lib/modules/manager/flux/readme.md +++ b/lib/modules/manager/flux/readme.md @@ -22,6 +22,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 8e4870b2245bf3..d76ff8fb5b2222 100644 --- a/lib/modules/manager/flux/schema.ts +++ b/lib/modules/manager/flux/schema.ts @@ -29,6 +29,7 @@ export const HelmRelease = KubernetesResource.extend({ .optional(), }), }), + values: z.record(z.unknown()).optional(), }), }); 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/github-actions/extract.spec.ts b/lib/modules/manager/github-actions/extract.spec.ts index 75479bef617333..f3d499e10adda7 100644 --- a/lib/modules/manager/github-actions/extract.spec.ts +++ b/lib/modules/manager/github-actions/extract.spec.ts @@ -467,7 +467,7 @@ describe('modules/manager/github-actions/extract', () => { build: steps: - name: "test1" - uses: https://github.com/actions/setup-node@56337c425554a6be30cdef71bf441f15be286854 # tag=v3.1.1 + uses: https://github.com/actions/cache/save@1bd1e32a3bdc45362d1e726936510720a7c30a57 # tag=v4.2.0 - name: "test2" uses: https://code.forgejo.org/actions/setup-node@56337c425554a6be30cdef71bf441f15be286854 # v3.1.1 - name: "test3" @@ -479,14 +479,18 @@ describe('modules/manager/github-actions/extract', () => { expect(res).toMatchObject({ deps: [ { - currentDigest: '56337c425554a6be30cdef71bf441f15be286854', - currentValue: 'v3.1.1', + depName: 'https://github.com/actions/cache', + packageName: 'actions/cache', + currentDigest: '1bd1e32a3bdc45362d1e726936510720a7c30a57', + currentValue: 'v4.2.0', replaceString: - 'https://github.com/actions/setup-node@56337c425554a6be30cdef71bf441f15be286854 # tag=v3.1.1', + 'https://github.com/actions/cache/save@1bd1e32a3bdc45362d1e726936510720a7c30a57 # tag=v4.2.0', datasource: 'github-tags', registryUrls: ['https://github.com/'], }, { + depName: 'https://code.forgejo.org/actions/setup-node', + packageName: 'actions/setup-node', currentDigest: '56337c425554a6be30cdef71bf441f15be286854', currentValue: 'v3.1.1', replaceString: diff --git a/lib/modules/manager/github-actions/extract.ts b/lib/modules/manager/github-actions/extract.ts index c498615e1f6eff..b797f8fc1e9f2c 100644 --- a/lib/modules/manager/github-actions/extract.ts +++ b/lib/modules/manager/github-actions/extract.ts @@ -10,12 +10,16 @@ import { GithubRunnersDatasource } from '../../datasource/github-runners'; import { GithubTagsDatasource } from '../../datasource/github-tags'; import * as dockerVersioning from '../../versioning/docker'; import { getDep } from '../dockerfile/extract'; -import type { PackageDependency, PackageFileContent } from '../types'; +import type { + ExtractConfig, + PackageDependency, + PackageFileContent, +} from '../types'; import type { Workflow } from './types'; const dockerActionRe = regEx(/^\s+uses\s*: ['"]?docker:\/\/([^'"]+)\s*$/); const actionRe = regEx( - /^\s+-?\s+?uses\s*: (?['"]?(?https:\/\/[.\w-]+\/)?(?[\w-]+\/[.\w-]+)(?\/.*)?@(?[^\s'"]+)['"]?(?:(?\s+)#\s*(((?:renovate\s*:\s*)?(?:pin\s+|tag\s*=\s*)?|(?:ratchet:[\w-]+\/[.\w-]+)?)@?(?([\w-]*-)?v?\d+(?:\.\d+(?:\.\d+)?)?)|(?:ratchet:exclude)))?)/, + /^\s+-?\s+?uses\s*: (?['"]?(?(?https:\/\/[.\w-]+\/)?(?[\w-]+\/[.\w-]+))(?\/.*)?@(?[^\s'"]+)['"]?(?:(?\s+)#\s*(((?:renovate\s*:\s*)?(?:pin\s+|tag\s*=\s*)?|(?:ratchet:[\w-]+\/[.\w-]+)?)@?(?([\w-]*-)?v?\d+(?:\.\d+(?:\.\d+)?)?)|(?:ratchet:exclude)))?)/, ); // SHA1 or SHA256, see https://github.blog/2020-10-19-git-2-29-released/ @@ -44,7 +48,10 @@ function detectCustomGitHubRegistryUrlsForActions(): PackageDependency { return {}; } -function extractWithRegex(content: string): PackageDependency[] { +function extractWithRegex( + content: string, + config: ExtractConfig, +): PackageDependency[] { const customRegistryUrlsPackageDependency = detectCustomGitHubRegistryUrlsForActions(); logger.trace('github-actions.extractWithRegex()'); @@ -57,7 +64,7 @@ function extractWithRegex(content: string): PackageDependency[] { const dockerMatch = dockerActionRe.exec(line); if (dockerMatch) { const [, currentFrom] = dockerMatch; - const dep = getDep(currentFrom); + const dep = getDep(currentFrom, true, config.registryAliases); dep.depType = 'docker'; deps.push(dep); continue; @@ -67,6 +74,7 @@ function extractWithRegex(content: string): PackageDependency[] { if (tagMatch?.groups) { const { depName, + packageName, currentValue, path = '', tag, @@ -83,12 +91,13 @@ function extractWithRegex(content: string): PackageDependency[] { } const dep: PackageDependency = { depName, + ...(packageName !== depName && { packageName }), commitMessageTopic: '{{{depName}}} action', datasource: GithubTagsDatasource.id, versioning: dockerVersioning.id, depType: 'action', replaceString, - autoReplaceStringTemplate: `${quotes}${registryUrl}{{depName}}${path}@{{#if newDigest}}{{newDigest}}${quotes}{{#if newValue}}${commentWhiteSpaces}# {{newValue}}{{/if}}{{/if}}{{#unless newDigest}}{{newValue}}${quotes}{{/unless}}`, + autoReplaceStringTemplate: `${quotes}{{depName}}${path}@{{#if newDigest}}{{newDigest}}${quotes}{{#if newValue}}${commentWhiteSpaces}# {{newValue}}{{/if}}{{/if}}{{#unless newDigest}}{{newValue}}${quotes}{{/unless}}`, ...(registryUrl ? detectDatasource(registryUrl) : customRegistryUrlsPackageDependency), @@ -126,11 +135,14 @@ function detectDatasource(registryUrl: string): PackageDependency { }; } -function extractContainer(container: unknown): PackageDependency | undefined { +function extractContainer( + container: unknown, + registryAliases: Record | undefined, +): PackageDependency | undefined { if (is.string(container)) { - return getDep(container); + return getDep(container, true, registryAliases); } else if (is.plainObject(container) && is.string(container.image)) { - return getDep(container.image); + return getDep(container.image, true, registryAliases); } return undefined; } @@ -181,6 +193,7 @@ function extractRunners(runner: unknown): PackageDependency[] { function extractWithYAMLParser( content: string, packageFile: string, + config: ExtractConfig, ): PackageDependency[] { logger.trace('github-actions.extractWithYAMLParser()'); const deps: PackageDependency[] = []; @@ -198,14 +211,14 @@ function extractWithYAMLParser( } for (const job of Object.values(pkg?.jobs ?? {})) { - const dep = extractContainer(job?.container); + const dep = extractContainer(job?.container, config.registryAliases); if (dep) { dep.depType = 'container'; deps.push(dep); } for (const service of Object.values(job?.services ?? {})) { - const dep = extractContainer(service); + const dep = extractContainer(service, config.registryAliases); if (dep) { dep.depType = 'service'; deps.push(dep); @@ -221,11 +234,12 @@ function extractWithYAMLParser( export function extractPackageFile( content: string, packageFile: string, + config: ExtractConfig = {}, // TODO: enforce ExtractConfig ): PackageFileContent | null { logger.trace(`github-actions.extractPackageFile(${packageFile})`); const deps = [ - ...extractWithRegex(content), - ...extractWithYAMLParser(content, packageFile), + ...extractWithRegex(content, config), + ...extractWithYAMLParser(content, packageFile, config), ]; if (!deps.length) { return null; diff --git a/lib/modules/manager/gradle/__fixtures__/2/libs.versions.toml b/lib/modules/manager/gradle/__fixtures__/2/libs.versions.toml deleted file mode 100644 index 62f98ea855c26c..00000000000000 --- a/lib/modules/manager/gradle/__fixtures__/2/libs.versions.toml +++ /dev/null @@ -1,17 +0,0 @@ -[versions] -kotlin = "1.5.21" -retro_fit = "2.8.2" - -[libraries] -okHttp = "com.squareup.okhttp3:okhttp:4.9.0" -okio = { module = "com.squareup.okio:okio", version = "2.8.0" } -picasso = { group = "com.squareup.picasso", name = "picasso", version = "2.5.1" } -retrofit2-retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retro_fit" } -google-firebase-analytics = { module = "com.google.firebase:firebase-analytics" } -google-firebase-crashlytics = { group = "com.google.firebase", name = "firebase-crashlytics" } -google-firebase-messaging = "com.google.firebase:firebase-messaging" - -[plugins] -kotlinJvm = { id = "org.jetbrains.kotlin.jvm", version = "1.5.21" } -kotlinSerialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } -multiJvm = "org.danilopianini.multi-jvm-test-plugin:0.3.0" diff --git a/lib/modules/manager/gradle/__fixtures__/3/libs.versions.toml b/lib/modules/manager/gradle/__fixtures__/3/libs.versions.toml deleted file mode 100644 index 7188d1a6c6b443..00000000000000 --- a/lib/modules/manager/gradle/__fixtures__/3/libs.versions.toml +++ /dev/null @@ -1,10 +0,0 @@ -[versions] -# Releases: http://someWebsite.com/junit/1.4.9 -mocha-junit-reporter = "2.0.2" -# JUnit 1.4.9 is awesome! -junit = "1.4.9" - - -[libraries] -junit-legacy = { module = "junit:junit", version.ref = "junit" } -mocha-junit = { module = "mocha-junit:mocha-junit", version.ref = "mocha.junit.reporter" } diff --git a/lib/modules/manager/gradle/__fixtures__/1/libs.versions.toml b/lib/modules/manager/gradle/__fixtures__/libs.versions.toml similarity index 100% rename from lib/modules/manager/gradle/__fixtures__/1/libs.versions.toml rename to lib/modules/manager/gradle/__fixtures__/libs.versions.toml diff --git a/lib/modules/manager/gradle/__snapshots__/parser.spec.ts.snap b/lib/modules/manager/gradle/__snapshots__/parser.spec.ts.snap deleted file mode 100644 index 571951909582d3..00000000000000 --- a/lib/modules/manager/gradle/__snapshots__/parser.spec.ts.snap +++ /dev/null @@ -1,103 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`modules/manager/gradle/parser calculations parses fixture from "gradle" manager 1`] = ` -[ - { - "currentValue": "1.5.2.RELEASE", - "depName": "org.springframework.boot:spring-boot-gradle-plugin", - "groupName": "springBootVersion", - "managerData": { - "fileReplacePosition": 53, - "packageFile": "build.gradle", - }, - }, - { - "currentValue": "1.2.3", - "depName": "com.github.jengelman.gradle.plugins:shadow", - "managerData": { - "fileReplacePosition": 417, - "packageFile": "build.gradle", - }, - }, - { - "currentValue": "0.1", - "depName": "com.fkorotkov:gradle-libraries-plugin", - "managerData": { - "fileReplacePosition": 481, - "packageFile": "build.gradle", - }, - }, - { - "currentValue": "0.2.3", - "depName": "gradle.plugin.se.patrikerdes:gradle-use-latest-versions-plugin", - "managerData": { - "fileReplacePosition": 568, - "packageFile": "build.gradle", - }, - }, - { - "currentValue": "3.1.1", - "depName": "org.apache.openjpa:openjpa", - "managerData": { - "fileReplacePosition": 621, - "packageFile": "build.gradle", - }, - }, - { - "currentValue": "0.13.0", - "depName": "com.gradle.publish:plugin-publish-plugin", - "managerData": { - "fileReplacePosition": 688, - "packageFile": "build.gradle", - }, - }, - { - "currentValue": "6.0.9.RELEASE", - "depName": "org.grails:gorm-hibernate5-spring-boot", - "managerData": { - "fileReplacePosition": 1882, - "packageFile": "build.gradle", - }, - }, - { - "currentValue": "6.0.5", - "depName": "mysql:mysql-connector-java", - "managerData": { - "fileReplacePosition": 1938, - "packageFile": "build.gradle", - }, - }, - { - "currentValue": "1.0-groovy-2.4", - "depName": "org.spockframework:spock-spring", - "managerData": { - "fileReplacePosition": 1996, - "packageFile": "build.gradle", - }, - }, - { - "currentValue": "1.3", - "depName": "org.hamcrest:hamcrest-core", - "managerData": { - "fileReplacePosition": 2101, - "packageFile": "build.gradle", - }, - }, - { - "currentValue": "3.1", - "depName": "cglib:cglib-nodep", - "managerData": { - "fileReplacePosition": 2189, - "packageFile": "build.gradle", - }, - }, - { - "currentValue": "3.1.1", - "depName": "org.apache.openjpa:openjpa", - "managerData": { - "fileReplacePosition": 2295, - "packageFile": "build.gradle", - }, - }, -] -`; diff --git a/lib/modules/manager/gradle/extract.spec.ts b/lib/modules/manager/gradle/extract.spec.ts index 7a0900ddfc2b3c..25c24846e3805c 100644 --- a/lib/modules/manager/gradle/extract.spec.ts +++ b/lib/modules/manager/gradle/extract.spec.ts @@ -1,4 +1,4 @@ -import { codeBlock, stripIndent } from 'common-tags'; +import { codeBlock } from 'common-tags'; import { Fixtures } from '../../../../test/fixtures'; import { fs, logger, partial } from '../../../../test/util'; import type { ExtractConfig } from '../types'; @@ -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', }, ], }, @@ -499,7 +499,7 @@ describe('modules/manager/gradle/extract', () => { describe('version catalogs', () => { it('works with dependency catalogs', async () => { const fsMock = { - 'gradle/libs.versions.toml': Fixtures.get('1/libs.versions.toml'), + 'gradle/libs.versions.toml': Fixtures.get('libs.versions.toml'), }; mockFs(fsMock); @@ -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, @@ -614,118 +614,6 @@ describe('modules/manager/gradle/extract', () => { ]); }); - it('supports versions declared as single string', async () => { - const fsMock = { - 'gradle/libs.versions.toml': Fixtures.get('2/libs.versions.toml'), - }; - mockFs(fsMock); - - const res = await extractAllPackageFiles( - partial(), - Object.keys(fsMock), - ); - - expect(res).toMatchObject([ - { - packageFile: 'gradle/libs.versions.toml', - deps: [ - { - depName: 'com.squareup.okhttp3:okhttp', - currentValue: '4.9.0', - managerData: { - fileReplacePosition: 100, - packageFile: 'gradle/libs.versions.toml', - }, - }, - { - depName: 'com.squareup.okio:okio', - currentValue: '2.8.0', - managerData: { - fileReplacePosition: 162, - packageFile: 'gradle/libs.versions.toml', - }, - }, - { - depName: 'com.squareup.picasso:picasso', - currentValue: '2.5.1', - managerData: { - fileReplacePosition: 244, - packageFile: 'gradle/libs.versions.toml', - }, - }, - { - depName: 'com.squareup.retrofit2:retrofit', - groupName: 'retro.fit', - currentValue: '2.8.2', - managerData: { - fileReplacePosition: 42, - packageFile: 'gradle/libs.versions.toml', - }, - }, - { - depName: 'google-firebase-analytics', - managerData: { - packageFile: 'gradle/libs.versions.toml', - }, - skipReason: 'unspecified-version', - }, - { - depName: 'google-firebase-crashlytics', - managerData: { - packageFile: 'gradle/libs.versions.toml', - }, - skipReason: 'unspecified-version', - }, - { - depName: 'google-firebase-messaging', - managerData: { - packageFile: 'gradle/libs.versions.toml', - }, - skipReason: 'unspecified-version', - }, - { - depName: 'org.jetbrains.kotlin.jvm', - depType: 'plugin', - currentValue: '1.5.21', - commitMessageTopic: 'plugin kotlinJvm', - packageName: - 'org.jetbrains.kotlin.jvm:org.jetbrains.kotlin.jvm.gradle.plugin', - managerData: { - fileReplacePosition: 663, - packageFile: 'gradle/libs.versions.toml', - }, - registryUrls: ['https://plugins.gradle.org/m2/'], - }, - { - depName: 'org.jetbrains.kotlin.plugin.serialization', - depType: 'plugin', - currentValue: '1.5.21', - packageName: - 'org.jetbrains.kotlin.plugin.serialization:org.jetbrains.kotlin.plugin.serialization.gradle.plugin', - managerData: { - fileReplacePosition: 21, - packageFile: 'gradle/libs.versions.toml', - }, - registryUrls: ['https://plugins.gradle.org/m2/'], - }, - { - depName: 'org.danilopianini.multi-jvm-test-plugin', - depType: 'plugin', - currentValue: '0.3.0', - commitMessageTopic: 'plugin multiJvm', - packageName: - 'org.danilopianini.multi-jvm-test-plugin:org.danilopianini.multi-jvm-test-plugin.gradle.plugin', - managerData: { - fileReplacePosition: 824, - packageFile: 'gradle/libs.versions.toml', - }, - registryUrls: ['https://plugins.gradle.org/m2/'], - }, - ], - }, - ]); - }); - it('ignores empty TOML file', async () => { const fsMock = { 'gradle/libs.versions.toml': '', @@ -742,7 +630,7 @@ describe('modules/manager/gradle/extract', () => { it('deletes commit message for plugins with version reference', async () => { const fsMock = { - 'gradle/libs.versions.toml': stripIndent` + 'gradle/libs.versions.toml': codeBlock` [versions] detekt = "1.18.1" @@ -765,7 +653,7 @@ describe('modules/manager/gradle/extract', () => { deps: [ { depName: 'io.gitlab.arturbosch.detekt:detekt-formatting', - groupName: 'detekt', + sharedVariableName: 'detekt', currentValue: '1.18.1', managerData: { fileReplacePosition: 21, @@ -784,52 +672,13 @@ describe('modules/manager/gradle/extract', () => { fileReplacePosition: 21, packageFile: 'gradle/libs.versions.toml', }, - groupName: 'detekt', + sharedVariableName: 'detekt', fileReplacePosition: 21, }, ], }, ]); }); - - it('changes the dependency version, not the comment version', async () => { - const fsMock = { - 'gradle/libs.versions.toml': Fixtures.get('3/libs.versions.toml'), - }; - mockFs(fsMock); - - const res = await extractAllPackageFiles( - partial(), - Object.keys(fsMock), - ); - expect(res).toMatchObject([ - { - packageFile: 'gradle/libs.versions.toml', - deps: [ - { - depName: 'junit:junit', - groupName: 'junit', - currentValue: '1.4.9', - managerData: { - fileReplacePosition: 124, - packageFile: 'gradle/libs.versions.toml', - }, - fileReplacePosition: 124, - }, - { - depName: 'mocha-junit:mocha-junit', - groupName: 'mocha.junit.reporter', - currentValue: '2.0.2', - managerData: { - fileReplacePosition: 82, - packageFile: 'gradle/libs.versions.toml', - }, - fileReplacePosition: 82, - }, - ], - }, - ]); - }); }); describe('apply from', () => { @@ -996,7 +845,7 @@ describe('modules/manager/gradle/extract', () => { it('parses versions files', async () => { const fsMock = { 'versions.props': `org.apache.lucene:* = 1.2.3`, - 'versions.lock': stripIndent` + 'versions.lock': codeBlock` # Run ./gradlew --write-locks to regenerate this file org.apache.lucene:lucene-core:1.2.3 (10 constraints: 95be0c15) org.apache.lucene:lucene-codecs:1.2.3 (5 constraints: 1231231) @@ -1020,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, @@ -1031,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, @@ -1046,7 +895,7 @@ describe('modules/manager/gradle/extract', () => { it('plugin not used due to lockfile not a GCV lockfile', async () => { const fsMock = { 'versions.props': `org.apache.lucene:* = 1.2.3`, - 'versions.lock': stripIndent` + 'versions.lock': codeBlock` This is NOT a lock file `, }; @@ -1075,14 +924,14 @@ describe('modules/manager/gradle/extract', () => { it('supports multiple levels of glob', async () => { const fsMock = { - 'versions.props': stripIndent` + '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': stripIndent` + '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) @@ -1128,7 +977,7 @@ describe('modules/manager/gradle/extract', () => { depName: 'org.apache.lucene:a.c', currentValue: '2', lockedVersion: '1', - groupName: 'org.apache.lucene:a.*', + sharedVariableName: 'org.apache.lucene:a.*', fileReplacePosition: 65, depType: 'dependencies', }, @@ -1140,7 +989,7 @@ describe('modules/manager/gradle/extract', () => { depName: 'org.apache.lucene:a.d', currentValue: '2', lockedVersion: '1', - groupName: 'org.apache.lucene:a.*', + sharedVariableName: 'org.apache.lucene:a.*', fileReplacePosition: 65, depType: 'dependencies', }, @@ -1152,7 +1001,7 @@ describe('modules/manager/gradle/extract', () => { depName: 'org.apache.lucene:d', currentValue: '3', lockedVersion: '1', - groupName: 'org.apache.lucene:*', + sharedVariableName: 'org.apache.lucene:*', fileReplacePosition: 39, depType: 'dependencies', }, @@ -1164,7 +1013,7 @@ describe('modules/manager/gradle/extract', () => { depName: 'org.apache.lucene:e.f', currentValue: '3', lockedVersion: '1', - groupName: 'org.apache.lucene:*', + sharedVariableName: 'org.apache.lucene:*', fileReplacePosition: 39, depType: 'dependencies', }, @@ -1176,7 +1025,7 @@ describe('modules/manager/gradle/extract', () => { depName: 'org.apache.foo-bar:a', currentValue: '5', lockedVersion: '1', - groupName: 'org.apache.foo*:*', + 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 new file mode 100644 index 00000000000000..6f470a04b77c07 --- /dev/null +++ b/lib/modules/manager/gradle/extract/catalog.spec.ts @@ -0,0 +1,194 @@ +import { codeBlock } from 'common-tags'; +import { parseCatalog } from './catalog'; + +describe('modules/manager/gradle/extract/catalog', () => { + it('supports versions declared as single string', () => { + const input = codeBlock` + [versions] + kotlin = "1.5.21" + retro_fit = "2.8.2" + + [libraries] + okHttp = "com.squareup.okhttp3:okhttp:4.9.0" + okio = { module = "com.squareup.okio:okio", version = "2.8.0" } + picasso = { group = "com.squareup.picasso", name = "picasso", version = "2.5.1" } + retrofit2-retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retro_fit" } + google-firebase-analytics = { module = "com.google.firebase:firebase-analytics" } + google-firebase-crashlytics = { group = "com.google.firebase", name = "firebase-crashlytics" } + google-firebase-messaging = "com.google.firebase:firebase-messaging" + + [plugins] + kotlinJvm = { id = "org.jetbrains.kotlin.jvm", version = "1.5.21" } + kotlinSerialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } + multiJvm = "org.danilopianini.multi-jvm-test-plugin:0.3.0" + `; + const res = parseCatalog('gradle/libs.versions.toml', input); + expect(res).toStrictEqual([ + { + depName: 'com.squareup.okhttp3:okhttp', + currentValue: '4.9.0', + managerData: { + fileReplacePosition: 100, + packageFile: 'gradle/libs.versions.toml', + }, + }, + { + depName: 'com.squareup.okio:okio', + currentValue: '2.8.0', + managerData: { + fileReplacePosition: 162, + packageFile: 'gradle/libs.versions.toml', + }, + }, + { + depName: 'com.squareup.picasso:picasso', + currentValue: '2.5.1', + managerData: { + fileReplacePosition: 244, + packageFile: 'gradle/libs.versions.toml', + }, + }, + { + depName: 'com.squareup.retrofit2:retrofit', + sharedVariableName: 'retro.fit', + currentValue: '2.8.2', + managerData: { + fileReplacePosition: 42, + packageFile: 'gradle/libs.versions.toml', + }, + }, + { + depName: 'google-firebase-analytics', + managerData: { + packageFile: 'gradle/libs.versions.toml', + }, + skipReason: 'unspecified-version', + }, + { + depName: 'google-firebase-crashlytics', + managerData: { + packageFile: 'gradle/libs.versions.toml', + }, + skipReason: 'unspecified-version', + }, + { + depName: 'google-firebase-messaging', + managerData: { + packageFile: 'gradle/libs.versions.toml', + }, + skipReason: 'unspecified-version', + }, + { + depName: 'org.jetbrains.kotlin.jvm', + depType: 'plugin', + currentValue: '1.5.21', + commitMessageTopic: 'plugin kotlinJvm', + packageName: + 'org.jetbrains.kotlin.jvm:org.jetbrains.kotlin.jvm.gradle.plugin', + managerData: { + fileReplacePosition: 663, + packageFile: 'gradle/libs.versions.toml', + }, + }, + { + depName: 'org.jetbrains.kotlin.plugin.serialization', + depType: 'plugin', + currentValue: '1.5.21', + sharedVariableName: 'kotlin', + packageName: + 'org.jetbrains.kotlin.plugin.serialization:org.jetbrains.kotlin.plugin.serialization.gradle.plugin', + managerData: { + fileReplacePosition: 21, + packageFile: 'gradle/libs.versions.toml', + }, + }, + { + depName: 'org.danilopianini.multi-jvm-test-plugin', + depType: 'plugin', + currentValue: '0.3.0', + commitMessageTopic: 'plugin multiJvm', + packageName: + 'org.danilopianini.multi-jvm-test-plugin:org.danilopianini.multi-jvm-test-plugin.gradle.plugin', + managerData: { + fileReplacePosition: 824, + packageFile: 'gradle/libs.versions.toml', + }, + }, + ]); + }); + + it('deletes commit message for plugins with version reference', () => { + const input = 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" } + `; + const res = parseCatalog('gradle/libs.versions.toml', input); + + expect(res).toStrictEqual([ + { + depName: 'io.gitlab.arturbosch.detekt:detekt-formatting', + sharedVariableName: 'detekt', + currentValue: '1.18.1', + managerData: { + fileReplacePosition: 21, + packageFile: 'gradle/libs.versions.toml', + }, + }, + { + depType: 'plugin', + depName: 'io.gitlab.arturbosch.detekt', + packageName: + 'io.gitlab.arturbosch.detekt:io.gitlab.arturbosch.detekt.gradle.plugin', + currentValue: '1.18.1', + managerData: { + fileReplacePosition: 21, + packageFile: 'gradle/libs.versions.toml', + }, + sharedVariableName: 'detekt', + }, + ]); + }); + + it('changes the dependency version, not the comment version', () => { + const input = codeBlock` + [versions] + # Releases: http://someWebsite.com/junit/1.4.9 + mocha-junit-reporter = "2.0.2" + # JUnit 1.4.9 is awesome! + junit = "1.4.9" + + + [libraries] + junit-legacy = { module = "junit:junit", version.ref = "junit" } + mocha-junit = { module = "mocha-junit:mocha-junit", version.ref = "mocha.junit.reporter" } + `; + const res = parseCatalog('gradle/libs.versions.toml', input); + + expect(res).toStrictEqual([ + { + depName: 'junit:junit', + sharedVariableName: 'junit', + currentValue: '1.4.9', + managerData: { + fileReplacePosition: 124, + packageFile: 'gradle/libs.versions.toml', + }, + }, + { + depName: 'mocha-junit:mocha-junit', + sharedVariableName: 'mocha.junit.reporter', + currentValue: '2.0.2', + managerData: { + fileReplacePosition: 82, + packageFile: 'gradle/libs.versions.toml', + }, + }, + ]); + }); +}); 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 5ebaef86501b14..850031576ba663 100644 --- a/lib/modules/manager/gradle/extract/consistent-versions-plugin.spec.ts +++ b/lib/modules/manager/gradle/extract/consistent-versions-plugin.spec.ts @@ -1,16 +1,17 @@ -import { stripIndent } from 'common-tags'; +import { codeBlock } from 'common-tags'; import { + parseGcv, parseLockFile, parsePropsFile, usesGcv, } from './consistent-versions-plugin'; describe('modules/manager/gradle/extract/consistent-versions-plugin', () => { - it('gradle-consistent-versions plugin works for sub folders', () => { + it('works for sub folders', () => { const fsMock = { 'mysub/build.gradle.kts': `(this file contains) 'com.palantir.consistent-versions'`, 'mysub/versions.props': `org.apache.lucene:* = 1.2.3`, - 'mysub/versions.lock': stripIndent` + 'mysub/versions.lock': codeBlock` # Run ./gradlew --write-locks to regenerate this file org.apache.lucene:lucene-core:1.2.3`, 'othersub/build.gradle.kts': `nothing here`, @@ -24,7 +25,7 @@ describe('modules/manager/gradle/extract/consistent-versions-plugin', () => { const fsMock = { 'build.gradle.kts': `(this file contains) 'com.palantir.consistent-versions'`, 'versions.props': `org.apache.lucene:* = 1.2.3`, - 'versions.lock': stripIndent` + 'versions.lock': codeBlock` # Run ./gradlew writeVersionsLock to regenerate this file org.apache.lucene:lucene-core:1.2.3`, }; @@ -36,7 +37,7 @@ describe('modules/manager/gradle/extract/consistent-versions-plugin', () => { const fsMock = { 'build.gradle.kts': `(this file contains) 'com.palantir.consistent-versions'`, 'versions.props': `org.apache.lucene:* = 1.2.3`, - 'versions.lock': stripIndent` + 'versions.lock': codeBlock` # Run ./gradlew writeVersionsLocks to regenerate this file org.apache.lucene:lucene-core:1.2.3`, }; @@ -44,7 +45,7 @@ describe('modules/manager/gradle/extract/consistent-versions-plugin', () => { expect(usesGcv('versions.props', fsMock)).toBeTrue(); }); - it('gradle-consistent-versions plugin correct position for CRLF and LF', () => { + it('correct position for CRLF and LF', () => { const crlfProps = parsePropsFile(`a.b:c.d=1\r\na.b:c.e=2`); expect(crlfProps).toBeArrayOfSize(2); expect(crlfProps[0].has('a.b:c.e')).toBeTrue(); @@ -56,8 +57,8 @@ describe('modules/manager/gradle/extract/consistent-versions-plugin', () => { expect(lfProps[0].get('a.b:c.e')).toMatchObject({ filePos: 18 }); }); - it('gradle-consistent-versions plugin test bogus input lines', () => { - const parsedProps = parsePropsFile(stripIndent` + it('test bogus input lines', () => { + const parsedProps = parsePropsFile(codeBlock` # comment:foo.bar = 1 123.foo:bar = 2 this has:spaces = 3 @@ -71,7 +72,7 @@ describe('modules/manager/gradle/extract/consistent-versions-plugin', () => { expect(parsedProps[0]).toMatchObject({ size: 1 }); // no 7 is valid exact dep expect(parsedProps[1]).toMatchObject({ size: 1 }); // no 8 is valid glob dep - const parsedLock = parseLockFile(stripIndent` + const parsedLock = parseLockFile(codeBlock` # comment:foo.bar:1 (10 constraints: 95be0c15) 123.foo:bar:2 (10 constraints: 95be0c15) this has:spaces:3 (10 constraints: 95be0c15) @@ -92,4 +93,96 @@ describe('modules/manager/gradle/extract/consistent-versions-plugin', () => { depType: 'test', }); }); + + it('supports multiple levels of glob', () => { + 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) + `, + }; + const res = parseGcv('versions.props', fsMock); + + // Each lock dep is only present once, with highest prio for exact prop match, then globs from longest to shortest + expect(res).toStrictEqual([ + { + managerData: { + packageFile: 'versions.props', + fileReplacePosition: 91, + }, + depName: 'org.apache.lucene:a.b', + currentValue: '1', + lockedVersion: '1', + depType: 'dependencies', + }, + { + managerData: { + packageFile: 'versions.props', + fileReplacePosition: 65, + }, + depName: 'org.apache.lucene:a.c', + currentValue: '2', + lockedVersion: '1', + sharedVariableName: 'org.apache.lucene:a.*', + depType: 'dependencies', + }, + { + managerData: { + packageFile: 'versions.props', + fileReplacePosition: 65, + }, + depName: 'org.apache.lucene:a.d', + currentValue: '2', + lockedVersion: '1', + sharedVariableName: 'org.apache.lucene:a.*', + depType: 'dependencies', + }, + { + managerData: { + packageFile: 'versions.props', + fileReplacePosition: 39, + }, + depName: 'org.apache.lucene:d', + currentValue: '3', + lockedVersion: '1', + sharedVariableName: 'org.apache.lucene:*', + depType: 'dependencies', + }, + { + managerData: { + packageFile: 'versions.props', + fileReplacePosition: 39, + }, + depName: 'org.apache.lucene:e.f', + currentValue: '3', + lockedVersion: '1', + sharedVariableName: 'org.apache.lucene:*', + depType: 'dependencies', + }, + { + managerData: { + fileReplacePosition: 113, + packageFile: 'versions.props', + }, + depName: 'org.apache.foo-bar:a', + currentValue: '5', + lockedVersion: '1', + 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 668c6b3ff188cb..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} @@ -759,16 +763,28 @@ describe('modules/manager/gradle/parser', () => { describe('heuristic dependency matching', () => { it.each` - input | output - ${'("foo", "bar", "1.2.3")'} | ${{ depName: 'foo:bar', currentValue: '1.2.3' }} - ${'("foo", "bar", "1.2.3", "4.5.6")'} | ${null} - ${'(["foo", "bar", "1.2.3"])'} | ${null} - ${'someMethod("foo", "bar", "1.2.3")'} | ${{ depName: 'foo:bar', currentValue: '1.2.3' }} - ${'listOf("foo", "bar", "baz")'} | ${null} + input | output + ${'("foo", "bar", "1.2.3")'} | ${{ depName: 'foo:bar', currentValue: '1.2.3' }} + ${'("foo", "bar", "1.2.3", "4.5.6")'} | ${null} + ${'(["foo", "bar", "1.2.3"])'} | ${null} + ${'someMethod("foo", "bar", "1.2.3")'} | ${{ depName: 'foo:bar', currentValue: '1.2.3' }} + ${'listOf("foo", "bar", "baz")'} | ${null} + ${'java { registerFeature(foo) { capability("foo", "bar", "1.2.3") } }'} | ${null} `('$input', ({ input, output }) => { const { deps } = parseGradle(input); expect(deps).toMatchObject([output].filter(is.truthy)); }); + + it('handles 3 independent dependencies mismatched as groupId, artifactId, version', () => { + const { deps } = parseGradle( + 'someConfig("foo:bar:1.2.3", "foo:baz:4.5.6", "foo:qux:7.8.9")', + ); + expect(deps).toMatchObject([ + { depName: 'foo:bar', currentValue: '1.2.3' }, + { depName: 'foo:baz', currentValue: '4.5.6' }, + { depName: 'foo:qux', currentValue: '7.8.9' }, + ]); + }); }); describe('calculations', () => { @@ -791,7 +807,106 @@ describe('modules/manager/gradle/parser', () => { content.slice(managerData!.fileReplacePosition).indexOf(currentValue!), ); expect(replacementIndices.every((idx) => idx === 0)).toBeTrue(); - expect(deps).toMatchSnapshot(); + expect(deps).toMatchObject([ + { + currentValue: '1.5.2.RELEASE', + depName: 'org.springframework.boot:spring-boot-gradle-plugin', + sharedVariableName: 'springBootVersion', + managerData: { + fileReplacePosition: 53, + packageFile: 'build.gradle', + }, + }, + { + currentValue: '1.2.3', + depName: 'com.github.jengelman.gradle.plugins:shadow', + managerData: { + fileReplacePosition: 417, + packageFile: 'build.gradle', + }, + }, + { + currentValue: '0.1', + depName: 'com.fkorotkov:gradle-libraries-plugin', + managerData: { + fileReplacePosition: 481, + packageFile: 'build.gradle', + }, + }, + { + currentValue: '0.2.3', + depName: + 'gradle.plugin.se.patrikerdes:gradle-use-latest-versions-plugin', + managerData: { + fileReplacePosition: 568, + packageFile: 'build.gradle', + }, + }, + { + currentValue: '3.1.1', + depName: 'org.apache.openjpa:openjpa', + managerData: { + fileReplacePosition: 621, + packageFile: 'build.gradle', + }, + }, + { + currentValue: '0.13.0', + depName: 'com.gradle.publish:plugin-publish-plugin', + managerData: { + fileReplacePosition: 688, + packageFile: 'build.gradle', + }, + }, + { + currentValue: '6.0.9.RELEASE', + depName: 'org.grails:gorm-hibernate5-spring-boot', + managerData: { + fileReplacePosition: 1882, + packageFile: 'build.gradle', + }, + }, + { + currentValue: '6.0.5', + depName: 'mysql:mysql-connector-java', + managerData: { + fileReplacePosition: 1938, + packageFile: 'build.gradle', + }, + }, + { + currentValue: '1.0-groovy-2.4', + depName: 'org.spockframework:spock-spring', + managerData: { + fileReplacePosition: 1996, + packageFile: 'build.gradle', + }, + }, + { + currentValue: '1.3', + depName: 'org.hamcrest:hamcrest-core', + managerData: { + fileReplacePosition: 2101, + packageFile: 'build.gradle', + }, + }, + { + currentValue: '3.1', + depName: 'cglib:cglib-nodep', + managerData: { + fileReplacePosition: 2189, + packageFile: 'build.gradle', + }, + }, + { + currentValue: '3.1.1', + depName: 'org.apache.openjpa:openjpa', + managerData: { + fileReplacePosition: 2295, + packageFile: 'build.gradle', + }, + }, + ]); }); }); @@ -928,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' }} @@ -982,7 +1097,7 @@ describe('modules/manager/gradle/parser', () => { deps: [ { depName: 'org.slf4j:slf4j-api', - groupName: 'Versions.baz', + sharedVariableName: 'Versions.baz', currentValue: '1.2.3', }, { @@ -991,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', }, ], @@ -1055,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', }, ], }); @@ -1107,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.ts b/lib/modules/manager/gradle/parser.ts index d9f0f4e6111792..b0459572b2d084 100644 --- a/lib/modules/manager/gradle/parser.ts +++ b/lib/modules/manager/gradle/parser.ts @@ -18,7 +18,7 @@ import type { PackageVariables, ParseGradleResult, } from './types'; -import { isDependencyString, parseDependencyString } from './utils'; +import { parseDependencyString } from './utils'; const groovy = lang.createLang('groovy'); const ctx: Ctx = { @@ -127,28 +127,27 @@ export function parseProps( ): { vars: PackageVariables; deps: PackageDependency[] } { let offset = 0; const vars: PackageVariables = {}; - const deps: PackageDependency[] = []; + const deps: PackageDependency[] = []; + for (const line of input.split(newlineRegex)) { const lineMatch = propRegex.exec(line); if (lineMatch?.groups) { const { key, value, leftPart } = lineMatch.groups; - if (isDependencyString(value)) { - const dep = parseDependencyString(value); - if (dep) { - deps.push({ - ...dep, - managerData: { - fileReplacePosition: - offset + leftPart.length + dep.depName!.length + 1, - packageFile, - }, - }); - } + const replacePosition = offset + leftPart.length; + const dep = parseDependencyString(value); + if (dep) { + deps.push({ + ...dep, + managerData: { + fileReplacePosition: replacePosition + dep.depName!.length + 1, + packageFile, + }, + }); } else { vars[key] = { key, value, - fileReplacePosition: offset + leftPart.length, + fileReplacePosition: replacePosition, packageFile, }; } diff --git a/lib/modules/manager/gradle/parser/common.ts b/lib/modules/manager/gradle/parser/common.ts index fffc610c0cac41..2c201804407bce 100644 --- a/lib/modules/manager/gradle/parser/common.ts +++ b/lib/modules/manager/gradle/parser/common.ts @@ -267,23 +267,13 @@ export const qTemplateString = q ctx.tmpTokenStore.templateTokens = []; return ctx; }, - search: q.alt( - qStringValue.handler((ctx) => { + search: q + .alt(qStringValue, qPropertyAccessIdentifier, qVariableAccessIdentifier) + .handler((ctx) => { ctx.tmpTokenStore.templateTokens?.push(...ctx.varTokens); ctx.varTokens = []; return ctx; }), - qPropertyAccessIdentifier.handler((ctx) => { - ctx.tmpTokenStore.templateTokens?.push(...ctx.varTokens); - ctx.varTokens = []; - return ctx; - }), - qVariableAccessIdentifier.handler((ctx) => { - ctx.tmpTokenStore.templateTokens?.push(...ctx.varTokens); - ctx.varTokens = []; - return ctx; - }), - ), }) .handler((ctx) => { ctx.varTokens = ctx.tmpTokenStore.templateTokens!; @@ -321,14 +311,24 @@ export const qDotOrBraceExpr = ( matcher: q.QueryBuilder, ): q.QueryBuilder => q.sym(symValue).alt( - q.alt( - q.op('.').join(matcher), - q.tree({ - type: 'wrapped-tree', - maxDepth: 1, - startsWith: '{', - endsWith: '}', - search: matcher, - }), - ), + q.op('.').join(matcher), + q.tree({ + type: 'wrapped-tree', + maxDepth: 1, + startsWith: '{', + endsWith: '}', + search: matcher, + }), ); + +export const qGroupId = qValueMatcher.handler((ctx) => + storeInTokenMap(ctx, 'groupId'), +); + +export const qArtifactId = qValueMatcher.handler((ctx) => + storeInTokenMap(ctx, 'artifactId'), +); + +export const qVersion = qValueMatcher.handler((ctx) => + storeInTokenMap(ctx, 'version'), +); diff --git a/lib/modules/manager/gradle/parser/dependencies.ts b/lib/modules/manager/gradle/parser/dependencies.ts index d8778737edaaf8..e9fb2b1265fe66 100644 --- a/lib/modules/manager/gradle/parser/dependencies.ts +++ b/lib/modules/manager/gradle/parser/dependencies.ts @@ -4,8 +4,12 @@ import type { Ctx } from '../types'; import { GRADLE_PLUGINS, cleanupTempVars, + qArtifactId, + qDotOrBraceExpr, + qGroupId, qTemplateString, qValueMatcher, + qVersion, storeInTokenMap, storeVarToken, } from './common'; @@ -16,18 +20,6 @@ import { handleLongFormDep, } from './handlers'; -const qGroupId = qValueMatcher.handler((ctx) => - storeInTokenMap(ctx, 'groupId'), -); - -const qArtifactId = qValueMatcher.handler((ctx) => - storeInTokenMap(ctx, 'artifactId'), -); - -const qVersion = qValueMatcher.handler((ctx) => - storeInTokenMap(ctx, 'version'), -); - // "foo:bar:1.2.3" // "foo:bar:$baz" // "foo" + "${bar}" + baz @@ -204,4 +196,6 @@ export const qDependencies = q.alt( qKotlinShortNotationDependencies, qKotlinMapNotationDependencies, qImplicitGradlePlugin, + // avoid heuristic matching of gradle feature variant capabilities + qDotOrBraceExpr('java', q.sym('registerFeature').tree()), ); diff --git a/lib/modules/manager/gradle/parser/handlers.ts b/lib/modules/manager/gradle/parser/handlers.ts index 229671b249eaed..5aaba92f773cf7 100644 --- a/lib/modules/manager/gradle/parser/handlers.ts +++ b/lib/modules/manager/gradle/parser/handlers.ts @@ -6,7 +6,7 @@ import { regEx } from '../../../../util/regex'; import type { PackageDependency } from '../../types'; import type { parseGradle as parseGradleCallback } from '../parser'; import type { Ctx, GradleManagerData } from '../types'; -import { parseDependencyString } from '../utils'; +import { isDependencyString, parseDependencyString } from '../utils'; import { GRADLE_PLUGINS, REGISTRY_URLS, @@ -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, @@ -169,6 +169,22 @@ export function handleLongFormDep(ctx: Ctx): Ctx { return ctx; } + // Special handling: 3 independent dependencies mismatched as groupId, artifactId, version + if ( + isDependencyString(groupId) && + isDependencyString(artifactId) && + isDependencyString(version) + ) { + ctx.tokenMap.templateStringTokens = groupIdTokens; + handleDepString(ctx); + ctx.tokenMap.templateStringTokens = artifactIdTokens; + handleDepString(ctx); + ctx.tokenMap.templateStringTokens = versionTokens; + handleDepString(ctx); + + return ctx; + } + const dep = parseDependencyString([groupId, artifactId, version].join(':')); if (!dep) { return ctx; @@ -181,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, @@ -190,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, @@ -231,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, @@ -413,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/parser/plugins.ts b/lib/modules/manager/gradle/parser/plugins.ts index 5cf27b58c11891..aebb081067abe2 100644 --- a/lib/modules/manager/gradle/parser/plugins.ts +++ b/lib/modules/manager/gradle/parser/plugins.ts @@ -4,16 +4,12 @@ import type { Ctx } from '../types'; import { cleanupTempVars, qStringValue, - qValueMatcher, + qVersion, storeInTokenMap, storeVarToken, } from './common'; import { handlePlugin } from './handlers'; -const qVersion = qValueMatcher.handler((ctx) => - storeInTokenMap(ctx, 'version'), -); - export const qPlugins = q .sym(regEx(/^(?:id|kotlin)$/), storeVarToken) .handler((ctx) => storeInTokenMap(ctx, 'methodName')) diff --git a/lib/modules/manager/gradle/parser/registry-urls.ts b/lib/modules/manager/gradle/parser/registry-urls.ts index 341dc37d547ec2..e684135f808852 100644 --- a/lib/modules/manager/gradle/parser/registry-urls.ts +++ b/lib/modules/manager/gradle/parser/registry-urls.ts @@ -32,6 +32,7 @@ const qUri = q // mavenCentral { ... } const qPredefinedRegistries = q .sym(regEx(`^(?:${Object.keys(REGISTRY_URLS).join('|')})$`), storeVarToken) + .handler((ctx) => storeInTokenMap(ctx, 'registryUrl')) .alt( q.tree({ type: 'wrapped-tree', @@ -45,10 +46,31 @@ const qPredefinedRegistries = q endsWith: '}', }), ) - .handler((ctx) => storeInTokenMap(ctx, 'registryUrl')) .handler(handlePredefinedRegistryUrl) .handler(cleanupTempVars); +// { url = "https://some.repo" } +const qMavenArtifactRegistry = q.tree({ + type: 'wrapped-tree', + maxDepth: 1, + startsWith: '{', + endsWith: '}', + search: q.alt( + q + .sym('name') + .opt(q.op('=')) + .join(qValueMatcher) + .handler((ctx) => storeInTokenMap(ctx, 'name')), + q.sym('url').opt(q.op('=')).join(qUri), + q.sym('setUrl').tree({ + maxDepth: 1, + startsWith: '(', + endsWith: ')', + search: q.begin().join(qUri).end(), + }), + ), +}); + // maven(url = uri("https://foo.bar/baz")) // maven { name = some; url = "https://foo.bar/${name}" } const qCustomRegistryUrl = q @@ -61,26 +83,7 @@ const qCustomRegistryUrl = q endsWith: ')', search: q.begin().opt(q.sym('url').op('=')).join(qUri).end(), }), - q.tree({ - type: 'wrapped-tree', - maxDepth: 1, - startsWith: '{', - endsWith: '}', - search: q.alt( - q - .sym('name') - .opt(q.op('=')) - .join(qValueMatcher) - .handler((ctx) => storeInTokenMap(ctx, 'name')), - q.sym('url').opt(q.op('=')).join(qUri), - q.sym('setUrl').tree({ - maxDepth: 1, - startsWith: '(', - endsWith: ')', - search: q.begin().join(qUri).end(), - }), - ), - }), + qMavenArtifactRegistry, ) .handler(handleCustomRegistryUrl) .handler(cleanupTempVars); diff --git a/lib/modules/manager/gradle/parser/version-catalogs.ts b/lib/modules/manager/gradle/parser/version-catalogs.ts index 272688ee6084b1..c4c1259ccf424d 100644 --- a/lib/modules/manager/gradle/parser/version-catalogs.ts +++ b/lib/modules/manager/gradle/parser/version-catalogs.ts @@ -2,6 +2,8 @@ import { query as q } from 'good-enough-parser'; import type { Ctx } from '../types'; import { cleanupTempVars, + qArtifactId, + qGroupId, qStringValue, qStringValueAsSymbol, qValueMatcher, @@ -10,14 +12,6 @@ import { } from './common'; import { handleLibraryDep, handlePlugin } from './handlers'; -const qGroupId = qValueMatcher.handler((ctx) => - storeInTokenMap(ctx, 'groupId'), -); - -const qArtifactId = qValueMatcher.handler((ctx) => - storeInTokenMap(ctx, 'artifactId'), -); - const qVersionCatalogVersion = q .op('.') .alt( 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/gradle/utils.spec.ts b/lib/modules/manager/gradle/utils.spec.ts index 1de059b86c62b9..d8879d0ebf2bd3 100644 --- a/lib/modules/manager/gradle/utils.spec.ts +++ b/lib/modules/manager/gradle/utils.spec.ts @@ -1,7 +1,13 @@ -import type { VariableRegistry } from './types'; +import type { PackageVariables, VariableRegistry } from './types'; import { getVars, isDependencyString, + isGradleBuildFile, + isGradleScriptFile, + isGradleVersionsFile, + isKotlinSourceFile, + isPropsFile, + isTOMLFile, parseDependencyString, reorderFiles, toAbsolutePath, @@ -10,66 +16,83 @@ import { } from './utils'; describe('modules/manager/gradle/utils', () => { - it('versionLikeSubstring', () => { - [ - '1.2.3', - '[1.0,2.0]', - '(,2.0[', - '2.1.1.RELEASE', - '1.0.+', - '2022-05-10_55', - ].forEach((input) => { - expect(versionLikeSubstring(input)).toEqual(input); - expect(versionLikeSubstring(`${input}'`)).toEqual(input); - expect(versionLikeSubstring(`${input}"`)).toEqual(input); - expect(versionLikeSubstring(`${input}\n`)).toEqual(input); - expect(versionLikeSubstring(`${input} `)).toEqual(input); - expect(versionLikeSubstring(`${input}$`)).toEqual(input); + describe('versionLikeSubstring', () => { + it('extracts the actual version', () => { + const inputs = [ + '1.2.3', + '[1.0,2.0]', + '(,2.0[', + '2.1.1.RELEASE', + '1.0.+', + '2022-05-10_55', + ]; + const suffixes = ['', "'", '"', '\n', ' ', '$']; + + for (const input of inputs) { + for (const suffix of suffixes) { + expect(versionLikeSubstring(`${input}${suffix}`)).toEqual(input); + } + } }); - expect(versionLikeSubstring('')).toBeNull(); - expect(versionLikeSubstring(undefined)).toBeNull(); - expect(versionLikeSubstring(null)).toBeNull(); - expect(versionLikeSubstring('foobar')).toBeNull(); - expect(versionLikeSubstring('latest')).toBeNull(); - }); - it('isDependencyString', () => { - expect(isDependencyString('foo:bar:1.2.3')).toBeTrue(); - expect(isDependencyString('foo.foo:bar.bar:1.2.3')).toBeTrue(); - expect(isDependencyString('foo:bar:baz:qux')).toBeFalse(); - expect(isDependencyString('foo.bar:baz:1.2.3')).toBeTrue(); - expect(isDependencyString('foo.bar:baz:1.2.3:linux-cpu-x86_64')).toBeTrue(); - expect(isDependencyString('foo.bar:baz:1.2.+')).toBeTrue(); - expect(isDependencyString('foo:bar:baz:qux:quux')).toBeFalse(); - expect(isDependencyString("foo:bar:1.2.3'")).toBeFalse(); - expect(isDependencyString('foo:bar:1.2.3"')).toBeFalse(); - expect(isDependencyString('-Xep:ParameterName:OFF')).toBeFalse(); - expect(isDependencyString('foo$bar:baz:1.2.+')).toBeFalse(); - expect(isDependencyString('scm:git:https://some.git')).toBeFalse(); + it('returns null for invalid inputs', () => { + const inputs = ['', undefined, null, 'foobar', 'latest']; + for (const input of inputs) { + expect(versionLikeSubstring(input)).toBeNull(); + } + }); }); - it('parseDependencyString', () => { - expect(parseDependencyString('foo:bar:1.2.3')).toMatchObject({ - depName: 'foo:bar', - currentValue: '1.2.3', + describe('isDependencyString', () => { + it.each` + input | output + ${'foo:bar:1.2.3'} | ${true} + ${'foo.foo:bar.bar:1.2.3'} | ${true} + ${'foo.bar:baz:1.2.3'} | ${true} + ${'foo.bar:baz:1.2.3:linux-cpu-x86_64'} | ${true} + ${'foo:bar:1.2.3@zip'} | ${true} + ${'foo:bar:x86@x86'} | ${true} + ${'foo.bar:baz:1.2.+'} | ${true} + ${'foo:bar:baz:qux'} | ${false} + ${'foo:bar:baz:qux:quux'} | ${false} + ${"foo:bar:1.2.3'"} | ${false} + ${'foo:bar:1.2.3"'} | ${false} + ${'-Xep:ParameterName:OFF'} | ${false} + ${'foo$bar:baz:1.2.+'} | ${false} + ${'scm:git:https://some.git'} | ${false} + ${'foo.bar:baz:1.2.3:linux-cpu$-x86_64'} | ${false} + ${'foo:bar:1.2.3@zip@foo'} | ${false} + `('$input', ({ input, output }) => { + expect(isDependencyString(input)).toBe(output); }); - expect(parseDependencyString('foo.foo:bar.bar:1.2.3')).toMatchObject({ - depName: 'foo.foo:bar.bar', - currentValue: '1.2.3', - }); - expect(parseDependencyString('foo.bar:baz:1.2.3')).toMatchObject({ - depName: 'foo.bar:baz', - currentValue: '1.2.3', - }); - expect(parseDependencyString('foo:bar:1.2.+')).toMatchObject({ - depName: 'foo:bar', - currentValue: '1.2.+', + }); + + describe('parseDependencyString', () => { + it.each` + input | output + ${'foo:bar:1.2.3'} | ${{ depName: 'foo:bar', currentValue: '1.2.3' }} + ${'foo.foo:bar.bar:1.2.3'} | ${{ depName: 'foo.foo:bar.bar', currentValue: '1.2.3' }} + ${'foo.bar:baz:1.2.3'} | ${{ depName: 'foo.bar:baz', currentValue: '1.2.3' }} + ${'foo:bar:1.2.+'} | ${{ depName: 'foo:bar', currentValue: '1.2.+' }} + ${'foo:bar:1.2.3@zip'} | ${{ depName: 'foo:bar', currentValue: '1.2.3', dataType: 'zip' }} + ${'foo:bar:baz:qux'} | ${null} + ${'foo:bar:baz:qux:quux'} | ${null} + ${"foo:bar:1.2.3'"} | ${null} + ${'foo:bar:1.2.3"'} | ${null} + ${'-Xep:ParameterName:OFF'} | ${null} + `('$input', ({ input, output }) => { + expect(parseDependencyString(input)).toEqual(output); }); - expect(parseDependencyString('foo:bar:baz:qux')).toBeNull(); - expect(parseDependencyString('foo:bar:baz:qux:quux')).toBeNull(); - expect(parseDependencyString("foo:bar:1.2.3'")).toBeNull(); - expect(parseDependencyString('foo:bar:1.2.3"')).toBeNull(); - expect(parseDependencyString('-Xep:ParameterName:OFF')).toBeNull(); + }); + + it('filetype checks', () => { + expect(isGradleScriptFile('/a/Somefile.gradle.kts')).toBeTrue(); + expect(isGradleScriptFile('/a/Somefile.gradle')).toBeTrue(); + expect(isGradleVersionsFile('/a/versions.gradle.kts')).toBeTrue(); + expect(isGradleBuildFile('/a/build.gradle')).toBeTrue(); + expect(isPropsFile('/a/gradle.properties')).toBeTrue(); + expect(isKotlinSourceFile('/a/Somefile.kt')).toBeTrue(); + expect(isTOMLFile('/a/Somefile.toml')).toBeTrue(); }); it('reorderFiles', () => { @@ -175,20 +198,33 @@ describe('modules/manager/gradle/utils', () => { }); }); - it('updateVars', () => { - const registry: VariableRegistry = { - [toAbsolutePath('/foo/bar/baz')]: { + describe('updateVars', () => { + it('empty registry', () => { + const registry: VariableRegistry = {}; + const newVars: PackageVariables = { + qux: { key: 'qux', value: 'qux' }, + }; + updateVars(registry, '/foo/bar/baz', newVars); + expect(registry).toStrictEqual({ '/foo/bar/baz': newVars }); + }); + + it('updates the registry', () => { + const registry: VariableRegistry = { + [toAbsolutePath('/foo/bar/baz')]: { + bar: { key: 'bar', value: 'bar' }, + baz: { key: 'baz', value: 'baz' }, + }, + }; + + updateVars(registry, '/foo/bar/baz', { + qux: { key: 'qux', value: 'qux' }, + }); + const res = getVars(registry, '/foo/bar/baz/build.gradle'); + expect(res).toStrictEqual({ bar: { key: 'bar', value: 'bar' }, baz: { key: 'baz', value: 'baz' }, - }, - }; - - updateVars(registry, '/foo/bar/baz', { qux: { key: 'qux', value: 'qux' } }); - const res = getVars(registry, '/foo/bar/baz/build.gradle'); - expect(res).toStrictEqual({ - bar: { key: 'bar', value: 'bar' }, - baz: { key: 'baz', value: 'baz' }, - qux: { key: 'qux', value: 'qux' }, + qux: { key: 'qux', value: 'qux' }, + }); }); }); }); diff --git a/lib/modules/manager/gradle/utils.ts b/lib/modules/manager/gradle/utils.ts index 84de600b478a0f..8b238247ec5300 100644 --- a/lib/modules/manager/gradle/utils.ts +++ b/lib/modules/manager/gradle/utils.ts @@ -13,8 +13,7 @@ const artifactRegex = regEx( const versionLikeRegex = regEx('^(?[-_.\\[\\](),a-zA-Z0-9+]+)'); -// Extracts version-like and range-like strings -// from the beginning of input +// Extracts version-like and range-like strings from the beginning of input export function versionLikeSubstring( input: string | null | undefined, ): string | null { @@ -32,40 +31,32 @@ export function versionLikeSubstring( } export function isDependencyString(input: string): boolean { - const split = input?.split(':'); - if (split?.length !== 3 && split?.length !== 4) { + const parts = input.split(':'); + if (parts.length !== 3 && parts.length !== 4) { return false; } - // eslint-disable-next-line prefer-const - let [tempGroupId, tempArtifactId, tempVersionPart, optionalClassifier] = - split; + const [groupId, artifactId, versionPart, optionalClassifier] = parts; if (optionalClassifier && !artifactRegex.test(optionalClassifier)) { return false; } - if ( - tempVersionPart !== versionLikeSubstring(tempVersionPart) && - tempVersionPart.includes('@') - ) { - const versionSplit = tempVersionPart?.split('@'); - if (versionSplit?.length !== 2) { + let version = versionPart; + if (versionPart.includes('@')) { + const [actualVersion, ...rest] = versionPart.split('@'); + if (rest.length !== 1) { return false; } - [tempVersionPart] = versionSplit; + version = actualVersion; } - const [groupId, artifactId, versionPart] = [ - tempGroupId, - tempArtifactId, - tempVersionPart, - ]; + return !!( groupId && artifactId && - versionPart && + version && artifactRegex.test(groupId) && artifactRegex.test(artifactId) && - versionPart === versionLikeSubstring(versionPart) + version === versionLikeSubstring(version) ); } @@ -75,18 +66,14 @@ export function parseDependencyString( if (!isDependencyString(input)) { return null; } - const [groupId, artifactId, FullValue] = input.split(':'); - if (FullValue === versionLikeSubstring(FullValue)) { - return { - depName: `${groupId}:${artifactId}`, - currentValue: FullValue, - }; - } - const [currentValue, dataType] = FullValue.split('@'); + + const [groupId, artifactId, fullValue] = input.split(':'); + const [currentValue, dataType] = fullValue.split('@'); + return { depName: `${groupId}:${artifactId}`, currentValue, - dataType, + ...(dataType && { dataType }), }; } diff --git a/lib/modules/manager/haskell-cabal/extract.spec.ts b/lib/modules/manager/haskell-cabal/extract.spec.ts new file mode 100644 index 00000000000000..7625c210396a08 --- /dev/null +++ b/lib/modules/manager/haskell-cabal/extract.spec.ts @@ -0,0 +1,94 @@ +import { + countPackageNameLength, + countPrecedingIndentation, + extractNamesAndRanges, + findExtents, + splitSingleDependency, +} from './extract'; + +describe('modules/manager/haskell-cabal/extract', () => { + describe('countPackageNameLength', () => { + it.each` + input | expected + ${'-'} | ${null} + ${'-j'} | ${null} + ${'-H'} | ${null} + ${'j-'} | ${null} + ${'3-'} | ${null} + ${'-3'} | ${null} + ${'3'} | ${null} + ${'ÃĻ'} | ${null} + ${'ÃĻe'} | ${null} + ${'j'} | ${1} + ${'H'} | ${1} + ${'0ad'} | ${3} + ${'3d'} | ${2} + ${'aeson'} | ${5} + ${'lens'} | ${4} + ${'parsec'} | ${6} + `('matches $input', ({ input, expected }) => { + const maybeIndex = countPackageNameLength(input); + expect(maybeIndex).toStrictEqual(expected); + }); + }); + + describe('countPrecedingIndentation()', () => { + it.each` + content | index | expected + ${'\tbuild-depends: base\n\tother-field: hi'} | ${1} | ${1} + ${' build-depends: base'} | ${1} | ${1} + ${'a\tb'} | ${0} | ${0} + ${'a\tb'} | ${2} | ${1} + ${'a b'} | ${2} | ${1} + ${' b'} | ${2} | ${2} + `( + 'countPrecedingIndentation($content, $index)', + ({ content, index, expected }) => { + expect(countPrecedingIndentation(content, index)).toBe(expected); + }, + ); + }); + + describe('findExtents()', () => { + it.each` + content | indent | expected + ${'a: b\n\tc: d'} | ${1} | ${10} + ${'a: b'} | ${2} | ${4} + ${'a: b\n\tc: d'} | ${2} | ${4} + ${'a: b\n '} | ${2} | ${6} + ${'a: b\n c: d\ne: f'} | ${1} | ${10} + `('findExtents($indent, $content)', ({ indent, content, expected }) => { + expect(findExtents(indent, content)).toBe(expected); + }); + }); + + describe('splitSingleDependency()', () => { + it.each` + depLine | expectedName | expectedRange + ${'base >=2 && <3'} | ${'base'} | ${'>=2 && <3'} + ${'base >=2 && <3 '} | ${'base'} | ${'>=2 && <3'} + ${'base>=2&&<3'} | ${'base'} | ${'>=2&&<3'} + ${'base'} | ${'base'} | ${''} + `( + 'splitSingleDependency($depLine)', + ({ depLine, expectedName, expectedRange }) => { + const res = splitSingleDependency(depLine); + expect(res?.name).toEqual(expectedName); + expect(res?.range).toEqual(expectedRange); + }, + ); + + // The first hyphen makes the package name invalid + expect(splitSingleDependency('-invalid-package-name')).toBeNull(); + }); + + describe('extractNamesAndRanges()', () => { + it('trims replaceString', () => { + const res = extractNamesAndRanges(' a , b '); + expect(res).toEqual([ + { currentValue: '', packageName: 'a', replaceString: 'a' }, + { currentValue: '', packageName: 'b', replaceString: 'b' }, + ]); + }); + }); +}); diff --git a/lib/modules/manager/haskell-cabal/extract.ts b/lib/modules/manager/haskell-cabal/extract.ts new file mode 100644 index 00000000000000..80231c3e5c7a93 --- /dev/null +++ b/lib/modules/manager/haskell-cabal/extract.ts @@ -0,0 +1,190 @@ +import { regEx } from '../../../util/regex'; + +const buildDependsRegex = regEx( + /(?build-depends[ \t]*:)/i, +); +function isNonASCII(str: string): boolean { + for (let i = 0; i < str.length; i++) { + if (str.charCodeAt(i) > 127) { + return true; + } + } + return false; +} + +export function countPackageNameLength(input: string): number | null { + if (input.length < 1 || isNonASCII(input)) { + return null; + } + if (!regEx(/^[A-Za-z0-9]/).test(input[0])) { + // Must start with letter or number + return null; + } + let idx = 1; + while (idx < input.length) { + if (regEx(/[A-Za-z0-9-]/).test(input[idx])) { + idx++; + } else { + break; + } + } + if (!regEx(/[A-Za-z]/).test(input.slice(0, idx))) { + // Must contain a letter + return null; + } + if (idx - 1 < input.length && input[idx - 1] === '-') { + // Can't end in a hyphen + return null; + } + return idx; +} + +export interface CabalDependency { + packageName: string; + currentValue: string; + replaceString: string; +} + +/** + * Find extents of field contents + * + * @param {number} indent - + * Indention level maintained within the block. + * Any indention lower than this means it's outside the field. + * Lines with this level or more are included in the field. + * @returns {number} + * Index just after the end of the block. + * Note that it may be after the end of the string. + */ +export function findExtents(indent: number, content: string): number { + let blockIdx: number = 0; + let mode: 'finding-newline' | 'finding-indention' = 'finding-newline'; + for (;;) { + if (mode === 'finding-newline') { + while (content[blockIdx++] !== '\n') { + if (blockIdx >= content.length) { + break; + } + } + if (blockIdx >= content.length) { + return content.length; + } + mode = 'finding-indention'; + } else { + let thisIndent = 0; + for (;;) { + if ([' ', '\t'].includes(content[blockIdx])) { + thisIndent += 1; + blockIdx++; + if (blockIdx >= content.length) { + return content.length; + } + continue; + } + mode = 'finding-newline'; + blockIdx++; + break; + } + if (thisIndent < indent) { + // go back to before the newline + for (;;) { + if (content[blockIdx--] === '\n') { + break; + } + } + return blockIdx + 1; + } + mode = 'finding-newline'; + } + } +} + +/** + * Find indention level of build-depends + * + * @param {number} match - + * Search starts at this index, and proceeds backwards. + * @returns {number} + * Number of indention levels found before 'match'. + */ +export function countPrecedingIndentation( + content: string, + match: number, +): number { + let whitespaceIdx = match - 1; + let indent = 0; + while (whitespaceIdx >= 0 && [' ', '\t'].includes(content[whitespaceIdx])) { + indent += 1; + whitespaceIdx--; + } + return indent; +} + +/** + * Find one 'build-depends' field name usage and its field value + * + * @returns {{buildDependsContent: string, lengthProcessed: number}} + * buildDependsContent: + * the contents of the field, excluding the field name and the colon. + * + * lengthProcessed: + * points to after the end of the field. Note that the field does _not_ + * necessarily start at `content.length - lengthProcessed`. + * + * Returns null if no 'build-depends' field is found. + */ +export function findDepends( + content: string, +): { buildDependsContent: string; lengthProcessed: number } | null { + const matchObj = buildDependsRegex.exec(content); + if (!matchObj?.groups) { + return null; + } + const indent = countPrecedingIndentation(content, matchObj.index); + const ourIdx: number = + matchObj.index + matchObj.groups['buildDependsFieldName'].length; + const extent: number = findExtents(indent + 1, content.slice(ourIdx)); + return { + buildDependsContent: content.slice(ourIdx, ourIdx + extent), + lengthProcessed: ourIdx + extent, + }; +} + +/** + * Split a cabal single dependency into its constituent parts. + * The first part is the package name, an optional second part contains + * the version constraint. + * + * For example 'base == 3.2' would be split into 'base' and ' == 3.2'. + * + * @returns {{name: string, range: string}} + * Null if the trimmed string doesn't begin with a package name. + */ +export function splitSingleDependency( + input: string, +): { name: string; range: string } | null { + const match = countPackageNameLength(input); + if (match === null) { + return null; + } + const name: string = input.slice(0, match); + const range = input.slice(match).trim(); + return { name, range }; +} + +export function extractNamesAndRanges(content: string): CabalDependency[] { + const list = content.split(','); + const deps = []; + for (const untrimmedReplaceString of list) { + const replaceString = untrimmedReplaceString.trim(); + const maybeNameRange = splitSingleDependency(replaceString); + if (maybeNameRange !== null) { + deps.push({ + currentValue: maybeNameRange.range, + packageName: maybeNameRange.name, + replaceString, + }); + } + } + return deps; +} diff --git a/lib/modules/manager/haskell-cabal/index.spec.ts b/lib/modules/manager/haskell-cabal/index.spec.ts new file mode 100644 index 00000000000000..7409938d36745b --- /dev/null +++ b/lib/modules/manager/haskell-cabal/index.spec.ts @@ -0,0 +1,55 @@ +import { codeBlock } from 'common-tags'; +import { extractPackageFile, getRangeStrategy } from '.'; + +const minimalCabalFile = codeBlock` +cabal-version: 3.4 +name: minimal +version: 0.1.0.0 + +executable my-cli-entry-point + main-is: Main.hs + build-depends: base>=4.20`; + +describe('modules/manager/haskell-cabal/index', () => { + describe('extractPackageFile()', () => { + it.each` + content | expected + ${'build-depends: base,'} | ${['base']} + ${'build-depends:,other,other2'} | ${['other', 'other2']} + ${'build-depends : base'} | ${['base']} + ${'Build-Depends: base'} | ${['base']} + ${'build-depends: a\nbuild-depends: b'} | ${['a', 'b']} + ${'dependencies: base'} | ${[]} + `( + 'extractPackageFile($content).deps.map(x => x.packageName)', + ({ content, expected }) => { + expect( + extractPackageFile(content).deps.map((x) => x.packageName), + ).toStrictEqual(expected); + }, + ); + + expect(extractPackageFile(minimalCabalFile).deps).toStrictEqual([ + { + autoReplaceStringTemplate: '{{{depName}}} {{{newValue}}}', + currentValue: '>=4.20', + datasource: 'hackage', + depName: 'base', + packageName: 'base', + replaceString: 'base>=4.20', + versioning: 'pvp', + }, + ]); + }); + + describe('getRangeStrategy()', () => { + it.each` + input | expected + ${'auto'} | ${'widen'} + ${'widen'} | ${'widen'} + ${'replace'} | ${'replace'} + `('getRangeStrategy({ rangeStrategy: $input })', ({ input, expected }) => { + expect(getRangeStrategy({ rangeStrategy: input })).toBe(expected); + }); + }); +}); diff --git a/lib/modules/manager/haskell-cabal/index.ts b/lib/modules/manager/haskell-cabal/index.ts new file mode 100644 index 00000000000000..2616dd88f17d26 --- /dev/null +++ b/lib/modules/manager/haskell-cabal/index.ts @@ -0,0 +1,57 @@ +import type { Category } from '../../../constants'; +import type { RangeStrategy } from '../../../types'; +import { HackageDatasource } from '../../datasource/hackage'; +import * as pvpVersioning from '../../versioning/pvp'; +import type { + PackageDependency, + PackageFileContent, + RangeConfig, +} from '../types'; +import type { CabalDependency } from './extract'; +import { extractNamesAndRanges, findDepends } from './extract'; + +export const defaultConfig = { + fileMatch: ['\\.cabal$'], + pinDigests: false, +}; + +export const categories: Category[] = ['haskell']; + +export const supportedDatasources = [HackageDatasource.id]; + +export function extractPackageFile(content: string): PackageFileContent { + const deps = []; + let current = content; + for (;;) { + const maybeContent = findDepends(current); + if (maybeContent === null) { + break; + } + const cabalDeps: CabalDependency[] = extractNamesAndRanges( + maybeContent.buildDependsContent, + ); + for (const cabalDep of cabalDeps) { + const dep: PackageDependency = { + depName: cabalDep.packageName, + currentValue: cabalDep.currentValue, + datasource: HackageDatasource.id, + packageName: cabalDep.packageName, + versioning: pvpVersioning.id, + replaceString: cabalDep.replaceString.trim(), + autoReplaceStringTemplate: '{{{depName}}} {{{newValue}}}', + }; + deps.push(dep); + } + current = current.slice(maybeContent.lengthProcessed); + } + return { deps }; +} + +export function getRangeStrategy({ + rangeStrategy, +}: RangeConfig): RangeStrategy { + if (rangeStrategy === 'auto') { + return 'widen'; + } + return rangeStrategy; +} diff --git a/lib/modules/manager/haskell-cabal/readme.md b/lib/modules/manager/haskell-cabal/readme.md new file mode 100644 index 00000000000000..e2c90a6fac4fd3 --- /dev/null +++ b/lib/modules/manager/haskell-cabal/readme.md @@ -0,0 +1,10 @@ +Supports dependency extraction from `build-depends` fields in [Cabal package description files](https://cabal.readthedocs.io/en/3.12/cabal-package-description-file.html#pkg-field-build-depends). +They use the extension `.cabal`, and are used with the [Haskell programming language](https://www.haskell.org/). + +Limitations: + +- The dependencies of all components are mushed together in one big list. +- Fields like `pkgconfig-depends` and `build-tool-depends` are not handled. +- The default PVP versioning is [subject to limitations](../../versioning/pvp/index.md). + +If you need to change the versioning format, read the [versioning](../../versioning/index.md) documentation to learn more. 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/mix/__fixtures__/mix.exs b/lib/modules/manager/mix/__fixtures__/mix.exs index 9bc2b75a800d38..2ad51c305e58e1 100644 --- a/lib/modules/manager/mix/__fixtures__/mix.exs +++ b/lib/modules/manager/mix/__fixtures__/mix.exs @@ -27,13 +27,19 @@ defmodule MyProject.MixProject do {:secret, "~> 1.0", organization: "acme"}, {:also_secret, "~> 1.0", only: [:dev, :test], organization: "acme", runtime: false}, {:metrics, ">0.2.0 and <=1.0.0"}, - {:jason, ">= 1.0.0"}, + {:jason, ">= 1.0.0", only: :prod}, {:hackney, "~> 1.0", optional: true}, - {:hammer_backend_redis, "~> 6.1"}, + {:hammer_backend_redis, "~> 6.1", only: [:dev, :prod, :test]}, {:castore, "== 1.0.10"}, {:gun, "~> 2.0.0", hex: "grpc_gun"}, {:another_gun, "~> 0.4.0", hex: :raygun}, + {:credo, "~> 1.7", only: + [:test, + # prod, + :dev], + runtime: false}, + {:floki, "== 0.37.0", only: :test}, ] end end diff --git a/lib/modules/manager/mix/__fixtures__/mix.lock b/lib/modules/manager/mix/__fixtures__/mix.lock index d90b44ee2d1c38..106d497cd6b91e 100644 --- a/lib/modules/manager/mix/__fixtures__/mix.lock +++ b/lib/modules/manager/mix/__fixtures__/mix.lock @@ -1,13 +1,17 @@ %{ "another_gun": {:hex, :raygun, "0.4.0", "7744e99dd695f61e78ad5e047cce0affb3edfc6f93a92278598ab553b9c5091f", [:mix], [{:httpoison, "~> 0.8 or ~> 1.0", [hex: :httpoison, repo: "hexpm", optional: false]}, {:jason, "~> 1.2", [hex: :jason, repo: "hexpm", optional: false]}, {:plug, "~> 1.1", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "eee4b891e6e65c6a4b15386dc7b7a72b717f3c123cc0012cfd19e8f2ab21116d"}, + "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, "castore": {:hex, :castore, "1.0.10", "43bbeeac820f16c89f79721af1b3e092399b3a1ecc8df1a472738fd853574911", [:mix], [], "hexpm", "1b0b7ea14d889d9ea21202c43a4fa015eb913021cb535e8ed91946f4b77a8848"}, "certifi": {:hex, :certifi, "2.12.0", "2d1cca2ec95f59643862af91f001478c9863c2ac9cb6e2f89780bfd8de987329", [:rebar3], [], "hexpm", "ee68d85df22e554040cdb4be100f33873ac6051387baf6a8f6ce82272340ff1c"}, "cowboy": {:git, "https://github.com/ninenines/cowboy.git", "0c2e2224e372f01e6cf51a8e12d4856edb4cb8ac", [tag: "0.6.0"]}, "cowlib": {:hex, :cowlib, "2.13.0", "db8f7505d8332d98ef50a3ef34b34c1afddec7506e4ee4dd4a3a266285d282ca", [:make, :rebar3], [], "hexpm", "e1e1284dc3fc030a64b1ad0d8382ae7e99da46c3246b815318a4b848873800a4"}, + "credo": {:hex, :credo, "1.7.10", "6e64fe59be8da5e30a1b96273b247b5cf1cc9e336b5fd66302a64b25749ad44d", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "71fbc9a6b8be21d993deca85bf151df023a3097b01e09a2809d460348561d8cd"}, "decimal": {:hex, :decimal, "1.9.0", "83e8daf59631d632b171faabafb4a9f4242c514b0a06ba3df493951c08f64d07", [:mix], [], "hexpm", "b1f2343568eed6928f3e751cf2dffde95bfaa19dd95d09e8a9ea92ccfd6f7d85"}, "ecto": {:git, "https://github.com/elixir-ecto/ecto.git", "795036d997c7503b21fb64d6bf1a89b83c44f2b5", [ref: "795036d997c7503b21fb64d6bf1a89b83c44f2b5"]}, "secret": {:hex, :secret, "1.5.0", "344dbbf6610d205760ec37e2848bff2aab5a2de182bb5cdaa72cc2fd19d74535", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm", "19c205c8de0e2e5817f2250100281c58e717cb11ff1bb410bf661ee78c24e79b"}, "also_secret": {:hex, :also_secret, "1.3.4", "344dbbf6610d205760ec37e2848bff2aab5a2de182bb5cdaa72cc2fd19d74535", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm", "19c205c8de0e2e5817f2250100281c58e717cb11ff1bb410bf661ee78c24e79b"}, + "file_system": {:hex, :file_system, "1.0.1", "79e8ceaddb0416f8b8cd02a0127bdbababe7bf4a23d2a395b983c1f8b3f73edd", [:mix], [], "hexpm", "4414d1f38863ddf9120720cd976fce5bdde8e91d8283353f0e31850fa89feb9e"}, + "floki": {:hex, :floki, "0.37.0", "b83e0280bbc6372f2a403b2848013650b16640cd2470aea6701f0632223d719e", [:mix], [], "hexpm", "516a0c15a69f78c47dc8e0b9b3724b29608aa6619379f91b1ffa47109b5d0dd3"}, "gun": {:hex, :grpc_gun, "2.0.1", "221b792df3a93e8fead96f697cbaf920120deacced85c6cd3329d2e67f0871f8", [:rebar3], [{:cowlib, "~> 2.11", [hex: :cowlib, repo: "hexpm", optional: false]}], "hexpm", "795a65eb9d0ba16697e6b0e1886009ce024799e43bb42753f0c59b029f592831"}, "hackney": {:hex, :hackney, "1.20.1", "8d97aec62ddddd757d128bfd1df6c5861093419f8f7a4223823537bad5d064e2", [:rebar3], [{:certifi, "~> 2.12.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "fe9094e5f1a2a2c0a7d10918fee36bfec0ec2a979994cff8cfe8058cd9af38e3"}, "hammer": {:hex, :hammer, "6.2.1", "5ae9c33e3dceaeb42de0db46bf505bd9c35f259c8defb03390cd7556fea67ee2", [:mix], [{:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: false]}], "hexpm", "b9476d0c13883d2dc0cc72e786bac6ac28911fba7cc2e04b70ce6a6d9c4b2bdc"}, diff --git a/lib/modules/manager/mix/extract.spec.ts b/lib/modules/manager/mix/extract.spec.ts index 3663073aabc20c..a20ea0327fd715 100644 --- a/lib/modules/manager/mix/extract.spec.ts +++ b/lib/modules/manager/mix/extract.spec.ts @@ -20,12 +20,14 @@ describe('modules/manager/mix/extract', () => { currentValue: '~> 0.8.1', datasource: 'hex', depName: 'postgrex', + depType: 'prod', packageName: 'postgrex', }, { currentValue: '<1.7.0 or ~>1.7.1', datasource: 'hex', depName: 'ranch', + depType: 'prod', packageName: 'ranch', }, { @@ -33,6 +35,7 @@ describe('modules/manager/mix/extract', () => { currentValue: '0.6.0', datasource: 'github-tags', depName: 'cowboy', + depType: 'prod', packageName: 'ninenines/cowboy', }, { @@ -40,6 +43,7 @@ describe('modules/manager/mix/extract', () => { currentValue: 'main', datasource: 'git-tags', depName: 'phoenix', + depType: 'prod', packageName: 'https://github.com/phoenixframework/phoenix.git', }, { @@ -47,42 +51,49 @@ describe('modules/manager/mix/extract', () => { currentValue: undefined, datasource: 'github-tags', depName: 'ecto', + depType: 'prod', packageName: 'elixir-ecto/ecto', }, { currentValue: '~> 1.0', datasource: 'hex', depName: 'secret', + depType: 'prod', packageName: 'secret:acme', }, { currentValue: '~> 1.0', datasource: 'hex', depName: 'also_secret', + depType: 'dev', packageName: 'also_secret:acme', }, { currentValue: '>0.2.0 and <=1.0.0', datasource: 'hex', depName: 'metrics', + depType: 'prod', packageName: 'metrics', }, { currentValue: '>= 1.0.0', datasource: 'hex', depName: 'jason', + depType: 'prod', packageName: 'jason', }, { currentValue: '~> 1.0', datasource: 'hex', depName: 'hackney', + depType: 'prod', packageName: 'hackney', }, { currentValue: '~> 6.1', datasource: 'hex', depName: 'hammer_backend_redis', + depType: 'prod', packageName: 'hammer_backend_redis', }, { @@ -90,20 +101,38 @@ describe('modules/manager/mix/extract', () => { currentVersion: '1.0.10', datasource: 'hex', depName: 'castore', + depType: 'prod', packageName: 'castore', }, { currentValue: '~> 2.0.0', datasource: 'hex', depName: 'gun', + depType: 'prod', packageName: 'grpc_gun', }, { currentValue: '~> 0.4.0', datasource: 'hex', depName: 'another_gun', + depType: 'prod', packageName: 'raygun', }, + { + currentValue: '~> 1.7', + datasource: 'hex', + depName: 'credo', + depType: 'dev', + packageName: 'credo', + }, + { + currentValue: '== 0.37.0', + currentVersion: '0.37.0', + datasource: 'hex', + depName: 'floki', + depType: 'dev', + packageName: 'floki', + }, ]); }); @@ -116,6 +145,7 @@ describe('modules/manager/mix/extract', () => { currentValue: '~> 0.8.1', datasource: 'hex', depName: 'postgrex', + depType: 'prod', packageName: 'postgrex', lockedVersion: '0.8.4', }, @@ -123,6 +153,7 @@ describe('modules/manager/mix/extract', () => { currentValue: '<1.7.0 or ~>1.7.1', datasource: 'hex', depName: 'ranch', + depType: 'prod', packageName: 'ranch', lockedVersion: '1.7.1', }, @@ -131,6 +162,7 @@ describe('modules/manager/mix/extract', () => { currentValue: '0.6.0', datasource: 'github-tags', depName: 'cowboy', + depType: 'prod', packageName: 'ninenines/cowboy', lockedVersion: '0.6.0', }, @@ -139,6 +171,7 @@ describe('modules/manager/mix/extract', () => { currentValue: 'main', datasource: 'git-tags', depName: 'phoenix', + depType: 'prod', packageName: 'https://github.com/phoenixframework/phoenix.git', lockedVersion: undefined, }, @@ -147,6 +180,7 @@ describe('modules/manager/mix/extract', () => { currentValue: undefined, datasource: 'github-tags', depName: 'ecto', + depType: 'prod', packageName: 'elixir-ecto/ecto', lockedVersion: undefined, }, @@ -154,6 +188,7 @@ describe('modules/manager/mix/extract', () => { currentValue: '~> 1.0', datasource: 'hex', depName: 'secret', + depType: 'prod', packageName: 'secret:acme', lockedVersion: '1.5.0', }, @@ -161,6 +196,7 @@ describe('modules/manager/mix/extract', () => { currentValue: '~> 1.0', datasource: 'hex', depName: 'also_secret', + depType: 'dev', packageName: 'also_secret:acme', lockedVersion: '1.3.4', }, @@ -168,6 +204,7 @@ describe('modules/manager/mix/extract', () => { currentValue: '>0.2.0 and <=1.0.0', datasource: 'hex', depName: 'metrics', + depType: 'prod', packageName: 'metrics', lockedVersion: '1.0.0', }, @@ -175,6 +212,7 @@ describe('modules/manager/mix/extract', () => { currentValue: '>= 1.0.0', datasource: 'hex', depName: 'jason', + depType: 'prod', packageName: 'jason', lockedVersion: '1.4.4', }, @@ -182,6 +220,7 @@ describe('modules/manager/mix/extract', () => { currentValue: '~> 1.0', datasource: 'hex', depName: 'hackney', + depType: 'prod', packageName: 'hackney', lockedVersion: '1.20.1', }, @@ -189,6 +228,7 @@ describe('modules/manager/mix/extract', () => { currentValue: '~> 6.1', datasource: 'hex', depName: 'hammer_backend_redis', + depType: 'prod', packageName: 'hammer_backend_redis', lockedVersion: '6.2.0', }, @@ -197,6 +237,7 @@ describe('modules/manager/mix/extract', () => { currentVersion: '1.0.10', datasource: 'hex', depName: 'castore', + depType: 'prod', packageName: 'castore', lockedVersion: '1.0.10', }, @@ -204,6 +245,7 @@ describe('modules/manager/mix/extract', () => { currentValue: '~> 2.0.0', datasource: 'hex', depName: 'gun', + depType: 'prod', packageName: 'grpc_gun', lockedVersion: '2.0.1', }, @@ -211,9 +253,27 @@ describe('modules/manager/mix/extract', () => { currentValue: '~> 0.4.0', datasource: 'hex', depName: 'another_gun', + depType: 'prod', packageName: 'raygun', lockedVersion: '0.4.0', }, + { + currentValue: '~> 1.7', + datasource: 'hex', + depName: 'credo', + depType: 'dev', + packageName: 'credo', + lockedVersion: '1.7.10', + }, + { + currentValue: '== 0.37.0', + currentVersion: '0.37.0', + datasource: 'hex', + depName: 'floki', + depType: 'dev', + lockedVersion: '0.37.0', + packageName: 'floki', + }, ]); }); }); diff --git a/lib/modules/manager/mix/extract.ts b/lib/modules/manager/mix/extract.ts index 3d9c45e00d74f4..9d8c5a90b65392 100644 --- a/lib/modules/manager/mix/extract.ts +++ b/lib/modules/manager/mix/extract.ts @@ -20,6 +20,8 @@ const lockedVersionRegExp = regEx( /^\s+"(?\w+)".*?"(?\d+\.\d+\.\d+)"/, ); const hexRegexp = regEx(/hex:\s*(?:"(?[^"]+)"|:(?\w+))/); +const onlyValueRegexp = regEx(/only:\s*(?\[[^\]]*\]|:\w+)/); +const onlyEnvironmentsRegexp = regEx(/:(\w+)/gm); export async function extractPackageFile( content: string, @@ -48,22 +50,28 @@ export async function extractPackageFile( const hexGroups = hexRegexp.exec(opts)?.groups; const hex = hexGroups?.strValue ?? hexGroups?.atomValue; - let dep: PackageDependency; + const onlyValue = onlyValueRegexp.exec(opts)?.groups?.only; + const onlyEnvironments = []; + let match; + if (onlyValue) { + while ((match = onlyEnvironmentsRegexp.exec(onlyValue)) !== null) { + onlyEnvironments.push(match[1]); + } + } + + const dep: PackageDependency = { + depName: app, + depType: 'prod', + }; if (git ?? github) { - dep = { - depName: app, - currentDigest: ref, - currentValue: branchOrTag, - datasource: git ? GitTagsDatasource.id : GithubTagsDatasource.id, - packageName: git ?? github, - }; + dep.currentDigest = ref; + dep.currentValue = branchOrTag; + dep.datasource = git ? GitTagsDatasource.id : GithubTagsDatasource.id; + dep.packageName = git ?? github; } else { - dep = { - depName: app, - currentValue: requirement, - datasource: HexDatasource.id, - }; + dep.currentValue = requirement; + dep.datasource = HexDatasource.id; if (organization) { dep.packageName = `${app}:${organization}`; } else if (hex) { @@ -71,11 +79,16 @@ export async function extractPackageFile( } else { dep.packageName = app; } + if (requirement?.startsWith('==')) { dep.currentVersion = requirement.replace(regEx(/^==\s*/), ''); } } + if (onlyValue !== undefined && !onlyEnvironments.includes('prod')) { + dep.depType = 'dev'; + } + deps.set(app, dep); logger.trace({ dep }, `setting ${app}`); depMatchGroups = depMatchRegExp.exec(depBuffer)?.groups; diff --git a/lib/modules/manager/mix/index.ts b/lib/modules/manager/mix/index.ts index e9722265580591..df1fa52ec6cf6d 100644 --- a/lib/modules/manager/mix/index.ts +++ b/lib/modules/manager/mix/index.ts @@ -5,6 +5,7 @@ import { HexDatasource } from '../../datasource/hex'; export { extractPackageFile } from './extract'; export { updateArtifacts } from './artifacts'; +export { getRangeStrategy } from './range'; export const url = 'https://hexdocs.pm/mix/Mix.html'; export const categories: Category[] = ['elixir']; diff --git a/lib/modules/manager/mix/range.spec.ts b/lib/modules/manager/mix/range.spec.ts new file mode 100644 index 00000000000000..0efd919e8455cb --- /dev/null +++ b/lib/modules/manager/mix/range.spec.ts @@ -0,0 +1,47 @@ +import type { RangeConfig } from '../types'; +import { getRangeStrategy } from '.'; + +describe('modules/manager/mix/range', () => { + it('returns same if not auto', () => { + const config: RangeConfig = { rangeStrategy: 'pin' }; + expect(getRangeStrategy(config)).toBe('pin'); + + config.rangeStrategy = 'widen'; + expect(getRangeStrategy(config)).toBe('widen'); + }); + + it('widens complex bump', () => { + const config: RangeConfig = { + rangeStrategy: 'bump', + depType: 'prod', + currentValue: '>= 1.6.0 and < 2.0.0', + }; + expect(getRangeStrategy(config)).toBe('widen'); + }); + + it('bumps non-complex bump', () => { + const config: RangeConfig = { + rangeStrategy: 'bump', + depType: 'prod', + currentValue: '~>1.0.0', + }; + expect(getRangeStrategy(config)).toBe('bump'); + }); + + it('widens complex auto', () => { + const config: RangeConfig = { + rangeStrategy: 'auto', + depType: 'prod', + currentValue: '<1.7.0 or ~>1.7.1', + }; + expect(getRangeStrategy(config)).toBe('widen'); + }); + + it('defaults to update-lockfile', () => { + const config: RangeConfig = { + rangeStrategy: 'auto', + depType: 'prod', + }; + expect(getRangeStrategy(config)).toBe('update-lockfile'); + }); +}); diff --git a/lib/modules/manager/mix/range.ts b/lib/modules/manager/mix/range.ts new file mode 100644 index 00000000000000..4d6e563eb5123e --- /dev/null +++ b/lib/modules/manager/mix/range.ts @@ -0,0 +1,26 @@ +import { parseRange } from 'semver-utils'; +import { logger } from '../../../logger'; +import type { RangeStrategy } from '../../../types'; +import type { RangeConfig } from '../types'; + +export function getRangeStrategy(config: RangeConfig): RangeStrategy { + const { currentValue, rangeStrategy } = config; + const isComplexRange = currentValue + ? parseRange(currentValue).length > 1 + : false; + + if (rangeStrategy === 'bump' && isComplexRange) { + logger.debug( + { currentValue }, + 'Replacing bump strategy for complex range with widen', + ); + return 'widen'; + } + if (rangeStrategy !== 'auto') { + return rangeStrategy; + } + if (isComplexRange) { + return 'widen'; + } + return 'update-lockfile'; +} diff --git a/lib/modules/manager/mix/readme.md b/lib/modules/manager/mix/readme.md index f63ab44019224e..7924c9704caa2e 100644 --- a/lib/modules/manager/mix/readme.md +++ b/lib/modules/manager/mix/readme.md @@ -1,3 +1,27 @@ -The `mix` manager extracts dependencies for the `hex` datasource and uses Renovate's implementation of Hex SemVer to evaluate updates. +The `mix` manager uses Renovate's implementation of [Elixir SemVer](https://hexdocs.pm/elixir/Version.html#module-requirements) to evaluate update ranges. -The `mix` package manager itself is also used to keep the lock file up-to-date. +The `mix` package manager itself is used to keep the lock file up-to-date. + +The following `depTypes` are currently supported by the `mix` manager : + +- `prod`: all dependencies by default +- `dev`: dependencies with [`:only` option](https://hexdocs.pm/mix/Mix.Tasks.Deps.html#module-dependency-definition-options) not containing `:prod` + +### Default `rangeStrategy=auto` behavior + +Renovate's default [`rangeStrategy`](../../../configuration-options.md#rangestrategy) is `"auto"`. +Here's how `"auto"` works with the `mix` manager: + +| Version type | New version | Old range | New range after update | What Renovate does | +| :----------------------- | :---------- | :-------------------- | :--------------------- | :------------------------------------------------------------------------ | +| Complex range | `1.7.2` | `< 1.7.0 or ~> 1.7.1` | `< 1.7.0 or ~> 1.7.2` | Widen range to include the new version. | +| Simple range | `0.39.0` | `<= 0.38.0` | `<= 0.39.0` | If update outside current range: widens range to include the new version. | +| Exact version constraint | `0.13.0` | `== 0.12.0` | `== 0.13.0` | Replace old version with new version. | + +### Recommended `rangeStrategy` for apps and libraries + +For applications, we recommend using `rangeStrategy=pin`. +This pins your dependencies to exact versions, which is generally considered [best practice for apps](../../../dependency-pinning.md). + +For libraries, use `rangeStrategy=widen` with version ranges in your `mix.exs`. +This allows for greater compatibility with other projects that may use your library as a dependency. diff --git a/lib/modules/manager/npm/post-update/index.ts b/lib/modules/manager/npm/post-update/index.ts index b77df6d1b0d86f..5b3c139175b566 100644 --- a/lib/modules/manager/npm/post-update/index.ts +++ b/lib/modules/manager/npm/post-update/index.ts @@ -370,14 +370,6 @@ export async function getAdditionalFiles( logger.debug('Skipping lock file generation'); return { artifactErrors, updatedArtifacts }; } - if ( - config.reuseExistingBranch && - !config.updatedPackageFiles?.length && - config.upgrades?.every((upgrade) => upgrade.isLockfileUpdate) - ) { - logger.debug('Existing branch contains all necessary lock file updates'); - return { artifactErrors, updatedArtifacts }; - } logger.debug('Getting updated lock files'); if ( config.updateType === 'lockFileMaintenance' && 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/npm/update/package-version/index.ts b/lib/modules/manager/npm/update/package-version/index.ts index d40c34be61b408..03f70cfb76ac2c 100644 --- a/lib/modules/manager/npm/update/package-version/index.ts +++ b/lib/modules/manager/npm/update/package-version/index.ts @@ -35,7 +35,7 @@ export function bumpPackageVersion( parsedContent.optionalDependencies?.[mirrorPackage] ?? parsedContent.peerDependencies?.[mirrorPackage]; if (!newPjVersion) { - logger.warn('bumpVersion mirror package not found: ' + mirrorPackage); + logger.warn({ mirrorPackage }, 'bumpVersion mirror package not found'); return { bumpedContent }; } } else { diff --git a/lib/modules/manager/nuget/__fixtures__/sample.csproj b/lib/modules/manager/nuget/__fixtures__/sample.csproj index 37a002bbce8089..36f5a469eb9fe7 100644 --- a/lib/modules/manager/nuget/__fixtures__/sample.csproj +++ b/lib/modules/manager/nuget/__fixtures__/sample.csproj @@ -3,6 +3,7 @@ netcoreapp1.1 0.1.0 + 4.5.0 @@ -10,9 +11,10 @@ - - - + + + + diff --git a/lib/modules/manager/nuget/__snapshots__/extract.spec.ts.snap b/lib/modules/manager/nuget/__snapshots__/extract.spec.ts.snap index 55c20db0dc876c..60fcf38b3c7145 100644 --- a/lib/modules/manager/nuget/__snapshots__/extract.spec.ts.snap +++ b/lib/modules/manager/nuget/__snapshots__/extract.spec.ts.snap @@ -14,6 +14,43 @@ exports[`modules/manager/nuget/extract extractPackageFile() extracts all depende "depName": "Microsoft.VisualStudio.Web.CodeGeneration.Tools", "depType": "nuget", }, + { + "currentValue": "undefined", + "datasource": "nuget", + "depName": "NotUpdatable3", + "depType": "nuget", + "skipReason": "invalid-version", + }, + { + "datasource": "nuget", + "depName": "NotUpdatable3", + "depType": "nuget", + "skipReason": "invalid-version", + }, + { + "datasource": "nuget", + "depName": "NotUpdatable3", + "depType": "nuget", + "skipReason": "invalid-version", + }, + { + "datasource": "nuget", + "depName": "NotUpdatable3", + "depType": "nuget", + "skipReason": "invalid-version", + }, + { + "datasource": "nuget", + "depName": "NotUpdatable2", + "depType": "nuget", + "skipReason": "invalid-version", + }, + { + "datasource": "nuget", + "depName": "NotUpdatable1", + "depType": "nuget", + "skipReason": "invalid-version", + }, { "currentValue": "1.2.3", "datasource": "nuget", @@ -87,22 +124,24 @@ exports[`modules/manager/nuget/extract extractPackageFile() extracts all depende "depType": "nuget", }, { - "currentValue": "1.1.2", "datasource": "nuget", "depName": "Microsoft.AspNetCore.Hosting", "depType": "nuget", + "skipReason": "invalid-version", }, { - "currentValue": "4.1.0", + "currentValue": "4.5.0", "datasource": "nuget", "depName": "Autofac.Extensions.DependencyInjection", "depType": "nuget", + "sharedVariableName": "AutofacVersion", }, { "currentValue": "4.5.0", "datasource": "nuget", "depName": "Autofac", "depType": "nuget", + "sharedVariableName": "AutofacVersion", }, ] `; @@ -115,6 +154,36 @@ exports[`modules/manager/nuget/extract extractPackageFile() extracts all depende "depName": "Microsoft.VisualStudio.Web.CodeGeneration.Tools", "depType": "nuget", }, + { + "datasource": "nuget", + "depName": "NotUpdatable3", + "depType": "nuget", + "skipReason": "invalid-version", + }, + { + "datasource": "nuget", + "depName": "NotUpdatable3", + "depType": "nuget", + "skipReason": "invalid-version", + }, + { + "datasource": "nuget", + "depName": "NotUpdatable3", + "depType": "nuget", + "skipReason": "invalid-version", + }, + { + "datasource": "nuget", + "depName": "NotUpdatable2", + "depType": "nuget", + "skipReason": "invalid-version", + }, + { + "datasource": "nuget", + "depName": "NotUpdatable1", + "depType": "nuget", + "skipReason": "invalid-version", + }, { "currentValue": "1.2.3", "datasource": "nuget", diff --git a/lib/modules/manager/nuget/extract.spec.ts b/lib/modules/manager/nuget/extract.spec.ts index 8b608fc92c3cf8..592ff57f668989 100644 --- a/lib/modules/manager/nuget/extract.spec.ts +++ b/lib/modules/manager/nuget/extract.spec.ts @@ -57,7 +57,7 @@ describe('modules/manager/nuget/extract', () => { const sample = Fixtures.get(packageFile); const res = await extractPackageFile(sample, packageFile, config); expect(res?.deps).toMatchSnapshot(); - expect(res?.deps).toHaveLength(17); + expect(res?.deps).toHaveLength(23); }); it('extracts msbuild sdk from the Sdk attr of Project element', async () => { @@ -157,7 +157,7 @@ describe('modules/manager/nuget/extract', () => { const sample = Fixtures.get(packageFile); const res = await extractPackageFile(sample, packageFile, config); expect(res?.deps).toMatchSnapshot(); - expect(res?.deps).toHaveLength(17); + expect(res?.deps).toHaveLength(22); }); it('extracts ContainerBaseImage', async () => { diff --git a/lib/modules/manager/nuget/extract.ts b/lib/modules/manager/nuget/extract.ts index 19961664e499a6..3c9e6d8e9d768f 100644 --- a/lib/modules/manager/nuget/extract.ts +++ b/lib/modules/manager/nuget/extract.ts @@ -1,9 +1,8 @@ import is from '@sindresorhus/is'; -import type { XmlElement, XmlNode } from 'xmldoc'; -import { XmlDocument } from 'xmldoc'; +import type { XmlNode } from 'xmldoc'; +import { XmlDocument, XmlElement } from 'xmldoc'; import { logger } from '../../../logger'; import { getSiblingFileName, localPathExists } from '../../../util/fs'; -import { hasKey } from '../../../util/object'; import { regEx } from '../../../util/regex'; import { NugetDatasource } from '../../datasource/nuget'; import { getDep } from '../dockerfile/extract'; @@ -28,7 +27,7 @@ import { applyRegistries, findVersion, getConfiguredRegistries } from './util'; * so we don't include it in the extracting regexp */ const checkVersion = regEx( - `^\\s*(?:[[])?(?:(?[^"(,[\\]]+)\\s*(?:,\\s*[)\\]]|])?)\\s*$`, + /^\s*(?:[[])?(?:(?[^"(,[\]]+)\s*(?:,\s*[)\]]|])?)\s*$/, ); const elemNames = new Set([ 'PackageReference', @@ -37,12 +36,13 @@ const elemNames = new Set([ 'GlobalPackageReference', ]); -function isXmlElem(node: XmlNode): boolean { - return hasKey('name', node); +function isXmlElem(node: XmlNode): node is XmlElement { + return node instanceof XmlElement; } function extractDepsFromXml(xmlNode: XmlDocument): NugetPackageDependency[] { const results: NugetPackageDependency[] = []; + const vars = new Map(); const todo: XmlElement[] = [xmlNode]; while (todo.length) { const child = todo.pop()!; @@ -58,23 +58,56 @@ function extractDepsFromXml(xmlNode: XmlDocument): NugetPackageDependency[] { if (elemNames.has(name)) { const depName = attr?.Include || attr?.Update; - const version = + + if (!depName) { + continue; + } + + const dep: NugetPackageDependency = { + datasource: NugetDatasource.id, + depType: 'nuget', + depName, + }; + + let currentValue: string | undefined = attr?.Version ?? attr?.version ?? child.valueWithPath('Version') ?? attr?.VersionOverride ?? child.valueWithPath('VersionOverride'); - const currentValue = is.nonEmptyStringAndNotWhitespace(version) - ? checkVersion.exec(version)?.groups?.currentValue?.trim() - : undefined; - if (depName && currentValue) { - results.push({ - datasource: NugetDatasource.id, - depType: 'nuget', - depName, - currentValue, + + if (!is.nonEmptyStringAndNotWhitespace(currentValue)) { + dep.skipReason = 'invalid-version'; + } + + let sharedVariableName: string | undefined; + + currentValue = currentValue + ?.trim() + ?.replace(/^\$\((\w+)\)$/, (match, key) => { + const val = vars.get(key); + if (val) { + sharedVariableName = key; + return val; + } + return match; }); + + if (sharedVariableName) { + dep.sharedVariableName = sharedVariableName; } + + currentValue = checkVersion + .exec(currentValue) + ?.groups?.currentValue?.trim(); + + if (currentValue) { + dep.currentValue = currentValue; + } else { + dep.skipReason = 'invalid-version'; + } + + results.push(dep); } else if (name === 'Sdk') { const depName = attr?.Name; const version = attr?.Version; @@ -101,8 +134,21 @@ function extractDepsFromXml(xmlNode: XmlDocument): NugetPackageDependency[] { }); } } + + const propertyGroup = child.childNamed('PropertyGroup'); + if (propertyGroup) { + for (const propChild of propertyGroup.children) { + if (isXmlElem(propChild)) { + const { name, val } = propChild; + if (!['Version', 'TargetFramework'].includes(name)) { + vars.set(name, val); + } + } + } + } } - todo.push(...(child.children.filter(isXmlElem) as XmlElement[])); + + todo.push(...child.children.filter(isXmlElem)); } } return results; diff --git a/lib/modules/manager/pep621/processors/uv.ts b/lib/modules/manager/pep621/processors/uv.ts index d7de0dc1195b32..637ef35df54f1f 100644 --- a/lib/modules/manager/pep621/processors/uv.ts +++ b/lib/modules/manager/pep621/processors/uv.ts @@ -11,7 +11,7 @@ import { find } from '../../../../util/host-rules'; import { Result } from '../../../../util/result'; import { parseUrl } from '../../../../util/url'; import { PypiDatasource } from '../../../datasource/pypi'; -import { getGoogleAuthTokenRaw } from '../../../datasource/util'; +import { getGoogleAuthHostRule } from '../../../datasource/util'; import type { PackageDependency, UpdateArtifact, @@ -265,12 +265,9 @@ async function getUsernamePassword( } if (url.hostname.endsWith('.pkg.dev')) { - const accessToken = await getGoogleAuthTokenRaw(); - if (accessToken) { - return { - username: 'oauth2accesstoken', - password: accessToken, - }; + const hostRule = await getGoogleAuthHostRule(); + if (hostRule) { + return hostRule; } else { logger.once.debug({ url }, 'Could not get Google access token'); } diff --git a/lib/modules/manager/pep621/utils.spec.ts b/lib/modules/manager/pep621/utils.spec.ts index 849bb0f26550cf..80d2ca16d8d9f2 100644 --- a/lib/modules/manager/pep621/utils.spec.ts +++ b/lib/modules/manager/pep621/utils.spec.ts @@ -4,17 +4,20 @@ import { parsePEP508 } from './utils'; describe('modules/manager/pep621/utils', () => { describe('parsePEP508()', () => { it.each` - value | success | packageName | currentValue | extras | marker - ${''} | ${false} | ${undefined} | ${undefined} | ${undefined} | ${undefined} - ${undefined} | ${false} | ${undefined} | ${undefined} | ${undefined} | ${undefined} - ${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.9,!=22.0'} | ${true} | ${'packaging'} | ${'>=20.9,!=22.0'} | ${undefined} | ${undefined} - ${'cachecontrol[filecache]>=0.12.11'} | ${true} | ${'cachecontrol'} | ${'>=0.12.11'} | ${['filecache']} | ${undefined} - ${'tomli>=1.1.0; python_version < "3.11"'} | ${true} | ${'tomli'} | ${'>=1.1.0'} | ${undefined} | ${'python_version < "3.11"'} - ${'typing-extensions; python_version < "3.8"'} | ${true} | ${'typing-extensions'} | ${undefined} | ${undefined} | ${'python_version < "3.8"'} - ${'typing-extensions[test-feature]; python_version < "3.8"'} | ${true} | ${'typing-extensions'} | ${undefined} | ${['test-feature']} | ${'python_version < "3.8"'} + value | success | packageName | currentValue | extras | marker + ${''} | ${false} | ${undefined} | ${undefined} | ${undefined} | ${undefined} + ${undefined} | ${false} | ${undefined} | ${undefined} | ${undefined} | ${undefined} + ${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} + ${'tomli>=1.1.0; python_version < "3.11"'} | ${true} | ${'tomli'} | ${'>=1.1.0'} | ${undefined} | ${'python_version < "3.11"'} + ${'typing-extensions; python_version < "3.8"'} | ${true} | ${'typing-extensions'} | ${undefined} | ${undefined} | ${'python_version < "3.8"'} + ${'typing-extensions[test-feature]; python_version < "3.8"'} | ${true} | ${'typing-extensions'} | ${undefined} | ${['test-feature']} | ${'python_version < "3.8"'} `( '(parse $value"', ({ value, success, packageName, currentValue, extras, marker }) => { diff --git a/lib/modules/manager/pep621/utils.ts b/lib/modules/manager/pep621/utils.ts index faf88e2006cc29..6df1b79ae4e018 100644 --- a/lib/modules/manager/pep621/utils.ts +++ b/lib/modules/manager/pep621/utils.ts @@ -10,7 +10,7 @@ import { PyProjectSchema } from './schema'; import type { Pep508ParseResult, Pep621ManagerData } from './types'; const pep508Regex = regEx( - /^(?[A-Z0-9._-]+)\s*(\[(?[A-Z0-9,._-]+)\])?\s*(?[^;]+)?(;\s*(?.*))?/i, + /^(?[A-Z0-9._-]+)\s*(\[(?[A-Z0-9\s,._-]+)\])?\s*(?[^;]+)?(;\s*(?.*))?/i, ); export const depTypes = { @@ -43,13 +43,22 @@ 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; } if (is.nonEmptyString(regExpExec.groups.extras)) { - result.extras = regExpExec.groups.extras.split(','); + // trim to remove allowed whitespace between brackets + result.extras = regExpExec.groups.extras.split(',').map((e) => e.trim()); } return result; diff --git a/lib/modules/manager/pip-compile/common.ts b/lib/modules/manager/pip-compile/common.ts index 6ec0b128fc9f56..5a2126198900be 100644 --- a/lib/modules/manager/pip-compile/common.ts +++ b/lib/modules/manager/pip-compile/common.ts @@ -216,7 +216,8 @@ export function extractPythonVersion( const match = pythonVersionRegex.exec(content); if (match?.groups === undefined) { logger.warn( - `pip-compile: failed to extract Python version from header in ${fileName} ${content}`, + { fileName, content }, + 'pip-compile: failed to extract Python version from header in file', ); return undefined; } diff --git a/lib/modules/manager/pip-compile/extract.spec.ts b/lib/modules/manager/pip-compile/extract.spec.ts index fd70448a9a3e1e..9fe1b1dbb65230 100644 --- a/lib/modules/manager/pip-compile/extract.spec.ts +++ b/lib/modules/manager/pip-compile/extract.spec.ts @@ -473,7 +473,8 @@ describe('modules/manager/pip-compile/extract', () => { const packageFiles = await extractAllPackageFiles({}, lockFiles); expect(packageFiles?.map((p) => p.lockFiles)).toEqual([['2.txt']]); expect(logger.warn).toHaveBeenCalledWith( - 'pip-compile: 1.in references reqs-no-headers.txt which does not appear to be a requirements file managed by pip-compile', + { packageFile: '1.in', requirementsFile: 'reqs-no-headers.txt' }, + 'pip-compile: Package file references a file which does not appear to be a requirements file managed by pip-compile', ); }); @@ -494,7 +495,8 @@ describe('modules/manager/pip-compile/extract', () => { const packageFiles = await extractAllPackageFiles({}, lockFiles); expect(packageFiles?.map((p) => p.lockFiles)).toEqual([['2.txt']]); expect(logger.warn).toHaveBeenCalledWith( - 'pip-compile: 1.in references unmanaged-file.txt which does not appear to be a requirements file managed by pip-compile', + { packageFile: '1.in', requirementsFile: 'unmanaged-file.txt' }, + 'pip-compile: Package file references a file which does not appear to be a requirements file managed by pip-compile', ); }); diff --git a/lib/modules/manager/pip-compile/extract.ts b/lib/modules/manager/pip-compile/extract.ts index 1ef63fc65d9ca0..d040d676015699 100644 --- a/lib/modules/manager/pip-compile/extract.ts +++ b/lib/modules/manager/pip-compile/extract.ts @@ -66,7 +66,10 @@ export async function extractAllPackageFiles( compileArgs = extractHeaderCommand(fileContent, fileMatch); compileDir = inferCommandExecDir(fileMatch, compileArgs.outputFile); } catch (error) { - logger.warn({ fileMatch }, `pip-compile: ${error.message}`); + logger.warn( + { fileMatch, errorMessage: error.message }, + 'pip-compile error', + ); continue; } lockFileArgs.set(fileMatch, compileArgs); @@ -212,7 +215,8 @@ export async function extractAllPackageFiles( } if (!sourceFiles) { logger.warn( - `pip-compile: ${packageFile.packageFile} references ${reqFile} which does not appear to be a requirements file managed by pip-compile`, + { packageFile: packageFile.packageFile, requirementsFile: reqFile }, + 'pip-compile: Package file references a file which does not appear to be a requirements file managed by pip-compile', ); continue; } diff --git a/lib/modules/manager/pipenv/artifacts.ts b/lib/modules/manager/pipenv/artifacts.ts index 8d2760ce357aa6..41ae62a97864b1 100644 --- a/lib/modules/manager/pipenv/artifacts.ts +++ b/lib/modules/manager/pipenv/artifacts.ts @@ -72,7 +72,8 @@ export function addExtraEnvVariable( extraEnv[environmentVariableName] !== environmentValue ) { logger.warn( - `Possible misconfiguration, ${environmentVariableName} is already set to a different value`, + { envVar: environmentVariableName }, + 'Possible misconfiguration, environment variable already set to a different value', ); } extraEnv[environmentVariableName] = environmentValue; diff --git a/lib/modules/manager/poetry/__fixtures__/pyproject.10.toml b/lib/modules/manager/poetry/__fixtures__/pyproject.10.toml index 65c5e06ba8d947..44e0eb41e200a9 100644 --- a/lib/modules/manager/poetry/__fixtures__/pyproject.10.toml +++ b/lib/modules/manager/poetry/__fixtures__/pyproject.10.toml @@ -16,6 +16,10 @@ url = "last.url" [[tool.poetry.source]] name = "five" +[[tool.poetry.source]] +name = "invalid-url" +url = "invalid-url" + [build-system] requires = ["poetry_core>=1.0", "wheel"] build-backend = "poetry.masonry.api" diff --git a/lib/modules/manager/poetry/artifacts.spec.ts b/lib/modules/manager/poetry/artifacts.spec.ts index 0ea60e8bb8a633..f7db72a8c48838 100644 --- a/lib/modules/manager/poetry/artifacts.spec.ts +++ b/lib/modules/manager/poetry/artifacts.spec.ts @@ -1,4 +1,5 @@ import { codeBlock } from 'common-tags'; +import { GoogleAuth as _googleAuth } from 'google-auth-library'; import { mockDeep } from 'jest-mock-extended'; import { join } from 'upath'; import { envMock, mockExecAll } from '../../../../test/exec-util'; @@ -15,16 +16,26 @@ import { updateArtifacts } from '.'; const pyproject1toml = Fixtures.get('pyproject.1.toml'); const pyproject10toml = Fixtures.get('pyproject.10.toml'); +const pyproject13toml = `[[tool.poetry.source]] +name = "some-gar-repo" +url = "https://someregion-python.pkg.dev/some-project/some-repo/simple/" + +[build-system] +requires = ["poetry_core>=1.0", "wheel"] +build-backend = "poetry.masonry.api" +`; jest.mock('../../../util/exec/env'); jest.mock('../../../util/fs'); jest.mock('../../datasource', () => mockDeep()); jest.mock('../../../util/host-rules', () => mockDeep()); +jest.mock('google-auth-library'); process.env.CONTAINERBASE = 'true'; const datasource = mocked(_datasource); const hostRules = mocked(_hostRules); +const googleAuth = mocked(_googleAuth); const adminConfig: RepoGlobalConfig = { localDir: join('/tmp/github/some/repo'), @@ -198,7 +209,99 @@ describe('modules/manager/poetry/artifacts', () => { }, }, ]); - expect(hostRules.find.mock.calls).toHaveLength(5); + expect(hostRules.find.mock.calls).toHaveLength(7); + expect(execSnapshots).toMatchObject([ + { + cmd: 'poetry update --lock --no-interaction dep1', + options: { + env: { + POETRY_HTTP_BASIC_ONE_PASSWORD: 'passwordOne', + POETRY_HTTP_BASIC_ONE_USERNAME: 'usernameOne', + POETRY_HTTP_BASIC_TWO_USERNAME: 'usernameTwo', + POETRY_HTTP_BASIC_FOUR_OH_FOUR_PASSWORD: 'passwordFour', + }, + }, + }, + ]); + }); + + it('passes Google Artifact Registry credentials environment vars', async () => { + // poetry.lock + fs.getSiblingFileName.mockReturnValueOnce('poetry.lock'); + fs.readLocalFile.mockResolvedValueOnce(null); + // pyproject.lock + fs.getSiblingFileName.mockReturnValueOnce('pyproject.lock'); + fs.readLocalFile.mockResolvedValueOnce('[metadata]\n'); + const execSnapshots = mockExecAll(); + fs.readLocalFile.mockResolvedValueOnce('New poetry.lock'); + googleAuth.mockImplementationOnce( + jest.fn().mockImplementationOnce(() => ({ + getAccessToken: jest.fn().mockResolvedValue('some-token'), + })), + ); + const updatedDeps = [{ depName: 'dep1' }]; + expect( + await updateArtifacts({ + packageFileName: 'pyproject.toml', + updatedDeps, + newPackageFileContent: pyproject13toml, + config, + }), + ).toEqual([ + { + file: { + type: 'addition', + path: 'pyproject.lock', + contents: 'New poetry.lock', + }, + }, + ]); + expect(hostRules.find.mock.calls).toHaveLength(3); + expect(execSnapshots).toMatchObject([ + { + cmd: 'poetry update --lock --no-interaction dep1', + options: { + env: { + POETRY_HTTP_BASIC_SOME_GAR_REPO_USERNAME: 'oauth2accesstoken', + POETRY_HTTP_BASIC_SOME_GAR_REPO_PASSWORD: 'some-token', + }, + }, + }, + ]); + }); + + it('continues if Google auth is not configured', async () => { + // poetry.lock + fs.getSiblingFileName.mockReturnValueOnce('poetry.lock'); + fs.readLocalFile.mockResolvedValueOnce(null); + // pyproject.lock + fs.getSiblingFileName.mockReturnValueOnce('pyproject.lock'); + fs.readLocalFile.mockResolvedValueOnce('[metadata]\n'); + const execSnapshots = mockExecAll(); + fs.readLocalFile.mockResolvedValueOnce('New poetry.lock'); + googleAuth.mockImplementation( + jest.fn().mockImplementation(() => ({ + getAccessToken: jest.fn().mockResolvedValue(undefined), + })), + ); + const updatedDeps = [{ depName: 'dep1' }]; + expect( + await updateArtifacts({ + packageFileName: 'pyproject.toml', + updatedDeps, + newPackageFileContent: pyproject13toml, + config, + }), + ).toEqual([ + { + file: { + type: 'addition', + path: 'pyproject.lock', + contents: 'New poetry.lock', + }, + }, + ]); + expect(hostRules.find.mock.calls).toHaveLength(3); expect(execSnapshots).toMatchObject([ { cmd: 'poetry update --lock --no-interaction dep1' }, ]); diff --git a/lib/modules/manager/poetry/artifacts.ts b/lib/modules/manager/poetry/artifacts.ts index d5582f619c5910..038c65b3bdf342 100644 --- a/lib/modules/manager/poetry/artifacts.ts +++ b/lib/modules/manager/poetry/artifacts.ts @@ -17,7 +17,9 @@ import { find } from '../../../util/host-rules'; import { regEx } from '../../../util/regex'; import { Result } from '../../../util/result'; import { parse as parseToml } from '../../../util/toml'; +import { parseUrl } from '../../../util/url'; import { PypiDatasource } from '../../datasource/pypi'; +import { getGoogleAuthHostRule } from '../../datasource/util'; import type { UpdateArtifact, UpdateArtifactsResult } from '../types'; import { Lockfile, PoetrySchemaToml } from './schema'; import type { PoetryFile, PoetrySource } from './types'; @@ -101,7 +103,7 @@ function getPoetrySources(content: string, fileName: string): PoetrySource[] { return []; } if (!pyprojectFile.tool?.poetry) { - logger.debug(`{$fileName} contains no poetry section`); + logger.debug(`${fileName} contains no poetry section`); return []; } @@ -115,20 +117,39 @@ function getPoetrySources(content: string, fileName: string): PoetrySource[] { return sourceArray; } -function getMatchingHostRule(url: string | undefined): HostRule { +async function getMatchingHostRule(url: string | undefined): Promise { const scopedMatch = find({ hostType: PypiDatasource.id, url }); - return is.nonEmptyObject(scopedMatch) ? scopedMatch : find({ url }); + const hostRule = is.nonEmptyObject(scopedMatch) ? scopedMatch : find({ url }); + if (hostRule) { + return hostRule; + } + + const parsedUrl = parseUrl(url); + if (!parsedUrl) { + logger.once.debug(`Failed to parse URL ${url}`); + return {}; + } + + if (parsedUrl.hostname.endsWith('.pkg.dev')) { + const hostRule = await getGoogleAuthHostRule(); + if (hostRule) { + return hostRule; + } + logger.once.debug(`Could not get Google access token (url=${url})`); + } + + return {}; } -function getSourceCredentialVars( +async function getSourceCredentialVars( pyprojectContent: string, packageFileName: string, -): NodeJS.ProcessEnv { +): Promise { const poetrySources = getPoetrySources(pyprojectContent, packageFileName); const envVars: NodeJS.ProcessEnv = {}; for (const source of poetrySources) { - const matchingHostRule = getMatchingHostRule(source.url); + const matchingHostRule = await getMatchingHostRule(source.url); const formattedSourceName = source.name .replace(regEx(/(\.|-)+/g), '_') .toUpperCase(); @@ -192,7 +213,10 @@ export async function updateArtifacts({ config.constraints?.poetry ?? getPoetryRequirement(newPackageFileContent, existingLockFileContent); const extraEnv = { - ...getSourceCredentialVars(newPackageFileContent, packageFileName), + ...(await getSourceCredentialVars( + newPackageFileContent, + packageFileName, + )), ...getGitEnvironmentVariables(['poetry']), PIP_CACHE_DIR: await ensureCacheDir('pip'), }; 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/pre-commit/__fixtures__/complex.pre-commit-config.yaml b/lib/modules/manager/pre-commit/__fixtures__/complex.pre-commit-config.yaml index 1d569aaa676f17..1b1eab5ea00dfd 100644 --- a/lib/modules/manager/pre-commit/__fixtures__/complex.pre-commit-config.yaml +++ b/lib/modules/manager/pre-commit/__fixtures__/complex.pre-commit-config.yaml @@ -13,11 +13,18 @@ repos: rev: 19.3b0 hooks: - id: black + language: python + additional_dependencies: + - "request==1.1.1" + - "" # broken pypi package - repo: https://gitlab.com/psf/black # should also detect gitlab rev: 19.3b0 hooks: - id: black + # missing language, not extracted + additional_dependencies: + - "urllib==24.9.0" - repo: http://gitlab.com/psf/black # should also detect http rev: 19.3b0 @@ -48,3 +55,7 @@ repos: - repo: some_invalid_url # case with invlalid url. rev: v1.0.0 + + # pre-commit meta hooks + - repo: meta + hooks: [] diff --git a/lib/modules/manager/pre-commit/__snapshots__/extract.spec.ts.snap b/lib/modules/manager/pre-commit/__snapshots__/extract.spec.ts.snap index af3eb630748fd7..7dea84085efd04 100644 --- a/lib/modules/manager/pre-commit/__snapshots__/extract.spec.ts.snap +++ b/lib/modules/manager/pre-commit/__snapshots__/extract.spec.ts.snap @@ -10,6 +10,14 @@ exports[`modules/manager/pre-commit/extract extractPackageFile() extracts from c "depType": "repository", "packageName": "pre-commit/pre-commit-hooks", }, + { + "currentValue": "==1.1.1", + "currentVersion": "1.1.1", + "datasource": "pypi", + "depName": "request", + "depType": "pre-commit-python", + "packageName": "request", + }, { "currentValue": "19.3b0", "datasource": "github-tags", diff --git a/lib/modules/manager/pre-commit/extract.spec.ts b/lib/modules/manager/pre-commit/extract.spec.ts index 1bdfd58d2757a7..5eaf7426a522a1 100644 --- a/lib/modules/manager/pre-commit/extract.spec.ts +++ b/lib/modules/manager/pre-commit/extract.spec.ts @@ -2,6 +2,7 @@ import { mockDeep } from 'jest-mock-extended'; import { Fixtures } from '../../../../test/fixtures'; import { mocked } from '../../../../test/util'; import * as _hostRules from '../../../util/host-rules'; +import { PypiDatasource } from '../../datasource/pypi'; import { extractPackageFile } from '.'; jest.mock('../../../util/host-rules', () => mockDeep()); @@ -81,6 +82,14 @@ describe('modules/manager/pre-commit/extract', () => { expect(result).toMatchSnapshot({ deps: [ { depName: 'pre-commit/pre-commit-hooks', currentValue: 'v3.3.0' }, + { + currentValue: '==1.1.1', + currentVersion: '1.1.1', + datasource: PypiDatasource.id, + depName: 'request', + depType: 'pre-commit-python', + packageName: 'request', + }, { depName: 'psf/black', currentValue: '19.3b0' }, { depName: 'psf/black', currentValue: '19.3b0' }, { depName: 'psf/black', currentValue: '19.3b0' }, diff --git a/lib/modules/manager/pre-commit/extract.ts b/lib/modules/manager/pre-commit/extract.ts index 8dc89e4e70a269..a127861cd65c24 100644 --- a/lib/modules/manager/pre-commit/extract.ts +++ b/lib/modules/manager/pre-commit/extract.ts @@ -7,6 +7,7 @@ import { regEx } from '../../../util/regex'; import { parseSingleYaml } from '../../../util/yaml'; import { GithubTagsDatasource } from '../../datasource/github-tags'; import { GitlabTagsDatasource } from '../../datasource/gitlab-tags'; +import { pep508ToPackageDependency } from '../pep621/utils'; import type { PackageDependency, PackageFileContent } from '../types'; import { matchesPrecommitConfigHeuristic, @@ -137,6 +138,23 @@ function findDependencies(precommitFile: PreCommitConfig): PackageDependency[] { } const packageDependencies: PackageDependency[] = []; precommitFile.repos.forEach((item) => { + // meta hooks is defined from pre-commit and doesn't support `additional_dependencies` + if (item.repo !== 'meta') { + item.hooks?.forEach((hook) => { + // normally language are not defined in yaml + // only support it when it's explicitly defined. + // this avoid to parse hooks from pre-commit-hooks.yaml from git repo + if (hook.language === 'python') { + hook.additional_dependencies?.map((req) => { + const dep = pep508ToPackageDependency('pre-commit-python', req); + if (dep) { + packageDependencies.push(dep); + } + }); + } + }); + } + if (matchesPrecommitDependencyHeuristic(item)) { logger.trace(item, 'Matched pre-commit dependency spec'); const repository = String(item.repo); diff --git a/lib/modules/manager/pre-commit/readme.md b/lib/modules/manager/pre-commit/readme.md index 9e91c6cf95cc7b..77949b696099d0 100644 --- a/lib/modules/manager/pre-commit/readme.md +++ b/lib/modules/manager/pre-commit/readme.md @@ -26,3 +26,33 @@ To enable the `pre-commit` manager, add the following config: ``` Alternatively, add `:enablePreCommit` to your `extends` array. + +### Additional Dependencies + +renovate has partial support for `additional_dependencies`, currently python only. + +for python hooks, you will need to **explicitly add language** to your hooks with `additional_dependencies` +to let renovatebot know what kind of dependencies they are. + +For example, this work for `request`: + +```yaml +- repo: https://github.com/psf/black + rev: 19.3b0 + hooks: + - id: black + language: python + additional_dependencies: + - 'request==1.1.1' +``` + +this won't work: + +```yaml +- repo: https://github.com/psf/black + rev: 19.3b0 + hooks: + - id: black + additional_dependencies: + - 'request==1.1.1' +``` diff --git a/lib/modules/manager/pre-commit/types.ts b/lib/modules/manager/pre-commit/types.ts index dadcf068e61e97..3d3b3cf2e12abc 100644 --- a/lib/modules/manager/pre-commit/types.ts +++ b/lib/modules/manager/pre-commit/types.ts @@ -2,7 +2,13 @@ export interface PreCommitConfig { repos: PreCommitDependency[]; } +export interface PreCommitHook { + language?: string; + additional_dependencies?: Array; +} + export interface PreCommitDependency { repo: string; + hooks?: Array; rev: string; } 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 2ce51aa306a0d9..6c93b44a19556a 100644 --- a/lib/modules/manager/types.ts +++ b/lib/modules/manager/types.ts @@ -106,6 +106,7 @@ export interface LookupUpdate { releaseTimestamp?: any; newVersionAgeInDays?: number; registryUrl?: string; + libYears?: number; } /** @@ -119,7 +120,7 @@ export interface PackageDependency> depName?: string; depType?: string; fileReplacePosition?: number; - groupName?: string; + sharedVariableName?: string; lineNumber?: number; packageName?: string; target?: string; @@ -144,6 +145,7 @@ export interface PackageDependency> digestOneAndOnly?: boolean; fixedVersion?: string; currentVersion?: string; + currentVersionTimestamp?: string; lockedVersion?: string; propSource?: string; registryUrls?: string[] | null; diff --git a/lib/modules/platform/azure/azure-helper.ts b/lib/modules/platform/azure/azure-helper.ts index 3fb4602d5547f6..3c96fc94caf5a9 100644 --- a/lib/modules/platform/azure/azure-helper.ts +++ b/lib/modules/platform/azure/azure-helper.ts @@ -87,11 +87,11 @@ export async function getFile( const result = WrappedExceptionSchema.safeParse(fileContent); if (result.success) { if (result.data.typeKey === 'GitItemNotFoundException') { - logger.warn(`Unable to find file ${filePath}`); + logger.warn({ filePath }, 'Unable to find file'); return null; } if (result.data.typeKey === 'GitUnresolvableToCommitException') { - logger.warn(`Unable to find branch ${branchName}`); + logger.warn({ branchName }, 'Unable to find branch'); return null; } } diff --git a/lib/modules/platform/azure/index.ts b/lib/modules/platform/azure/index.ts index 37deb70b83b355..0fd6bb8ccefcf1 100644 --- a/lib/modules/platform/azure/index.ts +++ b/lib/modules/platform/azure/index.ts @@ -822,11 +822,13 @@ export async function mergePr({ if (!isClosed) { logger.warn( - { pullRequestId, status: pr.status }, - `Expected PR to have status ${ - PullRequestStatus[PullRequestStatus.Completed] - // TODO #22198 - }. However, it is ${PullRequestStatus[pr.status!]}.`, + { + pullRequestId, + status: pr.status, + expectedPRStatus: PullRequestStatus[PullRequestStatus.Completed], + actualPRStatus: PullRequestStatus[pr.status!], + }, + 'Expected PR to have completed status. However, the PR has a different status', ); } return true; diff --git a/lib/modules/platform/azure/util.spec.ts b/lib/modules/platform/azure/util.spec.ts index bfdea61b104c98..14c277e276dda1 100644 --- a/lib/modules/platform/azure/util.spec.ts +++ b/lib/modules/platform/azure/util.spec.ts @@ -170,7 +170,7 @@ describe('modules/platform/azure/util', () => { it('should return an error', () => { expect(() => getProjectAndRepo('prjName/myRepoName/blalba')).toThrow( Error( - `prjName/myRepoName/blalba can be only structured this way : 'repository' or 'projectName/repository'!`, + `Azure repository can be only structured this way : 'repository' or 'projectName/repository'!`, ), ); }); diff --git a/lib/modules/platform/azure/util.ts b/lib/modules/platform/azure/util.ts index 74ca2ab7d27f5a..ccc3b43d7da2a5 100644 --- a/lib/modules/platform/azure/util.ts +++ b/lib/modules/platform/azure/util.ts @@ -160,8 +160,8 @@ export function getProjectAndRepo(str: string): { repo: strSplit[1], }; } - const msg = `${str} can be only structured this way : 'repository' or 'projectName/repository'!`; - logger.error(msg); + const msg = `Azure repository can be only structured this way : 'repository' or 'projectName/repository'!`; + logger.warn({ repository: str }, msg); throw new Error(msg); } diff --git a/lib/modules/platform/bitbucket-server/index.ts b/lib/modules/platform/bitbucket-server/index.ts index 5978a3682a6cc1..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,14 +199,13 @@ 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'); } - const msg = `The file is too big (${size}B)`; - logger.warn({ size }, msg); - throw new Error(msg); + logger.warn({ size }, 'The file is too big'); + throw new Error(`The file is too big (${size}B)`); } export async function getJsonFile( @@ -246,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`, ); @@ -304,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`, @@ -328,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 }, ); @@ -459,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 }, @@ -778,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; @@ -914,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.spec.ts b/lib/modules/platform/bitbucket/pr-cache.spec.ts index ac16cc38a228ea..5bf1d30da056f4 100644 --- a/lib/modules/platform/bitbucket/pr-cache.spec.ts +++ b/lib/modules/platform/bitbucket/pr-cache.spec.ts @@ -166,8 +166,8 @@ describe('modules/platform/bitbucket/pr-cache', () => { ); expect(res).toMatchObject([ - { number: 1, title: 'title' }, { number: 2, title: 'title' }, + { number: 1, title: 'title' }, ]); expect(cache).toEqual({ httpCache: {}, diff --git a/lib/modules/platform/bitbucket/pr-cache.ts b/lib/modules/platform/bitbucket/pr-cache.ts index 45ac62b30f091c..84e8fc4a31d3fe 100644 --- a/lib/modules/platform/bitbucket/pr-cache.ts +++ b/lib/modules/platform/bitbucket/pr-cache.ts @@ -11,6 +11,7 @@ import type { BitbucketPrCacheData, PagedResult, PrResponse } from './types'; import { prFieldsFilter, prInfo, prStates } from './utils'; export class BitbucketPrCache { + private items: Pr[] = []; private cache: BitbucketPrCacheData; private constructor( @@ -41,6 +42,7 @@ export class BitbucketPrCache { } repoCache.platform.bitbucket.pullRequestsCache = pullRequestCache; this.cache = pullRequestCache; + this.updateItems(); } private static async init( @@ -62,7 +64,7 @@ export class BitbucketPrCache { } private getPrs(): Pr[] { - return Object.values(this.cache.items); + return this.items; } static async getPrs( @@ -77,6 +79,7 @@ export class BitbucketPrCache { private setPr(pr: Pr): void { logger.debug(`Adding PR #${pr.number} to the PR cache`); this.cache.items[pr.number] = pr; + this.updateItems(); } static async setPr( @@ -144,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`); @@ -161,6 +164,16 @@ export class BitbucketPrCache { }, `PR cache sync finished`, ); + + this.updateItems(); return this; } + + /** + * Ensure the pr cache starts with the most recent PRs. + * JavaScript ensures that the cache is sorted by PR number. + */ + private updateItems(): void { + this.items = Object.values(this.cache.items).reverse(); + } } diff --git a/lib/modules/platform/gerrit/client.ts b/lib/modules/platform/gerrit/client.ts index 07460066d132e2..7d8553eb7d5ce6 100644 --- a/lib/modules/platform/gerrit/client.ts +++ b/lib/modules/platform/gerrit/client.ts @@ -31,7 +31,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', {}, ); @@ -39,9 +39,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); } @@ -49,7 +50,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; @@ -61,7 +62,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(''), @@ -79,16 +80,17 @@ class GerritClient { ): Promise { const options = [...this.requestDetails, ...(extraOptions ?? [])]; const queryString = getQueryString({ o: options }); - const changes = await this.gerritHttp.getJson( + const changes = await this.gerritHttp.getJsonUnchecked( `a/changes/${changeNumber}?${queryString}`, ); return changes.body; } 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; } @@ -104,10 +106,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/gerrit/scm.ts b/lib/modules/platform/gerrit/scm.ts index a81bd5d68de1ea..d0966fac380a2b 100644 --- a/lib/modules/platform/gerrit/scm.ts +++ b/lib/modules/platform/gerrit/scm.ts @@ -73,7 +73,8 @@ export class GerritScm extends DefaultGitScm { return !mergeInfo.mergeable; } else { logger.warn( - `There is no open change with branch=${branch} and baseBranch=${baseBranch}`, + { branch, baseBranch }, + 'There is no open change with this branch', ); return true; } 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 198ea0962ad7a5..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'; @@ -1166,10 +1167,10 @@ describe('modules/platform/gitea/index', () => { const res = await gitea.getPrList(); expect(res).toMatchObject([ - { number: 1, title: 'Some PR' }, - { number: 2, title: 'Other PR' }, - { number: 3, title: 'Draft PR' }, { number: 4, title: 'Merged PR' }, + { number: 3, title: 'Draft PR' }, + { number: 2, title: 'Other PR' }, + { number: 1, title: 'Some PR' }, ]); }); @@ -1209,10 +1210,10 @@ describe('modules/platform/gitea/index', () => { const res = await gitea.getPrList(); expect(res).toMatchObject([ - { number: 1, title: 'Some PR' }, - { number: 2, title: 'Other PR' }, - { number: 3, title: 'Draft PR' }, { number: 4, title: 'Merged PR' }, + { number: 3, title: 'Draft PR' }, + { number: 2, title: 'Other PR' }, + { number: 1, title: 'Some PR' }, ]); }); @@ -1244,16 +1245,16 @@ describe('modules/platform/gitea/index', () => { await initFakeRepo(scope); const res1 = await gitea.getPrList(); - expect(res1).toMatchObject([{ number: 1 }, { number: 2 }]); + expect(res1).toMatchObject([{ number: 2 }, { number: 1 }]); memCache.set('gitea-pr-cache-synced', false); const res2 = await gitea.getPrList(); expect(res2).toMatchObject([ - { number: 1 }, - { number: 2 }, - { number: 3 }, { number: 4 }, + { number: 3 }, + { number: 2 }, + { number: 1 }, ]); }); }); @@ -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/index.ts b/lib/modules/platform/gitea/index.ts index 31450e6c4480ff..73b5b6a442a7e7 100644 --- a/lib/modules/platform/gitea/index.ts +++ b/lib/modules/platform/gitea/index.ts @@ -592,7 +592,8 @@ const platform: Platform = { // would cause a HTTP 409 conflict error, which we hereby gracefully handle. if (err.statusCode === 409) { logger.warn( - `Attempting to gracefully recover from 409 Conflict response in createPr(${title}, ${sourceBranch})`, + { prTitle: title, sourceBranch }, + 'Attempting to gracefully recover from 409 Conflict response in createPr()', ); // Refresh cached PR list and search for pull request with matching information diff --git a/lib/modules/platform/gitea/pr-cache.ts b/lib/modules/platform/gitea/pr-cache.ts index b26085d97a95df..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'; @@ -11,6 +13,7 @@ import { API_PATH, toRenovatePR } from './utils'; export class GiteaPrCache { private cache: GiteaPrCacheData; + private items: Pr[] = []; private constructor( private repo: string, @@ -31,6 +34,7 @@ export class GiteaPrCache { } repoCache.platform.gitea.pullRequestsCache = pullRequestCache; this.cache = pullRequestCache; + this.updateItems(); } static forceSync(): void { @@ -54,7 +58,7 @@ export class GiteaPrCache { } private getPrs(): Pr[] { - return Object.values(this.cache.items); + return this.items; } static async getPrs( @@ -68,6 +72,7 @@ export class GiteaPrCache { private setPr(item: Pr): void { this.cache.items[item.number] = item; + this.updateItems(); } static async setPr( @@ -80,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; @@ -88,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); @@ -124,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) { @@ -137,6 +152,16 @@ export class GiteaPrCache { url = parseLinkHeader(res.headers.link)?.next?.url; } + this.updateItems(); + return this; } + + /** + * Ensure the pr cache starts with the most recent PRs. + * JavaScript ensures that the cache is sorted by PR number. + */ + private updateItems(): void { + this.items = Object.values(this.cache.items).reverse(); + } } 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.spec.ts b/lib/modules/platform/github/index.spec.ts index eb133f6ecae99b..9eaf850b78dce7 100644 --- a/lib/modules/platform/github/index.spec.ts +++ b/lib/modules/platform/github/index.spec.ts @@ -1531,6 +1531,57 @@ describe('modules/platform/github/index', () => { }); }); + describe('getIssue()', () => { + it('returns null if issues disabled', async () => { + const scope = httpMock.scope(githubApiHost); + initRepoMock(scope, 'some/repo', { hasIssuesEnabled: false }); + await github.initRepo({ repository: 'some/repo' }); + const res = await github.getIssue(1); + expect(res).toBeNull(); + }); + + it('returns issue', async () => { + const scope = httpMock.scope(githubApiHost); + initRepoMock(scope, 'some/repo'); + const issue = { + number: 1, + state: 'open', + title: 'title-1', + body: 'body-1', + }; + scope + .get('/repos/some/repo/issues/1') + .reply(200, { ...issue, updated_at: '2022-01-01T00:00:00Z' }); + await github.initRepo({ repository: 'some/repo' }); + const res = await github.getIssue(1); + expect(res).toMatchObject({ + ...issue, + lastModified: '2022-01-01T00:00:00Z', + }); + }); + + it('returns null if issue not found', async () => { + const scope = httpMock.scope(githubApiHost); + initRepoMock(scope, 'some/repo'); + scope.get('/repos/some/repo/issues/1').reply(404); + await github.initRepo({ repository: 'some/repo' }); + const res = await github.getIssue(1); + expect(res).toBeNull(); + }); + + it('logs debug message if issue deleted', async () => { + const scope = httpMock.scope(githubApiHost); + initRepoMock(scope, 'some/repo'); + scope.get('/repos/some/repo/issues/1').reply(410); + await github.initRepo({ repository: 'some/repo' }); + const res = await github.getIssue(1); + expect(res).toBeNull(); + expect(logger.logger.debug).toHaveBeenCalledWith( + 'Issue #1 has been deleted', + ); + }); + }); + describe('findIssue()', () => { it('returns null if no issue', async () => { httpMock diff --git a/lib/modules/platform/github/index.ts b/lib/modules/platform/github/index.ts index 93488565ba630a..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; } @@ -1231,7 +1237,6 @@ export async function getIssueList(): Promise { } export async function getIssue(number: number): Promise { - // istanbul ignore if if (config.hasIssuesEnabled === false) { return null; } @@ -1246,8 +1251,12 @@ export async function getIssue(number: number): Promise { ); GithubIssueCache.updateIssue(issue); return issue; - } catch (err) /* istanbul ignore next */ { + } catch (err) { logger.debug({ err, number }, 'Error getting issue'); + if (err.response?.statusCode === 410) { + logger.debug(`Issue #${number} has been deleted`); + GithubIssueCache.deleteIssue(number); + } return null; } } @@ -1544,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/issue.spec.ts b/lib/modules/platform/github/issue.spec.ts index 749364ddf5ad4e..8a9e9bd1cb82a4 100644 --- a/lib/modules/platform/github/issue.spec.ts +++ b/lib/modules/platform/github/issue.spec.ts @@ -159,6 +159,32 @@ describe('modules/platform/github/issue', () => { }); }); + it('removes particular issue from the cache', () => { + cache.platform = { + github: { + issuesCache: { + '1': { + number: 1, + body: 'body-1', + state: 'open', + title: 'title-1', + lastModified: '2020-01-01T00:00:00.000Z', + }, + }, + }, + }; + + GithubIssueCache.deleteIssue(1); + + expect(cache).toEqual({ + platform: { + github: { + issuesCache: {}, + }, + }, + }); + }); + it('reconciles cache', () => { cache.platform = { github: { diff --git a/lib/modules/platform/github/issue.ts b/lib/modules/platform/github/issue.ts index 1cc85151777233..11a5d050dceceb 100644 --- a/lib/modules/platform/github/issue.ts +++ b/lib/modules/platform/github/issue.ts @@ -85,6 +85,13 @@ export class GithubIssueCache { } } + static deleteIssue(number: number): void { + const cacheData = this.data; + if (cacheData) { + delete cacheData[number]; + } + } + /** * At the moment of repo initialization, repository cache is not available. * What we can do is to store issues for later reconciliation. 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 2460b206d92de0..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; @@ -1361,9 +1366,12 @@ export async function ensureComment({ if (topic) { logger.debug(`Ensuring comment "${massagedTopic!}" in #${number}`); body = `### ${topic}\n\n${sanitizedContent}`; - body = body - .replace(regEx(/Pull Request/g), 'Merge Request') - .replace(regEx(/PR/g), 'MR'); + body = smartTruncate( + body + .replace(regEx(/Pull Request/g), 'Merge Request') + .replace(regEx(/PR/g), 'MR'), + maxBodyLength(), + ); comments.forEach((comment: { body: string; id: number }) => { if (comment.body.startsWith(`### ${massagedTopic!}\n\n`)) { commentId = comment.id; @@ -1372,7 +1380,7 @@ export async function ensureComment({ }); } else { logger.debug(`Ensuring content-only comment in #${number}`); - body = `${sanitizedContent}`; + body = smartTruncate(`${sanitizedContent}`, maxBodyLength()); comments.forEach((comment: { body: string; id: number }) => { if (comment.body === body) { commentId = comment.id; 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/hex/index.spec.ts b/lib/modules/versioning/hex/index.spec.ts index 11a70b073c0033..ad88fa8c097417 100644 --- a/lib/modules/versioning/hex/index.spec.ts +++ b/lib/modules/versioning/hex/index.spec.ts @@ -76,6 +76,7 @@ describe('modules/versioning/hex/index', () => { ${'~> 1.2.0'} | ${'replace'} | ${'1.2.3'} | ${'2.0.7'} | ${'~> 2.0.0'} ${'~> 1.2.0'} | ${'pin'} | ${'1.2.3'} | ${'2.0.7'} | ${'== 2.0.7'} ${'~> 1.2.0'} | ${'bump'} | ${'1.2.3'} | ${'2.0.7'} | ${'~> 2.0.7'} + ${'~> 0.2 and <= 0.2.6'} | ${'widen'} | ${'0.2.6'} | ${'0.2.8'} | ${'~> 0.2 and <= 0.2.8'} ${'>= 1.0.0 and <= 2.0.0'} | ${'widen'} | ${'1.2.3'} | ${'2.0.7'} | ${'>= 1.0.0 and <= 2.0.7'} ${'>= 1.0.0 and <= 2.0.0'} | ${'replace'} | ${'1.2.3'} | ${'2.0.7'} | ${'<= 2.0.7'} ${'>= 1.0.0 and <= 2.0.0'} | ${'pin'} | ${'1.2.3'} | ${'2.0.7'} | ${'== 2.0.7'} diff --git a/lib/modules/versioning/hex/index.ts b/lib/modules/versioning/hex/index.ts index f82d9f9b1b034b..6dc5af45df8a14 100644 --- a/lib/modules/versioning/hex/index.ts +++ b/lib/modules/versioning/hex/index.ts @@ -31,7 +31,7 @@ function npm2hex(input: string): string { .map((str) => str.trim()) .filter((str) => str !== ''); let output = ''; - const operators = ['^', '=', '>', '<', '<=', '>=', '~']; + const operators = ['^', '=', '>', '<', '<=', '>=', '~>']; for (let i = 0; i < res.length; i += 1) { if (i === res.length - 1) { output += res[i]; diff --git a/lib/modules/versioning/pep440/range.ts b/lib/modules/versioning/pep440/range.ts index a4f4c5b26bb717..b450219bb72532 100644 --- a/lib/modules/versioning/pep440/range.ts +++ b/lib/modules/versioning/pep440/range.ts @@ -121,7 +121,7 @@ export function getNewValue({ if (!ranges.length) { // an empty string is an allowed value for PEP440 range // it means get any version - logger.warn('Empty currentValue: ' + currentValue); + logger.warn({ currentValue }, 'Empty currentValue'); return currentValue; } } catch (err) { diff --git a/lib/modules/versioning/pvp/index.spec.ts b/lib/modules/versioning/pvp/index.spec.ts index 900baa3ae7ef8e..de36293d2df97e 100644 --- a/lib/modules/versioning/pvp/index.spec.ts +++ b/lib/modules/versioning/pvp/index.spec.ts @@ -141,12 +141,12 @@ describe('modules/versioning/pvp/index', () => { describe('.getNewValue(newValueConfig)', () => { it.each` currentValue | newVersion | rangeStrategy | expected - ${'>=1.0 && <1.1'} | ${'1.1'} | ${'auto'} | ${'>=1.0 && <1.2'} - ${'>=1.2 && <1.3'} | ${'1.2.3'} | ${'auto'} | ${null} + ${'>=1.0 && <1.1'} | ${'1.1'} | ${'widen'} | ${'>=1.0 && <1.2'} + ${'>=1.2 && <1.3'} | ${'1.2.3'} | ${'widen'} | ${null} ${'>=1.0 && <1.1'} | ${'1.2.3'} | ${'update-lockfile'} | ${null} - ${'gibberish'} | ${'1.2.3'} | ${'auto'} | ${null} - ${'>=1.0 && <1.1'} | ${'0.9'} | ${'auto'} | ${null} - ${'>=1.0 && <1.1'} | ${''} | ${'auto'} | ${null} + ${'gibberish'} | ${'1.2.3'} | ${'widen'} | ${null} + ${'>=1.0 && <1.1'} | ${'0.9'} | ${'widen'} | ${null} + ${'>=1.0 && <1.1'} | ${''} | ${'widen'} | ${null} `( 'pvp.getNewValue({currentValue: "$currentValue", newVersion: "$newVersion", rangeStrategy: "$rangeStrategy"}) === $expected', ({ currentValue, newVersion, rangeStrategy, expected }) => { diff --git a/lib/modules/versioning/pvp/index.ts b/lib/modules/versioning/pvp/index.ts index 59e8b3026ab91c..ca6c5953796ebc 100644 --- a/lib/modules/versioning/pvp/index.ts +++ b/lib/modules/versioning/pvp/index.ts @@ -9,7 +9,7 @@ export const id = 'pvp'; export const displayName = 'Package Versioning Policy (Haskell)'; export const urls = ['https://pvp.haskell.org']; export const supportsRanges = true; -export const supportedRangeStrategies: RangeStrategy[] = ['auto']; +export const supportedRangeStrategies: RangeStrategy[] = ['widen']; const digitsAndDots = regEx(/^[\d.]+$/); @@ -112,7 +112,7 @@ function getNewValue({ newVersion, rangeStrategy, }: NewValueConfig): string | null { - if (rangeStrategy !== 'auto') { + if (rangeStrategy !== 'widen') { logger.info( { rangeStrategy, currentValue, newVersion }, `PVP can't handle this range strategy.`, diff --git a/lib/modules/versioning/regex/readme.md b/lib/modules/versioning/regex/readme.md index 1d84897af8dd6d..fc02e30bbb767a 100644 --- a/lib/modules/versioning/regex/readme.md +++ b/lib/modules/versioning/regex/readme.md @@ -49,13 +49,27 @@ Here is another example, this time for handling Bitnami Docker images, which use "packageRules": [ { "matchDatasources": ["docker"], - "matchPackageNamees": ["bitnami/**", "docker.io/bitnami/**"], + "matchPackageNames": ["bitnami/**", "docker.io/bitnami/**"], "versioning": "regex:^(?\\d+)\\.(?\\d+)\\.(?\\d+)(?:-(?.+)(?\\d+)-r(?\\d+))?$" } ] } ``` +Here is another example, this time for handling `ghcr.io/linuxserver/tautulli` Docker images, which use `major` and `build` indicators with string prefixes: + +```json +{ + "packageRules": [ + { + "matchDatasources": ["docker"], + "matchPackageNames": ["ghcr.io/linuxserver/tautulli"], + "versioning": "regex:^v(?\\d+)\\.(?\\d+)\\.(?\\d+)-ls(?.+)$" + } + ] +} +``` + Here is another example, this time for handling `ghcr.io/linuxserver/openssh-server` Docker images, which use `patch`, `build` and `revision` indicators with string prefixes: ```json @@ -63,7 +77,7 @@ Here is another example, this time for handling `ghcr.io/linuxserver/openssh-ser "packageRules": [ { "matchDatasources": ["docker"], - "matchPackageNamees": ["ghcr.io/linuxserver/openssh-server"], + "matchPackageNames": ["ghcr.io/linuxserver/openssh-server"], "versioning": "regex:^(?\\d+)\\.(?\\d+)_p(?\\d+)-r(?\\d)-ls(?.+)$" } ] 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/cache/repository/impl/s3.spec.ts b/lib/util/cache/repository/impl/s3.spec.ts index 8d2d102fbf5b14..f461b5e6ee2de1 100644 --- a/lib/util/cache/repository/impl/s3.spec.ts +++ b/lib/util/cache/repository/impl/s3.spec.ts @@ -129,7 +129,8 @@ describe('util/cache/repository/impl/s3', () => { s3Mock.on(GetObjectCommand, getObjectCommandInput).resolvesOnce({}); await expect(s3Cache.read()).resolves.toBeNull(); expect(logger.warn).toHaveBeenCalledWith( - "RepoCacheS3.read() - failure - expecting Readable return type got 'undefined' type instead", + { returnType: 'undefined' }, + 'RepoCacheS3.read() - failure - got unexpected return type', ); }); diff --git a/lib/util/cache/repository/impl/s3.ts b/lib/util/cache/repository/impl/s3.ts index 42bf18d134e932..a068066ff55841 100644 --- a/lib/util/cache/repository/impl/s3.ts +++ b/lib/util/cache/repository/impl/s3.ts @@ -41,7 +41,8 @@ export class RepoCacheS3 extends RepoCacheBase { return await streamToString(res); } logger.warn( - `RepoCacheS3.read() - failure - expecting Readable return type got '${typeof res}' type instead`, + { returnType: typeof res }, + 'RepoCacheS3.read() - failure - got unexpected return type', ); } catch (err) { // https://docs.aws.amazon.com/AmazonS3/latest/API/ErrorResponses.html diff --git a/lib/util/git/auth.ts b/lib/util/git/auth.ts index ad2726797ba201..7eefd20c6a6495 100644 --- a/lib/util/git/auth.ts +++ b/lib/util/git/auth.ts @@ -26,8 +26,8 @@ export function getGitAuthenticatedEnvironmentVariables( ): NodeJS.ProcessEnv { if (!token && !(username && password)) { logger.warn( - // TODO: types (#22198) - `Could not create environment variable for ${matchHost!} as neither token or username and password was set`, + { host: matchHost }, + `Could not create environment variable for host as neither token or username and password was set`, ); return { ...environmentVariables }; } @@ -41,9 +41,10 @@ export function getGitAuthenticatedEnvironmentVariables( gitConfigCount = parseInt(gitConfigCountEnvVariable, 10); if (Number.isNaN(gitConfigCount)) { logger.warn( - `Found GIT_CONFIG_COUNT env variable, but couldn't parse the value to an integer: ${String( - process.env.GIT_CONFIG_COUNT, - )}. Ignoring it.`, + { + GIT_CONFIG_COUNT: process.env.GIT_CONFIG_COUNT, + }, + `Found GIT_CONFIG_COUNT env variable, but couldn't parse the value to an integer. Ignoring it.`, ); gitConfigCount = 0; } diff --git a/lib/util/git/index.ts b/lib/util/git/index.ts index 475fb958b908dc..cabe042fb38fe0 100644 --- a/lib/util/git/index.ts +++ b/lib/util/git/index.ts @@ -369,10 +369,7 @@ export async function cloneSubmodules( git.submoduleUpdate(['--init', '--recursive', submodule]), ); } catch (err) { - logger.warn( - { err }, - `Unable to initialise git submodule at ${submodule}`, - ); + logger.warn({ err, submodule }, `Unable to initialise git submodule`); } } } 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 3c1b37bb755f65..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, @@ -342,6 +342,172 @@ describe('util/http/index', () => { memCache.reset(); }); + describe('getPlain', () => { + it('gets plain text with correct headers', async () => { + httpMock.scope(baseUrl).get('/').reply(200, 'plain text response', { + 'content-type': 'text/plain', + }); + + const res = await http.getPlain('http://renovate.com'); + expect(res.body).toBe('plain text response'); + expect(res.headers['content-type']).toBe('text/plain'); + }); + + it('works with custom options', async () => { + httpMock + .scope(baseUrl) + .get('/') + .matchHeader('custom', 'header') + .reply(200, 'plain text response'); + + const res = await http.getPlain('http://renovate.com', { + headers: { custom: 'header' }, + }); + expect(res.body).toBe('plain text response'); + }); + }); + + describe('getYamlUnchecked', () => { + it('parses yaml response without schema', async () => { + httpMock.scope(baseUrl).get('/').reply(200, 'x: 2\ny: 2'); + + 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'); + + const res = await http.getYaml('http://renovate.com', SomeSchema); + expect(res.body).toBe('2 + 2 = 4'); + }); + + it('parses yaml with options and schema', async () => { + httpMock + .scope(baseUrl) + .get('/') + .matchHeader('custom', 'header') + .reply(200, 'x: 2\ny: 2'); + + const res = await http.getYaml( + 'http://renovate.com', + { headers: { custom: 'header' } }, + SomeSchema, + ); + expect(res.body).toBe('2 + 2 = 4'); + }); + + it('throws on schema validation failure', async () => { + httpMock.scope(baseUrl).get('/').reply(200, 'foo: bar'); + + await expect( + 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', () => { + it('returns successful result with schema validation', async () => { + httpMock.scope('http://example.com').get('/').reply(200, 'x: 2\ny: 2'); + + const { val, err } = await http + .getYamlSafe('http://example.com', SomeSchema) + .unwrap(); + + expect(val).toBe('2 + 2 = 4'); + expect(err).toBeUndefined(); + }); + + it('returns schema error result', async () => { + httpMock + .scope('http://example.com') + .get('/') + .reply(200, 'x: "2"\ny: "2"'); + + const { val, err } = await http + .getYamlSafe('http://example.com', SomeSchema) + .unwrap(); + + expect(val).toBeUndefined(); + expect(err).toBeInstanceOf(ZodError); + }); + + it('returns error result for invalid yaml', async () => { + httpMock.scope('http://example.com').get('/').reply(200, '!@#$%^'); + + const { val, err } = await http + .getYamlSafe('http://example.com', SomeSchema) + .unwrap(); + + expect(val).toBeUndefined(); + expect(err).toBeDefined(); + }); + + it('returns error result for network errors', async () => { + httpMock + .scope('http://example.com') + .get('/') + .replyWithError('network error'); + + const { val, err } = await http + .getYamlSafe('http://example.com', SomeSchema) + .unwrap(); + + expect(val).toBeUndefined(); + expect(err).toBeInstanceOf(HttpError); + }); + + it('works with options and schema', async () => { + httpMock + .scope('http://example.com') + .get('/') + .matchHeader('custom', 'header') + .reply(200, 'x: 2\ny: 2'); + + const { val, err } = await http + .getYamlSafe( + 'http://example.com', + { headers: { custom: 'header' } }, + SomeSchema, + ) + .unwrap(); + + expect(val).toBe('2 + 2 = 4'); + expect(err).toBeUndefined(); + }); + }); + describe('getJson', () => { it('uses schema for response body', async () => { httpMock diff --git a/lib/util/http/index.ts b/lib/util/http/index.ts index 34ce5a691ecfa4..d6fb3e59faadcd 100644 --- a/lib/util/http/index.ts +++ b/lib/util/http/index.ts @@ -15,6 +15,7 @@ import { hash } from '../hash'; import { type AsyncResult, Result } from '../result'; import { type HttpRequestStatsDataPoint, HttpStats } from '../stats'; import { resolveBaseUrl } from '../url'; +import { parseSingleYaml } from '../yaml'; import { applyAuthorization, removeAuthorization } from './auth'; import { hooks } from './hooks'; import { applyHostRule, findMatchingRule } from './host-rules'; @@ -38,7 +39,7 @@ export { RequestError as HttpError }; export class EmptyResultError extends Error {} export type SafeJsonError = RequestError | ZodError | EmptyResultError; -type JsonArgs< +type HttpFnArgs< Opts extends HttpOptions, ResT = unknown, Schema extends ZodType = ZodType, @@ -272,7 +273,7 @@ export class Http { private async requestJson( method: InternalHttpOptions['method'], - { url, httpOptions: requestOptions, schema }: JsonArgs, + { url, httpOptions: requestOptions, schema }: HttpFnArgs, ): Promise> { const { body, ...httpOptions } = { ...requestOptions }; const opts: InternalHttpOptions = { @@ -302,8 +303,8 @@ export class Http { arg1: string, arg2: Opts | ZodType | undefined, arg3: ZodType | undefined, - ): JsonArgs { - const res: JsonArgs = { url: arg1 }; + ): HttpFnArgs { + const res: HttpFnArgs = { url: arg1 }; if (arg2 instanceof ZodType) { res.schema = arg2; @@ -328,30 +329,57 @@ export class Http { }); } - getJson(url: string, options?: Opts): Promise>; - getJson = 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>>; - getJson = ZodType>( + async getYaml>( url: string, options: Opts, schema: Schema, ): Promise>>; - getJson = ZodType>( + async getYaml>( arg1: string, arg2?: Opts | Schema, arg3?: Schema, - ): Promise> { - const args = this.resolveArgs(arg1, arg2, arg3); - return this.requestJson('get', args); + ): 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); + const body = await schema.parseAsync(parseSingleYaml(res.body)); + return { ...res, body }; } - getJsonSafe< + getYamlSafe< ResT extends NonNullable, Schema extends ZodType = ZodType, >(url: string, schema: Schema): AsyncResult, SafeJsonError>; - getJsonSafe< + getYamlSafe< ResT extends NonNullable, Schema extends ZodType = ZodType, >( @@ -359,10 +387,93 @@ export class Http { options: Opts, schema: Schema, ): AsyncResult, SafeJsonError>; - getJsonSafe< + getYamlSafe< ResT extends NonNullable, Schema extends ZodType = ZodType, >( + arg1: string, + arg2: Opts | Schema, + arg3?: Schema, + ): AsyncResult { + const url = arg1; + let schema: Schema; + let httpOptions: Opts | undefined; + if (arg3) { + schema = arg3; + httpOptions = arg2 as Opts; + } else { + schema = arg2 as Schema; + } + + let res: AsyncResult, SafeJsonError>; + if (httpOptions) { + res = Result.wrap(this.getYaml(url, httpOptions, schema)); + } else { + res = Result.wrap(this.getYaml(url, schema)); + } + + return res.transform((response) => Result.ok(response.body)); + } + + /** + * 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>( + url: string, + options: Opts, + schema: Schema, + ): Promise>>; + getJson>( + arg1: string, + arg2?: Opts | Schema, + arg3?: Schema, + ): Promise>> { + const args = this.resolveArgs>(arg1, arg2, arg3); + return this.requestJson>('get', args); + } + + /** + * 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, 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/pretty-time.spec.ts b/lib/util/pretty-time.spec.ts index 693e73c4fa8e6f..4a1017f1c10375 100644 --- a/lib/util/pretty-time.spec.ts +++ b/lib/util/pretty-time.spec.ts @@ -47,7 +47,7 @@ describe('util/pretty-time', () => { }); describe('satisfiesDateRange()', () => { - const t0 = DateTime.fromISO('2023-07-07T12:00:00'); + const t0 = DateTime.fromISO('2023-07-07T12:00:00Z'); beforeAll(() => { jest.useFakeTimers(); diff --git a/lib/util/result.ts b/lib/util/result.ts index 86f48acdf2620b..a4fff1f471f29a 100644 --- a/lib/util/result.ts +++ b/lib/util/result.ts @@ -1,5 +1,10 @@ -import type { SafeParseReturnType, ZodType, ZodTypeDef } from 'zod'; -import { ZodError, z } from 'zod'; +import type { + SafeParseReturnType, + input as ZodInput, + output as ZodOutput, + ZodType, +} from 'zod'; +import { NEVER, ZodError, ZodIssueCode } from 'zod'; import { logger } from '../logger'; type Val = NonNullable; @@ -532,30 +537,26 @@ export class Result { * Given a `schema` and `input`, returns a `Result` with `val` being the parsed value. * Additionally, `null` and `undefined` values are converted into Zod error. */ - static parse< - T, - Schema extends ZodType, - Input = unknown, - >( + static parse>( input: unknown, schema: Schema, - ): Result>, ZodError> { + ): Result>, ZodError>> { const parseResult = schema - .transform((result, ctx): NonNullable => { + .transform((result, ctx): NonNullable> => { if (result === undefined) { ctx.addIssue({ - code: z.ZodIssueCode.custom, + code: ZodIssueCode.custom, message: `Result can't accept nullish values, but input was parsed by Zod schema to undefined`, }); - return z.NEVER; + return NEVER; } if (result === null) { ctx.addIssue({ - code: z.ZodIssueCode.custom, + code: ZodIssueCode.custom, message: `Result can't accept nullish values, but input was parsed by Zod schema to null`, }); - return z.NEVER; + return NEVER; } return result; @@ -569,9 +570,9 @@ export class Result { * Given a `schema`, returns a `Result` with `val` being the parsed value. * Additionally, `null` and `undefined` values are converted into Zod error. */ - parse, Input = unknown>( + parse>( schema: Schema, - ): Result>, E | ZodError> { + ): Result>, E | ZodError>> { if (this.res.ok) { return Result.parse(this.res.val, schema); } @@ -862,9 +863,12 @@ export class AsyncResult * Given a `schema`, returns a `Result` with `val` being the parsed value. * Additionally, `null` and `undefined` values are converted into Zod error. */ - parse, Input = unknown>( + parse>( schema: Schema, - ): AsyncResult>, E | ZodError> { + ): AsyncResult< + NonNullable>, + E | ZodError> + > { return new AsyncResult( this.asyncResult .then((oldResult) => oldResult.parse(schema)) diff --git a/lib/util/timestamp.spec.ts b/lib/util/timestamp.spec.ts new file mode 100644 index 00000000000000..1926ea478aed71 --- /dev/null +++ b/lib/util/timestamp.spec.ts @@ -0,0 +1,41 @@ +import { TimestampSchema, asTimestamp } from './timestamp'; + +describe('util/timestamp', () => { + describe('asTimestamp', () => { + test.each` + input | expected + ${new Date('2021-01-01T00:00:00.000Z')} | ${'2021-01-01T00:00:00.000Z'} + ${new Date('2021-01-01T00:00:00.000-03:00')} | ${'2021-01-01T03:00:00.000Z'} + ${new Date('1999-01-01T00:00:00.000Z')} | ${null} + ${1609459200000} | ${'2021-01-01T00:00:00.000Z'} + ${1609459200} | ${'2021-01-01T00:00:00.000Z'} + ${-1} | ${null} + ${0} | ${null} + ${123} | ${null} + ${NaN} | ${null} + ${'2021-01-01T00:00:00.000Z'} | ${'2021-01-01T00:00:00.000Z'} + ${'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'} + ${'2010-05-20T22:43:19-07:00'} | ${'2010-05-21T05:43:19.000Z'} + ${'2021-10-11 07:47:24 -0700'} | ${'2021-10-11T14:47:24.000Z'} + ${'Wed, 21 Oct 2015 07:28:00 GMT'} | ${'2015-10-21T07:28:00.000Z'} + ${null} | ${null} + ${undefined} | ${null} + ${{}} | ${null} + ${[]} | ${null} + ${'invalid date'} | ${null} + ${'202x0101000000'} | ${null} + `('$input -> $expected', ({ input, expected }) => { + expect(asTimestamp(input)).toBe(expected); + expect(TimestampSchema.nullable().catch(null).parse(input)).toBe( + expected, + ); + }); + }); +}); diff --git a/lib/util/timestamp.ts b/lib/util/timestamp.ts new file mode 100644 index 00000000000000..5c0e3d32b9c9c1 --- /dev/null +++ b/lib/util/timestamp.ts @@ -0,0 +1,101 @@ +import { DateTime } from 'luxon'; +import { z } from 'zod'; + +export type Timestamp = string & { __timestamp: never }; + +const timezoneOffset = new Date().getTimezoneOffset() * 60000; + +const millenium = 946684800000; // 2000-01-01T00:00:00.000Z +const tomorrowOffset = 86400000; // 24 * 60 * 60 * 1000; + +function isValid(date: DateTime): boolean { + if (!date.isValid) { + return false; + } + const tomorrow = DateTime.now().toMillis() + tomorrowOffset; // 24 * 60 * 60 * 1000; + const ts = date.toMillis(); + return ts > millenium && ts < tomorrow; +} + +export function asTimestamp(input: unknown): Timestamp | null { + if (input instanceof Date) { + const date = DateTime.fromJSDate(input, { zone: 'UTC' }); + if (isValid(date)) { + return date.toISO() as Timestamp; + } + + return null; + } + + if (typeof input === 'number') { + const millisDate = DateTime.fromMillis(input, { zone: 'UTC' }); + if (isValid(millisDate)) { + return millisDate.toISO() as Timestamp; + } + + const secondsDate = DateTime.fromSeconds(input, { zone: 'UTC' }); + if (isValid(secondsDate)) { + return secondsDate.toISO() as Timestamp; + } + + return null; + } + + if (typeof input === 'string') { + const isoDate = DateTime.fromISO(input, { zone: 'UTC' }); + if (isValid(isoDate)) { + return isoDate.toISO() as Timestamp; + } + + const httpDate = DateTime.fromHTTP(input, { zone: 'UTC' }); + if (isValid(httpDate)) { + return httpDate.toISO() as Timestamp; + } + + const sqlDate = DateTime.fromSQL(input, { zone: 'UTC' }); + if (isValid(sqlDate)) { + return sqlDate.toISO() as Timestamp; + } + + const numberLikeDate = DateTime.fromFormat(input, 'yyyyMMddHHmmss', { + zone: 'UTC', + }); + if (isValid(numberLikeDate)) { + 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' }, + ); + if (isValid(fallbackDate)) { + return fallbackDate.toISO() as Timestamp; + } + + return null; + } + + return null; +} + +export const TimestampSchema = z.unknown().transform((input, ctx) => { + const timestamp = asTimestamp(input); + if (!timestamp) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: 'Invalid timestamp', + }); + return z.NEVER; + } + + return timestamp; +}); diff --git a/lib/workers/global/config/parse/env.spec.ts b/lib/workers/global/config/parse/env.spec.ts index 3961e8d3dd61cc..0dae85326e49c5 100644 --- a/lib/workers/global/config/parse/env.spec.ts +++ b/lib/workers/global/config/parse/env.spec.ts @@ -306,7 +306,11 @@ describe('workers/global/config/parse/env', () => { it('crashes', async () => { const envParam: NodeJS.ProcessEnv = { RENOVATE_CONFIG: '!@#' }; - await env.getConfig(envParam); + processExit.mockImplementationOnce(() => { + throw new Error('terminate function to simulate process.exit call'); + }); + + await expect(env.getConfig(envParam)).toReject(); expect(processExit).toHaveBeenCalledWith(1); }); diff --git a/lib/workers/global/config/parse/env.ts b/lib/workers/global/config/parse/env.ts index 3467b1ec1ada8b..79ed110d6b5be0 100644 --- a/lib/workers/global/config/parse/env.ts +++ b/lib/workers/global/config/parse/env.ts @@ -3,6 +3,7 @@ import JSON5 from 'json5'; import { getOptions } from '../../../../config/options'; import type { AllConfig } from '../../../../config/types'; import { logger } from '../../../../logger'; +import { parseJson } from '../../../../util/common'; import { coersions } from './coersions'; import type { ParseConfigOptions } from './types'; import { migrateAndValidateConfig } from './util'; @@ -118,102 +119,86 @@ function massageConvertedExperimentalVars( export async function getConfig( inputEnv: NodeJS.ProcessEnv, + configEnvKey = 'RENOVATE_CONFIG', ): Promise { - let env = inputEnv; - env = normalizePrefixes(inputEnv, inputEnv.ENV_PREFIX); - env = massageConvertedExperimentalVars(env); - env = renameEnvKeys(env); - // massage the values of migrated configuration keys - env = massageEnvKeyValues(env); + const env = prepareEnv(inputEnv); + const config = await parseAndValidateOrExit(env, configEnvKey); const options = getOptions(); + config.hostRules ??= []; - let config: AllConfig = {}; - - if (env.RENOVATE_CONFIG) { - try { - config = JSON5.parse(env.RENOVATE_CONFIG); - logger.debug({ config }, 'Detected config in env RENOVATE_CONFIG'); - - config = await migrateAndValidateConfig(config, 'RENOVATE_CONFIG'); - } catch (err) { - logger.fatal({ err }, 'Could not parse RENOVATE_CONFIG'); - process.exit(1); + for (const option of options) { + if (option.env === false) { + continue; } - } - config.hostRules ??= []; + const envName = getEnvName(option); + const envVal = env[envName]; + if (!envVal) { + continue; + } - options.forEach((option) => { - if (option.env !== false) { - const envName = getEnvName(option); - const envVal = env[envName]; - if (envVal) { - if (option.type === 'array' && option.subType === 'object') { - try { - const parsed = JSON5.parse(envVal); - if (is.array(parsed)) { - config[option.name] = parsed; - } else { - logger.debug( - { val: envVal, envName }, - 'Could not parse object array', - ); - } - } catch { - logger.debug( - { val: envVal, envName }, - 'Could not parse environment variable', - ); - } + if (option.type === 'array' && option.subType === 'object') { + try { + const parsed = JSON5.parse(envVal); + if (is.array(parsed)) { + config[option.name] = parsed; } else { - const coerce = coersions[option.type]; - config[option.name] = coerce(envVal); - if (option.name === 'dryRun') { - if ((config[option.name] as string) === 'true') { - logger.warn( - 'env config dryRun property has been changed to full', - ); - config[option.name] = 'full'; - } else if ((config[option.name] as string) === 'false') { - logger.warn( - 'env config dryRun property has been changed to null', - ); - delete config[option.name]; - } else if ((config[option.name] as string) === 'null') { - delete config[option.name]; - } - } - if (option.name === 'requireConfig') { - if ((config[option.name] as string) === 'true') { - logger.warn( - 'env config requireConfig property has been changed to required', - ); - config[option.name] = 'required'; - } else if ((config[option.name] as string) === 'false') { - logger.warn( - 'env config requireConfig property has been changed to optional', - ); - config[option.name] = 'optional'; - } - } - if (option.name === 'platformCommit') { - if ((config[option.name] as string) === 'true') { - logger.warn( - 'env config platformCommit property has been changed to enabled', - ); - config[option.name] = 'enabled'; - } else if ((config[option.name] as string) === 'false') { - logger.warn( - 'env config platformCommit property has been changed to disabled', - ); - config[option.name] = 'disabled'; - } - } + logger.debug( + { val: envVal, envName }, + 'Could not parse object array', + ); + } + } catch { + logger.debug( + { val: envVal, envName }, + 'Could not parse environment variable', + ); + } + } else { + const coerce = coersions[option.type]; + config[option.name] = coerce(envVal); + if (option.name === 'dryRun') { + if ((config[option.name] as string) === 'true') { + logger.warn('env config dryRun property has been changed to full'); + config[option.name] = 'full'; + } else if ((config[option.name] as string) === 'false') { + logger.warn('env config dryRun property has been changed to null'); + delete config[option.name]; + } else if ((config[option.name] as string) === 'null') { + delete config[option.name]; + } + } + + if (option.name === 'requireConfig') { + if ((config[option.name] as string) === 'true') { + logger.warn( + 'env config requireConfig property has been changed to required', + ); + config[option.name] = 'required'; + } else if ((config[option.name] as string) === 'false') { + logger.warn( + 'env config requireConfig property has been changed to optional', + ); + config[option.name] = 'optional'; + } + } + + if (option.name === 'platformCommit') { + if ((config[option.name] as string) === 'true') { + logger.warn( + 'env config platformCommit property has been changed to enabled', + ); + config[option.name] = 'enabled'; + } else if ((config[option.name] as string) === 'false') { + logger.warn( + 'env config platformCommit property has been changed to disabled', + ); + config[option.name] = 'disabled'; } } } - }); + } if (env.GITHUB_COM_TOKEN) { logger.debug(`Converting GITHUB_COM_TOKEN into a global host rule`); @@ -237,7 +222,39 @@ export async function getConfig( 'VSTS_TOKEN', ]; - unsupportedEnv.forEach((val) => delete env[val]); + for (const val of unsupportedEnv) { + delete env[val]; + } return config; } + +export function prepareEnv(inputEnv: NodeJS.ProcessEnv): NodeJS.ProcessEnv { + let env = normalizePrefixes(inputEnv, inputEnv.ENV_PREFIX); + env = massageConvertedExperimentalVars(env); + env = renameEnvKeys(env); + // massage the values of migrated configuration keys + return massageEnvKeyValues(env); +} + +export async function parseAndValidateOrExit( + env: NodeJS.ProcessEnv, + configEnvKey: string, +): Promise { + if (!env[configEnvKey]) { + return {}; + } + + try { + const config = parseJson( + env[configEnvKey], + `${configEnvKey}.env.json5`, + ) as AllConfig; + logger.debug({ config }, `Detected config in env ${configEnvKey}`); + + return await migrateAndValidateConfig(config, `${configEnvKey}`); + } catch (err) { + logger.fatal({ err }, `Could not parse ${configEnvKey}`); + process.exit(1); + } +} diff --git a/lib/workers/global/config/parse/file.ts b/lib/workers/global/config/parse/file.ts index cf6ecf20c69898..ec42d187db7c95 100644 --- a/lib/workers/global/config/parse/file.ts +++ b/lib/workers/global/config/parse/file.ts @@ -59,7 +59,7 @@ export async function getConfig(env: NodeJS.ProcessEnv): Promise { config = await getParsedContent(configFile); } catch (err) { if (err instanceof SyntaxError || err instanceof TypeError) { - logger.fatal(`Could not parse config file \n ${err.stack!}`); + logger.fatal({ error: err.stack }, 'Could not parse config file'); process.exit(1); } else if (err instanceof ReferenceError) { logger.fatal( diff --git a/lib/workers/global/config/parse/util.ts b/lib/workers/global/config/parse/util.ts index 9d007c8df4b4d8..2d0720599ea408 100644 --- a/lib/workers/global/config/parse/util.ts +++ b/lib/workers/global/config/parse/util.ts @@ -12,8 +12,8 @@ export async function migrateAndValidateConfig( const { isMigrated, migratedConfig } = migrateConfig(config); if (isMigrated) { logger.warn( - { originalConfig: config, migratedConfig }, - `${configType} needs migrating`, + { configType, originalConfig: config, migratedConfig }, + 'Config needs migrating', ); } const massagedConfig = massageConfig(migratedConfig); @@ -25,13 +25,10 @@ export async function migrateAndValidateConfig( const { warnings, errors } = await validateConfig('global', massagedConfig); if (warnings.length) { - logger.warn( - { warnings }, - `Config validation warnings found in ${configType}`, - ); + logger.warn({ configType, warnings }, 'Config validation warnings found'); } if (errors.length) { - logger.warn({ errors }, `Config validation errors found in ${configType}`); + logger.warn({ configType, errors }, 'Config validation errors found'); } return massagedConfig; diff --git a/lib/workers/global/index.ts b/lib/workers/global/index.ts index 488be90108dfd7..c774fe71610494 100644 --- a/lib/workers/global/index.ts +++ b/lib/workers/global/index.ts @@ -221,9 +221,12 @@ export async function start(): Promise { await exportStats(config); } catch (err) /* istanbul ignore next */ { if (err.message.startsWith('Init: ')) { - logger.fatal(err.message.substring(6)); + logger.fatal( + { errorMessage: err.message.substring(6) }, + 'Initialization error', + ); } else { - logger.fatal({ err }, `Fatal error: ${String(err.message)}`); + logger.fatal({ err }, 'Unknown error'); } if (!config!) { // return early if we can't parse config options diff --git a/lib/workers/repository/finalize/index.ts b/lib/workers/repository/finalize/index.ts index e530834c7ef705..88782016965f0b 100644 --- a/lib/workers/repository/finalize/index.ts +++ b/lib/workers/repository/finalize/index.ts @@ -4,7 +4,7 @@ import { platform } from '../../../modules/platform'; import * as repositoryCache from '../../../util/cache/repository'; import { clearRenovateRefs } from '../../../util/git'; import { PackageFiles } from '../package-files'; -import { validateReconfigureBranch } from '../reconfigure'; +import { checkReconfigureBranch } from '../reconfigure'; import { pruneStaleBranches } from './prune'; import { runBranchSummary, @@ -16,7 +16,7 @@ export async function finalizeRepo( config: RenovateConfig, branchList: string[], ): Promise { - await validateReconfigureBranch(config); + await checkReconfigureBranch(config); await repositoryCache.saveCache(); await pruneStaleBranches(config, branchList); await ensureIssuesClosing(); diff --git a/lib/workers/repository/finalize/prune.ts b/lib/workers/repository/finalize/prune.ts index 7d30c01f97a554..918751344bbe98 100644 --- a/lib/workers/repository/finalize/prune.ts +++ b/lib/workers/repository/finalize/prune.ts @@ -9,7 +9,7 @@ import { scm } from '../../../modules/platform/scm'; import { getBranchList, setUserRepoConfig } from '../../../util/git'; import { escapeRegExp, regEx } from '../../../util/regex'; import { uniqueStrings } from '../../../util/string'; -import { getReconfigureBranchName } from '../reconfigure'; +import { getReconfigureBranchName } from '../reconfigure/utils'; async function cleanUpBranches( config: RenovateConfig, diff --git a/lib/workers/repository/init/config.spec.ts b/lib/workers/repository/init/config.spec.ts new file mode 100644 index 00000000000000..33cedcd071fd81 --- /dev/null +++ b/lib/workers/repository/init/config.spec.ts @@ -0,0 +1,46 @@ +import type { AllConfig } from '../../../config/types'; +import { mergeStaticRepoEnvConfig } from './config'; + +describe('workers/repository/init/config', () => { + describe('mergeRepoEnvConfig()', () => { + type MergeRepoEnvTestCase = { + name: string; + env: NodeJS.ProcessEnv; + currentConfig: AllConfig; + wantConfig: AllConfig; + }; + + const testCases: MergeRepoEnvTestCase[] = [ + { + name: 'it does nothing', + env: {}, + currentConfig: { repositories: ['some/repo'] }, + wantConfig: { repositories: ['some/repo'] }, + }, + { + name: 'it merges env with the current config', + env: { RENOVATE_STATIC_REPO_CONFIG: '{"dependencyDashboard":true}' }, + currentConfig: { repositories: ['some/repo'] }, + wantConfig: { + dependencyDashboard: true, + repositories: ['some/repo'], + }, + }, + { + name: 'it ignores env with other renovate specific configuration options', + env: { RENOVATE_CONFIG: '{"dependencyDashboard":true}' }, + currentConfig: { repositories: ['some/repo'] }, + wantConfig: { repositories: ['some/repo'] }, + }, + ]; + + it.each(testCases)( + '$name', + async ({ env, currentConfig, wantConfig }: MergeRepoEnvTestCase) => { + const got = await mergeStaticRepoEnvConfig(currentConfig, env); + + expect(got).toEqual(wantConfig); + }, + ); + }); +}); diff --git a/lib/workers/repository/init/config.ts b/lib/workers/repository/init/config.ts index a8f9a14c6dfece..fe3122896b32ae 100644 --- a/lib/workers/repository/init/config.ts +++ b/lib/workers/repository/init/config.ts @@ -1,4 +1,7 @@ -import type { RenovateConfig } from '../../../config/types'; +import is from '@sindresorhus/is'; +import { mergeChildConfig } from '../../../config'; +import type { AllConfig, RenovateConfig } from '../../../config/types'; +import { parseAndValidateOrExit } from '../../global/config/parse/env'; import { checkOnboardingBranch } from '../onboarding/branch'; import { mergeInheritedConfig } from './inherited'; import { mergeRenovateConfig } from './merge'; @@ -10,7 +13,24 @@ export async function getRepoConfig( let config = { ...config_ }; config.baseBranch = config.defaultBranch; config = await mergeInheritedConfig(config); + config = await mergeStaticRepoEnvConfig(config, process.env); config = await checkOnboardingBranch(config); config = await mergeRenovateConfig(config); return config; } + +export async function mergeStaticRepoEnvConfig( + config: AllConfig, + env: NodeJS.ProcessEnv, +): Promise { + const repoEnvConfig = await parseAndValidateOrExit( + env, + 'RENOVATE_STATIC_REPO_CONFIG', + ); + + if (!is.nonEmptyObject(repoEnvConfig)) { + return config; + } + + return mergeChildConfig(config, repoEnvConfig); +} diff --git a/lib/workers/repository/init/index.spec.ts b/lib/workers/repository/init/index.spec.ts index 54e412fa97d74c..f36df0329d3686 100644 --- a/lib/workers/repository/init/index.spec.ts +++ b/lib/workers/repository/init/index.spec.ts @@ -61,10 +61,12 @@ describe('workers/repository/init/index', () => { ); await initRepo({}); expect(logger.logger.warn).toHaveBeenCalledWith( - "Configuration option 'filterUnavailableUsers' is not supported on the current platform 'undefined'.", + { platform: undefined }, + "Configuration option 'filterUnavailableUsers' is not supported on the current platform.", ); expect(logger.logger.warn).toHaveBeenCalledWith( - "Configuration option 'expandCodeOwnersGroups' is not supported on the current platform 'undefined'.", + { platform: undefined }, + "Configuration option 'expandCodeOwnersGroups' is not supported on the current platform.", ); }); }); diff --git a/lib/workers/repository/init/index.ts b/lib/workers/repository/init/index.ts index e8b36f4433224d..2e016734dfbd9f 100644 --- a/lib/workers/repository/init/index.ts +++ b/lib/workers/repository/init/index.ts @@ -30,7 +30,8 @@ function warnOnUnsupportedOptions(config: RenovateConfig): void { // TODO: types (#22198) const platform = GlobalConfig.get('platform')!; logger.warn( - `Configuration option 'filterUnavailableUsers' is not supported on the current platform '${platform}'.`, + { platform }, + `Configuration option 'filterUnavailableUsers' is not supported on the current platform.`, ); } @@ -38,7 +39,8 @@ function warnOnUnsupportedOptions(config: RenovateConfig): void { // TODO: types (#22198) const platform = GlobalConfig.get('platform')!; logger.warn( - `Configuration option 'expandCodeOwnersGroups' is not supported on the current platform '${platform}'.`, + { platform }, + `Configuration option 'expandCodeOwnersGroups' is not supported on the current platform.`, ); } } 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/init/vulnerability.ts b/lib/workers/repository/init/vulnerability.ts index 1d90436a9e42b4..dd93c1bee860f9 100644 --- a/lib/workers/repository/init/vulnerability.ts +++ b/lib/workers/repository/init/vulnerability.ts @@ -47,7 +47,7 @@ export function getFixedVersionByDatasource( return `[${fixedVersion},)`; } - // crates.io, Go, Hex, npm, RubyGems, PyPI + // crates.io, Go, Hackage, Hex, npm, RubyGems, PyPI return `>= ${fixedVersion}`; } diff --git a/lib/workers/repository/process/extract-update.ts b/lib/workers/repository/process/extract-update.ts index 8cc0163d84d363..f2a42103ec8c52 100644 --- a/lib/workers/repository/process/extract-update.ts +++ b/lib/workers/repository/process/extract-update.ts @@ -13,6 +13,7 @@ import { extractAllDependencies } from '../extract'; import { generateFingerprintConfig } from '../extract/extract-fingerprint-config'; import { branchifyUpgrades } from '../updates/branchify'; import { fetchUpdates } from './fetch'; +import { calculateLibYears } from './libyear'; import { sortBranches } from './sort'; import { Vulnerabilities } from './vulnerabilities'; import type { WriteUpdateResult } from './write'; @@ -211,6 +212,7 @@ export async function lookup( ): Promise { await fetchVulnerabilities(config, packageFiles); await fetchUpdates(config, packageFiles); + calculateLibYears(packageFiles); const { branches, branchList } = await branchifyUpgrades( config, packageFiles, diff --git a/lib/workers/repository/process/libyear.spec.ts b/lib/workers/repository/process/libyear.spec.ts new file mode 100644 index 00000000000000..e4a1f1fe24ff43 --- /dev/null +++ b/lib/workers/repository/process/libyear.spec.ts @@ -0,0 +1,104 @@ +import { logger } from '../../../../test/util'; +import type { PackageFile } from '../../../modules/manager/types'; +import { calculateLibYears } from './libyear'; + +describe('workers/repository/process/libyear', () => { + describe('calculateLibYears', () => { + it('returns early if no packageFiles', () => { + calculateLibYears(undefined); + expect(logger.logger.debug).not.toHaveBeenCalled(); + }); + + it('calculates libYears', () => { + const packageFiles: Record = { + dockerfile: [ + { + packageFile: 'Dockerfile', + deps: [ + { + depName: 'some/image', + currentVersion: '1.0.0', + updates: [{ newVersion: '2.0.0' }], + }, + ], + }, + ], + npm: [ + { + packageFile: 'package.json', + deps: [ + { + depName: 'dep1', + currentVersion: '0.1.0', + currentVersionTimestamp: '2019-07-01T00:00:00Z', + updates: [ + { + newVersion: '1.0.0', + releaseTimestamp: '2020-01-01T00:00:00Z', + }, + { + newVersion: '2.0.0', + releaseTimestamp: '2020-07-01T00:00:00Z', + }, + { + newVersion: '3.0.0', + }, + ], + }, + ], + }, + ], + bundler: [ + { + packageFile: 'Gemfile', + deps: [ + { + depName: 'dep2', + currentVersion: '1.0.0', + currentVersionTimestamp: '2019-07-01T00:00:00Z', + updates: [ + { + newVersion: '2.0.0', + releaseTimestamp: '2020-01-01T00:00:00Z', + }, + ], + }, + { + depName: 'dep3', + currentVersion: '1.0.0', + updates: [ + { + newVersion: '2.0.0', + releaseTimestamp: '2020-01-01T00:00:00Z', + }, + ], + }, + { + depName: 'dep4', + }, + ], + }, + ], + }; + calculateLibYears(packageFiles); + expect(logger.logger.debug).toHaveBeenCalledWith( + 'No releaseTimestamp for some/image update to 2.0.0', + ); + expect(logger.logger.debug).toHaveBeenCalledWith( + 'No releaseTimestamp for dep1 update to 3.0.0', + ); + expect(logger.logger.debug).toHaveBeenCalledWith( + { + managerLibYears: { + bundler: 0.5027322404371585, + dockerfile: 0, + npm: 1, + }, + // eslint-disable-next-line no-loss-of-precision + totalLibYears: 1.5027322404371585, + }, + 'Repository libYears', + ); + }); + }); +}); diff --git a/lib/workers/repository/process/libyear.ts b/lib/workers/repository/process/libyear.ts new file mode 100644 index 00000000000000..f2bf607b2aa1e9 --- /dev/null +++ b/lib/workers/repository/process/libyear.ts @@ -0,0 +1,59 @@ +import { DateTime } from 'luxon'; +import { logger } from '../../../logger'; +import type { PackageFile } from '../../../modules/manager/types'; + +export function calculateLibYears( + packageFiles?: Record, +): void { + if (!packageFiles) { + return; + } + const managerLibYears: Record = {}; + for (const [manager, files] of Object.entries(packageFiles)) { + for (const file of files) { + let fileLibYears = 0; + for (const dep of file.deps) { + if (dep.updates?.length) { + for (const update of dep.updates) { + if (!update.releaseTimestamp) { + logger.debug( + `No releaseTimestamp for ${dep.depName} update to ${update.newVersion}`, + ); + continue; + } + if (!dep.currentVersionTimestamp) { + logger.debug(`No currentVersionTimestamp for ${dep.depName}`); + continue; + } + // timestamps are in ISO format + const currentVersionDate = DateTime.fromISO( + dep.currentVersionTimestamp, + ); + const releaseDate = DateTime.fromISO(update.releaseTimestamp); + const libYears = releaseDate.diff( + currentVersionDate, + 'years', + ).years; + if (libYears >= 0) { + update.libYears = libYears; + } + } + // Set the highest libYears for the dep + const depLibYears = Math.max( + ...dep.updates.map((update) => update.libYears ?? 0), + 0, + ); + fileLibYears += depLibYears; + } + } + managerLibYears[manager] ??= 0; + managerLibYears[manager] += fileLibYears; + } + } + // Sum up the libYears for the repo + let totalLibYears = 0; + for (const libYears of Object.values(managerLibYears)) { + totalLibYears += libYears; + } + logger.debug({ managerLibYears, totalLibYears }, 'Repository libYears'); +} 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 e5599201820eaa..8922742ae9def5 100644 --- a/lib/workers/repository/process/vulnerabilities.spec.ts +++ b/lib/workers/repository/process/vulnerabilities.spec.ts @@ -296,8 +296,8 @@ describe('workers/repository/process/vulnerabilities', () => { packageFiles, ); expect(logger.logger.warn).toHaveBeenCalledWith( - { err }, - 'Error fetching vulnerability information for lodash', + { err, packageName: 'lodash' }, + 'Error fetching vulnerability information for package', ); }); @@ -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', ); }); @@ -840,6 +840,63 @@ describe('workers/repository/process/vulnerabilities', () => { ]); }); + it('returns packageRules for Hackage', async () => { + const packageFiles: Record = { + hackage: [ + { + deps: [ + { + depName: 'aeson', + currentValue: '0.4.0.0', + datasource: 'hackage', + }, + ], + packageFile: 'some-file', + }, + ], + }; + getVulnerabilitiesMock.mockResolvedValueOnce([ + { + id: 'HSEC-2023-0001', + summary: 'Hash flooding vulnerability in aeson', + details: + '# Hash flooding vulnerability in aeson\n\n*aeson* was vulnerable to hash flooding (a.k.a. hash DoS). The\nissue is a consequence of the HashMap implementation from\n*unordered-containers*. It results in a denial of service through\nCPU consumption. This technique has been used in real-world attacks\nagainst a variety of languages, libraries and frameworks over the\nyears.\n', + aliases: ['CVE-2022-3433'], + modified: '2023-06-13T09:03:52Z', + affected: [ + { + package: { + ecosystem: 'Hackage', + name: 'aeson', + }, + ranges: [ + { + type: 'ECOSYSTEM', + events: [{ introduced: '0.4.0.0' }, { fixed: '2.0.1.0' }], + }, + ], + }, + ], + }, + ]); + + await vulnerabilities.appendVulnerabilityPackageRules( + config, + packageFiles, + ); + + expect(config.packageRules).toHaveLength(1); + expect(config.packageRules).toMatchObject([ + { + matchDatasources: ['hackage'], + matchPackageNames: ['aeson'], + matchCurrentVersion: '0.4.0.0', + allowedVersions: '>= 2.0.1.0', + isVulnerabilityAlert: true, + }, + ]); + }); + it('filters not applicable vulnerability based on last_affected version', async () => { const packageFiles: Record = { poetry: [ diff --git a/lib/workers/repository/process/vulnerabilities.ts b/lib/workers/repository/process/vulnerabilities.ts index b3ed9b565632c1..96e7af3a3fe6ea 100644 --- a/lib/workers/repository/process/vulnerabilities.ts +++ b/lib/workers/repository/process/vulnerabilities.ts @@ -35,6 +35,7 @@ export class Vulnerabilities { > = { crate: 'crates.io', go: 'Go', + hackage: 'Hackage', hex: 'Hex', maven: 'Maven', npm: 'npm', @@ -248,8 +249,8 @@ export class Vulnerabilities { return { vulnerabilities, versioningApi }; } catch (err) { logger.warn( - { err }, - `Error fetching vulnerability information for ${packageName}`, + { err, packageName }, + 'Error fetching vulnerability information for package', ); return null; } @@ -482,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/reconfigure/index.spec.ts b/lib/workers/repository/reconfigure/index.spec.ts index d7b9e5a97dac5e..52aff264f7ebe1 100644 --- a/lib/workers/repository/reconfigure/index.spec.ts +++ b/lib/workers/repository/reconfigure/index.spec.ts @@ -1,242 +1,42 @@ -import { mock } from 'jest-mock-extended'; import type { RenovateConfig } from '../../../../test/util'; -import { fs, git, mocked, partial, platform, scm } from '../../../../test/util'; +import { logger, mocked, scm } from '../../../../test/util'; import { GlobalConfig } from '../../../config/global'; -import { logger } from '../../../logger'; -import type { Pr } from '../../../modules/platform/types'; -import * as _cache from '../../../util/cache/repository'; -import type { LongCommitSha } from '../../../util/git/types'; -import * as _merge from '../init/merge'; -import { validateReconfigureBranch } from '.'; +import * as _validate from './validate'; +import { checkReconfigureBranch } from '.'; -jest.mock('../../../util/cache/repository'); -jest.mock('../../../util/fs'); -jest.mock('../../../util/git'); -jest.mock('../init/merge'); +jest.mock('./validate'); -const cache = mocked(_cache); -const merge = mocked(_merge); +const validate = mocked(_validate); describe('workers/repository/reconfigure/index', () => { const config: RenovateConfig = { branchPrefix: 'prefix/', baseBranch: 'base', - statusCheckNames: partial({ - configValidation: 'renovate/config-validation', - }), }; beforeEach(() => { - config.repository = 'some/repo'; - merge.detectConfigFile.mockResolvedValue('renovate.json'); - scm.branchExists.mockResolvedValue(true); - cache.getCache.mockReturnValue({}); - git.getBranchCommit.mockReturnValue('sha' as LongCommitSha); - fs.readLocalFile.mockResolvedValue(null); - platform.getBranchStatusCheck.mockResolvedValue(null); GlobalConfig.reset(); + scm.branchExists.mockResolvedValue(true); + validate.validateReconfigureBranch.mockResolvedValue(undefined); }); it('no effect when running with platform=local', async () => { GlobalConfig.set({ platform: 'local' }); - await validateReconfigureBranch(config); - expect(logger.debug).toHaveBeenCalledWith( + await checkReconfigureBranch(config); + expect(logger.logger.debug).toHaveBeenCalledWith( 'Not attempting to reconfigure when running with local platform', ); }); it('no effect on repo with no reconfigure branch', async () => { scm.branchExists.mockResolvedValueOnce(false); - await validateReconfigureBranch(config); - expect(logger.debug).toHaveBeenCalledWith('No reconfigure branch found'); - }); - - it('logs error if config file search fails', async () => { - const err = new Error(); - merge.detectConfigFile.mockRejectedValueOnce(err as never); - await validateReconfigureBranch(config); - expect(logger.error).toHaveBeenCalledWith( - { err }, - 'Error while searching for config file in reconfigure branch', - ); - }); - - it('throws error if config file not found in reconfigure branch', async () => { - merge.detectConfigFile.mockResolvedValue(null); - await validateReconfigureBranch(config); - expect(logger.warn).toHaveBeenCalledWith( - 'No config file found in reconfigure branch', - ); - }); - - it('logs error if config file is unreadable', async () => { - const err = new Error(); - fs.readLocalFile.mockRejectedValueOnce(err as never); - await validateReconfigureBranch(config); - expect(logger.error).toHaveBeenCalledWith( - { err }, - 'Error while reading config file', - ); - }); - - it('throws error if config file is empty', async () => { - await validateReconfigureBranch(config); - expect(logger.warn).toHaveBeenCalledWith('Empty or invalid config file'); - }); - - it('throws error if config file content is invalid', async () => { - fs.readLocalFile.mockResolvedValueOnce(` - { - "name": - } - `); - await validateReconfigureBranch(config); - expect(logger.error).toHaveBeenCalledWith( - { err: expect.any(Object) }, - 'Error while parsing config file', - ); - expect(platform.setBranchStatus).toHaveBeenCalledWith({ - branchName: 'prefix/reconfigure', - context: 'renovate/config-validation', - description: 'Validation Failed - Unparsable config file', - state: 'red', - }); - }); - - it('handles failed validation', async () => { - fs.readLocalFile.mockResolvedValueOnce(` - { - "enabledManagers": ["docker"] - } - `); - await validateReconfigureBranch(config); - expect(logger.debug).toHaveBeenCalledWith( - { errors: expect.any(String) }, - 'Validation Errors', - ); - expect(platform.setBranchStatus).toHaveBeenCalledWith({ - branchName: 'prefix/reconfigure', - context: 'renovate/config-validation', - description: 'Validation Failed', - state: 'red', - }); - }); - - it('adds comment if reconfigure PR exists', async () => { - fs.readLocalFile.mockResolvedValueOnce(` - { - "enabledManagers": ["docker"] - } - `); - platform.findPr.mockResolvedValueOnce(mock({ number: 1 })); - await validateReconfigureBranch(config); - expect(logger.debug).toHaveBeenCalledWith( - { errors: expect.any(String) }, - 'Validation Errors', - ); - expect(platform.setBranchStatus).toHaveBeenCalled(); - expect(platform.ensureComment).toHaveBeenCalled(); - }); - - it('handles successful validation', async () => { - const pJson = ` - { - "renovate": { - "enabledManagers": ["npm"] - } - } - `; - merge.detectConfigFile.mockResolvedValue('package.json'); - fs.readLocalFile.mockResolvedValueOnce(pJson).mockResolvedValueOnce(pJson); - await validateReconfigureBranch(config); - expect(platform.setBranchStatus).toHaveBeenCalledWith({ - branchName: 'prefix/reconfigure', - context: 'renovate/config-validation', - description: 'Validation Successful', - state: 'green', - }); - }); - - it('skips adding status check if statusCheckNames.configValidation is null', async () => { - cache.getCache.mockReturnValueOnce({ - reconfigureBranchCache: { - reconfigureBranchSha: 'new-sha', - isConfigValid: false, - }, - }); - - await validateReconfigureBranch({ - ...config, - statusCheckNames: partial({ - configValidation: null, - }), - }); - expect(logger.debug).toHaveBeenCalledWith( - 'Status check is null or an empty string, skipping status check addition.', - ); - expect(platform.setBranchStatus).not.toHaveBeenCalled(); - }); - - it('skips adding status check if statusCheckNames.configValidation is empty string', async () => { - cache.getCache.mockReturnValueOnce({ - reconfigureBranchCache: { - reconfigureBranchSha: 'new-sha', - isConfigValid: false, - }, - }); - - await validateReconfigureBranch({ - ...config, - statusCheckNames: partial({ - configValidation: '', - }), - }); - expect(logger.debug).toHaveBeenCalledWith( - 'Status check is null or an empty string, skipping status check addition.', - ); - expect(platform.setBranchStatus).not.toHaveBeenCalled(); - }); - - it('skips validation if cache is valid', async () => { - cache.getCache.mockReturnValueOnce({ - reconfigureBranchCache: { - reconfigureBranchSha: 'sha', - isConfigValid: false, - }, - }); - await validateReconfigureBranch(config); - expect(logger.debug).toHaveBeenCalledWith( - 'Skipping validation check as branch sha is unchanged', - ); - }); - - it('skips validation if status check present', async () => { - cache.getCache.mockReturnValueOnce({ - reconfigureBranchCache: { - reconfigureBranchSha: 'new_sha', - isConfigValid: false, - }, - }); - platform.getBranchStatusCheck.mockResolvedValueOnce('green'); - await validateReconfigureBranch(config); - expect(logger.debug).toHaveBeenCalledWith( - 'Skipping validation check because status check already exists.', + await checkReconfigureBranch(config); + expect(logger.logger.debug).toHaveBeenCalledWith( + 'No reconfigure branch found', ); }); - it('handles non-default config file', async () => { - merge.detectConfigFile.mockResolvedValue('.renovaterc'); - fs.readLocalFile.mockResolvedValueOnce(` - { - "enabledManagers": ["npm",] - } - `); - await validateReconfigureBranch(config); - expect(platform.setBranchStatus).toHaveBeenCalledWith({ - branchName: 'prefix/reconfigure', - context: 'renovate/config-validation', - description: 'Validation Successful', - state: 'green', - }); + it('validates reconfigure branch', async () => { + await expect(checkReconfigureBranch(config)).toResolve(); }); }); diff --git a/lib/workers/repository/reconfigure/index.ts b/lib/workers/repository/reconfigure/index.ts index abdb1d014649c0..5977918c3b214b 100644 --- a/lib/workers/repository/reconfigure/index.ts +++ b/lib/workers/repository/reconfigure/index.ts @@ -1,49 +1,15 @@ -import is from '@sindresorhus/is'; -import JSON5 from 'json5'; import { GlobalConfig } from '../../../config/global'; import type { RenovateConfig } from '../../../config/types'; -import { validateConfig } from '../../../config/validation'; import { logger } from '../../../logger'; -import { platform } from '../../../modules/platform'; -import { ensureComment } from '../../../modules/platform/comment'; import { scm } from '../../../modules/platform/scm'; -import type { BranchStatus } from '../../../types'; -import { getCache } from '../../../util/cache/repository'; -import { readLocalFile } from '../../../util/fs'; -import { getBranchCommit } from '../../../util/git'; -import { regEx } from '../../../util/regex'; -import { detectConfigFile } from '../init/merge'; -import { - deleteReconfigureBranchCache, - setReconfigureBranchCache, -} from './reconfigure-cache'; +import { deleteReconfigureBranchCache } from './reconfigure-cache'; +import { getReconfigureBranchName } from './utils'; +import { validateReconfigureBranch } from './validate'; -async function setBranchStatus( - branchName: string, - description: string, - state: BranchStatus, - context?: string | null, -): Promise { - if (!is.nonEmptyString(context)) { - // already logged this case when validating the status check - return; - } - - await platform.setBranchStatus({ - branchName, - context, - description, - state, - }); -} - -export function getReconfigureBranchName(prefix: string): string { - return `${prefix}reconfigure`; -} -export async function validateReconfigureBranch( +export async function checkReconfigureBranch( config: RenovateConfig, ): Promise { - logger.debug('validateReconfigureBranch()'); + logger.debug('checkReconfigureBranch()'); if (GlobalConfig.get('platform') === 'local') { logger.debug( 'Not attempting to reconfigure when running with local platform', @@ -51,10 +17,8 @@ export async function validateReconfigureBranch( return; } - const context = config.statusCheckNames?.configValidation; - - const branchName = getReconfigureBranchName(config.branchPrefix!); - const branchExists = await scm.branchExists(branchName); + const reconfigureBranch = getReconfigureBranchName(config.branchPrefix!); + const branchExists = await scm.branchExists(reconfigureBranch); // this is something the user initiates, so skip if no branch exists if (!branchExists) { @@ -63,141 +27,5 @@ export async function validateReconfigureBranch( return; } - // look for config file - // 1. check reconfigure branch cache and use the configFileName if it exists - // 2. checkout reconfigure branch and look for the config file, don't assume default configFileName - const branchSha = getBranchCommit(branchName)!; - const cache = getCache(); - let configFileName: string | null = null; - const reconfigureCache = cache.reconfigureBranchCache; - // only use valid cached information - if (reconfigureCache?.reconfigureBranchSha === branchSha) { - logger.debug('Skipping validation check as branch sha is unchanged'); - return; - } - - if (context) { - const validationStatus = await platform.getBranchStatusCheck( - branchName, - context, - ); - - // if old status check is present skip validation - if (is.nonEmptyString(validationStatus)) { - logger.debug( - 'Skipping validation check because status check already exists.', - ); - return; - } - } else { - logger.debug( - 'Status check is null or an empty string, skipping status check addition.', - ); - } - - try { - await scm.checkoutBranch(branchName); - configFileName = await detectConfigFile(); - } catch (err) { - logger.error( - { err }, - 'Error while searching for config file in reconfigure branch', - ); - } - - if (!is.nonEmptyString(configFileName)) { - logger.warn('No config file found in reconfigure branch'); - await setBranchStatus( - branchName, - 'Validation Failed - No config file found', - 'red', - context, - ); - setReconfigureBranchCache(branchSha, false); - await scm.checkoutBranch(config.defaultBranch!); - return; - } - - let configFileRaw: string | null = null; - try { - configFileRaw = await readLocalFile(configFileName, 'utf8'); - } catch (err) { - logger.error({ err }, 'Error while reading config file'); - } - - if (!is.nonEmptyString(configFileRaw)) { - logger.warn('Empty or invalid config file'); - await setBranchStatus( - branchName, - 'Validation Failed - Empty/Invalid config file', - 'red', - context, - ); - setReconfigureBranchCache(branchSha, false); - await scm.checkoutBranch(config.baseBranch!); - return; - } - - let configFileParsed: any; - try { - configFileParsed = JSON5.parse(configFileRaw); - // no need to confirm renovate field in package.json we already do it in `detectConfigFile()` - if (configFileName === 'package.json') { - configFileParsed = configFileParsed.renovate; - } - } catch (err) { - logger.error({ err }, 'Error while parsing config file'); - await setBranchStatus( - branchName, - 'Validation Failed - Unparsable config file', - 'red', - context, - ); - setReconfigureBranchCache(branchSha, false); - await scm.checkoutBranch(config.baseBranch!); - return; - } - - // perform validation and provide a passing or failing check run based on result - const validationResult = await validateConfig('repo', configFileParsed); - - // failing check - if (validationResult.errors.length > 0) { - logger.debug( - { errors: validationResult.errors.map((err) => err.message).join(', ') }, - 'Validation Errors', - ); - - // add comment to reconfigure PR if it exists - const branchPr = await platform.findPr({ - branchName, - state: 'open', - includeOtherAuthors: true, - }); - if (branchPr) { - let body = `There is an error with this repository's Renovate configuration that needs to be fixed.\n\n`; - body += `Location: \`${configFileName}\`\n`; - body += `Message: \`${validationResult.errors - .map((e) => e.message) - .join(', ') - .replace(regEx(/`/g), "'")}\`\n`; - - await ensureComment({ - number: branchPr.number, - topic: 'Action Required: Fix Renovate Configuration', - content: body, - }); - } - - await setBranchStatus(branchName, 'Validation Failed', 'red', context); - setReconfigureBranchCache(branchSha, false); - await scm.checkoutBranch(config.baseBranch!); - return; - } - - // passing check - await setBranchStatus(branchName, 'Validation Successful', 'green', context); - - setReconfigureBranchCache(branchSha, true); - await scm.checkoutBranch(config.baseBranch!); + await validateReconfigureBranch(config); } diff --git a/lib/workers/repository/reconfigure/utils.ts b/lib/workers/repository/reconfigure/utils.ts new file mode 100644 index 00000000000000..e5208d6a107c68 --- /dev/null +++ b/lib/workers/repository/reconfigure/utils.ts @@ -0,0 +1,3 @@ +export function getReconfigureBranchName(prefix: string): string { + return `${prefix}reconfigure`; +} diff --git a/lib/workers/repository/reconfigure/validate.spec.ts b/lib/workers/repository/reconfigure/validate.spec.ts new file mode 100644 index 00000000000000..730bf75e378edd --- /dev/null +++ b/lib/workers/repository/reconfigure/validate.spec.ts @@ -0,0 +1,228 @@ +import { mock } from 'jest-mock-extended'; +import type { RenovateConfig } from '../../../../test/util'; +import { fs, git, mocked, partial, platform, scm } from '../../../../test/util'; +import { GlobalConfig } from '../../../config/global'; +import { logger } from '../../../logger'; +import type { Pr } from '../../../modules/platform/types'; +import * as _cache from '../../../util/cache/repository'; +import type { LongCommitSha } from '../../../util/git/types'; +import * as _merge from '../init/merge'; +import { validateReconfigureBranch } from './validate'; + +jest.mock('../../../util/cache/repository'); +jest.mock('../../../util/fs'); +jest.mock('../../../util/git'); +jest.mock('../init/merge'); + +const cache = mocked(_cache); +const merge = mocked(_merge); + +describe('workers/repository/reconfigure/validate', () => { + const config: RenovateConfig = { + branchPrefix: 'prefix/', + baseBranch: 'base', + statusCheckNames: partial({ + configValidation: 'renovate/config-validation', + }), + }; + + beforeEach(() => { + config.repository = 'some/repo'; + merge.detectConfigFile.mockResolvedValue('renovate.json'); + scm.branchExists.mockResolvedValue(true); + cache.getCache.mockReturnValue({}); + git.getBranchCommit.mockReturnValue('sha' as LongCommitSha); + fs.readLocalFile.mockResolvedValue(null); + platform.getBranchStatusCheck.mockResolvedValue(null); + GlobalConfig.reset(); + }); + + it('logs error if config file search fails', async () => { + const err = new Error(); + merge.detectConfigFile.mockRejectedValueOnce(err as never); + await validateReconfigureBranch(config); + expect(logger.error).toHaveBeenCalledWith( + { err }, + 'Error while searching for config file in reconfigure branch', + ); + }); + + it('throws error if config file not found in reconfigure branch', async () => { + merge.detectConfigFile.mockResolvedValue(null); + await validateReconfigureBranch(config); + expect(logger.warn).toHaveBeenCalledWith( + 'No config file found in reconfigure branch', + ); + }); + + it('logs error if config file is unreadable', async () => { + const err = new Error(); + fs.readLocalFile.mockRejectedValueOnce(err as never); + await validateReconfigureBranch(config); + expect(logger.error).toHaveBeenCalledWith( + { err }, + 'Error while reading config file', + ); + }); + + it('throws error if config file is empty', async () => { + await validateReconfigureBranch(config); + expect(logger.warn).toHaveBeenCalledWith('Empty or invalid config file'); + }); + + it('throws error if config file content is invalid', async () => { + fs.readLocalFile.mockResolvedValueOnce(` + { + "name": + } + `); + await validateReconfigureBranch(config); + expect(logger.error).toHaveBeenCalledWith( + { err: expect.any(Object) }, + 'Error while parsing config file', + ); + expect(platform.setBranchStatus).toHaveBeenCalledWith({ + branchName: 'prefix/reconfigure', + context: 'renovate/config-validation', + description: 'Validation Failed - Unparsable config file', + state: 'red', + }); + }); + + it('handles failed validation', async () => { + fs.readLocalFile.mockResolvedValueOnce(` + { + "enabledManagers": ["docker"] + } + `); + await validateReconfigureBranch(config); + expect(logger.debug).toHaveBeenCalledWith( + { errors: expect.any(String) }, + 'Validation Errors', + ); + expect(platform.setBranchStatus).toHaveBeenCalledWith({ + branchName: 'prefix/reconfigure', + context: 'renovate/config-validation', + description: 'Validation Failed', + state: 'red', + }); + }); + + it('adds comment if reconfigure PR exists', async () => { + fs.readLocalFile.mockResolvedValueOnce(` + { + "enabledManagers": ["docker"] + } + `); + platform.findPr.mockResolvedValueOnce(mock({ number: 1 })); + await validateReconfigureBranch(config); + expect(logger.debug).toHaveBeenCalledWith( + { errors: expect.any(String) }, + 'Validation Errors', + ); + expect(platform.setBranchStatus).toHaveBeenCalled(); + expect(platform.ensureComment).toHaveBeenCalled(); + }); + + it('handles successful validation', async () => { + const pJson = ` + { + "renovate": { + "enabledManagers": ["npm"] + } + } + `; + merge.detectConfigFile.mockResolvedValue('package.json'); + fs.readLocalFile.mockResolvedValueOnce(pJson).mockResolvedValueOnce(pJson); + await validateReconfigureBranch(config); + expect(platform.setBranchStatus).toHaveBeenCalledWith({ + branchName: 'prefix/reconfigure', + context: 'renovate/config-validation', + description: 'Validation Successful', + state: 'green', + }); + }); + + it('skips adding status check if statusCheckNames.configValidation is null', async () => { + cache.getCache.mockReturnValueOnce({ + reconfigureBranchCache: { + reconfigureBranchSha: 'new-sha', + isConfigValid: false, + }, + }); + + await validateReconfigureBranch({ + ...config, + statusCheckNames: partial({ + configValidation: null, + }), + }); + expect(logger.debug).toHaveBeenCalledWith( + 'Status check is null or an empty string, skipping status check addition.', + ); + expect(platform.setBranchStatus).not.toHaveBeenCalled(); + }); + + it('skips adding status check if statusCheckNames.configValidation is empty string', async () => { + cache.getCache.mockReturnValueOnce({ + reconfigureBranchCache: { + reconfigureBranchSha: 'new-sha', + isConfigValid: false, + }, + }); + + await validateReconfigureBranch({ + ...config, + statusCheckNames: partial({ + configValidation: '', + }), + }); + expect(logger.debug).toHaveBeenCalledWith( + 'Status check is null or an empty string, skipping status check addition.', + ); + expect(platform.setBranchStatus).not.toHaveBeenCalled(); + }); + + it('skips validation if cache is valid', async () => { + cache.getCache.mockReturnValueOnce({ + reconfigureBranchCache: { + reconfigureBranchSha: 'sha', + isConfigValid: false, + }, + }); + await validateReconfigureBranch(config); + expect(logger.debug).toHaveBeenCalledWith( + 'Skipping validation check as branch sha is unchanged', + ); + }); + + it('skips validation if status check present', async () => { + cache.getCache.mockReturnValueOnce({ + reconfigureBranchCache: { + reconfigureBranchSha: 'new_sha', + isConfigValid: false, + }, + }); + platform.getBranchStatusCheck.mockResolvedValueOnce('green'); + await validateReconfigureBranch(config); + expect(logger.debug).toHaveBeenCalledWith( + 'Skipping validation check because status check already exists.', + ); + }); + + it('handles non-default config file', async () => { + merge.detectConfigFile.mockResolvedValue('.renovaterc'); + fs.readLocalFile.mockResolvedValueOnce(` + { + "enabledManagers": ["npm",] + } + `); + await validateReconfigureBranch(config); + expect(platform.setBranchStatus).toHaveBeenCalledWith({ + branchName: 'prefix/reconfigure', + context: 'renovate/config-validation', + description: 'Validation Successful', + state: 'green', + }); + }); +}); diff --git a/lib/workers/repository/reconfigure/validate.ts b/lib/workers/repository/reconfigure/validate.ts new file mode 100644 index 00000000000000..ca1b6a68d668c4 --- /dev/null +++ b/lib/workers/repository/reconfigure/validate.ts @@ -0,0 +1,184 @@ +import is from '@sindresorhus/is'; +import JSON5 from 'json5'; +import type { RenovateConfig } from '../../../config/types'; +import { validateConfig } from '../../../config/validation'; +import { logger } from '../../../logger'; +import { platform } from '../../../modules/platform'; +import { ensureComment } from '../../../modules/platform/comment'; +import { scm } from '../../../modules/platform/scm'; +import type { BranchStatus } from '../../../types'; +import { getCache } from '../../../util/cache/repository'; +import { readLocalFile } from '../../../util/fs'; +import { getBranchCommit } from '../../../util/git'; +import { regEx } from '../../../util/regex'; +import { detectConfigFile } from '../init/merge'; +import { setReconfigureBranchCache } from './reconfigure-cache'; +import { getReconfigureBranchName } from './utils'; + +async function setBranchStatus( + branchName: string, + description: string, + state: BranchStatus, + context?: string | null, +): Promise { + if (!is.nonEmptyString(context)) { + // already logged this case when validating the status check + return; + } + + await platform.setBranchStatus({ + branchName, + context, + description, + state, + }); +} + +export async function validateReconfigureBranch( + config: RenovateConfig, +): Promise { + logger.debug('validateReconfigureBranch()'); + + const context = config.statusCheckNames?.configValidation; + const branchName = getReconfigureBranchName(config.branchPrefix!); + + // look for config file + // 1. check reconfigure branch cache and use the configFileName if it exists + // 2. checkout reconfigure branch and look for the config file, don't assume default configFileName + const branchSha = getBranchCommit(branchName)!; + const cache = getCache(); + let configFileName: string | null = null; + const reconfigureCache = cache.reconfigureBranchCache; + // only use valid cached information + if (reconfigureCache?.reconfigureBranchSha === branchSha) { + logger.debug('Skipping validation check as branch sha is unchanged'); + return; + } + + if (context) { + const validationStatus = await platform.getBranchStatusCheck( + branchName, + context, + ); + + // if old status check is present skip validation + if (is.nonEmptyString(validationStatus)) { + logger.debug( + 'Skipping validation check because status check already exists.', + ); + return; + } + } else { + logger.debug( + 'Status check is null or an empty string, skipping status check addition.', + ); + } + + try { + await scm.checkoutBranch(branchName); + configFileName = await detectConfigFile(); + } catch (err) { + logger.error( + { err }, + 'Error while searching for config file in reconfigure branch', + ); + } + + if (!is.nonEmptyString(configFileName)) { + logger.warn('No config file found in reconfigure branch'); + await setBranchStatus( + branchName, + 'Validation Failed - No config file found', + 'red', + context, + ); + setReconfigureBranchCache(branchSha, false); + await scm.checkoutBranch(config.defaultBranch!); + return; + } + + let configFileRaw: string | null = null; + try { + configFileRaw = await readLocalFile(configFileName, 'utf8'); + } catch (err) { + logger.error({ err }, 'Error while reading config file'); + } + + if (!is.nonEmptyString(configFileRaw)) { + logger.warn('Empty or invalid config file'); + await setBranchStatus( + branchName, + 'Validation Failed - Empty/Invalid config file', + 'red', + context, + ); + setReconfigureBranchCache(branchSha, false); + await scm.checkoutBranch(config.baseBranch!); + return; + } + + let configFileParsed: any; + try { + configFileParsed = JSON5.parse(configFileRaw); + // no need to confirm renovate field in package.json we already do it in `detectConfigFile()` + if (configFileName === 'package.json') { + configFileParsed = configFileParsed.renovate; + } + } catch (err) { + logger.error({ err }, 'Error while parsing config file'); + await setBranchStatus( + branchName, + 'Validation Failed - Unparsable config file', + 'red', + context, + ); + setReconfigureBranchCache(branchSha, false); + await scm.checkoutBranch(config.baseBranch!); + return; + } + + // perform validation and provide a passing or failing check based on result + const validationResult = await validateConfig('repo', configFileParsed); + + // failing check + if (validationResult.errors.length > 0) { + logger.debug( + { errors: validationResult.errors.map((err) => err.message).join(', ') }, + 'Validation Errors', + ); + + const reconfigurePr = await platform.findPr({ + branchName, + state: 'open', + includeOtherAuthors: true, + }); + + // add comment to reconfigure PR if it exists + if (reconfigurePr) { + let body = `There is an error with this repository's Renovate configuration that needs to be fixed.\n\n`; + body += `Location: \`${configFileName}\`\n`; + body += `Message: \`${validationResult.errors + .map((e) => e.message) + .join(', ') + .replace(regEx(/`/g), "'")}\`\n`; + + await ensureComment({ + number: reconfigurePr.number, + topic: 'Action Required: Fix Renovate Configuration', + content: body, + }); + } + + await setBranchStatus(branchName, 'Validation Failed', 'red', context); + setReconfigureBranchCache(branchSha, false); + await scm.checkoutBranch(config.baseBranch!); + return; + } + + // passing check + await setBranchStatus(branchName, 'Validation Successful', 'green', context); + + setReconfigureBranchCache(branchSha, true); + await scm.checkoutBranch(config.baseBranch!); + return; +} diff --git a/lib/workers/repository/update/branch/schedule.ts b/lib/workers/repository/update/branch/schedule.ts index 7789ebcc4c0e66..aa85a8ede739bc 100644 --- a/lib/workers/repository/update/branch/schedule.ts +++ b/lib/workers/repository/update/branch/schedule.ts @@ -108,7 +108,10 @@ export function cronMatches( const nextRun = parsedCron.nextRun(); // istanbul ignore if: should not happen if (!nextRun) { - logger.warn(`Invalid cron schedule ${cron}. No next run is possible`); + logger.warn( + { schedule: cron }, + 'Invalid cron schedule. No next run is possible', + ); return false; } @@ -144,7 +147,8 @@ export function isScheduledNow( } if (!is.array(configSchedule)) { logger.warn( - `config schedule is not an array: ${JSON.stringify(configSchedule)}`, + { schedule: configSchedule }, + 'config schedule is not an array', ); configSchedule = [configSchedule]; } 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/update/pr/index.spec.ts b/lib/workers/repository/update/pr/index.spec.ts index c0a8f6ac090895..2583501774f4b4 100644 --- a/lib/workers/repository/update/pr/index.spec.ts +++ b/lib/workers/repository/update/pr/index.spec.ts @@ -730,9 +730,9 @@ describe('workers/repository/update/pr/index', () => { assignAutomerge: false, }); - expect(logger.logger.error).toHaveBeenCalledWith( - { err }, - 'Failed to ensure PR: ' + prTitle, + expect(logger.logger.warn).toHaveBeenCalledWith( + { err, prTitle }, + 'Failed to ensure PR', ); }); diff --git a/lib/workers/repository/update/pr/index.ts b/lib/workers/repository/update/pr/index.ts index edc85177054180..aa6817daf31a35 100644 --- a/lib/workers/repository/update/pr/index.ts +++ b/lib/workers/repository/update/pr/index.ts @@ -573,7 +573,7 @@ export async function ensurePr( logger.debug('Passing error up'); throw err; } - logger.error({ err }, 'Failed to ensure PR: ' + prTitle); + logger.warn({ err, prTitle }, 'Failed to ensure PR'); } if (existingPr) { return { type: 'with-pr', pr: existingPr }; 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/package.json b/package.json index eab73b3ccfedf8..e849a97a597b75 100644 --- a/package.json +++ b/package.json @@ -139,18 +139,18 @@ "pnpm": "^9.0.0" }, "volta": { - "node": "22.11.0", - "pnpm": "9.15.1" + "node": "22.13.0", + "pnpm": "9.15.3" }, "dependencies": { - "@aws-sdk/client-codecommit": "3.699.0", - "@aws-sdk/client-ec2": "3.701.0", - "@aws-sdk/client-ecr": "3.699.0", - "@aws-sdk/client-rds": "3.699.0", - "@aws-sdk/client-s3": "3.701.0", - "@aws-sdk/credential-providers": "3.699.0", + "@aws-sdk/client-codecommit": "3.726.1", + "@aws-sdk/client-ec2": "3.726.1", + "@aws-sdk/client-ecr": "3.726.1", + "@aws-sdk/client-rds": "3.726.1", + "@aws-sdk/client-s3": "3.726.1", + "@aws-sdk/credential-providers": "3.726.1", "@breejs/later": "4.2.0", - "@cdktf/hcl2json": "0.20.10", + "@cdktf/hcl2json": "0.20.11", "@opentelemetry/api": "1.9.0", "@opentelemetry/context-async-hooks": "1.30.0", "@opentelemetry/exporter-trace-otlp-http": "0.57.0", @@ -164,13 +164,13 @@ "@qnighy/marshal": "0.1.3", "@renovatebot/detect-tools": "1.1.0", "@renovatebot/kbpgp": "4.0.1", - "@renovatebot/osv-offline": "1.5.10", + "@renovatebot/osv-offline": "1.5.11", "@renovatebot/pep440": "4.0.1", "@renovatebot/ruby-semver": "4.0.0", "@sindresorhus/is": "4.6.0", - "@yarnpkg/core": "4.1.6", + "@yarnpkg/core": "4.2.0", "@yarnpkg/parsers": "3.0.2", - "agentkeepalive": "4.5.0", + "agentkeepalive": "4.6.0", "aggregate-error": "3.1.0", "async-mutex": "0.5.0", "auth-header": "1.0.0", @@ -200,14 +200,14 @@ "fs-extra": "11.2.0", "git-url-parse": "16.0.0", "github-url-from-git": "1.5.0", - "glob": "11.0.0", + "glob": "11.0.1", "global-agent": "3.0.0", "good-enough-parser": "1.1.23", "google-auth-library": "9.15.0", "got": "11.8.6", "graph-data-structure": "4.3.0", "handlebars": "4.7.8", - "ignore": "6.0.2", + "ignore": "7.0.0", "ini": "5.0.0", "json-dup-key-validator": "1.0.3", "json-stringify-pretty-compact": "3.0.0", @@ -223,7 +223,7 @@ "ms": "2.1.3", "nanoid": "3.3.8", "neotraverse": "0.6.18", - "node-html-parser": "6.1.13", + "node-html-parser": "7.0.1", "p-all": "3.0.0", "p-map": "4.0.0", "p-queue": "6.6.2", @@ -250,11 +250,11 @@ "validate-npm-package-name": "6.0.0", "vuln-vects": "1.1.0", "xmldoc": "1.3.0", - "yaml": "2.6.1", + "yaml": "2.7.0", "zod": "3.24.1" }, "optionalDependencies": { - "better-sqlite3": "11.7.0", + "better-sqlite3": "11.7.2", "openpgp": "6.0.1", "re2": "1.21.4" }, @@ -269,7 +269,7 @@ "@openpgp/web-stream-tools": "0.1.3", "@renovate/eslint-plugin": "file:tools/eslint", "@semantic-release/exec": "6.0.3", - "@swc/core": "1.10.1", + "@swc/core": "1.10.7", "@types/auth-header": "1.0.6", "@types/aws4": "1.11.6", "@types/better-sqlite3": "7.6.12", @@ -281,7 +281,7 @@ "@types/clean-git-ref": "2.0.2", "@types/common-tags": "1.8.4", "@types/conventional-commits-detector": "1.0.2", - "@types/diff": "6.0.0", + "@types/diff": "7.0.0", "@types/eslint": "8.56.12", "@types/fs-extra": "11.0.4", "@types/git-url-parse": "9.0.3", @@ -291,15 +291,15 @@ "@types/js-yaml": "4.0.9", "@types/json-dup-key-validator": "1.0.2", "@types/linkify-markdown": "1.0.3", - "@types/lodash": "4.17.13", + "@types/lodash": "4.17.14", "@types/luxon": "3.4.2", "@types/markdown-it": "14.1.2", "@types/markdown-table": "2.0.0", "@types/marshal": "0.5.3", "@types/mdast": "3.0.15", - "@types/moo": "0.5.9", + "@types/moo": "0.5.10", "@types/ms": "0.7.34", - "@types/node": "20.17.10", + "@types/node": "22.10.5", "@types/parse-link-header": "2.0.3", "@types/punycode": "2.1.4", "@types/semver": "7.5.8", @@ -311,8 +311,8 @@ "@types/url-join": "4.0.3", "@types/validate-npm-package-name": "4.0.2", "@types/xmldoc": "1.1.9", - "@typescript-eslint/eslint-plugin": "8.18.1", - "@typescript-eslint/parser": "8.18.1", + "@typescript-eslint/eslint-plugin": "8.19.1", + "@typescript-eslint/parser": "8.19.1", "aws-sdk-client-mock": "4.1.0", "callsite": "1.0.0", "common-tags": "1.8.2", @@ -335,23 +335,23 @@ "jest-mock": "29.7.0", "jest-mock-extended": "3.0.7", "jest-snapshot": "29.7.0", - "markdownlint-cli2": "0.16.0", - "memfs": "4.15.1", + "markdownlint-cli2": "0.17.1", + "memfs": "4.17.0", "nock": "13.5.6", "npm-run-all2": "7.0.2", "nyc": "17.1.0", "pretty-format": "29.7.0", "rimraf": "6.0.1", - "semantic-release": "24.2.0", + "semantic-release": "24.2.1", "tar": "7.4.3", "tmp-promise": "3.0.3", "ts-jest": "29.2.5", "ts-node": "10.9.2", - "type-fest": "4.30.2", - "typescript": "5.7.2", + "type-fest": "4.32.0", + "typescript": "5.7.3", "unified": "9.2.2" }, - "packageManager": "pnpm@9.15.1", + "packageManager": "pnpm@9.15.3", "files": [ "dist", "renovate-schema.json" @@ -364,7 +364,7 @@ "safe-json-stringify" ], "overrides": { - "@semantic-release/github>@octokit/plugin-paginate-rest": "11.3.6" + "@semantic-release/github>@octokit/plugin-paginate-rest": "11.4.0" } } } diff --git a/pdm.lock b/pdm.lock index bbf491fb5d1424..2a60e46c387dca 100644 --- a/pdm.lock +++ b/pdm.lock @@ -48,58 +48,52 @@ files = [ [[package]] name = "charset-normalizer" -version = "3.4.0" -requires_python = ">=3.7.0" +version = "3.4.1" +requires_python = ">=3.7" summary = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." groups = ["default"] files = [ - {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-win32.whl", hash = "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-win32.whl", hash = "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-win32.whl", hash = "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b"}, - {file = "charset_normalizer-3.4.0-py3-none-any.whl", hash = "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079"}, - {file = "charset_normalizer-3.4.0.tar.gz", hash = "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8bfa33f4f2672964266e940dd22a195989ba31669bd84629f05fab3ef4e2d125"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-win32.whl", hash = "sha256:8417cb1f36cc0bc7eaba8ccb0e04d55f0ee52df06df3ad55259b9a323555fc8b"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:d7f50a1f8c450f3925cb367d011448c39239bb3eb4117c36a6d354794de4ce76"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-win32.whl", hash = "sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-win32.whl", hash = "sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971"}, + {file = "charset_normalizer-3.4.1-py3-none-any.whl", hash = "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85"}, + {file = "charset_normalizer-3.4.1.tar.gz", hash = "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3"}, ] [[package]] @@ -392,18 +386,18 @@ files = [ [[package]] name = "pygments" -version = "2.18.0" +version = "2.19.1" requires_python = ">=3.8" summary = "Pygments is a syntax highlighting package written in Python." groups = ["default"] files = [ - {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"}, - {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"}, + {file = "pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c"}, + {file = "pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f"}, ] [[package]] name = "pymdown-extensions" -version = "10.12" +version = "10.14" requires_python = ">=3.8" summary = "Extension pack for Python Markdown." groups = ["default"] @@ -412,8 +406,8 @@ dependencies = [ "pyyaml", ] files = [ - {file = "pymdown_extensions-10.12-py3-none-any.whl", hash = "sha256:49f81412242d3527b8b4967b990df395c89563043bc51a3d2d7d500e52123b77"}, - {file = "pymdown_extensions-10.12.tar.gz", hash = "sha256:b0ee1e0b2bef1071a47891ab17003bfe5bf824a398e13f49f8ed653b699369a7"}, + {file = "pymdown_extensions-10.14-py3-none-any.whl", hash = "sha256:202481f716cc8250e4be8fce997781ebf7917701b59652458ee47f2401f818b5"}, + {file = "pymdown_extensions-10.14.tar.gz", hash = "sha256:741bd7c4ff961ba40b7528d32284c53bc436b8b1645e8e37c3e57770b8700a34"}, ] [[package]] diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6308dec9b0d952..42951809e0fdaa 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,36 +5,36 @@ settings: excludeLinksFromLockfile: false overrides: - '@semantic-release/github>@octokit/plugin-paginate-rest': 11.3.6 + '@semantic-release/github>@octokit/plugin-paginate-rest': 11.4.0 importers: .: dependencies: '@aws-sdk/client-codecommit': - specifier: 3.699.0 - version: 3.699.0 + specifier: 3.726.1 + version: 3.726.1 '@aws-sdk/client-ec2': - specifier: 3.701.0 - version: 3.701.0 + specifier: 3.726.1 + version: 3.726.1 '@aws-sdk/client-ecr': - specifier: 3.699.0 - version: 3.699.0 + specifier: 3.726.1 + version: 3.726.1 '@aws-sdk/client-rds': - specifier: 3.699.0 - version: 3.699.0 + specifier: 3.726.1 + version: 3.726.1 '@aws-sdk/client-s3': - specifier: 3.701.0 - version: 3.701.0 + specifier: 3.726.1 + version: 3.726.1 '@aws-sdk/credential-providers': - specifier: 3.699.0 - version: 3.699.0(@aws-sdk/client-sso-oidc@3.699.0(@aws-sdk/client-sts@3.699.0)) + specifier: 3.726.1 + version: 3.726.1(@aws-sdk/client-sso-oidc@3.726.0(@aws-sdk/client-sts@3.726.1)) '@breejs/later': specifier: 4.2.0 version: 4.2.0 '@cdktf/hcl2json': - specifier: 0.20.10 - version: 0.20.10 + specifier: 0.20.11 + version: 0.20.11 '@opentelemetry/api': specifier: 1.9.0 version: 1.9.0 @@ -75,8 +75,8 @@ importers: specifier: 4.0.1 version: 4.0.1 '@renovatebot/osv-offline': - specifier: 1.5.10 - version: 1.5.10(encoding@0.1.13) + specifier: 1.5.11 + version: 1.5.11(encoding@0.1.13) '@renovatebot/pep440': specifier: 4.0.1 version: 4.0.1 @@ -87,14 +87,14 @@ importers: specifier: 4.6.0 version: 4.6.0 '@yarnpkg/core': - specifier: 4.1.6 - version: 4.1.6(typanion@3.14.0) + specifier: 4.2.0 + version: 4.2.0(typanion@3.14.0) '@yarnpkg/parsers': specifier: 3.0.2 version: 3.0.2 agentkeepalive: - specifier: 4.5.0 - version: 4.5.0 + specifier: 4.6.0 + version: 4.6.0 aggregate-error: specifier: 3.1.0 version: 3.1.0 @@ -183,8 +183,8 @@ importers: specifier: 1.5.0 version: 1.5.0 glob: - specifier: 11.0.0 - version: 11.0.0 + specifier: 11.0.1 + version: 11.0.1 global-agent: specifier: 3.0.0 version: 3.0.0 @@ -204,8 +204,8 @@ importers: specifier: 4.7.8 version: 4.7.8 ignore: - specifier: 6.0.2 - version: 6.0.2 + specifier: 7.0.0 + version: 7.0.0 ini: specifier: 5.0.0 version: 5.0.0 @@ -252,8 +252,8 @@ importers: specifier: 0.6.18 version: 0.6.18 node-html-parser: - specifier: 6.1.13 - version: 6.1.13 + specifier: 7.0.1 + version: 7.0.1 p-all: specifier: 3.0.0 version: 3.0.0 @@ -333,15 +333,15 @@ importers: specifier: 1.3.0 version: 1.3.0 yaml: - specifier: 2.6.1 - version: 2.6.1 + specifier: 2.7.0 + version: 2.7.0 zod: specifier: 3.24.1 version: 3.24.1 optionalDependencies: better-sqlite3: - specifier: 11.7.0 - version: 11.7.0 + specifier: 11.7.2 + version: 11.7.2 openpgp: specifier: 6.0.1 version: 6.0.1 @@ -372,16 +372,16 @@ importers: version: 2.2.3 '@openpgp/web-stream-tools': specifier: 0.1.3 - version: 0.1.3(typescript@5.7.2) + version: 0.1.3(typescript@5.7.3) '@renovate/eslint-plugin': specifier: file:tools/eslint version: '@renovatebot/eslint-plugin@file:tools/eslint' '@semantic-release/exec': specifier: 6.0.3 - version: 6.0.3(semantic-release@24.2.0(typescript@5.7.2)) + version: 6.0.3(semantic-release@24.2.1(typescript@5.7.3)) '@swc/core': - specifier: 1.10.1 - version: 1.10.1 + specifier: 1.10.7 + version: 1.10.7 '@types/auth-header': specifier: 1.0.6 version: 1.0.6 @@ -416,8 +416,8 @@ importers: specifier: 1.0.2 version: 1.0.2 '@types/diff': - specifier: 6.0.0 - version: 6.0.0 + specifier: 7.0.0 + version: 7.0.0 '@types/eslint': specifier: 8.56.12 version: 8.56.12 @@ -446,8 +446,8 @@ importers: specifier: 1.0.3 version: 1.0.3 '@types/lodash': - specifier: 4.17.13 - version: 4.17.13 + specifier: 4.17.14 + version: 4.17.14 '@types/luxon': specifier: 3.4.2 version: 3.4.2 @@ -464,14 +464,14 @@ importers: specifier: 3.0.15 version: 3.0.15 '@types/moo': - specifier: 0.5.9 - version: 0.5.9 + specifier: 0.5.10 + version: 0.5.10 '@types/ms': specifier: 0.7.34 version: 0.7.34 '@types/node': - specifier: 20.17.10 - version: 20.17.10 + specifier: 22.10.5 + version: 22.10.5 '@types/parse-link-header': specifier: 2.0.3 version: 2.0.3 @@ -506,11 +506,11 @@ importers: specifier: 1.1.9 version: 1.1.9 '@typescript-eslint/eslint-plugin': - specifier: 8.18.1 - version: 8.18.1(@typescript-eslint/parser@8.18.1(eslint@8.57.1)(typescript@5.7.2))(eslint@8.57.1)(typescript@5.7.2) + specifier: 8.19.1 + version: 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) '@typescript-eslint/parser': - specifier: 8.18.1 - version: 8.18.1(eslint@8.57.1)(typescript@5.7.2) + specifier: 8.19.1 + version: 8.19.1(eslint@8.57.1)(typescript@5.7.3) aws-sdk-client-mock: specifier: 4.1.0 version: 4.1.0 @@ -537,10 +537,10 @@ importers: version: 3.7.0(eslint-plugin-import@2.31.0)(eslint@8.57.1) eslint-plugin-import: specifier: 2.31.0 - version: 2.31.0(@typescript-eslint/parser@8.18.1(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-typescript@3.7.0)(eslint@8.57.1) + version: 2.31.0(@typescript-eslint/parser@8.19.1(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-typescript@3.7.0)(eslint@8.57.1) eslint-plugin-jest: specifier: 28.10.0 - version: 28.10.0(@typescript-eslint/eslint-plugin@8.18.1(@typescript-eslint/parser@8.18.1(eslint@8.57.1)(typescript@5.7.2))(eslint@8.57.1)(typescript@5.7.2))(eslint@8.57.1)(jest@29.7.0(@types/node@20.17.10)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@20.17.10)(typescript@5.7.2)))(typescript@5.7.2) + version: 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) eslint-plugin-jest-formatting: specifier: 3.1.0 version: 3.1.0(eslint@8.57.1) @@ -549,7 +549,7 @@ importers: version: 7.2.1(eslint@8.57.1) eslint-plugin-typescript-enum: specifier: 2.1.0 - version: 2.1.0(eslint@8.57.1)(typescript@5.7.2) + version: 2.1.0(eslint@8.57.1)(typescript@5.7.3) expect: specifier: 29.7.0 version: 29.7.0 @@ -564,25 +564,25 @@ importers: version: 9.1.7 jest: specifier: 29.7.0 - version: 29.7.0(@types/node@20.17.10)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@20.17.10)(typescript@5.7.2)) + version: 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)) jest-extended: specifier: 4.0.2 - version: 4.0.2(jest@29.7.0(@types/node@20.17.10)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@20.17.10)(typescript@5.7.2))) + version: 4.0.2(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))) jest-mock: specifier: 29.7.0 version: 29.7.0 jest-mock-extended: specifier: 3.0.7 - version: 3.0.7(jest@29.7.0(@types/node@20.17.10)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@20.17.10)(typescript@5.7.2)))(typescript@5.7.2) + version: 3.0.7(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) jest-snapshot: specifier: 29.7.0 version: 29.7.0 markdownlint-cli2: - specifier: 0.16.0 - version: 0.16.0 + specifier: 0.17.1 + version: 0.17.1 memfs: - specifier: 4.15.1 - version: 4.15.1 + specifier: 4.17.0 + version: 4.17.0 nock: specifier: 13.5.6 version: 13.5.6 @@ -599,8 +599,8 @@ importers: specifier: 6.0.1 version: 6.0.1 semantic-release: - specifier: 24.2.0 - version: 24.2.0(typescript@5.7.2) + specifier: 24.2.1 + version: 24.2.1(typescript@5.7.3) tar: specifier: 7.4.3 version: 7.4.3 @@ -609,16 +609,16 @@ importers: version: 3.0.3 ts-jest: specifier: 29.2.5 - version: 29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(jest@29.7.0(@types/node@20.17.10)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@20.17.10)(typescript@5.7.2)))(typescript@5.7.2) + version: 29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(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) ts-node: specifier: 10.9.2 - version: 10.9.2(@swc/core@1.10.1)(@types/node@20.17.10)(typescript@5.7.2) + version: 10.9.2(@swc/core@1.10.7)(@types/node@22.10.5)(typescript@5.7.3) type-fest: - specifier: 4.30.2 - version: 4.30.2 + specifier: 4.32.0 + version: 4.32.0 typescript: - specifier: 5.7.2 - version: 5.7.2 + specifier: 5.7.3 + version: 5.7.3 unified: specifier: 9.2.2 version: 9.2.2 @@ -655,204 +655,204 @@ packages: '@aws-crypto/util@5.2.0': resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} - '@aws-sdk/client-codecommit@3.699.0': - resolution: {integrity: sha512-aM0o4b3daNkjpk/XAKzrrOjdWFdUU/gd5m7fHvGhCLK/++bO3iw5DrcjXzLqEefeHp+lxs+mpMrjCssnXXfO9g==} - engines: {node: '>=16.0.0'} + '@aws-sdk/client-codecommit@3.726.1': + resolution: {integrity: sha512-mXRU4RRMkzaA4roL9uIwPWU3tXXzs3m99rA24PIkPzDlR7DubongJGloWAQz9naux0uRIIe+jIC8mk4l/DGdrw==} + engines: {node: '>=18.0.0'} - '@aws-sdk/client-cognito-identity@3.699.0': - resolution: {integrity: sha512-9tFt+we6AIvj/f1+nrLHuCWcQmyfux5gcBSOy9d9+zIG56YxGEX7S9TaZnybogpVV8A0BYWml36WvIHS9QjIpA==} - engines: {node: '>=16.0.0'} + '@aws-sdk/client-cognito-identity@3.726.1': + resolution: {integrity: sha512-ry0LrRm1/uo2EcPvjN38gQe2YhbnOXDhOw01j4e+aSbsBm2VumvY7d5DOLODC4i+95bxZq0pGvojqgHWM9oS0Q==} + engines: {node: '>=18.0.0'} - '@aws-sdk/client-ec2@3.701.0': - resolution: {integrity: sha512-JTGunZM2UGO/F5WaA16IwhwMMaIsEEoLER0CkehPEnSIt8Y3Qn5j28rJfpI7TRBcFkRW8kEfbHJHPILg62oMiw==} - engines: {node: '>=16.0.0'} + '@aws-sdk/client-ec2@3.726.1': + resolution: {integrity: sha512-XOAnxaZ3Gw9GCYyZ5ETwToWYNA/0Yjs3MmYfr7N7w+yhY9YFjg+MJjmW1c+LKvpM/Ykhroh2yGY5MQOHVPwlIw==} + engines: {node: '>=18.0.0'} - '@aws-sdk/client-ecr@3.699.0': - resolution: {integrity: sha512-hLcz7TZDx7tfxqrpcSm5xgMYitPpPDE4cKPk0BYAsu5RFg2Lo3QfooUnD5iKnaVbzJcY40BBHGChDrv7IhtERg==} - engines: {node: '>=16.0.0'} + '@aws-sdk/client-ecr@3.726.1': + resolution: {integrity: sha512-9PMFPLmDJ4Pq9eyQzbdax5sM4wdqi80UbhFpR86XbsI65To/dWcTy1Vi2xjMaiSsIOP4VMOvRgSC5V+338lyWQ==} + engines: {node: '>=18.0.0'} - '@aws-sdk/client-rds@3.699.0': - resolution: {integrity: sha512-i/S8sxyQDQbafjxaRTZBVP2/S/dCHlawr5ctz/dhK/HgO5LyHxac83JrpIlpLgndiFTC4h75ldRSjBuCcoRSJQ==} - engines: {node: '>=16.0.0'} + '@aws-sdk/client-rds@3.726.1': + resolution: {integrity: sha512-07kJxcvNeYw2ckf0Gwl6f7Ee6PYcmmbvrWl3i6COgmOd9pslWnOVJLYINpaee6qT4cRhHWWRApeLyQ0dEsCjdA==} + engines: {node: '>=18.0.0'} - '@aws-sdk/client-s3@3.701.0': - resolution: {integrity: sha512-7iXmPC5r7YNjvwSsRbGq9oLVgfIWZesXtEYl908UqMmRj2sVAW/leLopDnbLT7TEedqlK0RasOZT05I0JTNdKw==} - engines: {node: '>=16.0.0'} + '@aws-sdk/client-s3@3.726.1': + resolution: {integrity: sha512-UpOGcob87DiuS2d3fW6vDZg94g57mNiOSkzvR/6GOdvBSlUgk8LLwVzGASB71FdKMl1EGEr4MeD5uKH9JsG+dw==} + engines: {node: '>=18.0.0'} - '@aws-sdk/client-sso-oidc@3.699.0': - resolution: {integrity: sha512-u8a1GorY5D1l+4FQAf4XBUC1T10/t7neuwT21r0ymrtMFSK2a9QqVHKMoLkvavAwyhJnARSBM9/UQC797PFOFw==} - engines: {node: '>=16.0.0'} + '@aws-sdk/client-sso-oidc@3.726.0': + resolution: {integrity: sha512-5JzTX9jwev7+y2Jkzjz0pd1wobB5JQfPOQF3N2DrJ5Pao0/k6uRYwE4NqB0p0HlGrMTDm7xNq7OSPPIPG575Jw==} + engines: {node: '>=18.0.0'} peerDependencies: - '@aws-sdk/client-sts': ^3.699.0 + '@aws-sdk/client-sts': ^3.726.0 - '@aws-sdk/client-sso@3.696.0': - resolution: {integrity: sha512-q5TTkd08JS0DOkHfUL853tuArf7NrPeqoS5UOvqJho8ibV9Ak/a/HO4kNvy9Nj3cib/toHYHsQIEtecUPSUUrQ==} - engines: {node: '>=16.0.0'} + '@aws-sdk/client-sso@3.726.0': + resolution: {integrity: sha512-NM5pjv2qglEc4XN3nnDqtqGsSGv1k5YTmzDo3W3pObItHmpS8grSeNfX9zSH+aVl0Q8hE4ZIgvTPNZ+GzwVlqg==} + engines: {node: '>=18.0.0'} - '@aws-sdk/client-sts@3.699.0': - resolution: {integrity: sha512-++lsn4x2YXsZPIzFVwv3fSUVM55ZT0WRFmPeNilYIhZClxHLmVAWKH4I55cY9ry60/aTKYjzOXkWwyBKGsGvQg==} - engines: {node: '>=16.0.0'} + '@aws-sdk/client-sts@3.726.1': + resolution: {integrity: sha512-qh9Q9Vu1hrM/wMBOBIaskwnE4GTFaZu26Q6WHwyWNfj7J8a40vBxpW16c2vYXHLBtwRKM1be8uRLkmDwghpiNw==} + engines: {node: '>=18.0.0'} - '@aws-sdk/core@3.696.0': - resolution: {integrity: sha512-3c9III1k03DgvRZWg8vhVmfIXPG6hAciN9MzQTzqGngzWAELZF/WONRTRQuDFixVtarQatmLHYVw/atGeA2Byw==} - engines: {node: '>=16.0.0'} + '@aws-sdk/core@3.723.0': + resolution: {integrity: sha512-UraXNmvqj3vScSsTkjMwQkhei30BhXlW5WxX6JacMKVtl95c7z0qOXquTWeTalYkFfulfdirUhvSZrl+hcyqTw==} + engines: {node: '>=18.0.0'} - '@aws-sdk/credential-provider-cognito-identity@3.699.0': - resolution: {integrity: sha512-iuaTnudaBfEET+o444sDwf71Awe6UiZfH+ipUPmswAi2jZDwdFF1nxMKDEKL8/LV5WpXsdKSfwgS0RQeupURew==} - engines: {node: '>=16.0.0'} + '@aws-sdk/credential-provider-cognito-identity@3.726.1': + resolution: {integrity: sha512-/ZvcmEscWYHT0935QN1B1crz4RJzy0tXf20ViH9ShsC5e08jBn3qrjYhO4gUGjNDCwrWe3US8Mg6l1vrRrN1Og==} + engines: {node: '>=18.0.0'} - '@aws-sdk/credential-provider-env@3.696.0': - resolution: {integrity: sha512-T9iMFnJL7YTlESLpVFT3fg1Lkb1lD+oiaIC8KMpepb01gDUBIpj9+Y+pA/cgRWW0yRxmkDXNazAE2qQTVFGJzA==} - engines: {node: '>=16.0.0'} + '@aws-sdk/credential-provider-env@3.723.0': + resolution: {integrity: sha512-OuH2yULYUHTVDUotBoP/9AEUIJPn81GQ/YBtZLoo2QyezRJ2QiO/1epVtbJlhNZRwXrToLEDmQGA2QfC8c7pbA==} + engines: {node: '>=18.0.0'} - '@aws-sdk/credential-provider-http@3.696.0': - resolution: {integrity: sha512-GV6EbvPi2eq1+WgY/o2RFA3P7HGmnkIzCNmhwtALFlqMroLYWKE7PSeHw66Uh1dFQeVESn0/+hiUNhu1mB0emA==} - engines: {node: '>=16.0.0'} + '@aws-sdk/credential-provider-http@3.723.0': + resolution: {integrity: sha512-DTsKC6xo/kz/ZSs1IcdbQMTgiYbpGTGEd83kngFc1bzmw7AmK92DBZKNZpumf8R/UfSpTcj9zzUUmrWz1kD0eQ==} + engines: {node: '>=18.0.0'} - '@aws-sdk/credential-provider-ini@3.699.0': - resolution: {integrity: sha512-dXmCqjJnKmG37Q+nLjPVu22mNkrGHY8hYoOt3Jo9R2zr5MYV7s/NHsCHr+7E+BZ+tfZYLRPeB1wkpTeHiEcdRw==} - engines: {node: '>=16.0.0'} + '@aws-sdk/credential-provider-ini@3.726.0': + resolution: {integrity: sha512-seTtcKL2+gZX6yK1QRPr5mDJIBOatrpoyrO8D5b8plYtV/PDbDW3mtDJSWFHet29G61ZmlNElyXRqQCXn9WX+A==} + engines: {node: '>=18.0.0'} peerDependencies: - '@aws-sdk/client-sts': ^3.699.0 + '@aws-sdk/client-sts': ^3.726.0 - '@aws-sdk/credential-provider-node@3.699.0': - resolution: {integrity: sha512-MmEmNDo1bBtTgRmdNfdQksXu4uXe66s0p1hi1YPrn1h59Q605eq/xiWbGL6/3KdkViH6eGUuABeV2ODld86ylg==} - engines: {node: '>=16.0.0'} + '@aws-sdk/credential-provider-node@3.726.0': + resolution: {integrity: sha512-jjsewBcw/uLi24x8JbnuDjJad4VA9ROCE94uVRbEnGmUEsds75FWOKp3fWZLQlmjLtzsIbJOZLALkZP86liPaw==} + engines: {node: '>=18.0.0'} - '@aws-sdk/credential-provider-process@3.696.0': - resolution: {integrity: sha512-mL1RcFDe9sfmyU5K1nuFkO8UiJXXxLX4JO1gVaDIOvPqwStpUAwi3A1BoeZhWZZNQsiKI810RnYGo0E0WB/hUA==} - engines: {node: '>=16.0.0'} + '@aws-sdk/credential-provider-process@3.723.0': + resolution: {integrity: sha512-fgupvUjz1+jeoCBA7GMv0L6xEk92IN6VdF4YcFhsgRHlHvNgm7ayaoKQg7pz2JAAhG/3jPX6fp0ASNy+xOhmPA==} + engines: {node: '>=18.0.0'} - '@aws-sdk/credential-provider-sso@3.699.0': - resolution: {integrity: sha512-Ekp2cZG4pl9D8+uKWm4qO1xcm8/MeiI8f+dnlZm8aQzizeC+aXYy9GyoclSf6daK8KfRPiRfM7ZHBBL5dAfdMA==} - engines: {node: '>=16.0.0'} + '@aws-sdk/credential-provider-sso@3.726.0': + resolution: {integrity: sha512-WxkN76WeB08j2yw7jUH9yCMPxmT9eBFd9ZA/aACG7yzOIlsz7gvG3P2FQ0tVg25GHM0E4PdU3p/ByTOawzcOAg==} + engines: {node: '>=18.0.0'} - '@aws-sdk/credential-provider-web-identity@3.696.0': - resolution: {integrity: sha512-XJ/CVlWChM0VCoc259vWguFUjJDn/QwDqHwbx+K9cg3v6yrqXfK5ai+p/6lx0nQpnk4JzPVeYYxWRpaTsGC9rg==} - engines: {node: '>=16.0.0'} + '@aws-sdk/credential-provider-web-identity@3.723.0': + resolution: {integrity: sha512-tl7pojbFbr3qLcOE6xWaNCf1zEfZrIdSJtOPeSXfV/thFMMAvIjgf3YN6Zo1a6cxGee8zrV/C8PgOH33n+Ev/A==} + engines: {node: '>=18.0.0'} peerDependencies: - '@aws-sdk/client-sts': ^3.696.0 + '@aws-sdk/client-sts': ^3.723.0 - '@aws-sdk/credential-providers@3.699.0': - resolution: {integrity: sha512-jBjOntl9zN9Nvb0jmbMGRbiTzemDz64ij7W6BDavxBJRZpRoNeN0QCz6RolkCyXnyUJjo5mF2unY2wnv00A+LQ==} - engines: {node: '>=16.0.0'} + '@aws-sdk/credential-providers@3.726.1': + resolution: {integrity: sha512-hfRjdKYe65ioT1L9NZsDiRRoE4hPWacamUwsN/DjyMzctuCaL4vHkc5VXMfZj/s+17eUa+lyQFrLwel/zYpmgg==} + engines: {node: '>=18.0.0'} - '@aws-sdk/middleware-bucket-endpoint@3.696.0': - resolution: {integrity: sha512-V07jishKHUS5heRNGFpCWCSTjRJyQLynS/ncUeE8ZYtG66StOOQWftTwDfFOSoXlIqrXgb4oT9atryzXq7Z4LQ==} - engines: {node: '>=16.0.0'} + '@aws-sdk/middleware-bucket-endpoint@3.726.0': + resolution: {integrity: sha512-vpaP80rZqwu0C3ELayIcRIW84/nd1tadeoqllT+N9TDshuEvq4UJ+w47OBHB7RkHFJoc79lXXNYle0fdQdaE/A==} + engines: {node: '>=18.0.0'} - '@aws-sdk/middleware-expect-continue@3.696.0': - resolution: {integrity: sha512-vpVukqY3U2pb+ULeX0shs6L0aadNep6kKzjme/MyulPjtUDJpD3AekHsXRrCCGLmOqSKqRgQn5zhV9pQhHsb6Q==} - engines: {node: '>=16.0.0'} + '@aws-sdk/middleware-expect-continue@3.723.0': + resolution: {integrity: sha512-w/O0EkIzkiqvGu7U8Ke7tue0V0HYM5dZQrz6nVU+R8T2LddWJ+njEIHU4Wh8aHPLQXdZA5NQumv0xLPdEutykw==} + engines: {node: '>=18.0.0'} - '@aws-sdk/middleware-flexible-checksums@3.701.0': - resolution: {integrity: sha512-adNaPCyTT+CiVM0ufDiO1Fe7nlRmJdI9Hcgj0M9S6zR7Dw70Ra5z8Lslkd7syAccYvZaqxLklGjPQH/7GNxwTA==} - engines: {node: '>=16.0.0'} + '@aws-sdk/middleware-flexible-checksums@3.723.0': + resolution: {integrity: sha512-JY76mrUCLa0FHeMZp8X9+KK6uEuZaRZaQrlgq6zkXX/3udukH0T3YdFC+Y9uw5ddbiwZ5+KwgmlhnPpiXKfP4g==} + engines: {node: '>=18.0.0'} - '@aws-sdk/middleware-host-header@3.696.0': - resolution: {integrity: sha512-zELJp9Ta2zkX7ELggMN9qMCgekqZhFC5V2rOr4hJDEb/Tte7gpfKSObAnw/3AYiVqt36sjHKfdkoTsuwGdEoDg==} - engines: {node: '>=16.0.0'} + '@aws-sdk/middleware-host-header@3.723.0': + resolution: {integrity: sha512-LLVzLvk299pd7v4jN9yOSaWDZDfH0SnBPb6q+FDPaOCMGBY8kuwQso7e/ozIKSmZHRMGO3IZrflasHM+rI+2YQ==} + engines: {node: '>=18.0.0'} - '@aws-sdk/middleware-location-constraint@3.696.0': - resolution: {integrity: sha512-FgH12OB0q+DtTrP2aiDBddDKwL4BPOrm7w3VV9BJrSdkqQCNBPz8S1lb0y5eVH4tBG+2j7gKPlOv1wde4jF/iw==} - engines: {node: '>=16.0.0'} + '@aws-sdk/middleware-location-constraint@3.723.0': + resolution: {integrity: sha512-inp9tyrdRWjGOMu1rzli8i2gTo0P4X6L7nNRXNTKfyPNZcBimZ4H0H1B671JofSI5isaklVy5r4pvv2VjjLSHw==} + engines: {node: '>=18.0.0'} - '@aws-sdk/middleware-logger@3.696.0': - resolution: {integrity: sha512-KhkHt+8AjCxcR/5Zp3++YPJPpFQzxpr+jmONiT/Jw2yqnSngZ0Yspm5wGoRx2hS1HJbyZNuaOWEGuJoxLeBKfA==} - engines: {node: '>=16.0.0'} + '@aws-sdk/middleware-logger@3.723.0': + resolution: {integrity: sha512-chASQfDG5NJ8s5smydOEnNK7N0gDMyuPbx7dYYcm1t/PKtnVfvWF+DHCTrRC2Ej76gLJVCVizlAJKM8v8Kg3cg==} + engines: {node: '>=18.0.0'} - '@aws-sdk/middleware-recursion-detection@3.696.0': - resolution: {integrity: sha512-si/maV3Z0hH7qa99f9ru2xpS5HlfSVcasRlNUXKSDm611i7jFMWwGNLUOXFAOLhXotPX5G3Z6BLwL34oDeBMug==} - engines: {node: '>=16.0.0'} + '@aws-sdk/middleware-recursion-detection@3.723.0': + resolution: {integrity: sha512-7usZMtoynT9/jxL/rkuDOFQ0C2mhXl4yCm67Rg7GNTstl67u7w5WN1aIRImMeztaKlw8ExjoTyo6WTs1Kceh7A==} + engines: {node: '>=18.0.0'} - '@aws-sdk/middleware-sdk-ec2@3.696.0': - resolution: {integrity: sha512-HVMpblaaTQ1Ysku2nR6+N22aEgT7CDot+vsFutHNJCBPl+eEON5exp7IvsFC7sFCWmSfnMHTHtmmj5YIYHO1gQ==} - engines: {node: '>=16.0.0'} + '@aws-sdk/middleware-sdk-ec2@3.723.0': + resolution: {integrity: sha512-ZEDBQwIXquGIUgwsrWTVZjCnhUDnT10jBHYYn7NBUYJulX23mwn3avJnw5pZdukofLC/NuLtOCwnhtZ72kBDpg==} + engines: {node: '>=18.0.0'} - '@aws-sdk/middleware-sdk-rds@3.696.0': - resolution: {integrity: sha512-YSzPlVVgWfM+OfMM5LyuEP1A24zgKLNF9i+K8mtG+q2NpRJrXCbTlOEJUepCG58voYcL+GT8/Q0vwR7Btadi0w==} - engines: {node: '>=16.0.0'} + '@aws-sdk/middleware-sdk-rds@3.723.0': + resolution: {integrity: sha512-2zN/xmWP/iBO3r638y4mwwuZOJ1h08rVc13wqS6RzhebKJZvzPWmT7leB8ejEPYHOtzTC1hk1vvZt/WVB4Qqjw==} + engines: {node: '>=18.0.0'} - '@aws-sdk/middleware-sdk-s3@3.696.0': - resolution: {integrity: sha512-M7fEiAiN7DBMHflzOFzh1I2MNSlLpbiH2ubs87bdRc2wZsDPSbs4l3v6h3WLhxoQK0bq6vcfroudrLBgvCuX3Q==} - engines: {node: '>=16.0.0'} + '@aws-sdk/middleware-sdk-s3@3.723.0': + resolution: {integrity: sha512-wfjOvNJVp8LDWhq4wO5jtSMb8Vgf4tNlR7QTEQfoYc6AGU3WlK5xyUQcpfcpwytEhQTN9u0cJLQpSyXDO+qSCw==} + engines: {node: '>=18.0.0'} - '@aws-sdk/middleware-ssec@3.696.0': - resolution: {integrity: sha512-w/d6O7AOZ7Pg3w2d3BxnX5RmGNWb5X4RNxF19rJqcgu/xqxxE/QwZTNd5a7eTsqLXAUIfbbR8hh0czVfC1pJLA==} - engines: {node: '>=16.0.0'} + '@aws-sdk/middleware-ssec@3.723.0': + resolution: {integrity: sha512-Bs+8RAeSMik6ZYCGSDJzJieGsDDh2fRbh1HQG94T8kpwBXVxMYihm6e9Xp2cyl+w9fyyCnh0IdCKChP/DvrdhA==} + engines: {node: '>=18.0.0'} - '@aws-sdk/middleware-user-agent@3.696.0': - resolution: {integrity: sha512-Lvyj8CTyxrHI6GHd2YVZKIRI5Fmnugt3cpJo0VrKKEgK5zMySwEZ1n4dqPK6czYRWKd5+WnYHYAuU+Wdk6Jsjw==} - engines: {node: '>=16.0.0'} + '@aws-sdk/middleware-user-agent@3.726.0': + resolution: {integrity: sha512-hZvzuE5S0JmFie1r68K2wQvJbzyxJFdzltj9skgnnwdvLe8F/tz7MqLkm28uV0m4jeHk0LpiBo6eZaPkQiwsZQ==} + engines: {node: '>=18.0.0'} - '@aws-sdk/region-config-resolver@3.696.0': - resolution: {integrity: sha512-7EuH142lBXjI8yH6dVS/CZeiK/WZsmb/8zP6bQbVYpMrppSTgB3MzZZdxVZGzL5r8zPQOU10wLC4kIMy0qdBVQ==} - engines: {node: '>=16.0.0'} + '@aws-sdk/region-config-resolver@3.723.0': + resolution: {integrity: sha512-tGF/Cvch3uQjZIj34LY2mg8M2Dr4kYG8VU8Yd0dFnB1ybOEOveIK/9ypUo9ycZpB9oO6q01KRe5ijBaxNueUQg==} + engines: {node: '>=18.0.0'} - '@aws-sdk/signature-v4-multi-region@3.696.0': - resolution: {integrity: sha512-ijPkoLjXuPtgxAYlDoYls8UaG/VKigROn9ebbvPL/orEY5umedd3iZTcS9T+uAf4Ur3GELLxMQiERZpfDKaz3g==} - engines: {node: '>=16.0.0'} + '@aws-sdk/signature-v4-multi-region@3.723.0': + resolution: {integrity: sha512-lJlVAa5Sl589qO8lwMLVUtnlF1Q7I+6k1Iomv2goY9d1bRl4q2N5Pit2qJVr2AMW0sceQXeh23i2a/CKOqVAdg==} + engines: {node: '>=18.0.0'} - '@aws-sdk/token-providers@3.699.0': - resolution: {integrity: sha512-kuiEW9DWs7fNos/SM+y58HCPhcIzm1nEZLhe2/7/6+TvAYLuEWURYsbK48gzsxXlaJ2k/jGY3nIsA7RptbMOwA==} - engines: {node: '>=16.0.0'} + '@aws-sdk/token-providers@3.723.0': + resolution: {integrity: sha512-hniWi1x4JHVwKElANh9afKIMUhAutHVBRD8zo6usr0PAoj+Waf220+1ULS74GXtLXAPCiNXl5Og+PHA7xT8ElQ==} + engines: {node: '>=18.0.0'} peerDependencies: - '@aws-sdk/client-sso-oidc': ^3.699.0 + '@aws-sdk/client-sso-oidc': ^3.723.0 - '@aws-sdk/types@3.696.0': - resolution: {integrity: sha512-9rTvUJIAj5d3//U5FDPWGJ1nFJLuWb30vugGOrWk7aNZ6y9tuA3PI7Cc9dP8WEXKVyK1vuuk8rSFP2iqXnlgrw==} - engines: {node: '>=16.0.0'} + '@aws-sdk/types@3.723.0': + resolution: {integrity: sha512-LmK3kwiMZG1y5g3LGihT9mNkeNOmwEyPk6HGcJqh0wOSV4QpWoKu2epyKE4MLQNUUlz2kOVbVbOrwmI6ZcteuA==} + engines: {node: '>=18.0.0'} - '@aws-sdk/util-arn-parser@3.693.0': - resolution: {integrity: sha512-WC8x6ca+NRrtpAH64rWu+ryDZI3HuLwlEr8EU6/dbC/pt+r/zC0PBoC15VEygUaBA+isppCikQpGyEDu0Yj7gQ==} - engines: {node: '>=16.0.0'} + '@aws-sdk/util-arn-parser@3.723.0': + resolution: {integrity: sha512-ZhEfvUwNliOQROcAk34WJWVYTlTa4694kSVhDSjW6lE1bMataPnIN8A0ycukEzBXmd8ZSoBcQLn6lKGl7XIJ5w==} + engines: {node: '>=18.0.0'} - '@aws-sdk/util-endpoints@3.696.0': - resolution: {integrity: sha512-T5s0IlBVX+gkb9g/I6CLt4yAZVzMSiGnbUqWihWsHvQR1WOoIcndQy/Oz/IJXT9T2ipoy7a80gzV6a5mglrioA==} - engines: {node: '>=16.0.0'} + '@aws-sdk/util-endpoints@3.726.0': + resolution: {integrity: sha512-sLd30ASsPMoPn3XBK50oe/bkpJ4N8Bpb7SbhoxcY3Lk+fSASaWxbbXE81nbvCnkxrZCvkPOiDHzJCp1E2im71A==} + engines: {node: '>=18.0.0'} - '@aws-sdk/util-format-url@3.696.0': - resolution: {integrity: sha512-R6yK1LozUD1GdAZRPhNsIow6VNFJUTyyoIar1OCWaknlucBMcq7musF3DN3TlORBwfFMj5buHc2ET9OtMtzvuA==} - engines: {node: '>=16.0.0'} + '@aws-sdk/util-format-url@3.723.0': + resolution: {integrity: sha512-70+xUrdcnencPlCdV9XkRqmgj0vLDb8vm4mcEsgabg5QQ3S80KM0GEuhBAIGMkBWwNQTzCgQy2s7xOUlJPbu+g==} + engines: {node: '>=18.0.0'} - '@aws-sdk/util-locate-window@3.693.0': - resolution: {integrity: sha512-ttrag6haJLWABhLqtg1Uf+4LgHWIMOVSYL+VYZmAp2v4PUGOwWmWQH0Zk8RM7YuQcLfH/EoR72/Yxz6A4FKcuw==} - engines: {node: '>=16.0.0'} + '@aws-sdk/util-locate-window@3.723.0': + resolution: {integrity: sha512-Yf2CS10BqK688DRsrKI/EO6B8ff5J86NXe4C+VCysK7UOgN0l1zOTeTukZ3H8Q9tYYX3oaF1961o8vRkFm7Nmw==} + engines: {node: '>=18.0.0'} - '@aws-sdk/util-user-agent-browser@3.696.0': - resolution: {integrity: sha512-Z5rVNDdmPOe6ELoM5AhF/ja5tSjbe6ctSctDPb0JdDf4dT0v2MfwhJKzXju2RzX8Es/77Glh7MlaXLE0kCB9+Q==} + '@aws-sdk/util-user-agent-browser@3.723.0': + resolution: {integrity: sha512-Wh9I6j2jLhNFq6fmXydIpqD1WyQLyTfSxjW9B+PXSnPyk3jtQW8AKQur7p97rO8LAUzVI0bv8kb3ZzDEVbquIg==} - '@aws-sdk/util-user-agent-node@3.696.0': - resolution: {integrity: sha512-KhKqcfyXIB0SCCt+qsu4eJjsfiOrNzK5dCV7RAW2YIpp+msxGUUX0NdRE9rkzjiv+3EMktgJm3eEIS+yxtlVdQ==} - engines: {node: '>=16.0.0'} + '@aws-sdk/util-user-agent-node@3.726.0': + resolution: {integrity: sha512-iEj6KX9o6IQf23oziorveRqyzyclWai95oZHDJtYav3fvLJKStwSjygO4xSF7ycHcTYeCHSLO1FFOHgGVs4Viw==} + engines: {node: '>=18.0.0'} peerDependencies: aws-crt: '>=1.0.0' peerDependenciesMeta: aws-crt: optional: true - '@aws-sdk/xml-builder@3.696.0': - resolution: {integrity: sha512-dn1mX+EeqivoLYnY7p2qLrir0waPnCgS/0YdRCAVU2x14FgfUYCH6Im3w3oi2dMwhxfKY5lYVB5NKvZu7uI9lQ==} - engines: {node: '>=16.0.0'} + '@aws-sdk/xml-builder@3.723.0': + resolution: {integrity: sha512-5xK2SqGU1mzzsOeemy7cy3fGKxR1sEpUs4pEiIjaT0OIvU+fZaDVUEYWOqsgns6wI90XZEQJlXtI8uAHX/do5Q==} + engines: {node: '>=18.0.0'} '@babel/code-frame@7.26.2': resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} engines: {node: '>=6.9.0'} - '@babel/compat-data@7.26.3': - resolution: {integrity: sha512-nHIxvKPniQXpmQLb0vhY3VaFb3S0YrTAwpOWJZh1wn3oJPjJk9Asva204PsBdmAE8vpzfHudT8DB0scYvy9q0g==} + '@babel/compat-data@7.26.5': + resolution: {integrity: sha512-XvcZi1KWf88RVbF9wn8MN6tYFloU5qX8KjuF3E1PVBmJ9eypXfs4GRiJwLuTZL0iSnJUKn1BFPa5BPZZJyFzPg==} engines: {node: '>=6.9.0'} '@babel/core@7.26.0': resolution: {integrity: sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==} engines: {node: '>=6.9.0'} - '@babel/generator@7.26.3': - resolution: {integrity: sha512-6FF/urZvD0sTeO7k6/B15pMLC4CHUv1426lzr3N01aHJTl046uCAh9LXW/fzeXXjPNCJ6iABW5XaWOsIZB93aQ==} + '@babel/generator@7.26.5': + resolution: {integrity: sha512-2caSP6fN9I7HOe6nqhtft7V4g7/V/gfDsC3Ag4W7kEzzvRGKqiv0pu0HogPiZ3KaVSoNDhUws6IJjDjpfmYIXw==} engines: {node: '>=6.9.0'} - '@babel/helper-compilation-targets@7.25.9': - resolution: {integrity: sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==} + '@babel/helper-compilation-targets@7.26.5': + resolution: {integrity: sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA==} engines: {node: '>=6.9.0'} '@babel/helper-module-imports@7.25.9': @@ -865,8 +865,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-plugin-utils@7.25.9': - resolution: {integrity: sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==} + '@babel/helper-plugin-utils@7.26.5': + resolution: {integrity: sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==} engines: {node: '>=6.9.0'} '@babel/helper-string-parser@7.25.9': @@ -885,8 +885,8 @@ packages: resolution: {integrity: sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==} engines: {node: '>=6.9.0'} - '@babel/parser@7.26.3': - resolution: {integrity: sha512-WJ/CvmY8Mea8iDXo6a7RK2wbmJITT5fN3BEkRuFlxVyNx8jOKIIhmC4fSkTcPcf8JyavbBwIe6OpiCOBXt/IcA==} + '@babel/parser@7.26.5': + resolution: {integrity: sha512-SRJ4jYmXRqV1/Xc+TIVG84WjHBXKlxO9sHQnA2Pf12QQEAp1LOh6kDzNHXcUnbH1QI0FDoPPVOt+vyUDucxpaw==} engines: {node: '>=6.0.0'} hasBin: true @@ -989,12 +989,12 @@ packages: resolution: {integrity: sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==} engines: {node: '>=6.9.0'} - '@babel/traverse@7.26.4': - resolution: {integrity: sha512-fH+b7Y4p3yqvApJALCPJcwb0/XaOSgtK4pzV6WVjPR5GLFQBRI7pfoX2V2iM48NXvX07NUxxm1Vw98YjqTcU5w==} + '@babel/traverse@7.26.5': + resolution: {integrity: sha512-rkOSPOw+AXbgtwUga3U4u8RpoK9FEFWBNAlTpcnkLFjL5CT+oyHNuUUC/xx6XefEJ16r38r8Bc/lfp6rYuHeJQ==} engines: {node: '>=6.9.0'} - '@babel/types@7.26.3': - resolution: {integrity: sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==} + '@babel/types@7.26.5': + resolution: {integrity: sha512-L6mZmwFDK6Cjh1nRCLXpa6no13ZIioJDz7mdkzHv399pThrTa/k0nUlNaenOeh2kWu/iaOQYElEpKPUswUa9Vg==} engines: {node: '>=6.9.0'} '@bcoe/v8-coverage@0.2.3': @@ -1004,8 +1004,8 @@ packages: resolution: {integrity: sha512-EVMD0SgJtOuFeg0lAVbCwa+qeTKILb87jqvLyUtQswGD9+ce2nB52Y5zbTF1Hc0MDFfbydcMcxb47jSdhikVHA==} engines: {node: '>= 10'} - '@cdktf/hcl2json@0.20.10': - resolution: {integrity: sha512-oh8g9727sSEnwRjIjPYnhTn4mvvxclRcovf5GIkFED+4HpiBLioVUUsX33rFk6wZZh175uJBOAvQ/qVG+Uaqyw==} + '@cdktf/hcl2json@0.20.11': + resolution: {integrity: sha512-k4CJkbUPyI+k9KOQjJ6qu2dIrpqSkXukt9R+kDaizWVM4yc8HDMLHnelC0X2oWsfeQNE8wSAm20SXkGlPLoFmw==} '@colors/colors@1.5.0': resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} @@ -1231,12 +1231,12 @@ packages: resolution: {integrity: sha512-1LFfa/qnMQvEOAdzlQymH0ulepxbxnCYAKJZfMci/5XJyIHWgEYnDmgnKakbTh7CH2tFQ5O60oYDvns4i9RAIg==} engines: {node: '>= 18'} - '@octokit/core@6.1.2': - resolution: {integrity: sha512-hEb7Ma4cGJGEUNOAVmyfdB/3WirWMg5hDuNFVejGEDFqupeOysLc2sG6HJxY2etBp5YQu5Wtxwi020jS9xlUwg==} + '@octokit/core@6.1.3': + resolution: {integrity: sha512-z+j7DixNnfpdToYsOutStDgeRzJSMnbj8T1C/oQjB6Aa+kRfNjs/Fn7W6c8bmlt6mfy3FkgeKBRnDjxQow5dow==} engines: {node: '>= 18'} - '@octokit/endpoint@10.1.1': - resolution: {integrity: sha512-JYjh5rMOwXMJyUpj028cu0Gbp7qe/ihxfJMLc8VZBMMqSwLgOxDI1911gV4Enl1QSavAQNJcwmwBF9M0VvLh6Q==} + '@octokit/endpoint@10.1.2': + resolution: {integrity: sha512-XybpFv9Ms4hX5OCHMZqyODYqGTZ3H6K6Vva+M9LR7ib/xr1y1ZnlChYv9H680y77Vd/i/k+thXApeRASBQkzhA==} engines: {node: '>= 18'} '@octokit/endpoint@9.0.5': @@ -1247,12 +1247,12 @@ packages: resolution: {integrity: sha512-r+oZUH7aMFui1ypZnAvZmn0KSqAUgE1/tUXIWaqUCa1758ts/Jio84GZuzsvUkme98kv0WFY8//n0J1Z+vsIsQ==} engines: {node: '>= 18'} - '@octokit/graphql@8.1.1': - resolution: {integrity: sha512-ukiRmuHTi6ebQx/HFRCXKbDlOh/7xEV6QUXaE7MJEKGNAncGI/STSbOkl12qVXZrfZdpXctx5O9X1AIaebiDBg==} + '@octokit/graphql@8.1.2': + resolution: {integrity: sha512-bdlj/CJVjpaz06NBpfHhp4kGJaRZfz7AzC+6EwUImRtrwIw8dIgJ63Xg0OzV9pRn3rIzrt5c2sa++BL0JJ8GLw==} engines: {node: '>= 18'} - '@octokit/openapi-types@22.2.0': - resolution: {integrity: sha512-QBhVjcUa9W7Wwhm6DBFu6ZZ+1/t/oYxqc2tp81Pi41YNuJinbFRx8B133qVOrAaBbF7D/m0Et6f9/pZt9Rc+tg==} + '@octokit/openapi-types@23.0.1': + resolution: {integrity: sha512-izFjMJ1sir0jn0ldEKhZ7xegCTj/ObmEDlEfpFrx4k/JyZSMRHbO3/rBwgE7f3m2DHt+RrNGIVw4wSmwnm3t/g==} '@octokit/plugin-paginate-rest@11.3.1': resolution: {integrity: sha512-ryqobs26cLtM1kQxqeZui4v8FeznirUsksiA+RYemMPJ7Micju0WSkv50dBksTuZks9O5cg4wp+t8fZ/cLY56g==} @@ -1260,8 +1260,8 @@ packages: peerDependencies: '@octokit/core': '5' - '@octokit/plugin-paginate-rest@11.3.6': - resolution: {integrity: sha512-zcvqqf/+TicbTCa/Z+3w4eBJcAxCFymtc0UAIsR3dEVoNilWld4oXdscQ3laXamTszUZdusw97K8+DrbFiOwjw==} + '@octokit/plugin-paginate-rest@11.4.0': + resolution: {integrity: sha512-ttpGck5AYWkwMkMazNCZMqxKqIq1fJBNxBfsFwwfyYKTf914jKkLF0POMS3YkPBwp5g1c2Y4L79gDz01GhSr1g==} engines: {node: '>= 18'} peerDependencies: '@octokit/core': '>=6' @@ -1278,40 +1278,40 @@ packages: peerDependencies: '@octokit/core': ^5 - '@octokit/plugin-retry@7.1.2': - resolution: {integrity: sha512-XOWnPpH2kJ5VTwozsxGurw+svB2e61aWlmk5EVIYZPwFK5F9h4cyPyj9CIKRyMXMHSwpIsI3mPOdpMmrRhe7UQ==} + '@octokit/plugin-retry@7.1.3': + resolution: {integrity: sha512-8nKOXvYWnzv89gSyIvgFHmCBAxfQAOPRlkacUHL9r5oWtp5Whxl8Skb2n3ACZd+X6cYijD6uvmrQuPH/UCL5zQ==} engines: {node: '>= 18'} peerDependencies: '@octokit/core': '>=6' - '@octokit/plugin-throttling@9.3.2': - resolution: {integrity: sha512-FqpvcTpIWFpMMwIeSoypoJXysSAQ3R+ALJhXXSG1HTP3YZOIeLmcNcimKaXxTcws+Sh6yoRl13SJ5r8sXc1Fhw==} + '@octokit/plugin-throttling@9.4.0': + resolution: {integrity: sha512-IOlXxXhZA4Z3m0EEYtrrACkuHiArHLZ3CvqWwOez/pURNqRuwfoFlTPbN5Muf28pzFuztxPyiUiNwz8KctdZaQ==} engines: {node: '>= 18'} peerDependencies: - '@octokit/core': ^6.0.0 + '@octokit/core': ^6.1.3 '@octokit/request-error@5.1.0': resolution: {integrity: sha512-GETXfE05J0+7H2STzekpKObFe765O5dlAKUTLNGeH+x47z7JjXHfsHKo5z21D/o/IOZTUEI6nyWyR+bZVP/n5Q==} engines: {node: '>= 18'} - '@octokit/request-error@6.1.5': - resolution: {integrity: sha512-IlBTfGX8Yn/oFPMwSfvugfncK2EwRLjzbrpifNaMY8o/HTEAFqCA1FZxjD9cWvSKBHgrIhc4CSBIzMxiLsbzFQ==} + '@octokit/request-error@6.1.6': + resolution: {integrity: sha512-pqnVKYo/at0NuOjinrgcQYpEbv4snvP3bKMRqHaD9kIsk9u1LCpb2smHZi8/qJfgeNqLo5hNW4Z7FezNdEo0xg==} engines: {node: '>= 18'} '@octokit/request@8.4.0': resolution: {integrity: sha512-9Bb014e+m2TgBeEJGEbdplMVWwPmL1FPtggHQRkV+WVsMggPtEkLKPlcVYm/o8xKLkpJ7B+6N8WfQMtDLX2Dpw==} engines: {node: '>= 18'} - '@octokit/request@9.1.3': - resolution: {integrity: sha512-V+TFhu5fdF3K58rs1pGUJIDH5RZLbZm5BI+MNF+6o/ssFNT4vWlCh/tVpF3NxGtP15HUxTTMUbsG5llAuU2CZA==} + '@octokit/request@9.1.4': + resolution: {integrity: sha512-tMbOwGm6wDII6vygP3wUVqFTw3Aoo0FnVQyhihh8vVq12uO3P+vQZeo2CKMpWtPSogpACD0yyZAlVlQnjW71DA==} engines: {node: '>= 18'} '@octokit/rest@20.1.1': resolution: {integrity: sha512-MB4AYDsM5jhIHro/dq4ix1iWTLGToIGk6cWF5L6vanFaMble5jTX/UBQyiv05HsWnwUtY8JrfHy2LWfKwihqMw==} engines: {node: '>= 18'} - '@octokit/types@13.6.2': - resolution: {integrity: sha512-WpbZfZUcZU77DrSW4wbsSgTPfKcp286q3ItaIgvSbBpZJlu6mnYXAkjZz6LVZPXkEvLIM8McanyZejKTYUHipA==} + '@octokit/types@13.7.0': + resolution: {integrity: sha512-BXfRP+3P3IN6fd4uF3SniaHKOO4UXWBfkdR3vA8mIvaoO/wLjGN5qivUtW0QRitBHHMcfC41SLhNVYIZZE+wkA==} '@one-ini/wasm@0.1.1': resolution: {integrity: sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==} @@ -1547,11 +1547,11 @@ packages: resolution: {integrity: sha512-Uj52QvCuIr9qwvbPR3fymQFMwn0MIKItZrEKywNoSF7K4UVfrtBW3DGVQ9KZ2D5tFR3LgrlPdhNSYEkEVAQ4OA==} engines: {node: ^20.9.0 || ^22.11.0, pnpm: ^9.0.0} - '@renovatebot/osv-offline-db@1.6.0': - resolution: {integrity: sha512-cEOCTyd3+/7gPDmBn0pyJtF01+f9e/dJ1mOoML+v5AsP8GIPAzhtQUuIB5FiCxS4IsbP0qm34anYUZHGJldNJA==} + '@renovatebot/osv-offline-db@1.7.0': + resolution: {integrity: sha512-E24t9YfqJWkR2VbkUiatTEeUdWcTgVly/9JMAEYrLEjJPNZDQQEophsH19faOwFPnIoHhIpsNeTWf2iPhn4OEg==} - '@renovatebot/osv-offline@1.5.10': - resolution: {integrity: sha512-3Nu7bGVQGm0rJwGoHxZjc80cERtK7r25aii8aBwK2+JLAacC7xLju2WzuELt1TWSx/yt+QjA4ouWSC5/JnlmHw==} + '@renovatebot/osv-offline@1.5.11': + resolution: {integrity: sha512-y4lTOL90P1JpsAQ+gadSCXmeRP+tvRrFPCmKtsRUwq/00vO2HoTi9GgKRTEWS6QxtDVnKlHrQS0xbBCmdXySTA==} '@renovatebot/pep440@4.0.1': resolution: {integrity: sha512-jKodfnFIIGjK9PcoB7+2JkDQ+prjv3LHFMUS21F3+IEaiGomrvpiH27+gjyQRRwtSkkRnrxkqjEPdkj2IxC2qA==} @@ -1573,8 +1573,8 @@ packages: '@sec-ant/readable-stream@0.4.1': resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==} - '@semantic-release/commit-analyzer@13.0.0': - resolution: {integrity: sha512-KtXWczvTAB1ZFZ6B4O+w8HkfYm/OgQb1dUGNFZtDgQ0csggrmkq8sTxhd+lwGF8kMb59/RnG9o4Tn7M/I8dQ9Q==} + '@semantic-release/commit-analyzer@13.0.1': + resolution: {integrity: sha512-wdnBPHKkr9HhNhXOhZD5a2LNl91+hs8CC2vsAVYxtZH3y0dV3wKn+uZSN61rdJQZ8EGxzWB3inWocBHV9+u/CQ==} engines: {node: '>=20.8.1'} peerDependencies: semantic-release: '>=20.1.0' @@ -1605,8 +1605,8 @@ packages: peerDependencies: semantic-release: '>=20.1.0' - '@semantic-release/release-notes-generator@14.0.2': - resolution: {integrity: sha512-ur2l2tVLBfX3fSEO2rCy2X6Kzg5S7BHGqdwTHvJrpWp4mOEN7W4K/2kWAjvfAlwMenEKjMnDIhBbxxjnP0S9hw==} + '@semantic-release/release-notes-generator@14.0.3': + resolution: {integrity: sha512-XxAZRPWGwO5JwJtS83bRdoIhCiYIx8Vhr+u231pQAsdFIAbm19rSVJLdnBN+Avvk7CKvNQE/nJ4y7uqKH6WTiw==} engines: {node: '>=20.8.1'} peerDependencies: semantic-release: '>=20.1.0' @@ -1644,271 +1644,280 @@ packages: '@sinonjs/text-encoding@0.7.3': resolution: {integrity: sha512-DE427ROAphMQzU4ENbliGYrBSYPXF+TtLg9S8vzeA+OF4ZKzoDdzfL8sxuMUGS/lgRhM6j1URSk9ghf7Xo1tyA==} - '@smithy/abort-controller@3.1.9': - resolution: {integrity: sha512-yiW0WI30zj8ZKoSYNx90no7ugVn3khlyH/z5W8qtKBtVE6awRALbhSG+2SAHA1r6bO/6M9utxYKVZ3PCJ1rWxw==} - engines: {node: '>=16.0.0'} + '@smithy/abort-controller@4.0.1': + resolution: {integrity: sha512-fiUIYgIgRjMWznk6iLJz35K2YxSLHzLBA/RC6lBrKfQ8fHbPfvk7Pk9UvpKoHgJjI18MnbPuEju53zcVy6KF1g==} + engines: {node: '>=18.0.0'} - '@smithy/chunked-blob-reader-native@3.0.1': - resolution: {integrity: sha512-VEYtPvh5rs/xlyqpm5NRnfYLZn+q0SRPELbvBV+C/G7IQ+ouTuo+NKKa3ShG5OaFR8NYVMXls9hPYLTvIKKDrQ==} + '@smithy/chunked-blob-reader-native@4.0.0': + resolution: {integrity: sha512-R9wM2yPmfEMsUmlMlIgSzOyICs0x9uu7UTHoccMyt7BWw8shcGM8HqB355+BZCPBcySvbTYMs62EgEQkNxz2ig==} + engines: {node: '>=18.0.0'} - '@smithy/chunked-blob-reader@4.0.0': - resolution: {integrity: sha512-jSqRnZvkT4egkq/7b6/QRCNXmmYVcHwnJldqJ3IhVpQE2atObVJ137xmGeuGFhjFUr8gCEVAOKwSY79OvpbDaQ==} + '@smithy/chunked-blob-reader@5.0.0': + resolution: {integrity: sha512-+sKqDBQqb036hh4NPaUiEkYFkTUGYzRsn3EuFhyfQfMy6oGHEUJDurLP9Ufb5dasr/XiAmPNMr6wa9afjQB+Gw==} + engines: {node: '>=18.0.0'} - '@smithy/config-resolver@3.0.13': - resolution: {integrity: sha512-Gr/qwzyPaTL1tZcq8WQyHhTZREER5R1Wytmz4WnVGL4onA3dNk6Btll55c8Vr58pLdvWZmtG8oZxJTw3t3q7Jg==} - engines: {node: '>=16.0.0'} + '@smithy/config-resolver@4.0.1': + resolution: {integrity: sha512-Igfg8lKu3dRVkTSEm98QpZUvKEOa71jDX4vKRcvJVyRc3UgN3j7vFMf0s7xLQhYmKa8kyJGQgUJDOV5V3neVlQ==} + engines: {node: '>=18.0.0'} - '@smithy/core@2.5.5': - resolution: {integrity: sha512-G8G/sDDhXA7o0bOvkc7bgai6POuSld/+XhNnWAbpQTpLv2OZPvyqQ58tLPPlz0bSNsXktldDDREIv1LczFeNEw==} - engines: {node: '>=16.0.0'} + '@smithy/core@3.1.0': + resolution: {integrity: sha512-swFv0wQiK7TGHeuAp6lfF5Kw1dHWsTrCuc+yh4Kh05gEShjsE2RUxHucEerR9ih9JITNtaHcSpUThn5Y/vDw0A==} + engines: {node: '>=18.0.0'} - '@smithy/credential-provider-imds@3.2.8': - resolution: {integrity: sha512-ZCY2yD0BY+K9iMXkkbnjo+08T2h8/34oHd0Jmh6BZUSZwaaGlGCyBT/3wnS7u7Xl33/EEfN4B6nQr3Gx5bYxgw==} - engines: {node: '>=16.0.0'} + '@smithy/credential-provider-imds@4.0.1': + resolution: {integrity: sha512-l/qdInaDq1Zpznpmev/+52QomsJNZ3JkTl5yrTl02V6NBgJOQ4LY0SFw/8zsMwj3tLe8vqiIuwF6nxaEwgf6mg==} + engines: {node: '>=18.0.0'} - '@smithy/eventstream-codec@3.1.10': - resolution: {integrity: sha512-323B8YckSbUH0nMIpXn7HZsAVKHYHFUODa8gG9cHo0ySvA1fr5iWaNT+iIL0UCqUzG6QPHA3BSsBtRQou4mMqQ==} + '@smithy/eventstream-codec@4.0.1': + resolution: {integrity: sha512-Q2bCAAR6zXNVtJgifsU16ZjKGqdw/DyecKNgIgi7dlqw04fqDu0mnq+JmGphqheypVc64CYq3azSuCpAdFk2+A==} + engines: {node: '>=18.0.0'} - '@smithy/eventstream-serde-browser@3.0.14': - resolution: {integrity: sha512-kbrt0vjOIihW3V7Cqj1SXQvAI5BR8SnyQYsandva0AOR307cXAc+IhPngxIPslxTLfxwDpNu0HzCAq6g42kCPg==} - engines: {node: '>=16.0.0'} + '@smithy/eventstream-serde-browser@4.0.1': + resolution: {integrity: sha512-HbIybmz5rhNg+zxKiyVAnvdM3vkzjE6ccrJ620iPL8IXcJEntd3hnBl+ktMwIy12Te/kyrSbUb8UCdnUT4QEdA==} + engines: {node: '>=18.0.0'} - '@smithy/eventstream-serde-config-resolver@3.0.11': - resolution: {integrity: sha512-P2pnEp4n75O+QHjyO7cbw/vsw5l93K/8EWyjNCAAybYwUmj3M+hjSQZ9P5TVdUgEG08ueMAP5R4FkuSkElZ5tQ==} - engines: {node: '>=16.0.0'} + '@smithy/eventstream-serde-config-resolver@4.0.1': + resolution: {integrity: sha512-lSipaiq3rmHguHa3QFF4YcCM3VJOrY9oq2sow3qlhFY+nBSTF/nrO82MUQRPrxHQXA58J5G1UnU2WuJfi465BA==} + engines: {node: '>=18.0.0'} - '@smithy/eventstream-serde-node@3.0.13': - resolution: {integrity: sha512-zqy/9iwbj8Wysmvi7Lq7XFLeDgjRpTbCfwBhJa8WbrylTAHiAu6oQTwdY7iu2lxigbc9YYr9vPv5SzYny5tCXQ==} - engines: {node: '>=16.0.0'} + '@smithy/eventstream-serde-node@4.0.1': + resolution: {integrity: sha512-o4CoOI6oYGYJ4zXo34U8X9szDe3oGjmHgsMGiZM0j4vtNoT+h80TLnkUcrLZR3+E6HIxqW+G+9WHAVfl0GXK0Q==} + engines: {node: '>=18.0.0'} - '@smithy/eventstream-serde-universal@3.0.13': - resolution: {integrity: sha512-L1Ib66+gg9uTnqp/18Gz4MDpJPKRE44geOjOQ2SVc0eiaO5l255ADziATZgjQjqumC7yPtp1XnjHlF1srcwjKw==} - engines: {node: '>=16.0.0'} + '@smithy/eventstream-serde-universal@4.0.1': + resolution: {integrity: sha512-Z94uZp0tGJuxds3iEAZBqGU2QiaBHP4YytLUjwZWx+oUeohCsLyUm33yp4MMBmhkuPqSbQCXq5hDet6JGUgHWA==} + engines: {node: '>=18.0.0'} - '@smithy/fetch-http-handler@4.1.2': - resolution: {integrity: sha512-R7rU7Ae3ItU4rC0c5mB2sP5mJNbCfoDc8I5XlYjIZnquyUwec7fEo78F6DA3SmgJgkU1qTMcZJuGblxZsl10ZA==} + '@smithy/fetch-http-handler@5.0.1': + resolution: {integrity: sha512-3aS+fP28urrMW2KTjb6z9iFow6jO8n3MFfineGbndvzGZit3taZhKWtTorf+Gp5RpFDDafeHlhfsGlDCXvUnJA==} + engines: {node: '>=18.0.0'} - '@smithy/hash-blob-browser@3.1.10': - resolution: {integrity: sha512-elwslXOoNunmfS0fh55jHggyhccobFkexLYC1ZeZ1xP2BTSrcIBaHV2b4xUQOdctrSNOpMqOZH1r2XzWTEhyfA==} + '@smithy/hash-blob-browser@4.0.1': + resolution: {integrity: sha512-rkFIrQOKZGS6i1D3gKJ8skJ0RlXqDvb1IyAphksaFOMzkn3v3I1eJ8m7OkLj0jf1McP63rcCEoLlkAn/HjcTRw==} + engines: {node: '>=18.0.0'} - '@smithy/hash-node@3.0.11': - resolution: {integrity: sha512-emP23rwYyZhQBvklqTtwetkQlqbNYirDiEEwXl2v0GYWMnCzxst7ZaRAnWuy28njp5kAH54lvkdG37MblZzaHA==} - engines: {node: '>=16.0.0'} + '@smithy/hash-node@4.0.1': + resolution: {integrity: sha512-TJ6oZS+3r2Xu4emVse1YPB3Dq3d8RkZDKcPr71Nj/lJsdAP1c7oFzYqEn1IBc915TsgLl2xIJNuxCz+gLbLE0w==} + engines: {node: '>=18.0.0'} - '@smithy/hash-stream-node@3.1.10': - resolution: {integrity: sha512-olomK/jZQ93OMayW1zfTHwcbwBdhcZOHsyWyiZ9h9IXvc1mCD/VuvzbLb3Gy/qNJwI4MANPLctTp2BucV2oU/Q==} - engines: {node: '>=16.0.0'} + '@smithy/hash-stream-node@4.0.1': + resolution: {integrity: sha512-U1rAE1fxmReCIr6D2o/4ROqAQX+GffZpyMt3d7njtGDr2pUNmAKRWa49gsNVhCh2vVAuf3wXzWwNr2YN8PAXIw==} + engines: {node: '>=18.0.0'} - '@smithy/invalid-dependency@3.0.11': - resolution: {integrity: sha512-NuQmVPEJjUX6c+UELyVz8kUx8Q539EDeNwbRyu4IIF8MeV7hUtq1FB3SHVyki2u++5XLMFqngeMKk7ccspnNyQ==} + '@smithy/invalid-dependency@4.0.1': + resolution: {integrity: sha512-gdudFPf4QRQ5pzj7HEnu6FhKRi61BfH/Gk5Yf6O0KiSbr1LlVhgjThcvjdu658VE6Nve8vaIWB8/fodmS1rBPQ==} + engines: {node: '>=18.0.0'} '@smithy/is-array-buffer@2.2.0': resolution: {integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==} engines: {node: '>=14.0.0'} - '@smithy/is-array-buffer@3.0.0': - resolution: {integrity: sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==} - engines: {node: '>=16.0.0'} + '@smithy/is-array-buffer@4.0.0': + resolution: {integrity: sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw==} + engines: {node: '>=18.0.0'} - '@smithy/md5-js@3.0.11': - resolution: {integrity: sha512-3NM0L3i2Zm4bbgG6Ymi9NBcxXhryi3uE8fIfHJZIOfZVxOkGdjdgjR9A06SFIZCfnEIWKXZdm6Yq5/aPXFFhsQ==} + '@smithy/md5-js@4.0.1': + resolution: {integrity: sha512-HLZ647L27APi6zXkZlzSFZIjpo8po45YiyjMGJZM3gyDY8n7dPGdmxIIljLm4gPt/7rRvutLTTkYJpZVfG5r+A==} + engines: {node: '>=18.0.0'} - '@smithy/middleware-content-length@3.0.13': - resolution: {integrity: sha512-zfMhzojhFpIX3P5ug7jxTjfUcIPcGjcQYzB9t+rv0g1TX7B0QdwONW+ATouaLoD7h7LOw/ZlXfkq4xJ/g2TrIw==} - engines: {node: '>=16.0.0'} + '@smithy/middleware-content-length@4.0.1': + resolution: {integrity: sha512-OGXo7w5EkB5pPiac7KNzVtfCW2vKBTZNuCctn++TTSOMpe6RZO/n6WEC1AxJINn3+vWLKW49uad3lo/u0WJ9oQ==} + engines: {node: '>=18.0.0'} - '@smithy/middleware-endpoint@3.2.6': - resolution: {integrity: sha512-WAqzyulvvSKrT5c6VrQelgNVNNO7BlTQW9Z+s9tcG6G5CaBS1YBpPtT3VuhXLQbewSiGi7oXQROwpw26EG9PLQ==} - engines: {node: '>=16.0.0'} + '@smithy/middleware-endpoint@4.0.1': + resolution: {integrity: sha512-hCCOPu9+sRI7Wj0rZKKnGylKXBEd9cQJetzjQqe8cT4PWvtQAbvNVa6cgAONiZg9m8LaXtP9/waxm3C3eO4hiw==} + engines: {node: '>=18.0.0'} - '@smithy/middleware-retry@3.0.31': - resolution: {integrity: sha512-yq9wawrJLYHAYFpChLujxRN4My+SiKXvZk9Ml/CvTdRSA8ew+hvuR5LT+mjSlSBv3c4XJrkN8CWegkBaeD0Vrg==} - engines: {node: '>=16.0.0'} + '@smithy/middleware-retry@4.0.1': + resolution: {integrity: sha512-n3g2zZFgOWaz2ZYCy8+4wxSmq+HSTD8QKkRhFDv+nkxY1o7gzyp4PDz/+tOdcNPMPZ/A6Mt4aVECYNjQNiaHJw==} + engines: {node: '>=18.0.0'} - '@smithy/middleware-serde@3.0.11': - resolution: {integrity: sha512-KzPAeySp/fOoQA82TpnwItvX8BBURecpx6ZMu75EZDkAcnPtO6vf7q4aH5QHs/F1s3/snQaSFbbUMcFFZ086Mw==} - engines: {node: '>=16.0.0'} + '@smithy/middleware-serde@4.0.1': + resolution: {integrity: sha512-Fh0E2SOF+S+P1+CsgKyiBInAt3o2b6Qk7YOp2W0Qx2XnfTdfMuSDKUEcnrtpxCzgKJnqXeLUZYqtThaP0VGqtA==} + engines: {node: '>=18.0.0'} - '@smithy/middleware-stack@3.0.11': - resolution: {integrity: sha512-1HGo9a6/ikgOMrTrWL/WiN9N8GSVYpuRQO5kjstAq4CvV59bjqnh7TbdXGQ4vxLD3xlSjfBjq5t1SOELePsLnA==} - engines: {node: '>=16.0.0'} + '@smithy/middleware-stack@4.0.1': + resolution: {integrity: sha512-dHwDmrtR/ln8UTHpaIavRSzeIk5+YZTBtLnKwDW3G2t6nAupCiQUvNzNoHBpik63fwUaJPtlnMzXbQrNFWssIA==} + engines: {node: '>=18.0.0'} - '@smithy/node-config-provider@3.1.12': - resolution: {integrity: sha512-O9LVEu5J/u/FuNlZs+L7Ikn3lz7VB9hb0GtPT9MQeiBmtK8RSY3ULmsZgXhe6VAlgTw0YO+paQx4p8xdbs43vQ==} - engines: {node: '>=16.0.0'} + '@smithy/node-config-provider@4.0.1': + resolution: {integrity: sha512-8mRTjvCtVET8+rxvmzRNRR0hH2JjV0DFOmwXPrISmTIJEfnCBugpYYGAsCj8t41qd+RB5gbheSQ/6aKZCQvFLQ==} + engines: {node: '>=18.0.0'} - '@smithy/node-http-handler@3.3.2': - resolution: {integrity: sha512-t4ng1DAd527vlxvOfKFYEe6/QFBcsj7WpNlWTyjorwXXcKw3XlltBGbyHfSJ24QT84nF+agDha9tNYpzmSRZPA==} - engines: {node: '>=16.0.0'} + '@smithy/node-http-handler@4.0.1': + resolution: {integrity: sha512-ddQc7tvXiVLC5c3QKraGWde761KSk+mboCheZoWtuqnXh5l0WKyFy3NfDIM/dsKrI9HlLVH/21pi9wWK2gUFFA==} + engines: {node: '>=18.0.0'} - '@smithy/property-provider@3.1.11': - resolution: {integrity: sha512-I/+TMc4XTQ3QAjXfOcUWbSS073oOEAxgx4aZy8jHaf8JQnRkq2SZWw8+PfDtBvLUjcGMdxl+YwtzWe6i5uhL/A==} - engines: {node: '>=16.0.0'} + '@smithy/property-provider@4.0.1': + resolution: {integrity: sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ==} + engines: {node: '>=18.0.0'} - '@smithy/protocol-http@4.1.8': - resolution: {integrity: sha512-hmgIAVyxw1LySOwkgMIUN0kjN8TG9Nc85LJeEmEE/cNEe2rkHDUWhnJf2gxcSRFLWsyqWsrZGw40ROjUogg+Iw==} - engines: {node: '>=16.0.0'} + '@smithy/protocol-http@5.0.1': + resolution: {integrity: sha512-TE4cpj49jJNB/oHyh/cRVEgNZaoPaxd4vteJNB0yGidOCVR0jCw/hjPVsT8Q8FRmj8Bd3bFZt8Dh7xGCT+xMBQ==} + engines: {node: '>=18.0.0'} - '@smithy/querystring-builder@3.0.11': - resolution: {integrity: sha512-u+5HV/9uJaeLj5XTb6+IEF/dokWWkEqJ0XiaRRogyREmKGUgZnNecLucADLdauWFKUNbQfulHFEZEdjwEBjXRg==} - engines: {node: '>=16.0.0'} + '@smithy/querystring-builder@4.0.1': + resolution: {integrity: sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg==} + engines: {node: '>=18.0.0'} - '@smithy/querystring-parser@3.0.11': - resolution: {integrity: sha512-Je3kFvCsFMnso1ilPwA7GtlbPaTixa3WwC+K21kmMZHsBEOZYQaqxcMqeFFoU7/slFjKDIpiiPydvdJm8Q/MCw==} - engines: {node: '>=16.0.0'} + '@smithy/querystring-parser@4.0.1': + resolution: {integrity: sha512-Ma2XC7VS9aV77+clSFylVUnPZRindhB7BbmYiNOdr+CHt/kZNJoPP0cd3QxCnCFyPXC4eybmyE98phEHkqZ5Jw==} + engines: {node: '>=18.0.0'} - '@smithy/service-error-classification@3.0.11': - resolution: {integrity: sha512-QnYDPkyewrJzCyaeI2Rmp7pDwbUETe+hU8ADkXmgNusO1bgHBH7ovXJiYmba8t0fNfJx75fE8dlM6SEmZxheog==} - engines: {node: '>=16.0.0'} + '@smithy/service-error-classification@4.0.1': + resolution: {integrity: sha512-3JNjBfOWpj/mYfjXJHB4Txc/7E4LVq32bwzE7m28GN79+M1f76XHflUaSUkhOriprPDzev9cX/M+dEB80DNDKA==} + engines: {node: '>=18.0.0'} - '@smithy/shared-ini-file-loader@3.1.12': - resolution: {integrity: sha512-1xKSGI+U9KKdbG2qDvIR9dGrw3CNx+baqJfyr0igKEpjbHL5stsqAesYBzHChYHlelWtb87VnLWlhvfCz13H8Q==} - engines: {node: '>=16.0.0'} + '@smithy/shared-ini-file-loader@4.0.1': + resolution: {integrity: sha512-hC8F6qTBbuHRI/uqDgqqi6J0R4GtEZcgrZPhFQnMhfJs3MnUTGSnR1NSJCJs5VWlMydu0kJz15M640fJlRsIOw==} + engines: {node: '>=18.0.0'} - '@smithy/signature-v4@4.2.4': - resolution: {integrity: sha512-5JWeMQYg81TgU4cG+OexAWdvDTs5JDdbEZx+Qr1iPbvo91QFGzjy0IkXAKaXUHqmKUJgSHK0ZxnCkgZpzkeNTA==} - engines: {node: '>=16.0.0'} + '@smithy/signature-v4@5.0.1': + resolution: {integrity: sha512-nCe6fQ+ppm1bQuw5iKoeJ0MJfz2os7Ic3GBjOkLOPtavbD1ONoyE3ygjBfz2ythFWm4YnRm6OxW+8p/m9uCoIA==} + engines: {node: '>=18.0.0'} - '@smithy/smithy-client@3.5.1': - resolution: {integrity: sha512-PmjskH4Os1Eh3rd5vSsa5uVelZ4DRu+N5CBEgb9AT96hQSJGWSEb6pGxKV/PtKQSIp9ft3+KvnT8ViMKaguzgA==} - engines: {node: '>=16.0.0'} + '@smithy/smithy-client@4.1.0': + resolution: {integrity: sha512-NiboZnrsrZY+Cy5hQNbYi+nVNssXVi2I+yL4CIKNIanOhH8kpC5PKQ2jx/MQpwVr21a3XcVoQBArlpRF36OeEQ==} + engines: {node: '>=18.0.0'} - '@smithy/types@3.7.2': - resolution: {integrity: sha512-bNwBYYmN8Eh9RyjS1p2gW6MIhSO2rl7X9QeLM8iTdcGRP+eDiIWDt66c9IysCc22gefKszZv+ubV9qZc7hdESg==} - engines: {node: '>=16.0.0'} + '@smithy/types@4.1.0': + resolution: {integrity: sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==} + engines: {node: '>=18.0.0'} - '@smithy/url-parser@3.0.11': - resolution: {integrity: sha512-TmlqXkSk8ZPhfc+SQutjmFr5FjC0av3GZP4B/10caK1SbRwe/v+Wzu/R6xEKxoNqL+8nY18s1byiy6HqPG37Aw==} + '@smithy/url-parser@4.0.1': + resolution: {integrity: sha512-gPXcIEUtw7VlK8f/QcruNXm7q+T5hhvGu9tl63LsJPZ27exB6dtNwvh2HIi0v7JcXJ5emBxB+CJxwaLEdJfA+g==} + engines: {node: '>=18.0.0'} - '@smithy/util-base64@3.0.0': - resolution: {integrity: sha512-Kxvoh5Qtt0CDsfajiZOCpJxgtPHXOKwmM+Zy4waD43UoEMA+qPxxa98aE/7ZhdnBFZFXMOiBR5xbcaMhLtznQQ==} - engines: {node: '>=16.0.0'} + '@smithy/util-base64@4.0.0': + resolution: {integrity: sha512-CvHfCmO2mchox9kjrtzoHkWHxjHZzaFojLc8quxXY7WAAMAg43nuxwv95tATVgQFNDwd4M9S1qFzj40Ul41Kmg==} + engines: {node: '>=18.0.0'} - '@smithy/util-body-length-browser@3.0.0': - resolution: {integrity: sha512-cbjJs2A1mLYmqmyVl80uoLTJhAcfzMOyPgjwAYusWKMdLeNtzmMz9YxNl3/jRLoxSS3wkqkf0jwNdtXWtyEBaQ==} + '@smithy/util-body-length-browser@4.0.0': + resolution: {integrity: sha512-sNi3DL0/k64/LO3A256M+m3CDdG6V7WKWHdAiBBMUN8S3hK3aMPhwnPik2A/a2ONN+9doY9UxaLfgqsIRg69QA==} + engines: {node: '>=18.0.0'} - '@smithy/util-body-length-node@3.0.0': - resolution: {integrity: sha512-Tj7pZ4bUloNUP6PzwhN7K386tmSmEET9QtQg0TgdNOnxhZvCssHji+oZTUIuzxECRfG8rdm2PMw2WCFs6eIYkA==} - engines: {node: '>=16.0.0'} + '@smithy/util-body-length-node@4.0.0': + resolution: {integrity: sha512-q0iDP3VsZzqJyje8xJWEJCNIu3lktUGVoSy1KB0UWym2CL1siV3artm+u1DFYTLejpsrdGyCSWBdGNjJzfDPjg==} + engines: {node: '>=18.0.0'} '@smithy/util-buffer-from@2.2.0': resolution: {integrity: sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==} engines: {node: '>=14.0.0'} - '@smithy/util-buffer-from@3.0.0': - resolution: {integrity: sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==} - engines: {node: '>=16.0.0'} + '@smithy/util-buffer-from@4.0.0': + resolution: {integrity: sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug==} + engines: {node: '>=18.0.0'} - '@smithy/util-config-provider@3.0.0': - resolution: {integrity: sha512-pbjk4s0fwq3Di/ANL+rCvJMKM5bzAQdE5S/6RL5NXgMExFAi6UgQMPOm5yPaIWPpr+EOXKXRonJ3FoxKf4mCJQ==} - engines: {node: '>=16.0.0'} + '@smithy/util-config-provider@4.0.0': + resolution: {integrity: sha512-L1RBVzLyfE8OXH+1hsJ8p+acNUSirQnWQ6/EgpchV88G6zGBTDPdXiiExei6Z1wR2RxYvxY/XLw6AMNCCt8H3w==} + engines: {node: '>=18.0.0'} - '@smithy/util-defaults-mode-browser@3.0.31': - resolution: {integrity: sha512-eO+zkbqrPnmsagqzrmF7IJrCoU2wTQXWVYxMPqA9Oue55kw9WEvhyuw2XQzTVTCRcYsg6KgmV3YYhLlWQJfK1A==} - engines: {node: '>= 10.0.0'} + '@smithy/util-defaults-mode-browser@4.0.1': + resolution: {integrity: sha512-nkQifWzWUHw/D0aLPgyKut+QnJ5X+5E8wBvGfvrYLLZ86xPfVO6MoqfQo/9s4bF3Xscefua1M6KLZtobHMWrBg==} + engines: {node: '>=18.0.0'} - '@smithy/util-defaults-mode-node@3.0.31': - resolution: {integrity: sha512-0/nJfpSpbGZOs6qs42wCe2TdjobbnnD4a3YUUlvTXSQqLy4qa63luDaV04hGvqSHP7wQ7/WGehbvHkDhMZd1MQ==} - engines: {node: '>= 10.0.0'} + '@smithy/util-defaults-mode-node@4.0.1': + resolution: {integrity: sha512-LeAx2faB83litC9vaOdwFaldtto2gczUHxfFf8yoRwDU3cwL4/pDm7i0hxsuBCRk5mzHsrVGw+3EVCj32UZMdw==} + engines: {node: '>=18.0.0'} - '@smithy/util-endpoints@2.1.7': - resolution: {integrity: sha512-tSfcqKcN/Oo2STEYCABVuKgJ76nyyr6skGl9t15hs+YaiU06sgMkN7QYjo0BbVw+KT26zok3IzbdSOksQ4YzVw==} - engines: {node: '>=16.0.0'} + '@smithy/util-endpoints@3.0.1': + resolution: {integrity: sha512-zVdUENQpdtn9jbpD9SCFK4+aSiavRb9BxEtw9ZGUR1TYo6bBHbIoi7VkrFQ0/RwZlzx0wRBaRmPclj8iAoJCLA==} + engines: {node: '>=18.0.0'} - '@smithy/util-hex-encoding@3.0.0': - resolution: {integrity: sha512-eFndh1WEK5YMUYvy3lPlVmYY/fZcQE1D8oSf41Id2vCeIkKJXPcYDCZD+4+xViI6b1XSd7tE+s5AmXzz5ilabQ==} - engines: {node: '>=16.0.0'} + '@smithy/util-hex-encoding@4.0.0': + resolution: {integrity: sha512-Yk5mLhHtfIgW2W2WQZWSg5kuMZCVbvhFmC7rV4IO2QqnZdbEFPmQnCcGMAX2z/8Qj3B9hYYNjZOhWym+RwhePw==} + engines: {node: '>=18.0.0'} - '@smithy/util-middleware@3.0.11': - resolution: {integrity: sha512-dWpyc1e1R6VoXrwLoLDd57U1z6CwNSdkM69Ie4+6uYh2GC7Vg51Qtan7ITzczuVpqezdDTKJGJB95fFvvjU/ow==} - engines: {node: '>=16.0.0'} + '@smithy/util-middleware@4.0.1': + resolution: {integrity: sha512-HiLAvlcqhbzhuiOa0Lyct5IIlyIz0PQO5dnMlmQ/ubYM46dPInB+3yQGkfxsk6Q24Y0n3/JmcA1v5iEhmOF5mA==} + engines: {node: '>=18.0.0'} - '@smithy/util-retry@3.0.11': - resolution: {integrity: sha512-hJUC6W7A3DQgaee3Hp9ZFcOxVDZzmBIRBPlUAk8/fSOEl7pE/aX7Dci0JycNOnm9Mfr0KV2XjIlUOcGWXQUdVQ==} - engines: {node: '>=16.0.0'} + '@smithy/util-retry@4.0.1': + resolution: {integrity: sha512-WmRHqNVwn3kI3rKk1LsKcVgPBG6iLTBGC1iYOV3GQegwJ3E8yjzHytPt26VNzOWr1qu0xE03nK0Ug8S7T7oufw==} + engines: {node: '>=18.0.0'} - '@smithy/util-stream@3.3.2': - resolution: {integrity: sha512-sInAqdiVeisUGYAv/FrXpmJ0b4WTFmciTRqzhb7wVuem9BHvhIG7tpiYHLDWrl2stOokNZpTTGqz3mzB2qFwXg==} - engines: {node: '>=16.0.0'} + '@smithy/util-stream@4.0.1': + resolution: {integrity: sha512-Js16gOgU6Qht6qTPfuJgb+1YD4AEO+5Y1UPGWKSp3BNo8ONl/qhXSYDhFKJtwybRJynlCqvP5IeiaBsUmkSPTQ==} + engines: {node: '>=18.0.0'} - '@smithy/util-uri-escape@3.0.0': - resolution: {integrity: sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg==} - engines: {node: '>=16.0.0'} + '@smithy/util-uri-escape@4.0.0': + resolution: {integrity: sha512-77yfbCbQMtgtTylO9itEAdpPXSog3ZxMe09AEhm0dU0NLTalV70ghDZFR+Nfi1C60jnJoh/Re4090/DuZh2Omg==} + engines: {node: '>=18.0.0'} '@smithy/util-utf8@2.3.0': resolution: {integrity: sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==} engines: {node: '>=14.0.0'} - '@smithy/util-utf8@3.0.0': - resolution: {integrity: sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==} - engines: {node: '>=16.0.0'} + '@smithy/util-utf8@4.0.0': + resolution: {integrity: sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow==} + engines: {node: '>=18.0.0'} - '@smithy/util-waiter@3.2.0': - resolution: {integrity: sha512-PpjSboaDUE6yl+1qlg3Si57++e84oXdWGbuFUSAciXsVfEZJJJupR2Nb0QuXHiunt2vGR+1PTizOMvnUPaG2Qg==} - engines: {node: '>=16.0.0'} + '@smithy/util-waiter@4.0.2': + resolution: {integrity: sha512-piUTHyp2Axx3p/kc2CIJkYSv0BAaheBQmbACZgQSSfWUumWNW+R1lL+H9PDBxKJkvOeEX+hKYEFiwO8xagL8AQ==} + engines: {node: '>=18.0.0'} - '@swc/core-darwin-arm64@1.10.1': - resolution: {integrity: sha512-NyELPp8EsVZtxH/mEqvzSyWpfPJ1lugpTQcSlMduZLj1EASLO4sC8wt8hmL1aizRlsbjCX+r0PyL+l0xQ64/6Q==} + '@swc/core-darwin-arm64@1.10.7': + resolution: {integrity: sha512-SI0OFg987P6hcyT0Dbng3YRISPS9uhLX1dzW4qRrfqQdb0i75lPJ2YWe9CN47HBazrIA5COuTzrD2Dc0TcVsSQ==} engines: {node: '>=10'} cpu: [arm64] os: [darwin] - '@swc/core-darwin-x64@1.10.1': - resolution: {integrity: sha512-L4BNt1fdQ5ZZhAk5qoDfUnXRabDOXKnXBxMDJ+PWLSxOGBbWE6aJTnu4zbGjJvtot0KM46m2LPAPY8ttknqaZA==} + '@swc/core-darwin-x64@1.10.7': + resolution: {integrity: sha512-RFIAmWVicD/l3RzxgHW0R/G1ya/6nyMspE2cAeDcTbjHi0I5qgdhBWd6ieXOaqwEwiCd0Mot1g2VZrLGoBLsjQ==} engines: {node: '>=10'} cpu: [x64] os: [darwin] - '@swc/core-linux-arm-gnueabihf@1.10.1': - resolution: {integrity: sha512-Y1u9OqCHgvVp2tYQAJ7hcU9qO5brDMIrA5R31rwWQIAKDkJKtv3IlTHF0hrbWk1wPR0ZdngkQSJZple7G+Grvw==} + '@swc/core-linux-arm-gnueabihf@1.10.7': + resolution: {integrity: sha512-QP8vz7yELWfop5mM5foN6KkLylVO7ZUgWSF2cA0owwIaziactB2hCPZY5QU690coJouk9KmdFsPWDnaCFUP8tg==} engines: {node: '>=10'} cpu: [arm] os: [linux] - '@swc/core-linux-arm64-gnu@1.10.1': - resolution: {integrity: sha512-tNQHO/UKdtnqjc7o04iRXng1wTUXPgVd8Y6LI4qIbHVoVPwksZydISjMcilKNLKIwOoUQAkxyJ16SlOAeADzhQ==} + '@swc/core-linux-arm64-gnu@1.10.7': + resolution: {integrity: sha512-NgUDBGQcOeLNR+EOpmUvSDIP/F7i/OVOKxst4wOvT5FTxhnkWrW+StJGKj+DcUVSK5eWOYboSXr1y+Hlywwokw==} engines: {node: '>=10'} cpu: [arm64] os: [linux] - '@swc/core-linux-arm64-musl@1.10.1': - resolution: {integrity: sha512-x0L2Pd9weQ6n8dI1z1Isq00VHFvpBClwQJvrt3NHzmR+1wCT/gcYl1tp9P5xHh3ldM8Cn4UjWCw+7PaUgg8FcQ==} + '@swc/core-linux-arm64-musl@1.10.7': + resolution: {integrity: sha512-gp5Un3EbeSThBIh6oac5ZArV/CsSmTKj5jNuuUAuEsML3VF9vqPO+25VuxCvsRf/z3py+xOWRaN2HY/rjMeZog==} engines: {node: '>=10'} cpu: [arm64] os: [linux] - '@swc/core-linux-x64-gnu@1.10.1': - resolution: {integrity: sha512-yyYEwQcObV3AUsC79rSzN9z6kiWxKAVJ6Ntwq2N9YoZqSPYph+4/Am5fM1xEQYf/kb99csj0FgOelomJSobxQA==} + '@swc/core-linux-x64-gnu@1.10.7': + resolution: {integrity: sha512-k/OxLLMl/edYqbZyUNg6/bqEHTXJT15l9WGqsl/2QaIGwWGvles8YjruQYQ9d4h/thSXLT9gd8bExU2D0N+bUA==} engines: {node: '>=10'} cpu: [x64] os: [linux] - '@swc/core-linux-x64-musl@1.10.1': - resolution: {integrity: sha512-tcaS43Ydd7Fk7sW5ROpaf2Kq1zR+sI5K0RM+0qYLYYurvsJruj3GhBCaiN3gkzd8m/8wkqNqtVklWaQYSDsyqA==} + '@swc/core-linux-x64-musl@1.10.7': + resolution: {integrity: sha512-XeDoURdWt/ybYmXLCEE8aSiTOzEn0o3Dx5l9hgt0IZEmTts7HgHHVeRgzGXbR4yDo0MfRuX5nE1dYpTmCz0uyA==} engines: {node: '>=10'} cpu: [x64] os: [linux] - '@swc/core-win32-arm64-msvc@1.10.1': - resolution: {integrity: sha512-D3Qo1voA7AkbOzQ2UGuKNHfYGKL6eejN8VWOoQYtGHHQi1p5KK/Q7V1ku55oxXBsj79Ny5FRMqiRJpVGad7bjQ==} + '@swc/core-win32-arm64-msvc@1.10.7': + resolution: {integrity: sha512-nYAbi/uLS+CU0wFtBx8TquJw2uIMKBnl04LBmiVoFrsIhqSl+0MklaA9FVMGA35NcxSJfcm92Prl2W2LfSnTqQ==} engines: {node: '>=10'} cpu: [arm64] os: [win32] - '@swc/core-win32-ia32-msvc@1.10.1': - resolution: {integrity: sha512-WalYdFoU3454Og+sDKHM1MrjvxUGwA2oralknXkXL8S0I/8RkWZOB++p3pLaGbTvOO++T+6znFbQdR8KRaa7DA==} + '@swc/core-win32-ia32-msvc@1.10.7': + resolution: {integrity: sha512-+aGAbsDsIxeLxw0IzyQLtvtAcI1ctlXVvVcXZMNXIXtTURM876yNrufRo4ngoXB3jnb1MLjIIjgXfFs/eZTUSw==} engines: {node: '>=10'} cpu: [ia32] os: [win32] - '@swc/core-win32-x64-msvc@1.10.1': - resolution: {integrity: sha512-JWobfQDbTnoqaIwPKQ3DVSywihVXlQMbDuwik/dDWlj33A8oEHcjPOGs4OqcA3RHv24i+lfCQpM3Mn4FAMfacA==} + '@swc/core-win32-x64-msvc@1.10.7': + resolution: {integrity: sha512-TBf4clpDBjF/UUnkKrT0/th76/zwvudk5wwobiTFqDywMApHip5O0VpBgZ+4raY2TM8k5+ujoy7bfHb22zu17Q==} engines: {node: '>=10'} cpu: [x64] os: [win32] - '@swc/core@1.10.1': - resolution: {integrity: sha512-rQ4dS6GAdmtzKiCRt3LFVxl37FaY1cgL9kSUTnhQ2xc3fmHOd7jdJK/V4pSZMG1ruGTd0bsi34O2R0Olg9Zo/w==} + '@swc/core@1.10.7': + resolution: {integrity: sha512-py91kjI1jV5D5W/Q+PurBdGsdU5TFbrzamP7zSCqLdMcHkKi3rQEM5jkQcZr0MXXSJTaayLxS3MWYTBIkzPDrg==} engines: {node: '>=10'} peerDependencies: '@swc/helpers': '*' @@ -2016,8 +2025,11 @@ packages: '@types/conventional-commits-detector@1.0.2': resolution: {integrity: sha512-Yzo8dW+b2vziyDD9WNY+IPq4rcZyguHNuyNZC3wv0igpVFRd7VWHufl+vRQaCzDR2ftPTB1VPwbvXxWVpzBo+g==} - '@types/diff@6.0.0': - resolution: {integrity: sha512-dhVCYGv3ZSbzmQaBSagrv1WJ6rXCdkyTcDyoNu1MD8JohI7pR7k8wdZEm+mvdxRKXyHVwckFzWU1vJc+Z29MlA==} + '@types/debug@4.1.12': + resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} + + '@types/diff@7.0.0': + resolution: {integrity: sha512-sVpkpbnTJL9CYoDf4U+tHaQLe5HiTaHWY7m9FuYA7oMCHwC9ie0Vh9eIGapyzYrU3+pILlSY2fAc4elfw5m4dg==} '@types/emscripten@1.39.13': resolution: {integrity: sha512-cFq+fO/isvhvmuP/+Sl4K4jtU6E23DoivtbO4r50e3odaxAiVdbfSYRDdJ4gCdxx+3aRjhphS5ZMwIH4hFy/Cw==} @@ -2073,6 +2085,9 @@ packages: '@types/jsonfile@6.1.4': resolution: {integrity: sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==} + '@types/katex@0.16.7': + resolution: {integrity: sha512-HMwFiRujE5PjrgwHQ25+bsLJgowjGjm5Z8FVSf0N6PwgJrwxH0QxzHYDcKsTfV3wva0vzrpqMTJS2jXPr5BMEQ==} + '@types/keyv@3.1.4': resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} @@ -2082,8 +2097,8 @@ packages: '@types/linkify-markdown@1.0.3': resolution: {integrity: sha512-BnuGqDmpzmXCDMXHzgle/vMRUnbFcWclts0+n7Or421exav3XG6efl9gsxamLET6QPhX+pMnxcsHgnAO/daj9w==} - '@types/lodash@4.17.13': - resolution: {integrity: sha512-lfx+dftrEZcdBPczf9d0Qv0x+j/rfNCMuC6OcfXmO8gkfeNAY88PgKUbvG56whcN23gc27yenwF6oJZXGFpYxg==} + '@types/lodash@4.17.14': + resolution: {integrity: sha512-jsxagdikDiDBeIRaPYtArcT8my4tN1og7MtMRquFT3XNA6axxyHDRUemqDz/taRDdOUn0GnGHRCuff4q48sW9A==} '@types/luxon@3.4.2': resolution: {integrity: sha512-TifLZlFudklWlMBfhubvgqTXRzLDI5pCbGa4P8a3wPyUQSW+1xQ5eDsreP9DWHX3tjq1ke96uYG/nwundroWcA==} @@ -2106,17 +2121,17 @@ packages: '@types/minimist@1.2.5': resolution: {integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==} + '@types/moo@0.5.10': + resolution: {integrity: sha512-W6KzyZjXUYpwQfLK1O1UDzqcqYlul+lO7Bt71luyIIyNlOZwJaNeWWdqFs1C/f2hohZvUFHMk6oFNe9Rg48DbA==} + '@types/moo@0.5.5': resolution: {integrity: sha512-eXQpwnkI4Ntw5uJg6i2PINdRFWLr55dqjuYQaLHNjvqTzF14QdNWbCbml9sza0byyXNA0hZlHtcdN+VNDcgVHA==} - '@types/moo@0.5.9': - resolution: {integrity: sha512-ZsFVecFi66jGQ6L41TonEaBhsIVeVftTz6iQKWTctzacHhzYHWvv9S0IyAJi4BhN7vb9qCQ3+kpStP2vbZqmDg==} - '@types/ms@0.7.34': resolution: {integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==} - '@types/node@20.17.10': - resolution: {integrity: sha512-/jrvh5h6NXhEauFFexRin69nA0uHJ5gwk4iDivp/DeoEua3uwCUto6PC86IpRITBOs4+6i2I56K5x5b6WYGXHA==} + '@types/node@22.10.5': + resolution: {integrity: sha512-F8Q+SeGimwOo86fiovQh8qiXfFEh2/ocYv7tU5pJ3EXMSSxk1Joj5wefpFK2fHTf/N6HKGSxIDBT9f3gCxXPkQ==} '@types/normalize-package-data@2.4.4': resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} @@ -2187,8 +2202,8 @@ packages: '@types/yauzl@2.10.3': resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} - '@typescript-eslint/eslint-plugin@8.18.1': - resolution: {integrity: sha512-Ncvsq5CT3Gvh+uJG0Lwlho6suwDfUXH0HztslDf5I+F2wAFAZMRwYLEorumpKLzmO2suAXZ/td1tBg4NZIi9CQ==} + '@typescript-eslint/eslint-plugin@8.19.1': + resolution: {integrity: sha512-tJzcVyvvb9h/PB96g30MpxACd9IrunT7GF9wfA9/0TJ1LxGOJx1TdPzSbBBnNED7K9Ka8ybJsnEpiXPktolTLg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 @@ -2201,8 +2216,8 @@ packages: peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - '@typescript-eslint/parser@8.18.1': - resolution: {integrity: sha512-rBnTWHCdbYM2lh7hjyXqxk70wvon3p2FyaniZuey5TrcGBpfhVp0OxOa6gxr9Q9YhZFKyfbEnxc24ZnVbbUkCA==} + '@typescript-eslint/parser@8.19.1': + resolution: {integrity: sha512-67gbfv8rAwawjYx3fYArwldTQKoYfezNUT4D5ioWetr/xCrxXxvleo3uuiFuKfejipvq+og7mjz3b0G2bVyUCw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 @@ -2212,12 +2227,12 @@ packages: resolution: {integrity: sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@typescript-eslint/scope-manager@8.18.1': - resolution: {integrity: sha512-HxfHo2b090M5s2+/9Z3gkBhI6xBH8OJCFjH9MhQ+nnoZqxU3wNxkLT+VWXWSFWc3UF3Z+CfPAyqdCTdoXtDPCQ==} + '@typescript-eslint/scope-manager@8.19.1': + resolution: {integrity: sha512-60L9KIuN/xgmsINzonOcMDSB8p82h95hoBfSBtXuO4jlR1R9L1xSkmVZKgCPVfavDlXihh4ARNjXhh1gGnLC7Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/type-utils@8.18.1': - resolution: {integrity: sha512-jAhTdK/Qx2NJPNOTxXpMwlOiSymtR2j283TtPqXkKBdH8OAMmhiUfP0kJjc/qSE51Xrq02Gj9NY7MwK+UxVwHQ==} + '@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} peerDependencies: eslint: ^8.57.0 || ^9.0.0 @@ -2227,8 +2242,8 @@ packages: resolution: {integrity: sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@typescript-eslint/types@8.18.1': - resolution: {integrity: sha512-7uoAUsCj66qdNQNpH2G8MyTFlgerum8ubf21s3TSM3XmKXuIn+H2Sifh/ES2nPOPiYSRJWAk0fDkW0APBWcpfw==} + '@typescript-eslint/types@8.19.1': + resolution: {integrity: sha512-JBVHMLj7B1K1v1051ZaMMgLW4Q/jre5qGK0Ew6UgXz1Rqh+/xPzV1aW581OM00X6iOfyr1be+QyW8LOUf19BbA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@typescript-eslint/typescript-estree@5.62.0': @@ -2240,8 +2255,8 @@ packages: typescript: optional: true - '@typescript-eslint/typescript-estree@8.18.1': - resolution: {integrity: sha512-z8U21WI5txzl2XYOW7i9hJhxoKKNG1kcU4RzyNvKrdZDmbjkmLBo8bgeiOJmA06kizLI76/CCBAAGlTlEeUfyg==} + '@typescript-eslint/typescript-estree@8.19.1': + resolution: {integrity: sha512-jk/TZwSMJlxlNnqhy0Eod1PNEvCkpY6MXOXE/WLlblZ6ibb32i2We4uByoKPv1d0OD2xebDv4hbs3fm11SMw8Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <5.8.0' @@ -2252,8 +2267,8 @@ packages: peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - '@typescript-eslint/utils@8.18.1': - resolution: {integrity: sha512-8vikiIj2ebrC4WRdcAdDcmnu9Q/MXXwg+STf40BVfT8exDqBCUPdypvzcUPxEqRGKg9ALagZ0UWcYCtn+4W2iQ==} + '@typescript-eslint/utils@8.19.1': + resolution: {integrity: sha512-IxG5gLO0Ne+KaUc8iW1A+XuKLd63o4wlbI1Zp692n1xojCl/THvgIKXJXBZixTh5dd5+yTJ/VXH7GJaaw21qXA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 @@ -2263,15 +2278,15 @@ packages: resolution: {integrity: sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@typescript-eslint/visitor-keys@8.18.1': - resolution: {integrity: sha512-Vj0WLm5/ZsD013YeUKn+K0y8p1M0jPpxOkKdbD1wB0ns53a5piVY02zjf072TblEweAbcYiFiPoSMF3kp+VhhQ==} + '@typescript-eslint/visitor-keys@8.19.1': + resolution: {integrity: sha512-fzmjU8CHK853V/avYZAvuVut3ZTfwN5YtMaoi+X9Y9MA9keaWNHC3zEQ9zvyX/7Hj+5JkNyK1l7TOR2hevHB6Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@ungap/structured-clone@1.2.1': resolution: {integrity: sha512-fEzPV3hSkSMltkw152tJKNARhOupqbH96MZWyRjNaYZOMIzbrTeQDG+MTc6Mr2pgzFQzFxAfmhGDNP5QK++2ZA==} - '@yarnpkg/core@4.1.6': - resolution: {integrity: sha512-iF8LOSd4K0RVSB56c4IMYcXp6aiCT3wyWfMmiYSAiLm8tepwEtBOcrL9gzTzrT09NnDRz1CV/YB7iwfnUOMsAg==} + '@yarnpkg/core@4.2.0': + resolution: {integrity: sha512-h+cjnATkpO0ya6I5U4RYvOet/IsswOje3eBq9CsFM4XJZ2nS4WBBeFwYe0tqLD87IwKsoyuIdUwZjPHcn2DM8g==} engines: {node: '>=18.12.0'} '@yarnpkg/fslib@3.1.1': @@ -2324,8 +2339,8 @@ packages: resolution: {integrity: sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==} engines: {node: '>= 14'} - agentkeepalive@4.5.0: - resolution: {integrity: sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==} + agentkeepalive@4.6.0: + resolution: {integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==} engines: {node: '>= 8.0.0'} aggregate-error@3.1.0: @@ -2498,8 +2513,8 @@ packages: before-after-hook@3.0.2: resolution: {integrity: sha512-Nik3Sc0ncrMK4UUdXQmAnRtzmNQTAAXmXIopizwZ1W1t8QmfJj+zL4OA2I7XPTPW5z5TDqv4hRo/JzouDJnX3A==} - better-sqlite3@11.7.0: - resolution: {integrity: sha512-mXpa5jnIKKHeoGzBrUJrc65cXFKcILGZpU3FXR0pradUEm9MA7UZz02qfEejaMcm9iXrSOCenwwYMJ/tZ1y5Ig==} + better-sqlite3@11.7.2: + resolution: {integrity: sha512-10a57cHVDmfNQS4jrZ9AH2t+2ekzYh5Rhbcnb4ytpmYweoLdogDmyTt5D+hLiY9b44Mx9foowb/4iXBTO2yP3Q==} bignumber.js@9.1.2: resolution: {integrity: sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==} @@ -2536,8 +2551,8 @@ packages: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} - browserslist@4.24.3: - resolution: {integrity: sha512-1CPmv8iobE2fyRMV97dAcMVegvvWKxmq94hkLiAkUGwKVTyDLw33K+ZxiFrREKmmps4rIw6grcCFCnTMSZ/YiA==} + browserslist@4.24.4: + resolution: {integrity: sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true @@ -2619,8 +2634,8 @@ packages: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} - caniuse-lite@1.0.30001690: - resolution: {integrity: sha512-5ExiE3qQN6oF8Clf8ifIDcMRCRE/dMGcETG/XGMD8/XiXm6HXQgQTh1yZYLXXpSOsEUlJm1Xr7kGULZTuGtP/w==} + caniuse-lite@1.0.30001692: + resolution: {integrity: sha512-A95VKan0kdtrsnMubMKxEKUKImOPSuCpYgxSQBo036P5YYgVIcOYJEgt/txJWqObiRQeISNCfef9nvlQ0vbV7A==} chalk@2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} @@ -2648,12 +2663,21 @@ packages: character-entities-legacy@1.1.4: resolution: {integrity: sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==} + character-entities-legacy@3.0.0: + resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} + character-entities@1.2.4: resolution: {integrity: sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==} + character-entities@2.0.2: + resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} + character-reference-invalid@1.1.4: resolution: {integrity: sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==} + character-reference-invalid@2.0.1: + resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} + chownr@1.1.4: resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} @@ -2746,6 +2770,10 @@ packages: resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} engines: {node: '>=18'} + commander@8.3.0: + resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} + engines: {node: '>= 12'} + common-tags@1.8.2: resolution: {integrity: sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==} engines: {node: '>=4.0.0'} @@ -2799,8 +2827,8 @@ packages: convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - core-js-pure@3.39.0: - resolution: {integrity: sha512-7fEcWwKI4rJinnK+wLTezeg2smbFFdSBP6E2kQZNbnzM2s1rpKQ6aaRteZSSg7FLU3P0HGGVo/gbpfanU36urg==} + core-js-pure@3.40.0: + resolution: {integrity: sha512-AtDzVIgRrmRKQai62yuSIN5vNiQjcJakJb4fbhVw3ehxx7Lohphvw9SGNWKhLFqSxC4ilD0g/L1huAYFQU3Q6A==} core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} @@ -2886,6 +2914,9 @@ packages: resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} engines: {node: '>=0.10.0'} + decode-named-character-reference@1.0.2: + resolution: {integrity: sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==} + decompress-response@6.0.0: resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} engines: {node: '>=10'} @@ -2950,6 +2981,9 @@ packages: detect-node@2.1.0: resolution: {integrity: sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==} + devlop@1.1.0: + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + diff-sequences@29.6.3: resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -2988,8 +3022,8 @@ packages: resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} engines: {node: '>= 4'} - domutils@3.1.0: - resolution: {integrity: sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==} + domutils@3.2.2: + resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} dot-prop@5.3.0: resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==} @@ -3022,8 +3056,8 @@ packages: engines: {node: '>=0.10.0'} hasBin: true - electron-to-chromium@1.5.75: - resolution: {integrity: sha512-Lf3++DumRE/QmweGjU+ZcKqQ+3bKkU/qjaKYhIJKEOhgIO9Xs6IiAQFkfFoj+RhgDk4LUeNsLo6plExHqSyu6Q==} + electron-to-chromium@1.5.80: + resolution: {integrity: sha512-LTrKpW0AqIuHwmlVNV+cjFYTnXtM9K37OGhpe0ZI10ScPSxqVSryZHIY3WnCS5NSYbBODRTZyhRMS2h5FAEqAw==} email-addresses@5.0.0: resolution: {integrity: sha512-4OIPYlA6JXqtVn8zpHpGiI7vE6EQOAg16aGnDMIAlZVinnoZ8208tW1hAbjWydgN/4PLTT9q+O1K6AH/vALJGw==} @@ -3088,8 +3122,8 @@ packages: error-ex@1.3.2: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} - es-abstract@1.23.7: - resolution: {integrity: sha512-OygGC8kIcDhXX+6yAZRGLqwi2CmEXCbLQixeGUgYeR+Qwlppqmo7DIDr8XibtEBZp+fJcoYpoatp5qwLMEdcqQ==} + es-abstract@1.23.9: + resolution: {integrity: sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==} engines: {node: '>= 0.4'} es-define-property@1.0.1: @@ -3104,8 +3138,8 @@ packages: resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==} engines: {node: '>= 0.4'} - es-set-tostringtag@2.0.3: - resolution: {integrity: sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==} + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} engines: {node: '>= 0.4'} es-shim-unscopables@1.0.2: @@ -3319,11 +3353,14 @@ packages: engines: {node: '>= 10.17.0'} hasBin: true + fast-content-type-parse@2.0.1: + resolution: {integrity: sha512-nGqtvLrj5w0naR6tDPfB4cUmYCqouzyQiz6C5y/LtcDllJdrcc6WaWW6iXyIIOErTa/XRybj28aasdn4LkVk6Q==} + fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - fast-glob@3.3.2: - resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} engines: {node: '>=8.6.0'} fast-json-stable-stringify@2.1.0: @@ -3336,8 +3373,8 @@ packages: resolution: {integrity: sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==} hasBin: true - fastq@1.17.1: - resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} + fastq@1.18.0: + resolution: {integrity: sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw==} fb-watchman@2.0.2: resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} @@ -3479,14 +3516,18 @@ packages: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} - get-intrinsic@1.2.6: - resolution: {integrity: sha512-qxsEs+9A+u85HhllWJJFicJfPDhRmjzoYdl64aMWW9yRIJmSyxdn8IEkuIM530/7T+lv0TIHd8L6Q/ra0tEoeA==} + get-intrinsic@1.2.7: + resolution: {integrity: sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==} engines: {node: '>= 0.4'} get-package-type@0.1.0: resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} engines: {node: '>=8.0.0'} + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + get-stream@5.2.0: resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} engines: {node: '>=8'} @@ -3546,8 +3587,8 @@ packages: resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} hasBin: true - glob@11.0.0: - resolution: {integrity: sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g==} + glob@11.0.1: + resolution: {integrity: sha512-zrQDm8XPnYEKawJScsnM0QzobJxlT/kHOOlRTio8IH/GrmxRE5fjllkzdaHclIuNjUQTJYH2xHNIGfdpJkDJUw==} engines: {node: 20 || >=22} hasBin: true @@ -3756,8 +3797,8 @@ packages: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} - ignore@6.0.2: - resolution: {integrity: sha512-InwqeHHN2XpumIkMvpl/DCJVrAHgCsG5+cn1XlnLWGwtZBm8QJfSusItfrwx81CTp5agNZqpKU2J/ccC5nGT4A==} + ignore@7.0.0: + resolution: {integrity: sha512-lcX8PNQygAa22u/0BysEY8VhaFRzlOkvdlKczDPnJvrkJD1EuqzEky5VYYKM2iySIuaVIDv9N190DfSreSLw2A==} engines: {node: '>= 4'} immediate@3.0.6: @@ -3767,9 +3808,9 @@ packages: resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} engines: {node: '>=6'} - import-from-esm@1.3.4: - resolution: {integrity: sha512-7EyUlPFC0HOlBDpUFGfYstsU7XHxZJKAAMzCT8wZ0hMW7b+hG51LIKTDcsgtz8Pu6YC0HqRVbX+rVUtsGMUKvg==} - engines: {node: '>=16.20'} + import-from-esm@2.0.0: + resolution: {integrity: sha512-YVt14UZCgsX1vZQ3gKjkWVdBdHQ6eu3MPU1TBgL1H5orXe2+jWD006WCPPtOuwlQm10NuzOW5WawiF1Q9veW8g==} + engines: {node: '>=18.20'} import-in-the-middle@1.12.0: resolution: {integrity: sha512-yAgSE7GmtRcu4ZUSFX/4v69UGXwugFFSdIQJ14LHPOPPQrWv8Y7O9PHsw8Ovk7bKCLe4sjXMbZFqGFcLHpZ89w==} @@ -3831,9 +3872,15 @@ packages: is-alphabetical@1.0.4: resolution: {integrity: sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==} + is-alphabetical@2.0.1: + resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} + is-alphanumerical@1.0.4: resolution: {integrity: sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==} + is-alphanumerical@2.0.1: + resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==} + is-arguments@1.2.0: resolution: {integrity: sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==} engines: {node: '>= 0.4'} @@ -3845,8 +3892,8 @@ packages: is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - is-async-function@2.0.0: - resolution: {integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==} + is-async-function@2.1.0: + resolution: {integrity: sha512-GExz9MtyhlZyXYLxzlJRj5WUCE661zhDa1Yna52CN57AJsymh+DvXXjyveSioqSRdxvUrdKdvqB1b5cVKsNpWQ==} engines: {node: '>= 0.4'} is-bigint@1.1.0: @@ -3883,6 +3930,9 @@ packages: is-decimal@1.0.4: resolution: {integrity: sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==} + is-decimal@2.0.1: + resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} + is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -3899,8 +3949,8 @@ packages: resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} engines: {node: '>=6'} - is-generator-function@1.0.10: - resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==} + is-generator-function@1.1.0: + resolution: {integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==} engines: {node: '>= 0.4'} is-glob@4.0.3: @@ -3910,6 +3960,9 @@ packages: is-hexadecimal@1.0.4: resolution: {integrity: sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==} + is-hexadecimal@2.0.1: + resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} + is-lambda@1.0.1: resolution: {integrity: sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==} @@ -4301,6 +4354,10 @@ packages: jws@4.0.0: resolution: {integrity: sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==} + katex@0.16.19: + resolution: {integrity: sha512-3IA6DYVhxhBabjSLTNO9S4+OliA3Qvb8pBQXMfC4WxXJgLwZgnfDl0BmB4z6nBMdznBsZ+CGM8DrGZ5hcguDZg==} + hasBin: true + keybase-ecurve@1.0.1: resolution: {integrity: sha512-2GlVxDsNF+52LtYjgFsjoKuN7MQQgiVeR4HRdJxLuN8fm4mf4stGKPUjDJjky15c/98UsZseLjp7Ih5X0Sy1jQ==} @@ -4391,8 +4448,8 @@ packages: lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} - long@5.2.3: - resolution: {integrity: sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==} + long@5.2.4: + resolution: {integrity: sha512-qtzLbJE8hq7VabR3mISmVGtoXP8KGc2Z/AT8OuqlYD7JTR3oqrgwdjnk07wpj1twXxYmgDXgoKVWUG/fReSzHg==} longest-streak@2.0.4: resolution: {integrity: sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg==} @@ -4457,17 +4514,13 @@ packages: peerDependencies: markdownlint-cli2: '>=0.0.4' - markdownlint-cli2@0.16.0: - resolution: {integrity: sha512-oy5dJdOxGMKSwrlouxdEGf6N4O2Iz8oJ4/HO2Ix67o4vTK1AQNGjZUNwTIzfa5x+XbJ++dfgR1gLfILajsW+1Q==} + markdownlint-cli2@0.17.1: + resolution: {integrity: sha512-n1Im9lhKJJE12/u2N0GWBwPqeb0HGdylN8XpSFg9hbj35+QalY9Vi6mxwUQdG6wlSrrIq9ZDQ0Q85AQG9V2WOg==} engines: {node: '>=18'} hasBin: true - markdownlint-micromark@0.1.12: - resolution: {integrity: sha512-RlB6EwMGgc0sxcIhOQ2+aq7Zw1V2fBnzbXKGgYK/mVWdT7cz34fteKSwfYeo4rL6+L/q2tyC9QtD/PgZbkdyJQ==} - engines: {node: '>=18'} - - markdownlint@0.36.1: - resolution: {integrity: sha512-s73fU2CQN7WCgjhaQUQ8wYESQNzGRNOKDd+3xgVqu8kuTEhmwepd/mxOv1LR2oV046ONrTLBFsM7IoKWNvmy5g==} + markdownlint@0.37.3: + resolution: {integrity: sha512-eoQqH0291YCCjd+Pe1PUQ9AmWthlVmS0XWgcionkZ8q34ceZyRI+pYvsWksXJJL8OBkWCPwp1h/pnXxrPFC4oA==} engines: {node: '>=18'} marked-terminal@7.2.1: @@ -4507,8 +4560,8 @@ packages: mdurl@2.0.0: resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} - memfs@4.15.1: - resolution: {integrity: sha512-ufCzgFwiVnR6R9cCYuvwznJdhdYXEvFl0hpnM4cCtVaVkHuqBR+6fo2sqt1SSMdp+uiHw9GyPZr3OMM5tqjSmQ==} + memfs@4.17.0: + resolution: {integrity: sha512-4eirfZ7thblFmqFjywlTmuWVSvccHAJbn1r8qQLzmTO11qcqpohOjmY2mFce6x7x7WtskzRqApPD0hv+Oa74jg==} engines: {node: '>= 4.0.0'} memorystream@0.3.1: @@ -4534,9 +4587,84 @@ packages: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} + micromark-core-commonmark@2.0.2: + resolution: {integrity: sha512-FKjQKbxd1cibWMM1P9N+H8TwlgGgSkWZMmfuVucLCHaYqeSvJ0hFeHsIa65pA2nYbes0f8LDHPMrd9X7Ujxg9w==} + + micromark-extension-directive@3.0.2: + resolution: {integrity: sha512-wjcXHgk+PPdmvR58Le9d7zQYWy+vKEU9Se44p2CrCDPiLr2FMyiT4Fyb5UFKFC66wGB3kPlgD7q3TnoqPS7SZA==} + + micromark-extension-gfm-autolink-literal@2.1.0: + resolution: {integrity: sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==} + + micromark-extension-gfm-footnote@2.1.0: + resolution: {integrity: sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==} + + micromark-extension-gfm-table@2.1.0: + resolution: {integrity: sha512-Ub2ncQv+fwD70/l4ou27b4YzfNaCJOvyX4HxXU15m7mpYY+rjuWzsLIPZHJL253Z643RpbcP1oeIJlQ/SKW67g==} + + micromark-extension-math@3.1.0: + resolution: {integrity: sha512-lvEqd+fHjATVs+2v/8kg9i5Q0AP2k85H0WUOwpIVvUML8BapsMvh1XAogmQjOCsLpoKRCVQqEkQBB3NhVBcsOg==} + + micromark-factory-destination@2.0.1: + resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==} + + micromark-factory-label@2.0.1: + resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==} + + micromark-factory-space@2.0.1: + resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==} + + micromark-factory-title@2.0.1: + resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==} + + micromark-factory-whitespace@2.0.1: + resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==} + + micromark-util-character@2.1.1: + resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} + + micromark-util-chunked@2.0.1: + resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==} + + micromark-util-classify-character@2.0.1: + resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==} + + micromark-util-combine-extensions@2.0.1: + resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==} + + micromark-util-decode-numeric-character-reference@2.0.2: + resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==} + + micromark-util-encode@2.0.1: + resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} + + micromark-util-html-tag-name@2.0.1: + resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==} + + micromark-util-normalize-identifier@2.0.1: + resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==} + + micromark-util-resolve-all@2.0.1: + resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==} + + micromark-util-sanitize-uri@2.0.1: + resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} + + micromark-util-subtokenize@2.0.3: + resolution: {integrity: sha512-VXJJuNxYWSoYL6AJ6OQECCFGhIU2GGHMw8tahogePBrjkG8aCCas3ibkp7RnVOSTClg2is05/R7maAhF1XyQMg==} + + micromark-util-symbol@2.0.1: + resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} + + micromark-util-types@2.0.1: + resolution: {integrity: sha512-534m2WhVTddrcKVepwmVEVnUAmtrx9bfIjNoQHRqfnvdaHQiFytEhJoTgpWJvDEXCO5gLTQh3wYC1PgOJA4NSQ==} + micromark@2.11.4: resolution: {integrity: sha512-+WoovN/ppKolQOFIAajxi7Lu9kInbPxFuTBVEavFcL8eAfVstoc5MocPmqBeAdBOJV00uaVjegzH4+MA0DN/uA==} + micromark@4.0.1: + resolution: {integrity: sha512-eBPdkcoCNvYcxQOAKAlceo5SNdzZWfF+FcSupREAzdAh9rRmE239CEQAiTwIgblwnoM8zzj35sZ5ZwvSEOF6Kw==} + micromatch@4.0.8: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} @@ -4724,8 +4852,8 @@ packages: engines: {node: ^16.14.0 || >=18.0.0} hasBin: true - node-html-parser@6.1.13: - resolution: {integrity: sha512-qIsTMOY4C/dAa5Q5vsobRpOOvPfC4pB61UVW2uSwZNUp0QU/jCekTal1vMmbO0DgdHeLUJpv/ARmDqErVxA3Sg==} + node-html-parser@7.0.1: + resolution: {integrity: sha512-KGtmPY2kS0thCWGK0VuPyOS+pBKhhe8gXztzA2ilAOhbUbxa9homF1bOyKvhGzMLXUoRds9IOmr/v5lr/lqNmA==} node-int64@0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} @@ -4915,6 +5043,10 @@ packages: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} + own-keys@1.0.1: + resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} + engines: {node: '>= 0.4'} + p-all@3.0.0: resolution: {integrity: sha512-qUZbvbBFVXm6uJ7U/WDiO0fv6waBMbjlCm4E66oZdRR+egswICarIdHyVSZZHudH8T5SF8x/JG0q0duFzPnlBw==} engines: {node: '>=10'} @@ -5021,6 +5153,9 @@ packages: parse-entities@2.0.0: resolution: {integrity: sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==} + parse-entities@4.0.2: + resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==} + parse-json@4.0.0: resolution: {integrity: sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==} engines: {node: '>=4'} @@ -5277,15 +5412,15 @@ packages: redis@4.7.0: resolution: {integrity: sha512-zvmkHEAdGMn+hMRXuMBtu4Vo5P6rHQjLoHftu+lBqq8ZTA3RCVC/WzD790bkKKiNFp7d5/9PcSD19fJyyRvOdQ==} - reflect.getprototypeof@1.0.9: - resolution: {integrity: sha512-r0Ay04Snci87djAsI4U+WNRcSw5S4pOH7qFjd/veA5gC7TbqESR3tcj28ia95L/fYUDw11JKP7uqUKUAfVvV5Q==} + reflect.getprototypeof@1.0.10: + resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} engines: {node: '>= 0.4'} regenerator-runtime@0.14.1: resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} - regexp.prototype.flags@1.5.3: - resolution: {integrity: sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==} + regexp.prototype.flags@1.5.4: + resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} engines: {node: '>= 0.4'} registry-auth-token@5.0.3: @@ -5392,6 +5527,10 @@ packages: safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + safe-push-apply@1.0.0: + resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} + engines: {node: '>= 0.4'} + safe-regex-test@1.1.0: resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} engines: {node: '>= 0.4'} @@ -5406,8 +5545,8 @@ packages: sax@1.4.1: resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==} - semantic-release@24.2.0: - resolution: {integrity: sha512-fQfn6e/aYToRtVJYKqneFM1Rg3KP2gh3wSWtpYsLlz6uaPKlISrTzvYAFn+mYWo07F0X1Cz5ucU89AVE8X1mbg==} + semantic-release@24.2.1: + resolution: {integrity: sha512-z0/3cutKNkLQ4Oy0HTi3lubnjTsdjjgOqmxdPjeYWe6lhFqUPfwslZxRHv3HDZlN4MhnZitb9SLihDkZNxOXfQ==} engines: {node: '>=20.8.1'} hasBin: true @@ -5457,6 +5596,10 @@ packages: resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} engines: {node: '>= 0.4'} + set-proto@1.0.0: + resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} + engines: {node: '>= 0.4'} + shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -5816,14 +5959,14 @@ packages: trough@1.0.5: resolution: {integrity: sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==} - ts-api-utils@1.4.3: - resolution: {integrity: sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==} - engines: {node: '>=16'} + ts-api-utils@2.0.0: + resolution: {integrity: sha512-xCt/TOAc+EOHS1XPnijD3/yzpH6qg2xppZO1YDqGoVsNXfQfzHpOdNuXwrwOU8u4ITXJyDCTyt8w5g1sZv9ynQ==} + engines: {node: '>=18.12'} peerDependencies: - typescript: '>=4.2.0' + typescript: '>=4.8.4' - ts-essentials@10.0.3: - resolution: {integrity: sha512-/FrVAZ76JLTWxJOERk04fm8hYENDo0PWSP3YLQKxevLwWtxemGcl5JJEzN4iqfDlRve0ckyfFaOBu4xbNH/wZw==} + ts-essentials@10.0.4: + resolution: {integrity: sha512-lwYdz28+S4nicm+jFi6V58LaAIpxzhg9rLdgNC1VsdP/xiFBseGhF1M/shwCk6zMmwahBZdXcl34LVHrEang3A==} peerDependencies: typescript: '>=4.5.0' peerDependenciesMeta: @@ -5943,8 +6086,8 @@ packages: resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} engines: {node: '>=12.20'} - type-fest@4.30.2: - resolution: {integrity: sha512-UJShLPYi1aWqCdq9HycOL/gwsuqda1OISdBO3t8RlXQC4QvtuIz4b5FCfe2dQIWEpmlRExKmcTBfP1r9bhY7ig==} + type-fest@4.32.0: + resolution: {integrity: sha512-rfgpoi08xagF3JSdtJlCwMq9DGNDE0IMh3Mkpc1wUypg9vPi786AiqeBBKcqvIkq42azsBM85N490fyZjeUftw==} engines: {node: '>=16'} typed-array-buffer@1.0.3: @@ -5970,8 +6113,8 @@ packages: typedarray-to-buffer@3.1.5: resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} - typescript@5.7.2: - resolution: {integrity: sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==} + typescript@5.7.3: + resolution: {integrity: sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==} engines: {node: '>=14.17'} hasBin: true @@ -5993,8 +6136,8 @@ packages: underscore@1.13.7: resolution: {integrity: sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g==} - undici-types@6.19.8: - resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} + undici-types@6.20.0: + resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} unicode-emoji-modifier-base@1.0.0: resolution: {integrity: sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g==} @@ -6057,8 +6200,8 @@ packages: resolution: {integrity: sha512-1uEe95xksV1O0CYKXo8vQvN1JEbtJp7lb7C5U9HMsIp6IVwntkH/oNUzyVNQSd4S1sYk2FpSSW44FqMc8qee5w==} engines: {node: '>=4'} - update-browserslist-db@1.1.1: - resolution: {integrity: sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==} + update-browserslist-db@1.1.2: + resolution: {integrity: sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' @@ -6214,8 +6357,8 @@ packages: resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} engines: {node: '>=18'} - yaml@2.6.1: - resolution: {integrity: sha512-7r0XPzioN/Q9kXBro/XPnA6kznR73DHq+GXh5ON7ZozRO6aMjbmiBuKste2wslTFkC5d1dw0GooOCepZXJ2SAg==} + yaml@2.7.0: + resolution: {integrity: sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==} engines: {node: '>= 14'} hasBin: true @@ -6284,21 +6427,21 @@ snapshots: '@aws-crypto/crc32@5.2.0': dependencies: '@aws-crypto/util': 5.2.0 - '@aws-sdk/types': 3.696.0 + '@aws-sdk/types': 3.723.0 tslib: 2.8.1 '@aws-crypto/crc32c@5.2.0': dependencies: '@aws-crypto/util': 5.2.0 - '@aws-sdk/types': 3.696.0 + '@aws-sdk/types': 3.723.0 tslib: 2.8.1 '@aws-crypto/sha1-browser@5.2.0': dependencies: '@aws-crypto/supports-web-crypto': 5.2.0 '@aws-crypto/util': 5.2.0 - '@aws-sdk/types': 3.696.0 - '@aws-sdk/util-locate-window': 3.693.0 + '@aws-sdk/types': 3.723.0 + '@aws-sdk/util-locate-window': 3.723.0 '@smithy/util-utf8': 2.3.0 tslib: 2.8.1 @@ -6307,15 +6450,15 @@ snapshots: '@aws-crypto/sha256-js': 5.2.0 '@aws-crypto/supports-web-crypto': 5.2.0 '@aws-crypto/util': 5.2.0 - '@aws-sdk/types': 3.696.0 - '@aws-sdk/util-locate-window': 3.693.0 + '@aws-sdk/types': 3.723.0 + '@aws-sdk/util-locate-window': 3.723.0 '@smithy/util-utf8': 2.3.0 tslib: 2.8.1 '@aws-crypto/sha256-js@5.2.0': dependencies: '@aws-crypto/util': 5.2.0 - '@aws-sdk/types': 3.696.0 + '@aws-sdk/types': 3.723.0 tslib: 2.8.1 '@aws-crypto/supports-web-crypto@5.2.0': @@ -6324,768 +6467,768 @@ snapshots: '@aws-crypto/util@5.2.0': dependencies: - '@aws-sdk/types': 3.696.0 + '@aws-sdk/types': 3.723.0 '@smithy/util-utf8': 2.3.0 tslib: 2.8.1 - '@aws-sdk/client-codecommit@3.699.0': + '@aws-sdk/client-codecommit@3.726.1': dependencies: '@aws-crypto/sha256-browser': 5.2.0 '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/client-sso-oidc': 3.699.0(@aws-sdk/client-sts@3.699.0) - '@aws-sdk/client-sts': 3.699.0 - '@aws-sdk/core': 3.696.0 - '@aws-sdk/credential-provider-node': 3.699.0(@aws-sdk/client-sso-oidc@3.699.0(@aws-sdk/client-sts@3.699.0))(@aws-sdk/client-sts@3.699.0) - '@aws-sdk/middleware-host-header': 3.696.0 - '@aws-sdk/middleware-logger': 3.696.0 - '@aws-sdk/middleware-recursion-detection': 3.696.0 - '@aws-sdk/middleware-user-agent': 3.696.0 - '@aws-sdk/region-config-resolver': 3.696.0 - '@aws-sdk/types': 3.696.0 - '@aws-sdk/util-endpoints': 3.696.0 - '@aws-sdk/util-user-agent-browser': 3.696.0 - '@aws-sdk/util-user-agent-node': 3.696.0 - '@smithy/config-resolver': 3.0.13 - '@smithy/core': 2.5.5 - '@smithy/fetch-http-handler': 4.1.2 - '@smithy/hash-node': 3.0.11 - '@smithy/invalid-dependency': 3.0.11 - '@smithy/middleware-content-length': 3.0.13 - '@smithy/middleware-endpoint': 3.2.6 - '@smithy/middleware-retry': 3.0.31 - '@smithy/middleware-serde': 3.0.11 - '@smithy/middleware-stack': 3.0.11 - '@smithy/node-config-provider': 3.1.12 - '@smithy/node-http-handler': 3.3.2 - '@smithy/protocol-http': 4.1.8 - '@smithy/smithy-client': 3.5.1 - '@smithy/types': 3.7.2 - '@smithy/url-parser': 3.0.11 - '@smithy/util-base64': 3.0.0 - '@smithy/util-body-length-browser': 3.0.0 - '@smithy/util-body-length-node': 3.0.0 - '@smithy/util-defaults-mode-browser': 3.0.31 - '@smithy/util-defaults-mode-node': 3.0.31 - '@smithy/util-endpoints': 2.1.7 - '@smithy/util-middleware': 3.0.11 - '@smithy/util-retry': 3.0.11 - '@smithy/util-utf8': 3.0.0 + '@aws-sdk/client-sso-oidc': 3.726.0(@aws-sdk/client-sts@3.726.1) + '@aws-sdk/client-sts': 3.726.1 + '@aws-sdk/core': 3.723.0 + '@aws-sdk/credential-provider-node': 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) + '@aws-sdk/middleware-host-header': 3.723.0 + '@aws-sdk/middleware-logger': 3.723.0 + '@aws-sdk/middleware-recursion-detection': 3.723.0 + '@aws-sdk/middleware-user-agent': 3.726.0 + '@aws-sdk/region-config-resolver': 3.723.0 + '@aws-sdk/types': 3.723.0 + '@aws-sdk/util-endpoints': 3.726.0 + '@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/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-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/protocol-http': 5.0.1 + '@smithy/smithy-client': 4.1.0 + '@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-endpoints': 3.0.1 + '@smithy/util-middleware': 4.0.1 + '@smithy/util-retry': 4.0.1 + '@smithy/util-utf8': 4.0.0 '@types/uuid': 9.0.8 tslib: 2.8.1 uuid: 9.0.1 transitivePeerDependencies: - aws-crt - '@aws-sdk/client-cognito-identity@3.699.0': + '@aws-sdk/client-cognito-identity@3.726.1': dependencies: '@aws-crypto/sha256-browser': 5.2.0 '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/client-sso-oidc': 3.699.0(@aws-sdk/client-sts@3.699.0) - '@aws-sdk/client-sts': 3.699.0 - '@aws-sdk/core': 3.696.0 - '@aws-sdk/credential-provider-node': 3.699.0(@aws-sdk/client-sso-oidc@3.699.0(@aws-sdk/client-sts@3.699.0))(@aws-sdk/client-sts@3.699.0) - '@aws-sdk/middleware-host-header': 3.696.0 - '@aws-sdk/middleware-logger': 3.696.0 - '@aws-sdk/middleware-recursion-detection': 3.696.0 - '@aws-sdk/middleware-user-agent': 3.696.0 - '@aws-sdk/region-config-resolver': 3.696.0 - '@aws-sdk/types': 3.696.0 - '@aws-sdk/util-endpoints': 3.696.0 - '@aws-sdk/util-user-agent-browser': 3.696.0 - '@aws-sdk/util-user-agent-node': 3.696.0 - '@smithy/config-resolver': 3.0.13 - '@smithy/core': 2.5.5 - '@smithy/fetch-http-handler': 4.1.2 - '@smithy/hash-node': 3.0.11 - '@smithy/invalid-dependency': 3.0.11 - '@smithy/middleware-content-length': 3.0.13 - '@smithy/middleware-endpoint': 3.2.6 - '@smithy/middleware-retry': 3.0.31 - '@smithy/middleware-serde': 3.0.11 - '@smithy/middleware-stack': 3.0.11 - '@smithy/node-config-provider': 3.1.12 - '@smithy/node-http-handler': 3.3.2 - '@smithy/protocol-http': 4.1.8 - '@smithy/smithy-client': 3.5.1 - '@smithy/types': 3.7.2 - '@smithy/url-parser': 3.0.11 - '@smithy/util-base64': 3.0.0 - '@smithy/util-body-length-browser': 3.0.0 - '@smithy/util-body-length-node': 3.0.0 - '@smithy/util-defaults-mode-browser': 3.0.31 - '@smithy/util-defaults-mode-node': 3.0.31 - '@smithy/util-endpoints': 2.1.7 - '@smithy/util-middleware': 3.0.11 - '@smithy/util-retry': 3.0.11 - '@smithy/util-utf8': 3.0.0 + '@aws-sdk/client-sso-oidc': 3.726.0(@aws-sdk/client-sts@3.726.1) + '@aws-sdk/client-sts': 3.726.1 + '@aws-sdk/core': 3.723.0 + '@aws-sdk/credential-provider-node': 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) + '@aws-sdk/middleware-host-header': 3.723.0 + '@aws-sdk/middleware-logger': 3.723.0 + '@aws-sdk/middleware-recursion-detection': 3.723.0 + '@aws-sdk/middleware-user-agent': 3.726.0 + '@aws-sdk/region-config-resolver': 3.723.0 + '@aws-sdk/types': 3.723.0 + '@aws-sdk/util-endpoints': 3.726.0 + '@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/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-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/protocol-http': 5.0.1 + '@smithy/smithy-client': 4.1.0 + '@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-endpoints': 3.0.1 + '@smithy/util-middleware': 4.0.1 + '@smithy/util-retry': 4.0.1 + '@smithy/util-utf8': 4.0.0 tslib: 2.8.1 transitivePeerDependencies: - aws-crt - '@aws-sdk/client-ec2@3.701.0': + '@aws-sdk/client-ec2@3.726.1': dependencies: '@aws-crypto/sha256-browser': 5.2.0 '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/client-sso-oidc': 3.699.0(@aws-sdk/client-sts@3.699.0) - '@aws-sdk/client-sts': 3.699.0 - '@aws-sdk/core': 3.696.0 - '@aws-sdk/credential-provider-node': 3.699.0(@aws-sdk/client-sso-oidc@3.699.0(@aws-sdk/client-sts@3.699.0))(@aws-sdk/client-sts@3.699.0) - '@aws-sdk/middleware-host-header': 3.696.0 - '@aws-sdk/middleware-logger': 3.696.0 - '@aws-sdk/middleware-recursion-detection': 3.696.0 - '@aws-sdk/middleware-sdk-ec2': 3.696.0 - '@aws-sdk/middleware-user-agent': 3.696.0 - '@aws-sdk/region-config-resolver': 3.696.0 - '@aws-sdk/types': 3.696.0 - '@aws-sdk/util-endpoints': 3.696.0 - '@aws-sdk/util-user-agent-browser': 3.696.0 - '@aws-sdk/util-user-agent-node': 3.696.0 - '@smithy/config-resolver': 3.0.13 - '@smithy/core': 2.5.5 - '@smithy/fetch-http-handler': 4.1.2 - '@smithy/hash-node': 3.0.11 - '@smithy/invalid-dependency': 3.0.11 - '@smithy/middleware-content-length': 3.0.13 - '@smithy/middleware-endpoint': 3.2.6 - '@smithy/middleware-retry': 3.0.31 - '@smithy/middleware-serde': 3.0.11 - '@smithy/middleware-stack': 3.0.11 - '@smithy/node-config-provider': 3.1.12 - '@smithy/node-http-handler': 3.3.2 - '@smithy/protocol-http': 4.1.8 - '@smithy/smithy-client': 3.5.1 - '@smithy/types': 3.7.2 - '@smithy/url-parser': 3.0.11 - '@smithy/util-base64': 3.0.0 - '@smithy/util-body-length-browser': 3.0.0 - '@smithy/util-body-length-node': 3.0.0 - '@smithy/util-defaults-mode-browser': 3.0.31 - '@smithy/util-defaults-mode-node': 3.0.31 - '@smithy/util-endpoints': 2.1.7 - '@smithy/util-middleware': 3.0.11 - '@smithy/util-retry': 3.0.11 - '@smithy/util-utf8': 3.0.0 - '@smithy/util-waiter': 3.2.0 + '@aws-sdk/client-sso-oidc': 3.726.0(@aws-sdk/client-sts@3.726.1) + '@aws-sdk/client-sts': 3.726.1 + '@aws-sdk/core': 3.723.0 + '@aws-sdk/credential-provider-node': 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) + '@aws-sdk/middleware-host-header': 3.723.0 + '@aws-sdk/middleware-logger': 3.723.0 + '@aws-sdk/middleware-recursion-detection': 3.723.0 + '@aws-sdk/middleware-sdk-ec2': 3.723.0 + '@aws-sdk/middleware-user-agent': 3.726.0 + '@aws-sdk/region-config-resolver': 3.723.0 + '@aws-sdk/types': 3.723.0 + '@aws-sdk/util-endpoints': 3.726.0 + '@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/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-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/protocol-http': 5.0.1 + '@smithy/smithy-client': 4.1.0 + '@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-endpoints': 3.0.1 + '@smithy/util-middleware': 4.0.1 + '@smithy/util-retry': 4.0.1 + '@smithy/util-utf8': 4.0.0 + '@smithy/util-waiter': 4.0.2 '@types/uuid': 9.0.8 tslib: 2.8.1 uuid: 9.0.1 transitivePeerDependencies: - aws-crt - '@aws-sdk/client-ecr@3.699.0': + '@aws-sdk/client-ecr@3.726.1': dependencies: '@aws-crypto/sha256-browser': 5.2.0 '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/client-sso-oidc': 3.699.0(@aws-sdk/client-sts@3.699.0) - '@aws-sdk/client-sts': 3.699.0 - '@aws-sdk/core': 3.696.0 - '@aws-sdk/credential-provider-node': 3.699.0(@aws-sdk/client-sso-oidc@3.699.0(@aws-sdk/client-sts@3.699.0))(@aws-sdk/client-sts@3.699.0) - '@aws-sdk/middleware-host-header': 3.696.0 - '@aws-sdk/middleware-logger': 3.696.0 - '@aws-sdk/middleware-recursion-detection': 3.696.0 - '@aws-sdk/middleware-user-agent': 3.696.0 - '@aws-sdk/region-config-resolver': 3.696.0 - '@aws-sdk/types': 3.696.0 - '@aws-sdk/util-endpoints': 3.696.0 - '@aws-sdk/util-user-agent-browser': 3.696.0 - '@aws-sdk/util-user-agent-node': 3.696.0 - '@smithy/config-resolver': 3.0.13 - '@smithy/core': 2.5.5 - '@smithy/fetch-http-handler': 4.1.2 - '@smithy/hash-node': 3.0.11 - '@smithy/invalid-dependency': 3.0.11 - '@smithy/middleware-content-length': 3.0.13 - '@smithy/middleware-endpoint': 3.2.6 - '@smithy/middleware-retry': 3.0.31 - '@smithy/middleware-serde': 3.0.11 - '@smithy/middleware-stack': 3.0.11 - '@smithy/node-config-provider': 3.1.12 - '@smithy/node-http-handler': 3.3.2 - '@smithy/protocol-http': 4.1.8 - '@smithy/smithy-client': 3.5.1 - '@smithy/types': 3.7.2 - '@smithy/url-parser': 3.0.11 - '@smithy/util-base64': 3.0.0 - '@smithy/util-body-length-browser': 3.0.0 - '@smithy/util-body-length-node': 3.0.0 - '@smithy/util-defaults-mode-browser': 3.0.31 - '@smithy/util-defaults-mode-node': 3.0.31 - '@smithy/util-endpoints': 2.1.7 - '@smithy/util-middleware': 3.0.11 - '@smithy/util-retry': 3.0.11 - '@smithy/util-utf8': 3.0.0 - '@smithy/util-waiter': 3.2.0 + '@aws-sdk/client-sso-oidc': 3.726.0(@aws-sdk/client-sts@3.726.1) + '@aws-sdk/client-sts': 3.726.1 + '@aws-sdk/core': 3.723.0 + '@aws-sdk/credential-provider-node': 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) + '@aws-sdk/middleware-host-header': 3.723.0 + '@aws-sdk/middleware-logger': 3.723.0 + '@aws-sdk/middleware-recursion-detection': 3.723.0 + '@aws-sdk/middleware-user-agent': 3.726.0 + '@aws-sdk/region-config-resolver': 3.723.0 + '@aws-sdk/types': 3.723.0 + '@aws-sdk/util-endpoints': 3.726.0 + '@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/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-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/protocol-http': 5.0.1 + '@smithy/smithy-client': 4.1.0 + '@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-endpoints': 3.0.1 + '@smithy/util-middleware': 4.0.1 + '@smithy/util-retry': 4.0.1 + '@smithy/util-utf8': 4.0.0 + '@smithy/util-waiter': 4.0.2 tslib: 2.8.1 transitivePeerDependencies: - aws-crt - '@aws-sdk/client-rds@3.699.0': + '@aws-sdk/client-rds@3.726.1': dependencies: '@aws-crypto/sha256-browser': 5.2.0 '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/client-sso-oidc': 3.699.0(@aws-sdk/client-sts@3.699.0) - '@aws-sdk/client-sts': 3.699.0 - '@aws-sdk/core': 3.696.0 - '@aws-sdk/credential-provider-node': 3.699.0(@aws-sdk/client-sso-oidc@3.699.0(@aws-sdk/client-sts@3.699.0))(@aws-sdk/client-sts@3.699.0) - '@aws-sdk/middleware-host-header': 3.696.0 - '@aws-sdk/middleware-logger': 3.696.0 - '@aws-sdk/middleware-recursion-detection': 3.696.0 - '@aws-sdk/middleware-sdk-rds': 3.696.0 - '@aws-sdk/middleware-user-agent': 3.696.0 - '@aws-sdk/region-config-resolver': 3.696.0 - '@aws-sdk/types': 3.696.0 - '@aws-sdk/util-endpoints': 3.696.0 - '@aws-sdk/util-user-agent-browser': 3.696.0 - '@aws-sdk/util-user-agent-node': 3.696.0 - '@smithy/config-resolver': 3.0.13 - '@smithy/core': 2.5.5 - '@smithy/fetch-http-handler': 4.1.2 - '@smithy/hash-node': 3.0.11 - '@smithy/invalid-dependency': 3.0.11 - '@smithy/middleware-content-length': 3.0.13 - '@smithy/middleware-endpoint': 3.2.6 - '@smithy/middleware-retry': 3.0.31 - '@smithy/middleware-serde': 3.0.11 - '@smithy/middleware-stack': 3.0.11 - '@smithy/node-config-provider': 3.1.12 - '@smithy/node-http-handler': 3.3.2 - '@smithy/protocol-http': 4.1.8 - '@smithy/smithy-client': 3.5.1 - '@smithy/types': 3.7.2 - '@smithy/url-parser': 3.0.11 - '@smithy/util-base64': 3.0.0 - '@smithy/util-body-length-browser': 3.0.0 - '@smithy/util-body-length-node': 3.0.0 - '@smithy/util-defaults-mode-browser': 3.0.31 - '@smithy/util-defaults-mode-node': 3.0.31 - '@smithy/util-endpoints': 2.1.7 - '@smithy/util-middleware': 3.0.11 - '@smithy/util-retry': 3.0.11 - '@smithy/util-utf8': 3.0.0 - '@smithy/util-waiter': 3.2.0 + '@aws-sdk/client-sso-oidc': 3.726.0(@aws-sdk/client-sts@3.726.1) + '@aws-sdk/client-sts': 3.726.1 + '@aws-sdk/core': 3.723.0 + '@aws-sdk/credential-provider-node': 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) + '@aws-sdk/middleware-host-header': 3.723.0 + '@aws-sdk/middleware-logger': 3.723.0 + '@aws-sdk/middleware-recursion-detection': 3.723.0 + '@aws-sdk/middleware-sdk-rds': 3.723.0 + '@aws-sdk/middleware-user-agent': 3.726.0 + '@aws-sdk/region-config-resolver': 3.723.0 + '@aws-sdk/types': 3.723.0 + '@aws-sdk/util-endpoints': 3.726.0 + '@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/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-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/protocol-http': 5.0.1 + '@smithy/smithy-client': 4.1.0 + '@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-endpoints': 3.0.1 + '@smithy/util-middleware': 4.0.1 + '@smithy/util-retry': 4.0.1 + '@smithy/util-utf8': 4.0.0 + '@smithy/util-waiter': 4.0.2 tslib: 2.8.1 transitivePeerDependencies: - aws-crt - '@aws-sdk/client-s3@3.701.0': + '@aws-sdk/client-s3@3.726.1': dependencies: '@aws-crypto/sha1-browser': 5.2.0 '@aws-crypto/sha256-browser': 5.2.0 '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/client-sso-oidc': 3.699.0(@aws-sdk/client-sts@3.699.0) - '@aws-sdk/client-sts': 3.699.0 - '@aws-sdk/core': 3.696.0 - '@aws-sdk/credential-provider-node': 3.699.0(@aws-sdk/client-sso-oidc@3.699.0(@aws-sdk/client-sts@3.699.0))(@aws-sdk/client-sts@3.699.0) - '@aws-sdk/middleware-bucket-endpoint': 3.696.0 - '@aws-sdk/middleware-expect-continue': 3.696.0 - '@aws-sdk/middleware-flexible-checksums': 3.701.0 - '@aws-sdk/middleware-host-header': 3.696.0 - '@aws-sdk/middleware-location-constraint': 3.696.0 - '@aws-sdk/middleware-logger': 3.696.0 - '@aws-sdk/middleware-recursion-detection': 3.696.0 - '@aws-sdk/middleware-sdk-s3': 3.696.0 - '@aws-sdk/middleware-ssec': 3.696.0 - '@aws-sdk/middleware-user-agent': 3.696.0 - '@aws-sdk/region-config-resolver': 3.696.0 - '@aws-sdk/signature-v4-multi-region': 3.696.0 - '@aws-sdk/types': 3.696.0 - '@aws-sdk/util-endpoints': 3.696.0 - '@aws-sdk/util-user-agent-browser': 3.696.0 - '@aws-sdk/util-user-agent-node': 3.696.0 - '@aws-sdk/xml-builder': 3.696.0 - '@smithy/config-resolver': 3.0.13 - '@smithy/core': 2.5.5 - '@smithy/eventstream-serde-browser': 3.0.14 - '@smithy/eventstream-serde-config-resolver': 3.0.11 - '@smithy/eventstream-serde-node': 3.0.13 - '@smithy/fetch-http-handler': 4.1.2 - '@smithy/hash-blob-browser': 3.1.10 - '@smithy/hash-node': 3.0.11 - '@smithy/hash-stream-node': 3.1.10 - '@smithy/invalid-dependency': 3.0.11 - '@smithy/md5-js': 3.0.11 - '@smithy/middleware-content-length': 3.0.13 - '@smithy/middleware-endpoint': 3.2.6 - '@smithy/middleware-retry': 3.0.31 - '@smithy/middleware-serde': 3.0.11 - '@smithy/middleware-stack': 3.0.11 - '@smithy/node-config-provider': 3.1.12 - '@smithy/node-http-handler': 3.3.2 - '@smithy/protocol-http': 4.1.8 - '@smithy/smithy-client': 3.5.1 - '@smithy/types': 3.7.2 - '@smithy/url-parser': 3.0.11 - '@smithy/util-base64': 3.0.0 - '@smithy/util-body-length-browser': 3.0.0 - '@smithy/util-body-length-node': 3.0.0 - '@smithy/util-defaults-mode-browser': 3.0.31 - '@smithy/util-defaults-mode-node': 3.0.31 - '@smithy/util-endpoints': 2.1.7 - '@smithy/util-middleware': 3.0.11 - '@smithy/util-retry': 3.0.11 - '@smithy/util-stream': 3.3.2 - '@smithy/util-utf8': 3.0.0 - '@smithy/util-waiter': 3.2.0 + '@aws-sdk/client-sso-oidc': 3.726.0(@aws-sdk/client-sts@3.726.1) + '@aws-sdk/client-sts': 3.726.1 + '@aws-sdk/core': 3.723.0 + '@aws-sdk/credential-provider-node': 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) + '@aws-sdk/middleware-bucket-endpoint': 3.726.0 + '@aws-sdk/middleware-expect-continue': 3.723.0 + '@aws-sdk/middleware-flexible-checksums': 3.723.0 + '@aws-sdk/middleware-host-header': 3.723.0 + '@aws-sdk/middleware-location-constraint': 3.723.0 + '@aws-sdk/middleware-logger': 3.723.0 + '@aws-sdk/middleware-recursion-detection': 3.723.0 + '@aws-sdk/middleware-sdk-s3': 3.723.0 + '@aws-sdk/middleware-ssec': 3.723.0 + '@aws-sdk/middleware-user-agent': 3.726.0 + '@aws-sdk/region-config-resolver': 3.723.0 + '@aws-sdk/signature-v4-multi-region': 3.723.0 + '@aws-sdk/types': 3.723.0 + '@aws-sdk/util-endpoints': 3.726.0 + '@aws-sdk/util-user-agent-browser': 3.723.0 + '@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/eventstream-serde-browser': 4.0.1 + '@smithy/eventstream-serde-config-resolver': 4.0.1 + '@smithy/eventstream-serde-node': 4.0.1 + '@smithy/fetch-http-handler': 5.0.1 + '@smithy/hash-blob-browser': 4.0.1 + '@smithy/hash-node': 4.0.1 + '@smithy/hash-stream-node': 4.0.1 + '@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-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/protocol-http': 5.0.1 + '@smithy/smithy-client': 4.1.0 + '@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-endpoints': 3.0.1 + '@smithy/util-middleware': 4.0.1 + '@smithy/util-retry': 4.0.1 + '@smithy/util-stream': 4.0.1 + '@smithy/util-utf8': 4.0.0 + '@smithy/util-waiter': 4.0.2 tslib: 2.8.1 transitivePeerDependencies: - aws-crt - '@aws-sdk/client-sso-oidc@3.699.0(@aws-sdk/client-sts@3.699.0)': + '@aws-sdk/client-sso-oidc@3.726.0(@aws-sdk/client-sts@3.726.1)': dependencies: '@aws-crypto/sha256-browser': 5.2.0 '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/client-sts': 3.699.0 - '@aws-sdk/core': 3.696.0 - '@aws-sdk/credential-provider-node': 3.699.0(@aws-sdk/client-sso-oidc@3.699.0(@aws-sdk/client-sts@3.699.0))(@aws-sdk/client-sts@3.699.0) - '@aws-sdk/middleware-host-header': 3.696.0 - '@aws-sdk/middleware-logger': 3.696.0 - '@aws-sdk/middleware-recursion-detection': 3.696.0 - '@aws-sdk/middleware-user-agent': 3.696.0 - '@aws-sdk/region-config-resolver': 3.696.0 - '@aws-sdk/types': 3.696.0 - '@aws-sdk/util-endpoints': 3.696.0 - '@aws-sdk/util-user-agent-browser': 3.696.0 - '@aws-sdk/util-user-agent-node': 3.696.0 - '@smithy/config-resolver': 3.0.13 - '@smithy/core': 2.5.5 - '@smithy/fetch-http-handler': 4.1.2 - '@smithy/hash-node': 3.0.11 - '@smithy/invalid-dependency': 3.0.11 - '@smithy/middleware-content-length': 3.0.13 - '@smithy/middleware-endpoint': 3.2.6 - '@smithy/middleware-retry': 3.0.31 - '@smithy/middleware-serde': 3.0.11 - '@smithy/middleware-stack': 3.0.11 - '@smithy/node-config-provider': 3.1.12 - '@smithy/node-http-handler': 3.3.2 - '@smithy/protocol-http': 4.1.8 - '@smithy/smithy-client': 3.5.1 - '@smithy/types': 3.7.2 - '@smithy/url-parser': 3.0.11 - '@smithy/util-base64': 3.0.0 - '@smithy/util-body-length-browser': 3.0.0 - '@smithy/util-body-length-node': 3.0.0 - '@smithy/util-defaults-mode-browser': 3.0.31 - '@smithy/util-defaults-mode-node': 3.0.31 - '@smithy/util-endpoints': 2.1.7 - '@smithy/util-middleware': 3.0.11 - '@smithy/util-retry': 3.0.11 - '@smithy/util-utf8': 3.0.0 + '@aws-sdk/client-sts': 3.726.1 + '@aws-sdk/core': 3.723.0 + '@aws-sdk/credential-provider-node': 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) + '@aws-sdk/middleware-host-header': 3.723.0 + '@aws-sdk/middleware-logger': 3.723.0 + '@aws-sdk/middleware-recursion-detection': 3.723.0 + '@aws-sdk/middleware-user-agent': 3.726.0 + '@aws-sdk/region-config-resolver': 3.723.0 + '@aws-sdk/types': 3.723.0 + '@aws-sdk/util-endpoints': 3.726.0 + '@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/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-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/protocol-http': 5.0.1 + '@smithy/smithy-client': 4.1.0 + '@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-endpoints': 3.0.1 + '@smithy/util-middleware': 4.0.1 + '@smithy/util-retry': 4.0.1 + '@smithy/util-utf8': 4.0.0 tslib: 2.8.1 transitivePeerDependencies: - aws-crt - '@aws-sdk/client-sso@3.696.0': + '@aws-sdk/client-sso@3.726.0': dependencies: '@aws-crypto/sha256-browser': 5.2.0 '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/core': 3.696.0 - '@aws-sdk/middleware-host-header': 3.696.0 - '@aws-sdk/middleware-logger': 3.696.0 - '@aws-sdk/middleware-recursion-detection': 3.696.0 - '@aws-sdk/middleware-user-agent': 3.696.0 - '@aws-sdk/region-config-resolver': 3.696.0 - '@aws-sdk/types': 3.696.0 - '@aws-sdk/util-endpoints': 3.696.0 - '@aws-sdk/util-user-agent-browser': 3.696.0 - '@aws-sdk/util-user-agent-node': 3.696.0 - '@smithy/config-resolver': 3.0.13 - '@smithy/core': 2.5.5 - '@smithy/fetch-http-handler': 4.1.2 - '@smithy/hash-node': 3.0.11 - '@smithy/invalid-dependency': 3.0.11 - '@smithy/middleware-content-length': 3.0.13 - '@smithy/middleware-endpoint': 3.2.6 - '@smithy/middleware-retry': 3.0.31 - '@smithy/middleware-serde': 3.0.11 - '@smithy/middleware-stack': 3.0.11 - '@smithy/node-config-provider': 3.1.12 - '@smithy/node-http-handler': 3.3.2 - '@smithy/protocol-http': 4.1.8 - '@smithy/smithy-client': 3.5.1 - '@smithy/types': 3.7.2 - '@smithy/url-parser': 3.0.11 - '@smithy/util-base64': 3.0.0 - '@smithy/util-body-length-browser': 3.0.0 - '@smithy/util-body-length-node': 3.0.0 - '@smithy/util-defaults-mode-browser': 3.0.31 - '@smithy/util-defaults-mode-node': 3.0.31 - '@smithy/util-endpoints': 2.1.7 - '@smithy/util-middleware': 3.0.11 - '@smithy/util-retry': 3.0.11 - '@smithy/util-utf8': 3.0.0 + '@aws-sdk/core': 3.723.0 + '@aws-sdk/middleware-host-header': 3.723.0 + '@aws-sdk/middleware-logger': 3.723.0 + '@aws-sdk/middleware-recursion-detection': 3.723.0 + '@aws-sdk/middleware-user-agent': 3.726.0 + '@aws-sdk/region-config-resolver': 3.723.0 + '@aws-sdk/types': 3.723.0 + '@aws-sdk/util-endpoints': 3.726.0 + '@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/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-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/protocol-http': 5.0.1 + '@smithy/smithy-client': 4.1.0 + '@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-endpoints': 3.0.1 + '@smithy/util-middleware': 4.0.1 + '@smithy/util-retry': 4.0.1 + '@smithy/util-utf8': 4.0.0 tslib: 2.8.1 transitivePeerDependencies: - aws-crt - '@aws-sdk/client-sts@3.699.0': + '@aws-sdk/client-sts@3.726.1': dependencies: '@aws-crypto/sha256-browser': 5.2.0 '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/client-sso-oidc': 3.699.0(@aws-sdk/client-sts@3.699.0) - '@aws-sdk/core': 3.696.0 - '@aws-sdk/credential-provider-node': 3.699.0(@aws-sdk/client-sso-oidc@3.699.0(@aws-sdk/client-sts@3.699.0))(@aws-sdk/client-sts@3.699.0) - '@aws-sdk/middleware-host-header': 3.696.0 - '@aws-sdk/middleware-logger': 3.696.0 - '@aws-sdk/middleware-recursion-detection': 3.696.0 - '@aws-sdk/middleware-user-agent': 3.696.0 - '@aws-sdk/region-config-resolver': 3.696.0 - '@aws-sdk/types': 3.696.0 - '@aws-sdk/util-endpoints': 3.696.0 - '@aws-sdk/util-user-agent-browser': 3.696.0 - '@aws-sdk/util-user-agent-node': 3.696.0 - '@smithy/config-resolver': 3.0.13 - '@smithy/core': 2.5.5 - '@smithy/fetch-http-handler': 4.1.2 - '@smithy/hash-node': 3.0.11 - '@smithy/invalid-dependency': 3.0.11 - '@smithy/middleware-content-length': 3.0.13 - '@smithy/middleware-endpoint': 3.2.6 - '@smithy/middleware-retry': 3.0.31 - '@smithy/middleware-serde': 3.0.11 - '@smithy/middleware-stack': 3.0.11 - '@smithy/node-config-provider': 3.1.12 - '@smithy/node-http-handler': 3.3.2 - '@smithy/protocol-http': 4.1.8 - '@smithy/smithy-client': 3.5.1 - '@smithy/types': 3.7.2 - '@smithy/url-parser': 3.0.11 - '@smithy/util-base64': 3.0.0 - '@smithy/util-body-length-browser': 3.0.0 - '@smithy/util-body-length-node': 3.0.0 - '@smithy/util-defaults-mode-browser': 3.0.31 - '@smithy/util-defaults-mode-node': 3.0.31 - '@smithy/util-endpoints': 2.1.7 - '@smithy/util-middleware': 3.0.11 - '@smithy/util-retry': 3.0.11 - '@smithy/util-utf8': 3.0.0 + '@aws-sdk/client-sso-oidc': 3.726.0(@aws-sdk/client-sts@3.726.1) + '@aws-sdk/core': 3.723.0 + '@aws-sdk/credential-provider-node': 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) + '@aws-sdk/middleware-host-header': 3.723.0 + '@aws-sdk/middleware-logger': 3.723.0 + '@aws-sdk/middleware-recursion-detection': 3.723.0 + '@aws-sdk/middleware-user-agent': 3.726.0 + '@aws-sdk/region-config-resolver': 3.723.0 + '@aws-sdk/types': 3.723.0 + '@aws-sdk/util-endpoints': 3.726.0 + '@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/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-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/protocol-http': 5.0.1 + '@smithy/smithy-client': 4.1.0 + '@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-endpoints': 3.0.1 + '@smithy/util-middleware': 4.0.1 + '@smithy/util-retry': 4.0.1 + '@smithy/util-utf8': 4.0.0 tslib: 2.8.1 transitivePeerDependencies: - aws-crt - '@aws-sdk/core@3.696.0': - dependencies: - '@aws-sdk/types': 3.696.0 - '@smithy/core': 2.5.5 - '@smithy/node-config-provider': 3.1.12 - '@smithy/property-provider': 3.1.11 - '@smithy/protocol-http': 4.1.8 - '@smithy/signature-v4': 4.2.4 - '@smithy/smithy-client': 3.5.1 - '@smithy/types': 3.7.2 - '@smithy/util-middleware': 3.0.11 + '@aws-sdk/core@3.723.0': + dependencies: + '@aws-sdk/types': 3.723.0 + '@smithy/core': 3.1.0 + '@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/types': 4.1.0 + '@smithy/util-middleware': 4.0.1 fast-xml-parser: 4.4.1 tslib: 2.8.1 - '@aws-sdk/credential-provider-cognito-identity@3.699.0': + '@aws-sdk/credential-provider-cognito-identity@3.726.1': dependencies: - '@aws-sdk/client-cognito-identity': 3.699.0 - '@aws-sdk/types': 3.696.0 - '@smithy/property-provider': 3.1.11 - '@smithy/types': 3.7.2 + '@aws-sdk/client-cognito-identity': 3.726.1 + '@aws-sdk/types': 3.723.0 + '@smithy/property-provider': 4.0.1 + '@smithy/types': 4.1.0 tslib: 2.8.1 transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-env@3.696.0': + '@aws-sdk/credential-provider-env@3.723.0': dependencies: - '@aws-sdk/core': 3.696.0 - '@aws-sdk/types': 3.696.0 - '@smithy/property-provider': 3.1.11 - '@smithy/types': 3.7.2 + '@aws-sdk/core': 3.723.0 + '@aws-sdk/types': 3.723.0 + '@smithy/property-provider': 4.0.1 + '@smithy/types': 4.1.0 tslib: 2.8.1 - '@aws-sdk/credential-provider-http@3.696.0': - dependencies: - '@aws-sdk/core': 3.696.0 - '@aws-sdk/types': 3.696.0 - '@smithy/fetch-http-handler': 4.1.2 - '@smithy/node-http-handler': 3.3.2 - '@smithy/property-provider': 3.1.11 - '@smithy/protocol-http': 4.1.8 - '@smithy/smithy-client': 3.5.1 - '@smithy/types': 3.7.2 - '@smithy/util-stream': 3.3.2 + '@aws-sdk/credential-provider-http@3.723.0': + dependencies: + '@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/property-provider': 4.0.1 + '@smithy/protocol-http': 5.0.1 + '@smithy/smithy-client': 4.1.0 + '@smithy/types': 4.1.0 + '@smithy/util-stream': 4.0.1 tslib: 2.8.1 - '@aws-sdk/credential-provider-ini@3.699.0(@aws-sdk/client-sso-oidc@3.699.0(@aws-sdk/client-sts@3.699.0))(@aws-sdk/client-sts@3.699.0)': - dependencies: - '@aws-sdk/client-sts': 3.699.0 - '@aws-sdk/core': 3.696.0 - '@aws-sdk/credential-provider-env': 3.696.0 - '@aws-sdk/credential-provider-http': 3.696.0 - '@aws-sdk/credential-provider-process': 3.696.0 - '@aws-sdk/credential-provider-sso': 3.699.0(@aws-sdk/client-sso-oidc@3.699.0(@aws-sdk/client-sts@3.699.0)) - '@aws-sdk/credential-provider-web-identity': 3.696.0(@aws-sdk/client-sts@3.699.0) - '@aws-sdk/types': 3.696.0 - '@smithy/credential-provider-imds': 3.2.8 - '@smithy/property-provider': 3.1.11 - '@smithy/shared-ini-file-loader': 3.1.12 - '@smithy/types': 3.7.2 + '@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)': + dependencies: + '@aws-sdk/client-sts': 3.726.1 + '@aws-sdk/core': 3.723.0 + '@aws-sdk/credential-provider-env': 3.723.0 + '@aws-sdk/credential-provider-http': 3.723.0 + '@aws-sdk/credential-provider-process': 3.723.0 + '@aws-sdk/credential-provider-sso': 3.726.0(@aws-sdk/client-sso-oidc@3.726.0(@aws-sdk/client-sts@3.726.1)) + '@aws-sdk/credential-provider-web-identity': 3.723.0(@aws-sdk/client-sts@3.726.1) + '@aws-sdk/types': 3.723.0 + '@smithy/credential-provider-imds': 4.0.1 + '@smithy/property-provider': 4.0.1 + '@smithy/shared-ini-file-loader': 4.0.1 + '@smithy/types': 4.1.0 tslib: 2.8.1 transitivePeerDependencies: - '@aws-sdk/client-sso-oidc' - aws-crt - '@aws-sdk/credential-provider-node@3.699.0(@aws-sdk/client-sso-oidc@3.699.0(@aws-sdk/client-sts@3.699.0))(@aws-sdk/client-sts@3.699.0)': - dependencies: - '@aws-sdk/credential-provider-env': 3.696.0 - '@aws-sdk/credential-provider-http': 3.696.0 - '@aws-sdk/credential-provider-ini': 3.699.0(@aws-sdk/client-sso-oidc@3.699.0(@aws-sdk/client-sts@3.699.0))(@aws-sdk/client-sts@3.699.0) - '@aws-sdk/credential-provider-process': 3.696.0 - '@aws-sdk/credential-provider-sso': 3.699.0(@aws-sdk/client-sso-oidc@3.699.0(@aws-sdk/client-sts@3.699.0)) - '@aws-sdk/credential-provider-web-identity': 3.696.0(@aws-sdk/client-sts@3.699.0) - '@aws-sdk/types': 3.696.0 - '@smithy/credential-provider-imds': 3.2.8 - '@smithy/property-provider': 3.1.11 - '@smithy/shared-ini-file-loader': 3.1.12 - '@smithy/types': 3.7.2 + '@aws-sdk/credential-provider-node@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)': + dependencies: + '@aws-sdk/credential-provider-env': 3.723.0 + '@aws-sdk/credential-provider-http': 3.723.0 + '@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) + '@aws-sdk/credential-provider-process': 3.723.0 + '@aws-sdk/credential-provider-sso': 3.726.0(@aws-sdk/client-sso-oidc@3.726.0(@aws-sdk/client-sts@3.726.1)) + '@aws-sdk/credential-provider-web-identity': 3.723.0(@aws-sdk/client-sts@3.726.1) + '@aws-sdk/types': 3.723.0 + '@smithy/credential-provider-imds': 4.0.1 + '@smithy/property-provider': 4.0.1 + '@smithy/shared-ini-file-loader': 4.0.1 + '@smithy/types': 4.1.0 tslib: 2.8.1 transitivePeerDependencies: - '@aws-sdk/client-sso-oidc' - '@aws-sdk/client-sts' - aws-crt - '@aws-sdk/credential-provider-process@3.696.0': + '@aws-sdk/credential-provider-process@3.723.0': dependencies: - '@aws-sdk/core': 3.696.0 - '@aws-sdk/types': 3.696.0 - '@smithy/property-provider': 3.1.11 - '@smithy/shared-ini-file-loader': 3.1.12 - '@smithy/types': 3.7.2 + '@aws-sdk/core': 3.723.0 + '@aws-sdk/types': 3.723.0 + '@smithy/property-provider': 4.0.1 + '@smithy/shared-ini-file-loader': 4.0.1 + '@smithy/types': 4.1.0 tslib: 2.8.1 - '@aws-sdk/credential-provider-sso@3.699.0(@aws-sdk/client-sso-oidc@3.699.0(@aws-sdk/client-sts@3.699.0))': + '@aws-sdk/credential-provider-sso@3.726.0(@aws-sdk/client-sso-oidc@3.726.0(@aws-sdk/client-sts@3.726.1))': dependencies: - '@aws-sdk/client-sso': 3.696.0 - '@aws-sdk/core': 3.696.0 - '@aws-sdk/token-providers': 3.699.0(@aws-sdk/client-sso-oidc@3.699.0(@aws-sdk/client-sts@3.699.0)) - '@aws-sdk/types': 3.696.0 - '@smithy/property-provider': 3.1.11 - '@smithy/shared-ini-file-loader': 3.1.12 - '@smithy/types': 3.7.2 + '@aws-sdk/client-sso': 3.726.0 + '@aws-sdk/core': 3.723.0 + '@aws-sdk/token-providers': 3.723.0(@aws-sdk/client-sso-oidc@3.726.0(@aws-sdk/client-sts@3.726.1)) + '@aws-sdk/types': 3.723.0 + '@smithy/property-provider': 4.0.1 + '@smithy/shared-ini-file-loader': 4.0.1 + '@smithy/types': 4.1.0 tslib: 2.8.1 transitivePeerDependencies: - '@aws-sdk/client-sso-oidc' - aws-crt - '@aws-sdk/credential-provider-web-identity@3.696.0(@aws-sdk/client-sts@3.699.0)': + '@aws-sdk/credential-provider-web-identity@3.723.0(@aws-sdk/client-sts@3.726.1)': dependencies: - '@aws-sdk/client-sts': 3.699.0 - '@aws-sdk/core': 3.696.0 - '@aws-sdk/types': 3.696.0 - '@smithy/property-provider': 3.1.11 - '@smithy/types': 3.7.2 + '@aws-sdk/client-sts': 3.726.1 + '@aws-sdk/core': 3.723.0 + '@aws-sdk/types': 3.723.0 + '@smithy/property-provider': 4.0.1 + '@smithy/types': 4.1.0 tslib: 2.8.1 - '@aws-sdk/credential-providers@3.699.0(@aws-sdk/client-sso-oidc@3.699.0(@aws-sdk/client-sts@3.699.0))': - dependencies: - '@aws-sdk/client-cognito-identity': 3.699.0 - '@aws-sdk/client-sso': 3.696.0 - '@aws-sdk/client-sts': 3.699.0 - '@aws-sdk/core': 3.696.0 - '@aws-sdk/credential-provider-cognito-identity': 3.699.0 - '@aws-sdk/credential-provider-env': 3.696.0 - '@aws-sdk/credential-provider-http': 3.696.0 - '@aws-sdk/credential-provider-ini': 3.699.0(@aws-sdk/client-sso-oidc@3.699.0(@aws-sdk/client-sts@3.699.0))(@aws-sdk/client-sts@3.699.0) - '@aws-sdk/credential-provider-node': 3.699.0(@aws-sdk/client-sso-oidc@3.699.0(@aws-sdk/client-sts@3.699.0))(@aws-sdk/client-sts@3.699.0) - '@aws-sdk/credential-provider-process': 3.696.0 - '@aws-sdk/credential-provider-sso': 3.699.0(@aws-sdk/client-sso-oidc@3.699.0(@aws-sdk/client-sts@3.699.0)) - '@aws-sdk/credential-provider-web-identity': 3.696.0(@aws-sdk/client-sts@3.699.0) - '@aws-sdk/types': 3.696.0 - '@smithy/credential-provider-imds': 3.2.8 - '@smithy/property-provider': 3.1.11 - '@smithy/types': 3.7.2 + '@aws-sdk/credential-providers@3.726.1(@aws-sdk/client-sso-oidc@3.726.0(@aws-sdk/client-sts@3.726.1))': + dependencies: + '@aws-sdk/client-cognito-identity': 3.726.1 + '@aws-sdk/client-sso': 3.726.0 + '@aws-sdk/client-sts': 3.726.1 + '@aws-sdk/core': 3.723.0 + '@aws-sdk/credential-provider-cognito-identity': 3.726.1 + '@aws-sdk/credential-provider-env': 3.723.0 + '@aws-sdk/credential-provider-http': 3.723.0 + '@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) + '@aws-sdk/credential-provider-node': 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) + '@aws-sdk/credential-provider-process': 3.723.0 + '@aws-sdk/credential-provider-sso': 3.726.0(@aws-sdk/client-sso-oidc@3.726.0(@aws-sdk/client-sts@3.726.1)) + '@aws-sdk/credential-provider-web-identity': 3.723.0(@aws-sdk/client-sts@3.726.1) + '@aws-sdk/types': 3.723.0 + '@smithy/credential-provider-imds': 4.0.1 + '@smithy/property-provider': 4.0.1 + '@smithy/types': 4.1.0 tslib: 2.8.1 transitivePeerDependencies: - '@aws-sdk/client-sso-oidc' - aws-crt - '@aws-sdk/middleware-bucket-endpoint@3.696.0': + '@aws-sdk/middleware-bucket-endpoint@3.726.0': dependencies: - '@aws-sdk/types': 3.696.0 - '@aws-sdk/util-arn-parser': 3.693.0 - '@smithy/node-config-provider': 3.1.12 - '@smithy/protocol-http': 4.1.8 - '@smithy/types': 3.7.2 - '@smithy/util-config-provider': 3.0.0 + '@aws-sdk/types': 3.723.0 + '@aws-sdk/util-arn-parser': 3.723.0 + '@smithy/node-config-provider': 4.0.1 + '@smithy/protocol-http': 5.0.1 + '@smithy/types': 4.1.0 + '@smithy/util-config-provider': 4.0.0 tslib: 2.8.1 - '@aws-sdk/middleware-expect-continue@3.696.0': + '@aws-sdk/middleware-expect-continue@3.723.0': dependencies: - '@aws-sdk/types': 3.696.0 - '@smithy/protocol-http': 4.1.8 - '@smithy/types': 3.7.2 + '@aws-sdk/types': 3.723.0 + '@smithy/protocol-http': 5.0.1 + '@smithy/types': 4.1.0 tslib: 2.8.1 - '@aws-sdk/middleware-flexible-checksums@3.701.0': + '@aws-sdk/middleware-flexible-checksums@3.723.0': dependencies: '@aws-crypto/crc32': 5.2.0 '@aws-crypto/crc32c': 5.2.0 '@aws-crypto/util': 5.2.0 - '@aws-sdk/core': 3.696.0 - '@aws-sdk/types': 3.696.0 - '@smithy/is-array-buffer': 3.0.0 - '@smithy/node-config-provider': 3.1.12 - '@smithy/protocol-http': 4.1.8 - '@smithy/types': 3.7.2 - '@smithy/util-middleware': 3.0.11 - '@smithy/util-stream': 3.3.2 - '@smithy/util-utf8': 3.0.0 + '@aws-sdk/core': 3.723.0 + '@aws-sdk/types': 3.723.0 + '@smithy/is-array-buffer': 4.0.0 + '@smithy/node-config-provider': 4.0.1 + '@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-utf8': 4.0.0 tslib: 2.8.1 - '@aws-sdk/middleware-host-header@3.696.0': + '@aws-sdk/middleware-host-header@3.723.0': dependencies: - '@aws-sdk/types': 3.696.0 - '@smithy/protocol-http': 4.1.8 - '@smithy/types': 3.7.2 + '@aws-sdk/types': 3.723.0 + '@smithy/protocol-http': 5.0.1 + '@smithy/types': 4.1.0 tslib: 2.8.1 - '@aws-sdk/middleware-location-constraint@3.696.0': + '@aws-sdk/middleware-location-constraint@3.723.0': dependencies: - '@aws-sdk/types': 3.696.0 - '@smithy/types': 3.7.2 + '@aws-sdk/types': 3.723.0 + '@smithy/types': 4.1.0 tslib: 2.8.1 - '@aws-sdk/middleware-logger@3.696.0': + '@aws-sdk/middleware-logger@3.723.0': dependencies: - '@aws-sdk/types': 3.696.0 - '@smithy/types': 3.7.2 + '@aws-sdk/types': 3.723.0 + '@smithy/types': 4.1.0 tslib: 2.8.1 - '@aws-sdk/middleware-recursion-detection@3.696.0': + '@aws-sdk/middleware-recursion-detection@3.723.0': dependencies: - '@aws-sdk/types': 3.696.0 - '@smithy/protocol-http': 4.1.8 - '@smithy/types': 3.7.2 + '@aws-sdk/types': 3.723.0 + '@smithy/protocol-http': 5.0.1 + '@smithy/types': 4.1.0 tslib: 2.8.1 - '@aws-sdk/middleware-sdk-ec2@3.696.0': + '@aws-sdk/middleware-sdk-ec2@3.723.0': dependencies: - '@aws-sdk/types': 3.696.0 - '@aws-sdk/util-format-url': 3.696.0 - '@smithy/middleware-endpoint': 3.2.6 - '@smithy/protocol-http': 4.1.8 - '@smithy/signature-v4': 4.2.4 - '@smithy/smithy-client': 3.5.1 - '@smithy/types': 3.7.2 + '@aws-sdk/types': 3.723.0 + '@aws-sdk/util-format-url': 3.723.0 + '@smithy/middleware-endpoint': 4.0.1 + '@smithy/protocol-http': 5.0.1 + '@smithy/signature-v4': 5.0.1 + '@smithy/smithy-client': 4.1.0 + '@smithy/types': 4.1.0 tslib: 2.8.1 - '@aws-sdk/middleware-sdk-rds@3.696.0': + '@aws-sdk/middleware-sdk-rds@3.723.0': dependencies: - '@aws-sdk/types': 3.696.0 - '@aws-sdk/util-format-url': 3.696.0 - '@smithy/middleware-endpoint': 3.2.6 - '@smithy/protocol-http': 4.1.8 - '@smithy/signature-v4': 4.2.4 - '@smithy/types': 3.7.2 + '@aws-sdk/types': 3.723.0 + '@aws-sdk/util-format-url': 3.723.0 + '@smithy/middleware-endpoint': 4.0.1 + '@smithy/protocol-http': 5.0.1 + '@smithy/signature-v4': 5.0.1 + '@smithy/types': 4.1.0 tslib: 2.8.1 - '@aws-sdk/middleware-sdk-s3@3.696.0': - dependencies: - '@aws-sdk/core': 3.696.0 - '@aws-sdk/types': 3.696.0 - '@aws-sdk/util-arn-parser': 3.693.0 - '@smithy/core': 2.5.5 - '@smithy/node-config-provider': 3.1.12 - '@smithy/protocol-http': 4.1.8 - '@smithy/signature-v4': 4.2.4 - '@smithy/smithy-client': 3.5.1 - '@smithy/types': 3.7.2 - '@smithy/util-config-provider': 3.0.0 - '@smithy/util-middleware': 3.0.11 - '@smithy/util-stream': 3.3.2 - '@smithy/util-utf8': 3.0.0 + '@aws-sdk/middleware-sdk-s3@3.723.0': + dependencies: + '@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/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/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-utf8': 4.0.0 tslib: 2.8.1 - '@aws-sdk/middleware-ssec@3.696.0': + '@aws-sdk/middleware-ssec@3.723.0': dependencies: - '@aws-sdk/types': 3.696.0 - '@smithy/types': 3.7.2 + '@aws-sdk/types': 3.723.0 + '@smithy/types': 4.1.0 tslib: 2.8.1 - '@aws-sdk/middleware-user-agent@3.696.0': + '@aws-sdk/middleware-user-agent@3.726.0': dependencies: - '@aws-sdk/core': 3.696.0 - '@aws-sdk/types': 3.696.0 - '@aws-sdk/util-endpoints': 3.696.0 - '@smithy/core': 2.5.5 - '@smithy/protocol-http': 4.1.8 - '@smithy/types': 3.7.2 + '@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/protocol-http': 5.0.1 + '@smithy/types': 4.1.0 tslib: 2.8.1 - '@aws-sdk/region-config-resolver@3.696.0': + '@aws-sdk/region-config-resolver@3.723.0': dependencies: - '@aws-sdk/types': 3.696.0 - '@smithy/node-config-provider': 3.1.12 - '@smithy/types': 3.7.2 - '@smithy/util-config-provider': 3.0.0 - '@smithy/util-middleware': 3.0.11 + '@aws-sdk/types': 3.723.0 + '@smithy/node-config-provider': 4.0.1 + '@smithy/types': 4.1.0 + '@smithy/util-config-provider': 4.0.0 + '@smithy/util-middleware': 4.0.1 tslib: 2.8.1 - '@aws-sdk/signature-v4-multi-region@3.696.0': + '@aws-sdk/signature-v4-multi-region@3.723.0': dependencies: - '@aws-sdk/middleware-sdk-s3': 3.696.0 - '@aws-sdk/types': 3.696.0 - '@smithy/protocol-http': 4.1.8 - '@smithy/signature-v4': 4.2.4 - '@smithy/types': 3.7.2 + '@aws-sdk/middleware-sdk-s3': 3.723.0 + '@aws-sdk/types': 3.723.0 + '@smithy/protocol-http': 5.0.1 + '@smithy/signature-v4': 5.0.1 + '@smithy/types': 4.1.0 tslib: 2.8.1 - '@aws-sdk/token-providers@3.699.0(@aws-sdk/client-sso-oidc@3.699.0(@aws-sdk/client-sts@3.699.0))': + '@aws-sdk/token-providers@3.723.0(@aws-sdk/client-sso-oidc@3.726.0(@aws-sdk/client-sts@3.726.1))': dependencies: - '@aws-sdk/client-sso-oidc': 3.699.0(@aws-sdk/client-sts@3.699.0) - '@aws-sdk/types': 3.696.0 - '@smithy/property-provider': 3.1.11 - '@smithy/shared-ini-file-loader': 3.1.12 - '@smithy/types': 3.7.2 + '@aws-sdk/client-sso-oidc': 3.726.0(@aws-sdk/client-sts@3.726.1) + '@aws-sdk/types': 3.723.0 + '@smithy/property-provider': 4.0.1 + '@smithy/shared-ini-file-loader': 4.0.1 + '@smithy/types': 4.1.0 tslib: 2.8.1 - '@aws-sdk/types@3.696.0': + '@aws-sdk/types@3.723.0': dependencies: - '@smithy/types': 3.7.2 + '@smithy/types': 4.1.0 tslib: 2.8.1 - '@aws-sdk/util-arn-parser@3.693.0': + '@aws-sdk/util-arn-parser@3.723.0': dependencies: tslib: 2.8.1 - '@aws-sdk/util-endpoints@3.696.0': + '@aws-sdk/util-endpoints@3.726.0': dependencies: - '@aws-sdk/types': 3.696.0 - '@smithy/types': 3.7.2 - '@smithy/util-endpoints': 2.1.7 + '@aws-sdk/types': 3.723.0 + '@smithy/types': 4.1.0 + '@smithy/util-endpoints': 3.0.1 tslib: 2.8.1 - '@aws-sdk/util-format-url@3.696.0': + '@aws-sdk/util-format-url@3.723.0': dependencies: - '@aws-sdk/types': 3.696.0 - '@smithy/querystring-builder': 3.0.11 - '@smithy/types': 3.7.2 + '@aws-sdk/types': 3.723.0 + '@smithy/querystring-builder': 4.0.1 + '@smithy/types': 4.1.0 tslib: 2.8.1 - '@aws-sdk/util-locate-window@3.693.0': + '@aws-sdk/util-locate-window@3.723.0': dependencies: tslib: 2.8.1 - '@aws-sdk/util-user-agent-browser@3.696.0': + '@aws-sdk/util-user-agent-browser@3.723.0': dependencies: - '@aws-sdk/types': 3.696.0 - '@smithy/types': 3.7.2 + '@aws-sdk/types': 3.723.0 + '@smithy/types': 4.1.0 bowser: 2.11.0 tslib: 2.8.1 - '@aws-sdk/util-user-agent-node@3.696.0': + '@aws-sdk/util-user-agent-node@3.726.0': dependencies: - '@aws-sdk/middleware-user-agent': 3.696.0 - '@aws-sdk/types': 3.696.0 - '@smithy/node-config-provider': 3.1.12 - '@smithy/types': 3.7.2 + '@aws-sdk/middleware-user-agent': 3.726.0 + '@aws-sdk/types': 3.723.0 + '@smithy/node-config-provider': 4.0.1 + '@smithy/types': 4.1.0 tslib: 2.8.1 - '@aws-sdk/xml-builder@3.696.0': + '@aws-sdk/xml-builder@3.723.0': dependencies: - '@smithy/types': 3.7.2 + '@smithy/types': 4.1.0 tslib: 2.8.1 '@babel/code-frame@7.26.2': @@ -7094,20 +7237,20 @@ snapshots: js-tokens: 4.0.0 picocolors: 1.1.1 - '@babel/compat-data@7.26.3': {} + '@babel/compat-data@7.26.5': {} '@babel/core@7.26.0': dependencies: '@ampproject/remapping': 2.3.0 '@babel/code-frame': 7.26.2 - '@babel/generator': 7.26.3 - '@babel/helper-compilation-targets': 7.25.9 + '@babel/generator': 7.26.5 + '@babel/helper-compilation-targets': 7.26.5 '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.0) '@babel/helpers': 7.26.0 - '@babel/parser': 7.26.3 + '@babel/parser': 7.26.5 '@babel/template': 7.25.9 - '@babel/traverse': 7.26.4 - '@babel/types': 7.26.3 + '@babel/traverse': 7.26.5 + '@babel/types': 7.26.5 convert-source-map: 2.0.0 debug: 4.4.0 gensync: 1.0.0-beta.2 @@ -7116,26 +7259,26 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/generator@7.26.3': + '@babel/generator@7.26.5': dependencies: - '@babel/parser': 7.26.3 - '@babel/types': 7.26.3 + '@babel/parser': 7.26.5 + '@babel/types': 7.26.5 '@jridgewell/gen-mapping': 0.3.8 '@jridgewell/trace-mapping': 0.3.25 jsesc: 3.1.0 - '@babel/helper-compilation-targets@7.25.9': + '@babel/helper-compilation-targets@7.26.5': dependencies: - '@babel/compat-data': 7.26.3 + '@babel/compat-data': 7.26.5 '@babel/helper-validator-option': 7.25.9 - browserslist: 4.24.3 + browserslist: 4.24.4 lru-cache: 5.1.1 semver: 6.3.1 '@babel/helper-module-imports@7.25.9': dependencies: - '@babel/traverse': 7.26.4 - '@babel/types': 7.26.3 + '@babel/traverse': 7.26.5 + '@babel/types': 7.26.5 transitivePeerDependencies: - supports-color @@ -7144,11 +7287,11 @@ snapshots: '@babel/core': 7.26.0 '@babel/helper-module-imports': 7.25.9 '@babel/helper-validator-identifier': 7.25.9 - '@babel/traverse': 7.26.4 + '@babel/traverse': 7.26.5 transitivePeerDependencies: - supports-color - '@babel/helper-plugin-utils@7.25.9': {} + '@babel/helper-plugin-utils@7.26.5': {} '@babel/helper-string-parser@7.25.9': {} @@ -7159,121 +7302,121 @@ snapshots: '@babel/helpers@7.26.0': dependencies: '@babel/template': 7.25.9 - '@babel/types': 7.26.3 + '@babel/types': 7.26.5 - '@babel/parser@7.26.3': + '@babel/parser@7.26.5': dependencies: - '@babel/types': 7.26.3 + '@babel/types': 7.26.5 '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-plugin-utils': 7.26.5 '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-plugin-utils': 7.26.5 '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-plugin-utils': 7.26.5 '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-plugin-utils': 7.26.5 '@babel/plugin-syntax-import-attributes@7.26.0(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-plugin-utils': 7.26.5 '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-plugin-utils': 7.26.5 '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-plugin-utils': 7.26.5 '@babel/plugin-syntax-jsx@7.25.9(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-plugin-utils': 7.26.5 '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-plugin-utils': 7.26.5 '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-plugin-utils': 7.26.5 '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-plugin-utils': 7.26.5 '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-plugin-utils': 7.26.5 '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-plugin-utils': 7.26.5 '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-plugin-utils': 7.26.5 '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-plugin-utils': 7.26.5 '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-plugin-utils': 7.26.5 '@babel/plugin-syntax-typescript@7.25.9(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-plugin-utils': 7.26.5 '@babel/runtime-corejs3@7.26.0': dependencies: - core-js-pure: 3.39.0 + core-js-pure: 3.40.0 regenerator-runtime: 0.14.1 '@babel/template@7.25.9': dependencies: '@babel/code-frame': 7.26.2 - '@babel/parser': 7.26.3 - '@babel/types': 7.26.3 + '@babel/parser': 7.26.5 + '@babel/types': 7.26.5 - '@babel/traverse@7.26.4': + '@babel/traverse@7.26.5': dependencies: '@babel/code-frame': 7.26.2 - '@babel/generator': 7.26.3 - '@babel/parser': 7.26.3 + '@babel/generator': 7.26.5 + '@babel/parser': 7.26.5 '@babel/template': 7.25.9 - '@babel/types': 7.26.3 + '@babel/types': 7.26.5 debug: 4.4.0 globals: 11.12.0 transitivePeerDependencies: - supports-color - '@babel/types@7.26.3': + '@babel/types@7.26.5': dependencies: '@babel/helper-string-parser': 7.25.9 '@babel/helper-validator-identifier': 7.25.9 @@ -7282,7 +7425,7 @@ snapshots: '@breejs/later@4.2.0': {} - '@cdktf/hcl2json@0.20.10': + '@cdktf/hcl2json@0.20.11': dependencies: fs-extra: 11.2.0 @@ -7358,27 +7501,27 @@ snapshots: '@jest/console@29.7.0': dependencies: '@jest/types': 29.6.3 - '@types/node': 20.17.10 + '@types/node': 22.10.5 chalk: 4.1.2 jest-message-util: 29.7.0 jest-util: 29.7.0 slash: 3.0.0 - '@jest/core@29.7.0(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@20.17.10)(typescript@5.7.2))': + '@jest/core@29.7.0(ts-node@10.9.2(@swc/core@1.10.7)(@types/node@22.10.5)(typescript@5.7.3))': dependencies: '@jest/console': 29.7.0 '@jest/reporters': 29.7.0 '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.17.10 + '@types/node': 22.10.5 ansi-escapes: 4.3.2 chalk: 4.1.2 ci-info: 3.9.0 exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@20.17.10)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@20.17.10)(typescript@5.7.2)) + jest-config: 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)) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -7403,7 +7546,7 @@ snapshots: dependencies: '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.17.10 + '@types/node': 22.10.5 jest-mock: 29.7.0 '@jest/expect-utils@29.4.1': @@ -7425,7 +7568,7 @@ snapshots: dependencies: '@jest/types': 29.6.3 '@sinonjs/fake-timers': 10.3.0 - '@types/node': 20.17.10 + '@types/node': 22.10.5 jest-message-util: 29.7.0 jest-mock: 29.7.0 jest-util: 29.7.0 @@ -7447,7 +7590,7 @@ snapshots: '@jest/transform': 29.7.0 '@jest/types': 29.6.3 '@jridgewell/trace-mapping': 0.3.25 - '@types/node': 20.17.10 + '@types/node': 22.10.5 chalk: 4.1.2 collect-v8-coverage: 1.0.2 exit: 0.1.2 @@ -7517,7 +7660,7 @@ snapshots: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 20.17.10 + '@types/node': 22.10.5 '@types/yargs': 17.0.33 chalk: 4.1.2 @@ -7579,7 +7722,7 @@ snapshots: '@nodelib/fs.walk@1.2.8': dependencies: '@nodelib/fs.scandir': 2.1.5 - fastq: 1.17.1 + fastq: 1.18.0 '@nolyfill/is-core-module@1.0.39': {} @@ -7613,53 +7756,53 @@ snapshots: '@octokit/graphql': 7.1.0 '@octokit/request': 8.4.0 '@octokit/request-error': 5.1.0 - '@octokit/types': 13.6.2 + '@octokit/types': 13.7.0 before-after-hook: 2.2.3 universal-user-agent: 6.0.1 - '@octokit/core@6.1.2': + '@octokit/core@6.1.3': dependencies: '@octokit/auth-token': 5.1.1 - '@octokit/graphql': 8.1.1 - '@octokit/request': 9.1.3 - '@octokit/request-error': 6.1.5 - '@octokit/types': 13.6.2 + '@octokit/graphql': 8.1.2 + '@octokit/request': 9.1.4 + '@octokit/request-error': 6.1.6 + '@octokit/types': 13.7.0 before-after-hook: 3.0.2 universal-user-agent: 7.0.2 - '@octokit/endpoint@10.1.1': + '@octokit/endpoint@10.1.2': dependencies: - '@octokit/types': 13.6.2 + '@octokit/types': 13.7.0 universal-user-agent: 7.0.2 '@octokit/endpoint@9.0.5': dependencies: - '@octokit/types': 13.6.2 + '@octokit/types': 13.7.0 universal-user-agent: 6.0.1 '@octokit/graphql@7.1.0': dependencies: '@octokit/request': 8.4.0 - '@octokit/types': 13.6.2 + '@octokit/types': 13.7.0 universal-user-agent: 6.0.1 - '@octokit/graphql@8.1.1': + '@octokit/graphql@8.1.2': dependencies: - '@octokit/request': 9.1.3 - '@octokit/types': 13.6.2 + '@octokit/request': 9.1.4 + '@octokit/types': 13.7.0 universal-user-agent: 7.0.2 - '@octokit/openapi-types@22.2.0': {} + '@octokit/openapi-types@23.0.1': {} '@octokit/plugin-paginate-rest@11.3.1(@octokit/core@5.2.0)': dependencies: '@octokit/core': 5.2.0 - '@octokit/types': 13.6.2 + '@octokit/types': 13.7.0 - '@octokit/plugin-paginate-rest@11.3.6(@octokit/core@6.1.2)': + '@octokit/plugin-paginate-rest@11.4.0(@octokit/core@6.1.3)': dependencies: - '@octokit/core': 6.1.2 - '@octokit/types': 13.6.2 + '@octokit/core': 6.1.3 + '@octokit/types': 13.7.0 '@octokit/plugin-request-log@4.0.1(@octokit/core@5.2.0)': dependencies: @@ -7668,43 +7811,44 @@ snapshots: '@octokit/plugin-rest-endpoint-methods@13.2.2(@octokit/core@5.2.0)': dependencies: '@octokit/core': 5.2.0 - '@octokit/types': 13.6.2 + '@octokit/types': 13.7.0 - '@octokit/plugin-retry@7.1.2(@octokit/core@6.1.2)': + '@octokit/plugin-retry@7.1.3(@octokit/core@6.1.3)': dependencies: - '@octokit/core': 6.1.2 - '@octokit/request-error': 6.1.5 - '@octokit/types': 13.6.2 + '@octokit/core': 6.1.3 + '@octokit/request-error': 6.1.6 + '@octokit/types': 13.7.0 bottleneck: 2.19.5 - '@octokit/plugin-throttling@9.3.2(@octokit/core@6.1.2)': + '@octokit/plugin-throttling@9.4.0(@octokit/core@6.1.3)': dependencies: - '@octokit/core': 6.1.2 - '@octokit/types': 13.6.2 + '@octokit/core': 6.1.3 + '@octokit/types': 13.7.0 bottleneck: 2.19.5 '@octokit/request-error@5.1.0': dependencies: - '@octokit/types': 13.6.2 + '@octokit/types': 13.7.0 deprecation: 2.3.1 once: 1.4.0 - '@octokit/request-error@6.1.5': + '@octokit/request-error@6.1.6': dependencies: - '@octokit/types': 13.6.2 + '@octokit/types': 13.7.0 '@octokit/request@8.4.0': dependencies: '@octokit/endpoint': 9.0.5 '@octokit/request-error': 5.1.0 - '@octokit/types': 13.6.2 + '@octokit/types': 13.7.0 universal-user-agent: 6.0.1 - '@octokit/request@9.1.3': + '@octokit/request@9.1.4': dependencies: - '@octokit/endpoint': 10.1.1 - '@octokit/request-error': 6.1.5 - '@octokit/types': 13.6.2 + '@octokit/endpoint': 10.1.2 + '@octokit/request-error': 6.1.6 + '@octokit/types': 13.7.0 + fast-content-type-parse: 2.0.1 universal-user-agent: 7.0.2 '@octokit/rest@20.1.1': @@ -7714,15 +7858,15 @@ snapshots: '@octokit/plugin-request-log': 4.0.1(@octokit/core@5.2.0) '@octokit/plugin-rest-endpoint-methods': 13.2.2(@octokit/core@5.2.0) - '@octokit/types@13.6.2': + '@octokit/types@13.7.0': dependencies: - '@octokit/openapi-types': 22.2.0 + '@octokit/openapi-types': 23.0.1 '@one-ini/wasm@0.1.1': {} - '@openpgp/web-stream-tools@0.1.3(typescript@5.7.2)': + '@openpgp/web-stream-tools@0.1.3(typescript@5.7.3)': optionalDependencies: - typescript: 5.7.2 + typescript: 5.7.3 '@opentelemetry/api-logs@0.57.0': dependencies: @@ -7979,14 +8123,14 @@ snapshots: triplesec: 4.0.3 tweetnacl: 1.0.3 - '@renovatebot/osv-offline-db@1.6.0': + '@renovatebot/osv-offline-db@1.7.0': dependencies: '@seald-io/nedb': 4.0.4 - '@renovatebot/osv-offline@1.5.10(encoding@0.1.13)': + '@renovatebot/osv-offline@1.5.11(encoding@0.1.13)': dependencies: '@octokit/rest': 20.1.1 - '@renovatebot/osv-offline-db': 1.6.0 + '@renovatebot/osv-offline-db': 1.7.0 adm-zip: 0.5.16 fs-extra: 11.2.0 got: 11.8.6 @@ -8011,17 +8155,17 @@ snapshots: '@sec-ant/readable-stream@0.4.1': {} - '@semantic-release/commit-analyzer@13.0.0(semantic-release@24.2.0(typescript@5.7.2))': + '@semantic-release/commit-analyzer@13.0.1(semantic-release@24.2.1(typescript@5.7.3))': dependencies: conventional-changelog-angular: 8.0.0 conventional-changelog-writer: 8.0.0 conventional-commits-filter: 5.0.0 conventional-commits-parser: 6.0.0 debug: 4.4.0 - import-from-esm: 1.3.4 + import-from-esm: 2.0.0 lodash-es: 4.17.21 micromatch: 4.0.8 - semantic-release: 24.2.0(typescript@5.7.2) + semantic-release: 24.2.1(typescript@5.7.3) transitivePeerDependencies: - supports-color @@ -8029,7 +8173,7 @@ snapshots: '@semantic-release/error@4.0.0': {} - '@semantic-release/exec@6.0.3(semantic-release@24.2.0(typescript@5.7.2))': + '@semantic-release/exec@6.0.3(semantic-release@24.2.1(typescript@5.7.3))': dependencies: '@semantic-release/error': 3.0.0 aggregate-error: 3.1.0 @@ -8037,16 +8181,16 @@ snapshots: execa: 5.1.1 lodash: 4.17.21 parse-json: 5.2.0 - semantic-release: 24.2.0(typescript@5.7.2) + semantic-release: 24.2.1(typescript@5.7.3) transitivePeerDependencies: - supports-color - '@semantic-release/github@11.0.1(semantic-release@24.2.0(typescript@5.7.2))': + '@semantic-release/github@11.0.1(semantic-release@24.2.1(typescript@5.7.3))': dependencies: - '@octokit/core': 6.1.2 - '@octokit/plugin-paginate-rest': 11.3.6(@octokit/core@6.1.2) - '@octokit/plugin-retry': 7.1.2(@octokit/core@6.1.2) - '@octokit/plugin-throttling': 9.3.2(@octokit/core@6.1.2) + '@octokit/core': 6.1.3 + '@octokit/plugin-paginate-rest': 11.4.0(@octokit/core@6.1.3) + '@octokit/plugin-retry': 7.1.3(@octokit/core@6.1.3) + '@octokit/plugin-throttling': 9.4.0(@octokit/core@6.1.3) '@semantic-release/error': 4.0.0 aggregate-error: 5.0.0 debug: 4.4.0 @@ -8058,12 +8202,12 @@ snapshots: lodash-es: 4.17.21 mime: 4.0.6 p-filter: 4.1.0 - semantic-release: 24.2.0(typescript@5.7.2) + semantic-release: 24.2.1(typescript@5.7.3) url-join: 5.0.0 transitivePeerDependencies: - supports-color - '@semantic-release/npm@12.0.1(semantic-release@24.2.0(typescript@5.7.2))': + '@semantic-release/npm@12.0.1(semantic-release@24.2.1(typescript@5.7.3))': dependencies: '@semantic-release/error': 4.0.0 aggregate-error: 5.0.0 @@ -8076,11 +8220,11 @@ snapshots: rc: 1.2.8 read-pkg: 9.0.1 registry-auth-token: 5.0.3 - semantic-release: 24.2.0(typescript@5.7.2) + semantic-release: 24.2.1(typescript@5.7.3) semver: 7.6.3 tempy: 3.1.0 - '@semantic-release/release-notes-generator@14.0.2(semantic-release@24.2.0(typescript@5.7.2))': + '@semantic-release/release-notes-generator@14.0.3(semantic-release@24.2.1(typescript@5.7.3))': dependencies: conventional-changelog-angular: 8.0.0 conventional-changelog-writer: 8.0.0 @@ -8088,11 +8232,11 @@ snapshots: conventional-commits-parser: 6.0.0 debug: 4.4.0 get-stream: 7.0.1 - import-from-esm: 1.3.4 + import-from-esm: 2.0.0 into-stream: 7.0.0 lodash-es: 4.17.21 read-package-up: 11.0.0 - semantic-release: 24.2.0(typescript@5.7.2) + semantic-release: 24.2.1(typescript@5.7.3) transitivePeerDependencies: - supports-color @@ -8128,250 +8272,250 @@ snapshots: '@sinonjs/text-encoding@0.7.3': {} - '@smithy/abort-controller@3.1.9': + '@smithy/abort-controller@4.0.1': dependencies: - '@smithy/types': 3.7.2 + '@smithy/types': 4.1.0 tslib: 2.8.1 - '@smithy/chunked-blob-reader-native@3.0.1': + '@smithy/chunked-blob-reader-native@4.0.0': dependencies: - '@smithy/util-base64': 3.0.0 + '@smithy/util-base64': 4.0.0 tslib: 2.8.1 - '@smithy/chunked-blob-reader@4.0.0': + '@smithy/chunked-blob-reader@5.0.0': dependencies: tslib: 2.8.1 - '@smithy/config-resolver@3.0.13': + '@smithy/config-resolver@4.0.1': dependencies: - '@smithy/node-config-provider': 3.1.12 - '@smithy/types': 3.7.2 - '@smithy/util-config-provider': 3.0.0 - '@smithy/util-middleware': 3.0.11 + '@smithy/node-config-provider': 4.0.1 + '@smithy/types': 4.1.0 + '@smithy/util-config-provider': 4.0.0 + '@smithy/util-middleware': 4.0.1 tslib: 2.8.1 - '@smithy/core@2.5.5': + '@smithy/core@3.1.0': dependencies: - '@smithy/middleware-serde': 3.0.11 - '@smithy/protocol-http': 4.1.8 - '@smithy/types': 3.7.2 - '@smithy/util-body-length-browser': 3.0.0 - '@smithy/util-middleware': 3.0.11 - '@smithy/util-stream': 3.3.2 - '@smithy/util-utf8': 3.0.0 + '@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-utf8': 4.0.0 tslib: 2.8.1 - '@smithy/credential-provider-imds@3.2.8': + '@smithy/credential-provider-imds@4.0.1': dependencies: - '@smithy/node-config-provider': 3.1.12 - '@smithy/property-provider': 3.1.11 - '@smithy/types': 3.7.2 - '@smithy/url-parser': 3.0.11 + '@smithy/node-config-provider': 4.0.1 + '@smithy/property-provider': 4.0.1 + '@smithy/types': 4.1.0 + '@smithy/url-parser': 4.0.1 tslib: 2.8.1 - '@smithy/eventstream-codec@3.1.10': + '@smithy/eventstream-codec@4.0.1': dependencies: '@aws-crypto/crc32': 5.2.0 - '@smithy/types': 3.7.2 - '@smithy/util-hex-encoding': 3.0.0 + '@smithy/types': 4.1.0 + '@smithy/util-hex-encoding': 4.0.0 tslib: 2.8.1 - '@smithy/eventstream-serde-browser@3.0.14': + '@smithy/eventstream-serde-browser@4.0.1': dependencies: - '@smithy/eventstream-serde-universal': 3.0.13 - '@smithy/types': 3.7.2 + '@smithy/eventstream-serde-universal': 4.0.1 + '@smithy/types': 4.1.0 tslib: 2.8.1 - '@smithy/eventstream-serde-config-resolver@3.0.11': + '@smithy/eventstream-serde-config-resolver@4.0.1': dependencies: - '@smithy/types': 3.7.2 + '@smithy/types': 4.1.0 tslib: 2.8.1 - '@smithy/eventstream-serde-node@3.0.13': + '@smithy/eventstream-serde-node@4.0.1': dependencies: - '@smithy/eventstream-serde-universal': 3.0.13 - '@smithy/types': 3.7.2 + '@smithy/eventstream-serde-universal': 4.0.1 + '@smithy/types': 4.1.0 tslib: 2.8.1 - '@smithy/eventstream-serde-universal@3.0.13': + '@smithy/eventstream-serde-universal@4.0.1': dependencies: - '@smithy/eventstream-codec': 3.1.10 - '@smithy/types': 3.7.2 + '@smithy/eventstream-codec': 4.0.1 + '@smithy/types': 4.1.0 tslib: 2.8.1 - '@smithy/fetch-http-handler@4.1.2': + '@smithy/fetch-http-handler@5.0.1': dependencies: - '@smithy/protocol-http': 4.1.8 - '@smithy/querystring-builder': 3.0.11 - '@smithy/types': 3.7.2 - '@smithy/util-base64': 3.0.0 + '@smithy/protocol-http': 5.0.1 + '@smithy/querystring-builder': 4.0.1 + '@smithy/types': 4.1.0 + '@smithy/util-base64': 4.0.0 tslib: 2.8.1 - '@smithy/hash-blob-browser@3.1.10': + '@smithy/hash-blob-browser@4.0.1': dependencies: - '@smithy/chunked-blob-reader': 4.0.0 - '@smithy/chunked-blob-reader-native': 3.0.1 - '@smithy/types': 3.7.2 + '@smithy/chunked-blob-reader': 5.0.0 + '@smithy/chunked-blob-reader-native': 4.0.0 + '@smithy/types': 4.1.0 tslib: 2.8.1 - '@smithy/hash-node@3.0.11': + '@smithy/hash-node@4.0.1': dependencies: - '@smithy/types': 3.7.2 - '@smithy/util-buffer-from': 3.0.0 - '@smithy/util-utf8': 3.0.0 + '@smithy/types': 4.1.0 + '@smithy/util-buffer-from': 4.0.0 + '@smithy/util-utf8': 4.0.0 tslib: 2.8.1 - '@smithy/hash-stream-node@3.1.10': + '@smithy/hash-stream-node@4.0.1': dependencies: - '@smithy/types': 3.7.2 - '@smithy/util-utf8': 3.0.0 + '@smithy/types': 4.1.0 + '@smithy/util-utf8': 4.0.0 tslib: 2.8.1 - '@smithy/invalid-dependency@3.0.11': + '@smithy/invalid-dependency@4.0.1': dependencies: - '@smithy/types': 3.7.2 + '@smithy/types': 4.1.0 tslib: 2.8.1 '@smithy/is-array-buffer@2.2.0': dependencies: tslib: 2.8.1 - '@smithy/is-array-buffer@3.0.0': + '@smithy/is-array-buffer@4.0.0': dependencies: tslib: 2.8.1 - '@smithy/md5-js@3.0.11': + '@smithy/md5-js@4.0.1': dependencies: - '@smithy/types': 3.7.2 - '@smithy/util-utf8': 3.0.0 + '@smithy/types': 4.1.0 + '@smithy/util-utf8': 4.0.0 tslib: 2.8.1 - '@smithy/middleware-content-length@3.0.13': + '@smithy/middleware-content-length@4.0.1': dependencies: - '@smithy/protocol-http': 4.1.8 - '@smithy/types': 3.7.2 + '@smithy/protocol-http': 5.0.1 + '@smithy/types': 4.1.0 tslib: 2.8.1 - '@smithy/middleware-endpoint@3.2.6': + '@smithy/middleware-endpoint@4.0.1': dependencies: - '@smithy/core': 2.5.5 - '@smithy/middleware-serde': 3.0.11 - '@smithy/node-config-provider': 3.1.12 - '@smithy/shared-ini-file-loader': 3.1.12 - '@smithy/types': 3.7.2 - '@smithy/url-parser': 3.0.11 - '@smithy/util-middleware': 3.0.11 + '@smithy/core': 3.1.0 + '@smithy/middleware-serde': 4.0.1 + '@smithy/node-config-provider': 4.0.1 + '@smithy/shared-ini-file-loader': 4.0.1 + '@smithy/types': 4.1.0 + '@smithy/url-parser': 4.0.1 + '@smithy/util-middleware': 4.0.1 tslib: 2.8.1 - '@smithy/middleware-retry@3.0.31': + '@smithy/middleware-retry@4.0.1': dependencies: - '@smithy/node-config-provider': 3.1.12 - '@smithy/protocol-http': 4.1.8 - '@smithy/service-error-classification': 3.0.11 - '@smithy/smithy-client': 3.5.1 - '@smithy/types': 3.7.2 - '@smithy/util-middleware': 3.0.11 - '@smithy/util-retry': 3.0.11 + '@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/types': 4.1.0 + '@smithy/util-middleware': 4.0.1 + '@smithy/util-retry': 4.0.1 tslib: 2.8.1 uuid: 9.0.1 - '@smithy/middleware-serde@3.0.11': + '@smithy/middleware-serde@4.0.1': dependencies: - '@smithy/types': 3.7.2 + '@smithy/types': 4.1.0 tslib: 2.8.1 - '@smithy/middleware-stack@3.0.11': + '@smithy/middleware-stack@4.0.1': dependencies: - '@smithy/types': 3.7.2 + '@smithy/types': 4.1.0 tslib: 2.8.1 - '@smithy/node-config-provider@3.1.12': + '@smithy/node-config-provider@4.0.1': dependencies: - '@smithy/property-provider': 3.1.11 - '@smithy/shared-ini-file-loader': 3.1.12 - '@smithy/types': 3.7.2 + '@smithy/property-provider': 4.0.1 + '@smithy/shared-ini-file-loader': 4.0.1 + '@smithy/types': 4.1.0 tslib: 2.8.1 - '@smithy/node-http-handler@3.3.2': + '@smithy/node-http-handler@4.0.1': dependencies: - '@smithy/abort-controller': 3.1.9 - '@smithy/protocol-http': 4.1.8 - '@smithy/querystring-builder': 3.0.11 - '@smithy/types': 3.7.2 + '@smithy/abort-controller': 4.0.1 + '@smithy/protocol-http': 5.0.1 + '@smithy/querystring-builder': 4.0.1 + '@smithy/types': 4.1.0 tslib: 2.8.1 - '@smithy/property-provider@3.1.11': + '@smithy/property-provider@4.0.1': dependencies: - '@smithy/types': 3.7.2 + '@smithy/types': 4.1.0 tslib: 2.8.1 - '@smithy/protocol-http@4.1.8': + '@smithy/protocol-http@5.0.1': dependencies: - '@smithy/types': 3.7.2 + '@smithy/types': 4.1.0 tslib: 2.8.1 - '@smithy/querystring-builder@3.0.11': + '@smithy/querystring-builder@4.0.1': dependencies: - '@smithy/types': 3.7.2 - '@smithy/util-uri-escape': 3.0.0 + '@smithy/types': 4.1.0 + '@smithy/util-uri-escape': 4.0.0 tslib: 2.8.1 - '@smithy/querystring-parser@3.0.11': + '@smithy/querystring-parser@4.0.1': dependencies: - '@smithy/types': 3.7.2 + '@smithy/types': 4.1.0 tslib: 2.8.1 - '@smithy/service-error-classification@3.0.11': + '@smithy/service-error-classification@4.0.1': dependencies: - '@smithy/types': 3.7.2 + '@smithy/types': 4.1.0 - '@smithy/shared-ini-file-loader@3.1.12': + '@smithy/shared-ini-file-loader@4.0.1': dependencies: - '@smithy/types': 3.7.2 + '@smithy/types': 4.1.0 tslib: 2.8.1 - '@smithy/signature-v4@4.2.4': + '@smithy/signature-v4@5.0.1': dependencies: - '@smithy/is-array-buffer': 3.0.0 - '@smithy/protocol-http': 4.1.8 - '@smithy/types': 3.7.2 - '@smithy/util-hex-encoding': 3.0.0 - '@smithy/util-middleware': 3.0.11 - '@smithy/util-uri-escape': 3.0.0 - '@smithy/util-utf8': 3.0.0 + '@smithy/is-array-buffer': 4.0.0 + '@smithy/protocol-http': 5.0.1 + '@smithy/types': 4.1.0 + '@smithy/util-hex-encoding': 4.0.0 + '@smithy/util-middleware': 4.0.1 + '@smithy/util-uri-escape': 4.0.0 + '@smithy/util-utf8': 4.0.0 tslib: 2.8.1 - '@smithy/smithy-client@3.5.1': + '@smithy/smithy-client@4.1.0': dependencies: - '@smithy/core': 2.5.5 - '@smithy/middleware-endpoint': 3.2.6 - '@smithy/middleware-stack': 3.0.11 - '@smithy/protocol-http': 4.1.8 - '@smithy/types': 3.7.2 - '@smithy/util-stream': 3.3.2 + '@smithy/core': 3.1.0 + '@smithy/middleware-endpoint': 4.0.1 + '@smithy/middleware-stack': 4.0.1 + '@smithy/protocol-http': 5.0.1 + '@smithy/types': 4.1.0 + '@smithy/util-stream': 4.0.1 tslib: 2.8.1 - '@smithy/types@3.7.2': + '@smithy/types@4.1.0': dependencies: tslib: 2.8.1 - '@smithy/url-parser@3.0.11': + '@smithy/url-parser@4.0.1': dependencies: - '@smithy/querystring-parser': 3.0.11 - '@smithy/types': 3.7.2 + '@smithy/querystring-parser': 4.0.1 + '@smithy/types': 4.1.0 tslib: 2.8.1 - '@smithy/util-base64@3.0.0': + '@smithy/util-base64@4.0.0': dependencies: - '@smithy/util-buffer-from': 3.0.0 - '@smithy/util-utf8': 3.0.0 + '@smithy/util-buffer-from': 4.0.0 + '@smithy/util-utf8': 4.0.0 tslib: 2.8.1 - '@smithy/util-body-length-browser@3.0.0': + '@smithy/util-body-length-browser@4.0.0': dependencies: tslib: 2.8.1 - '@smithy/util-body-length-node@3.0.0': + '@smithy/util-body-length-node@4.0.0': dependencies: tslib: 2.8.1 @@ -8380,66 +8524,66 @@ snapshots: '@smithy/is-array-buffer': 2.2.0 tslib: 2.8.1 - '@smithy/util-buffer-from@3.0.0': + '@smithy/util-buffer-from@4.0.0': dependencies: - '@smithy/is-array-buffer': 3.0.0 + '@smithy/is-array-buffer': 4.0.0 tslib: 2.8.1 - '@smithy/util-config-provider@3.0.0': + '@smithy/util-config-provider@4.0.0': dependencies: tslib: 2.8.1 - '@smithy/util-defaults-mode-browser@3.0.31': + '@smithy/util-defaults-mode-browser@4.0.1': dependencies: - '@smithy/property-provider': 3.1.11 - '@smithy/smithy-client': 3.5.1 - '@smithy/types': 3.7.2 + '@smithy/property-provider': 4.0.1 + '@smithy/smithy-client': 4.1.0 + '@smithy/types': 4.1.0 bowser: 2.11.0 tslib: 2.8.1 - '@smithy/util-defaults-mode-node@3.0.31': + '@smithy/util-defaults-mode-node@4.0.1': dependencies: - '@smithy/config-resolver': 3.0.13 - '@smithy/credential-provider-imds': 3.2.8 - '@smithy/node-config-provider': 3.1.12 - '@smithy/property-provider': 3.1.11 - '@smithy/smithy-client': 3.5.1 - '@smithy/types': 3.7.2 + '@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/types': 4.1.0 tslib: 2.8.1 - '@smithy/util-endpoints@2.1.7': + '@smithy/util-endpoints@3.0.1': dependencies: - '@smithy/node-config-provider': 3.1.12 - '@smithy/types': 3.7.2 + '@smithy/node-config-provider': 4.0.1 + '@smithy/types': 4.1.0 tslib: 2.8.1 - '@smithy/util-hex-encoding@3.0.0': + '@smithy/util-hex-encoding@4.0.0': dependencies: tslib: 2.8.1 - '@smithy/util-middleware@3.0.11': + '@smithy/util-middleware@4.0.1': dependencies: - '@smithy/types': 3.7.2 + '@smithy/types': 4.1.0 tslib: 2.8.1 - '@smithy/util-retry@3.0.11': + '@smithy/util-retry@4.0.1': dependencies: - '@smithy/service-error-classification': 3.0.11 - '@smithy/types': 3.7.2 + '@smithy/service-error-classification': 4.0.1 + '@smithy/types': 4.1.0 tslib: 2.8.1 - '@smithy/util-stream@3.3.2': + '@smithy/util-stream@4.0.1': dependencies: - '@smithy/fetch-http-handler': 4.1.2 - '@smithy/node-http-handler': 3.3.2 - '@smithy/types': 3.7.2 - '@smithy/util-base64': 3.0.0 - '@smithy/util-buffer-from': 3.0.0 - '@smithy/util-hex-encoding': 3.0.0 - '@smithy/util-utf8': 3.0.0 + '@smithy/fetch-http-handler': 5.0.1 + '@smithy/node-http-handler': 4.0.1 + '@smithy/types': 4.1.0 + '@smithy/util-base64': 4.0.0 + '@smithy/util-buffer-from': 4.0.0 + '@smithy/util-hex-encoding': 4.0.0 + '@smithy/util-utf8': 4.0.0 tslib: 2.8.1 - '@smithy/util-uri-escape@3.0.0': + '@smithy/util-uri-escape@4.0.0': dependencies: tslib: 2.8.1 @@ -8448,62 +8592,62 @@ snapshots: '@smithy/util-buffer-from': 2.2.0 tslib: 2.8.1 - '@smithy/util-utf8@3.0.0': + '@smithy/util-utf8@4.0.0': dependencies: - '@smithy/util-buffer-from': 3.0.0 + '@smithy/util-buffer-from': 4.0.0 tslib: 2.8.1 - '@smithy/util-waiter@3.2.0': + '@smithy/util-waiter@4.0.2': dependencies: - '@smithy/abort-controller': 3.1.9 - '@smithy/types': 3.7.2 + '@smithy/abort-controller': 4.0.1 + '@smithy/types': 4.1.0 tslib: 2.8.1 - '@swc/core-darwin-arm64@1.10.1': + '@swc/core-darwin-arm64@1.10.7': optional: true - '@swc/core-darwin-x64@1.10.1': + '@swc/core-darwin-x64@1.10.7': optional: true - '@swc/core-linux-arm-gnueabihf@1.10.1': + '@swc/core-linux-arm-gnueabihf@1.10.7': optional: true - '@swc/core-linux-arm64-gnu@1.10.1': + '@swc/core-linux-arm64-gnu@1.10.7': optional: true - '@swc/core-linux-arm64-musl@1.10.1': + '@swc/core-linux-arm64-musl@1.10.7': optional: true - '@swc/core-linux-x64-gnu@1.10.1': + '@swc/core-linux-x64-gnu@1.10.7': optional: true - '@swc/core-linux-x64-musl@1.10.1': + '@swc/core-linux-x64-musl@1.10.7': optional: true - '@swc/core-win32-arm64-msvc@1.10.1': + '@swc/core-win32-arm64-msvc@1.10.7': optional: true - '@swc/core-win32-ia32-msvc@1.10.1': + '@swc/core-win32-ia32-msvc@1.10.7': optional: true - '@swc/core-win32-x64-msvc@1.10.1': + '@swc/core-win32-x64-msvc@1.10.7': optional: true - '@swc/core@1.10.1': + '@swc/core@1.10.7': dependencies: '@swc/counter': 0.1.3 '@swc/types': 0.1.17 optionalDependencies: - '@swc/core-darwin-arm64': 1.10.1 - '@swc/core-darwin-x64': 1.10.1 - '@swc/core-linux-arm-gnueabihf': 1.10.1 - '@swc/core-linux-arm64-gnu': 1.10.1 - '@swc/core-linux-arm64-musl': 1.10.1 - '@swc/core-linux-x64-gnu': 1.10.1 - '@swc/core-linux-x64-musl': 1.10.1 - '@swc/core-win32-arm64-msvc': 1.10.1 - '@swc/core-win32-ia32-msvc': 1.10.1 - '@swc/core-win32-x64-msvc': 1.10.1 + '@swc/core-darwin-arm64': 1.10.7 + '@swc/core-darwin-x64': 1.10.7 + '@swc/core-linux-arm-gnueabihf': 1.10.7 + '@swc/core-linux-arm64-gnu': 1.10.7 + '@swc/core-linux-arm64-musl': 1.10.7 + '@swc/core-linux-x64-gnu': 1.10.7 + '@swc/core-linux-x64-musl': 1.10.7 + '@swc/core-win32-arm64-msvc': 1.10.7 + '@swc/core-win32-ia32-msvc': 1.10.7 + '@swc/core-win32-x64-msvc': 1.10.7 '@swc/counter@0.1.3': {} @@ -8564,52 +8708,52 @@ snapshots: '@types/aws4@1.11.6': dependencies: - '@types/node': 20.17.10 + '@types/node': 22.10.5 '@types/babel__core@7.20.5': dependencies: - '@babel/parser': 7.26.3 - '@babel/types': 7.26.3 + '@babel/parser': 7.26.5 + '@babel/types': 7.26.5 '@types/babel__generator': 7.6.8 '@types/babel__template': 7.4.4 '@types/babel__traverse': 7.20.6 '@types/babel__generator@7.6.8': dependencies: - '@babel/types': 7.26.3 + '@babel/types': 7.26.5 '@types/babel__template@7.4.4': dependencies: - '@babel/parser': 7.26.3 - '@babel/types': 7.26.3 + '@babel/parser': 7.26.5 + '@babel/types': 7.26.5 '@types/babel__traverse@7.20.6': dependencies: - '@babel/types': 7.26.3 + '@babel/types': 7.26.5 '@types/better-sqlite3@7.6.12': dependencies: - '@types/node': 20.17.10 + '@types/node': 22.10.5 '@types/breejs__later@4.1.5': {} '@types/bunyan@1.8.11': dependencies: - '@types/node': 20.17.10 + '@types/node': 22.10.5 '@types/bunyan@1.8.9': dependencies: - '@types/node': 20.17.10 + '@types/node': 22.10.5 '@types/cacache@17.0.2': dependencies: - '@types/node': 20.17.10 + '@types/node': 22.10.5 '@types/cacheable-request@6.0.3': dependencies: '@types/http-cache-semantics': 4.0.4 '@types/keyv': 3.1.4 - '@types/node': 20.17.10 + '@types/node': 22.10.5 '@types/responselike': 1.0.3 '@types/callsite@1.0.34': {} @@ -8622,7 +8766,11 @@ snapshots: '@types/conventional-commits-detector@1.0.2': {} - '@types/diff@6.0.0': {} + '@types/debug@4.1.12': + dependencies: + '@types/ms': 0.7.34 + + '@types/diff@7.0.0': {} '@types/emscripten@1.39.13': {} @@ -8636,7 +8784,7 @@ snapshots: '@types/fs-extra@11.0.4': dependencies: '@types/jsonfile': 6.1.4 - '@types/node': 20.17.10 + '@types/node': 22.10.5 '@types/git-url-parse@9.0.3': {} @@ -8646,7 +8794,7 @@ snapshots: '@types/graceful-fs@4.1.9': dependencies: - '@types/node': 20.17.10 + '@types/node': 22.10.5 '@types/http-cache-semantics@4.0.4': {} @@ -8672,17 +8820,19 @@ snapshots: '@types/jsonfile@6.1.4': dependencies: - '@types/node': 20.17.10 + '@types/node': 22.10.5 + + '@types/katex@0.16.7': {} '@types/keyv@3.1.4': dependencies: - '@types/node': 20.17.10 + '@types/node': 22.10.5 '@types/linkify-it@5.0.0': {} '@types/linkify-markdown@1.0.3': {} - '@types/lodash@4.17.13': {} + '@types/lodash@4.17.14': {} '@types/luxon@3.4.2': {} @@ -8695,7 +8845,7 @@ snapshots: '@types/marshal@0.5.3': dependencies: - '@types/node': 20.17.10 + '@types/node': 22.10.5 '@types/mdast@3.0.15': dependencies: @@ -8705,15 +8855,15 @@ snapshots: '@types/minimist@1.2.5': {} - '@types/moo@0.5.5': {} + '@types/moo@0.5.10': {} - '@types/moo@0.5.9': {} + '@types/moo@0.5.5': {} '@types/ms@0.7.34': {} - '@types/node@20.17.10': + '@types/node@22.10.5': dependencies: - undici-types: 6.19.8 + undici-types: 6.20.0 '@types/normalize-package-data@2.4.4': {} @@ -8725,7 +8875,7 @@ snapshots: '@types/responselike@1.0.3': dependencies: - '@types/node': 20.17.10 + '@types/node': 22.10.5 '@types/semver-stable@3.0.2': {} @@ -8745,7 +8895,7 @@ snapshots: '@types/tar@6.1.13': dependencies: - '@types/node': 20.17.10 + '@types/node': 22.10.5 minipass: 4.2.8 '@types/tmp@0.2.6': {} @@ -8770,43 +8920,43 @@ snapshots: '@types/yauzl@2.10.3': dependencies: - '@types/node': 20.17.10 + '@types/node': 22.10.5 optional: true - '@typescript-eslint/eslint-plugin@8.18.1(@typescript-eslint/parser@8.18.1(eslint@8.57.1)(typescript@5.7.2))(eslint@8.57.1)(typescript@5.7.2)': + '@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)': dependencies: '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.18.1(eslint@8.57.1)(typescript@5.7.2) - '@typescript-eslint/scope-manager': 8.18.1 - '@typescript-eslint/type-utils': 8.18.1(eslint@8.57.1)(typescript@5.7.2) - '@typescript-eslint/utils': 8.18.1(eslint@8.57.1)(typescript@5.7.2) - '@typescript-eslint/visitor-keys': 8.18.1 + '@typescript-eslint/parser': 8.19.1(eslint@8.57.1)(typescript@5.7.3) + '@typescript-eslint/scope-manager': 8.19.1 + '@typescript-eslint/type-utils': 8.19.1(eslint@8.57.1)(typescript@5.7.3) + '@typescript-eslint/utils': 8.19.1(eslint@8.57.1)(typescript@5.7.3) + '@typescript-eslint/visitor-keys': 8.19.1 eslint: 8.57.1 graphemer: 1.4.0 ignore: 5.3.2 natural-compare: 1.4.0 - ts-api-utils: 1.4.3(typescript@5.7.2) - typescript: 5.7.2 + ts-api-utils: 2.0.0(typescript@5.7.3) + typescript: 5.7.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/experimental-utils@5.62.0(eslint@8.57.1)(typescript@5.7.2)': + '@typescript-eslint/experimental-utils@5.62.0(eslint@8.57.1)(typescript@5.7.3)': dependencies: - '@typescript-eslint/utils': 5.62.0(eslint@8.57.1)(typescript@5.7.2) + '@typescript-eslint/utils': 5.62.0(eslint@8.57.1)(typescript@5.7.3) eslint: 8.57.1 transitivePeerDependencies: - supports-color - typescript - '@typescript-eslint/parser@8.18.1(eslint@8.57.1)(typescript@5.7.2)': + '@typescript-eslint/parser@8.19.1(eslint@8.57.1)(typescript@5.7.3)': dependencies: - '@typescript-eslint/scope-manager': 8.18.1 - '@typescript-eslint/types': 8.18.1 - '@typescript-eslint/typescript-estree': 8.18.1(typescript@5.7.2) - '@typescript-eslint/visitor-keys': 8.18.1 + '@typescript-eslint/scope-manager': 8.19.1 + '@typescript-eslint/types': 8.19.1 + '@typescript-eslint/typescript-estree': 8.19.1(typescript@5.7.3) + '@typescript-eslint/visitor-keys': 8.19.1 debug: 4.4.0 eslint: 8.57.1 - typescript: 5.7.2 + typescript: 5.7.3 transitivePeerDependencies: - supports-color @@ -8815,27 +8965,27 @@ snapshots: '@typescript-eslint/types': 5.62.0 '@typescript-eslint/visitor-keys': 5.62.0 - '@typescript-eslint/scope-manager@8.18.1': + '@typescript-eslint/scope-manager@8.19.1': dependencies: - '@typescript-eslint/types': 8.18.1 - '@typescript-eslint/visitor-keys': 8.18.1 + '@typescript-eslint/types': 8.19.1 + '@typescript-eslint/visitor-keys': 8.19.1 - '@typescript-eslint/type-utils@8.18.1(eslint@8.57.1)(typescript@5.7.2)': + '@typescript-eslint/type-utils@8.19.1(eslint@8.57.1)(typescript@5.7.3)': dependencies: - '@typescript-eslint/typescript-estree': 8.18.1(typescript@5.7.2) - '@typescript-eslint/utils': 8.18.1(eslint@8.57.1)(typescript@5.7.2) + '@typescript-eslint/typescript-estree': 8.19.1(typescript@5.7.3) + '@typescript-eslint/utils': 8.19.1(eslint@8.57.1)(typescript@5.7.3) debug: 4.4.0 eslint: 8.57.1 - ts-api-utils: 1.4.3(typescript@5.7.2) - typescript: 5.7.2 + ts-api-utils: 2.0.0(typescript@5.7.3) + typescript: 5.7.3 transitivePeerDependencies: - supports-color '@typescript-eslint/types@5.62.0': {} - '@typescript-eslint/types@8.18.1': {} + '@typescript-eslint/types@8.19.1': {} - '@typescript-eslint/typescript-estree@5.62.0(typescript@5.7.2)': + '@typescript-eslint/typescript-estree@5.62.0(typescript@5.7.3)': dependencies: '@typescript-eslint/types': 5.62.0 '@typescript-eslint/visitor-keys': 5.62.0 @@ -8843,34 +8993,34 @@ snapshots: globby: 11.1.0 is-glob: 4.0.3 semver: 7.6.3 - tsutils: 3.21.0(typescript@5.7.2) + tsutils: 3.21.0(typescript@5.7.3) optionalDependencies: - typescript: 5.7.2 + typescript: 5.7.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/typescript-estree@8.18.1(typescript@5.7.2)': + '@typescript-eslint/typescript-estree@8.19.1(typescript@5.7.3)': dependencies: - '@typescript-eslint/types': 8.18.1 - '@typescript-eslint/visitor-keys': 8.18.1 + '@typescript-eslint/types': 8.19.1 + '@typescript-eslint/visitor-keys': 8.19.1 debug: 4.4.0 - fast-glob: 3.3.2 + fast-glob: 3.3.3 is-glob: 4.0.3 minimatch: 9.0.5 semver: 7.6.3 - ts-api-utils: 1.4.3(typescript@5.7.2) - typescript: 5.7.2 + 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.2)': + '@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) '@types/json-schema': 7.0.15 '@types/semver': 7.5.8 '@typescript-eslint/scope-manager': 5.62.0 '@typescript-eslint/types': 5.62.0 - '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.7.2) + '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.7.3) eslint: 8.57.1 eslint-scope: 5.1.1 semver: 7.6.3 @@ -8878,14 +9028,14 @@ snapshots: - supports-color - typescript - '@typescript-eslint/utils@8.18.1(eslint@8.57.1)(typescript@5.7.2)': + '@typescript-eslint/utils@8.19.1(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.18.1 - '@typescript-eslint/types': 8.18.1 - '@typescript-eslint/typescript-estree': 8.18.1(typescript@5.7.2) + '@typescript-eslint/scope-manager': 8.19.1 + '@typescript-eslint/types': 8.19.1 + '@typescript-eslint/typescript-estree': 8.19.1(typescript@5.7.3) eslint: 8.57.1 - typescript: 5.7.2 + typescript: 5.7.3 transitivePeerDependencies: - supports-color @@ -8894,14 +9044,14 @@ snapshots: '@typescript-eslint/types': 5.62.0 eslint-visitor-keys: 3.4.3 - '@typescript-eslint/visitor-keys@8.18.1': + '@typescript-eslint/visitor-keys@8.19.1': dependencies: - '@typescript-eslint/types': 8.18.1 + '@typescript-eslint/types': 8.19.1 eslint-visitor-keys: 4.2.0 '@ungap/structured-clone@1.2.1': {} - '@yarnpkg/core@4.1.6(typanion@3.14.0)': + '@yarnpkg/core@4.2.0(typanion@3.14.0)': dependencies: '@arcanis/slice-ansi': 1.1.1 '@types/semver': 7.5.8 @@ -8917,7 +9067,7 @@ snapshots: cross-spawn: 7.0.6 diff: 5.2.0 dotenv: 16.4.7 - fast-glob: 3.3.2 + fast-glob: 3.3.3 got: 11.8.6 lodash: 4.17.21 micromatch: 4.0.8 @@ -8954,7 +9104,7 @@ snapshots: chalk: 3.0.0 clipanion: 4.0.0-rc.4(typanion@3.14.0) cross-spawn: 7.0.6 - fast-glob: 3.3.2 + fast-glob: 3.3.3 micromatch: 4.0.8 tslib: 2.8.1 transitivePeerDependencies: @@ -8981,7 +9131,7 @@ snapshots: agent-base@7.1.3: {} - agentkeepalive@4.5.0: + agentkeepalive@4.6.0: dependencies: humanize-ms: 1.2.1 @@ -9060,9 +9210,9 @@ snapshots: dependencies: call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.7 + es-abstract: 1.23.9 es-object-atoms: 1.0.0 - get-intrinsic: 1.2.6 + get-intrinsic: 1.2.7 is-string: 1.1.1 array-union@2.1.0: {} @@ -9071,7 +9221,7 @@ snapshots: dependencies: call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.7 + es-abstract: 1.23.9 es-errors: 1.3.0 es-object-atoms: 1.0.0 es-shim-unscopables: 1.0.2 @@ -9080,14 +9230,14 @@ snapshots: dependencies: call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.7 + es-abstract: 1.23.9 es-shim-unscopables: 1.0.2 array.prototype.flatmap@1.3.3: dependencies: call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.7 + es-abstract: 1.23.9 es-shim-unscopables: 1.0.2 arraybuffer.prototype.slice@1.0.4: @@ -9095,9 +9245,9 @@ snapshots: array-buffer-byte-length: 1.0.2 call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.7 + es-abstract: 1.23.9 es-errors: 1.3.0 - get-intrinsic: 1.2.6 + get-intrinsic: 1.2.7 is-array-buffer: 3.0.5 arrify@1.0.1: {} @@ -9142,7 +9292,7 @@ snapshots: babel-plugin-istanbul@6.1.1: dependencies: - '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-plugin-utils': 7.26.5 '@istanbuljs/load-nyc-config': 1.1.0 '@istanbuljs/schema': 0.1.3 istanbul-lib-instrument: 5.2.1 @@ -9153,7 +9303,7 @@ snapshots: babel-plugin-jest-hoist@29.6.3: dependencies: '@babel/template': 7.25.9 - '@babel/types': 7.26.3 + '@babel/types': 7.26.5 '@types/babel__core': 7.20.5 '@types/babel__traverse': 7.20.6 @@ -9194,7 +9344,7 @@ snapshots: before-after-hook@3.0.2: {} - better-sqlite3@11.7.0: + better-sqlite3@11.7.2: dependencies: bindings: 1.5.0 prebuild-install: 7.1.2 @@ -9237,12 +9387,12 @@ snapshots: dependencies: fill-range: 7.1.1 - browserslist@4.24.3: + browserslist@4.24.4: dependencies: - caniuse-lite: 1.0.30001690 - electron-to-chromium: 1.5.75 + caniuse-lite: 1.0.30001692 + electron-to-chromium: 1.5.80 node-releases: 2.0.19 - update-browserslist-db: 1.1.1(browserslist@4.24.3) + update-browserslist-db: 1.1.2(browserslist@4.24.4) bs-logger@0.2.6: dependencies: @@ -9327,13 +9477,13 @@ snapshots: dependencies: call-bind-apply-helpers: 1.0.1 es-define-property: 1.0.1 - get-intrinsic: 1.2.6 + get-intrinsic: 1.2.7 set-function-length: 1.2.2 call-bound@1.0.3: dependencies: call-bind-apply-helpers: 1.0.1 - get-intrinsic: 1.2.6 + get-intrinsic: 1.2.7 callsite@1.0.0: {} @@ -9349,7 +9499,7 @@ snapshots: camelcase@6.3.0: {} - caniuse-lite@1.0.30001690: {} + caniuse-lite@1.0.30001692: {} chalk@2.4.2: dependencies: @@ -9375,10 +9525,16 @@ snapshots: character-entities-legacy@1.1.4: {} + character-entities-legacy@3.0.0: {} + character-entities@1.2.4: {} + character-entities@2.0.2: {} + character-reference-invalid@1.1.4: {} + character-reference-invalid@2.0.1: {} + chownr@1.1.4: optional: true @@ -9463,6 +9619,8 @@ snapshots: commander@12.1.0: {} + commander@8.3.0: {} + common-tags@1.8.2: {} commondir@1.0.1: {} @@ -9514,26 +9672,26 @@ snapshots: convert-source-map@2.0.0: {} - core-js-pure@3.39.0: {} + core-js-pure@3.40.0: {} core-util-is@1.0.3: {} - cosmiconfig@9.0.0(typescript@5.7.2): + cosmiconfig@9.0.0(typescript@5.7.3): dependencies: env-paths: 2.2.1 import-fresh: 3.3.0 js-yaml: 4.1.0 parse-json: 5.2.0 optionalDependencies: - typescript: 5.7.2 + typescript: 5.7.3 - create-jest@29.7.0(@types/node@20.17.10)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@20.17.10)(typescript@5.7.2)): + create-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)): dependencies: '@jest/types': 29.6.3 chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@20.17.10)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@20.17.10)(typescript@5.7.2)) + jest-config: 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)) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -9563,7 +9721,7 @@ snapshots: boolbase: 1.0.0 css-what: 6.1.0 domhandler: 5.0.3 - domutils: 3.1.0 + domutils: 3.2.2 nth-check: 2.1.1 css-what@6.1.0: {} @@ -9603,6 +9761,10 @@ snapshots: decamelize@1.2.0: {} + decode-named-character-reference@1.0.2: + dependencies: + character-entities: 2.0.2 + decompress-response@6.0.0: dependencies: mimic-response: 3.1.0 @@ -9651,6 +9813,10 @@ snapshots: detect-node@2.1.0: {} + devlop@1.1.0: + dependencies: + dequal: 2.0.3 + diff-sequences@29.6.3: {} diff@4.0.2: {} @@ -9683,7 +9849,7 @@ snapshots: dependencies: domelementtype: 2.3.0 - domutils@3.1.0: + domutils@3.2.2: dependencies: dom-serializer: 2.0.0 domelementtype: 2.3.0 @@ -9722,7 +9888,7 @@ snapshots: dependencies: jake: 10.9.2 - electron-to-chromium@1.5.75: {} + electron-to-chromium@1.5.80: {} email-addresses@5.0.0: {} @@ -9776,7 +9942,7 @@ snapshots: dependencies: is-arrayish: 0.2.1 - es-abstract@1.23.7: + es-abstract@1.23.9: dependencies: array-buffer-byte-length: 1.0.2 arraybuffer.prototype.slice: 1.0.4 @@ -9789,10 +9955,11 @@ snapshots: es-define-property: 1.0.1 es-errors: 1.3.0 es-object-atoms: 1.0.0 - es-set-tostringtag: 2.0.3 + es-set-tostringtag: 2.1.0 es-to-primitive: 1.3.0 function.prototype.name: 1.1.8 - get-intrinsic: 1.2.6 + get-intrinsic: 1.2.7 + get-proto: 1.0.1 get-symbol-description: 1.1.0 globalthis: 1.0.4 gopd: 1.2.0 @@ -9813,9 +9980,12 @@ snapshots: object-inspect: 1.13.3 object-keys: 1.1.1 object.assign: 4.1.7 - regexp.prototype.flags: 1.5.3 + own-keys: 1.0.1 + regexp.prototype.flags: 1.5.4 safe-array-concat: 1.1.3 + safe-push-apply: 1.0.0 safe-regex-test: 1.1.0 + set-proto: 1.0.0 string.prototype.trim: 1.2.10 string.prototype.trimend: 1.0.9 string.prototype.trimstart: 1.0.8 @@ -9834,9 +10004,10 @@ snapshots: dependencies: es-errors: 1.3.0 - es-set-tostringtag@2.0.3: + es-set-tostringtag@2.1.0: dependencies: - get-intrinsic: 1.2.6 + es-errors: 1.3.0 + get-intrinsic: 1.2.7 has-tostringtag: 1.0.2 hasown: 2.0.2 @@ -9889,28 +10060,28 @@ snapshots: debug: 4.4.0 enhanced-resolve: 5.18.0 eslint: 8.57.1 - fast-glob: 3.3.2 + fast-glob: 3.3.3 get-tsconfig: 4.8.1 is-bun-module: 1.3.0 is-glob: 4.0.3 stable-hash: 0.0.4 optionalDependencies: - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.18.1(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-typescript@3.7.0)(eslint@8.57.1) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.19.1(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-typescript@3.7.0)(eslint@8.57.1) transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.18.1(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0)(eslint@8.57.1): + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.19.1(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0)(eslint@8.57.1): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 8.18.1(eslint@8.57.1)(typescript@5.7.2) + '@typescript-eslint/parser': 8.19.1(eslint@8.57.1)(typescript@5.7.3) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 eslint-import-resolver-typescript: 3.7.0(eslint-plugin-import@2.31.0)(eslint@8.57.1) transitivePeerDependencies: - supports-color - eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.18.1(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-typescript@3.7.0)(eslint@8.57.1): + eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.19.1(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-typescript@3.7.0)(eslint@8.57.1): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.8 @@ -9921,7 +10092,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.18.1(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0)(eslint@8.57.1) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.19.1(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0)(eslint@8.57.1) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -9933,7 +10104,7 @@ snapshots: string.prototype.trimend: 1.0.9 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.18.1(eslint@8.57.1)(typescript@5.7.2) + '@typescript-eslint/parser': 8.19.1(eslint@8.57.1)(typescript@5.7.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack @@ -9943,13 +10114,13 @@ snapshots: dependencies: eslint: 8.57.1 - eslint-plugin-jest@28.10.0(@typescript-eslint/eslint-plugin@8.18.1(@typescript-eslint/parser@8.18.1(eslint@8.57.1)(typescript@5.7.2))(eslint@8.57.1)(typescript@5.7.2))(eslint@8.57.1)(jest@29.7.0(@types/node@20.17.10)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@20.17.10)(typescript@5.7.2)))(typescript@5.7.2): + 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.18.1(eslint@8.57.1)(typescript@5.7.2) + '@typescript-eslint/utils': 8.19.1(eslint@8.57.1)(typescript@5.7.3) eslint: 8.57.1 optionalDependencies: - '@typescript-eslint/eslint-plugin': 8.18.1(@typescript-eslint/parser@8.18.1(eslint@8.57.1)(typescript@5.7.2))(eslint@8.57.1)(typescript@5.7.2) - jest: 29.7.0(@types/node@20.17.10)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@20.17.10)(typescript@5.7.2)) + '@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) + 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)) transitivePeerDependencies: - supports-color - typescript @@ -9959,9 +10130,9 @@ snapshots: '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1) eslint: 8.57.1 - eslint-plugin-typescript-enum@2.1.0(eslint@8.57.1)(typescript@5.7.2): + eslint-plugin-typescript-enum@2.1.0(eslint@8.57.1)(typescript@5.7.3): dependencies: - '@typescript-eslint/experimental-utils': 5.62.0(eslint@8.57.1)(typescript@5.7.2) + '@typescript-eslint/experimental-utils': 5.62.0(eslint@8.57.1)(typescript@5.7.3) transitivePeerDependencies: - eslint - supports-color @@ -10123,9 +10294,11 @@ snapshots: transitivePeerDependencies: - supports-color + fast-content-type-parse@2.0.1: {} + fast-deep-equal@3.1.3: {} - fast-glob@3.3.2: + fast-glob@3.3.3: dependencies: '@nodelib/fs.stat': 2.0.5 '@nodelib/fs.walk': 1.2.8 @@ -10141,7 +10314,7 @@ snapshots: dependencies: strnum: 1.0.5 - fastq@1.17.1: + fastq@1.18.0: dependencies: reusify: 1.0.4 @@ -10187,7 +10360,7 @@ snapshots: '@pnpm/read-project-manifest': 4.1.1 '@pnpm/types': 8.9.0 '@pnpm/util.lex-comparator': 1.0.0 - fast-glob: 3.3.2 + fast-glob: 3.3.3 p-filter: 2.1.0 find-up-simple@1.0.0: {} @@ -10304,14 +10477,14 @@ snapshots: get-caller-file@2.0.5: {} - get-intrinsic@1.2.6: + get-intrinsic@1.2.7: dependencies: call-bind-apply-helpers: 1.0.1 - dunder-proto: 1.0.1 es-define-property: 1.0.1 es-errors: 1.3.0 es-object-atoms: 1.0.0 function-bind: 1.1.2 + get-proto: 1.0.1 gopd: 1.2.0 has-symbols: 1.1.0 hasown: 2.0.2 @@ -10319,6 +10492,11 @@ snapshots: get-package-type@0.1.0: {} + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.0.0 + get-stream@5.2.0: dependencies: pump: 3.0.2 @@ -10338,7 +10516,7 @@ snapshots: dependencies: call-bound: 1.0.3 es-errors: 1.3.0 - get-intrinsic: 1.2.6 + get-intrinsic: 1.2.7 get-tsconfig@4.8.1: dependencies: @@ -10392,7 +10570,7 @@ snapshots: package-json-from-dist: 1.0.1 path-scurry: 1.11.1 - glob@11.0.0: + glob@11.0.1: dependencies: foreground-child: 3.3.0 jackspeak: 4.0.2 @@ -10434,7 +10612,7 @@ snapshots: dependencies: array-union: 2.1.0 dir-glob: 3.0.1 - fast-glob: 3.3.2 + fast-glob: 3.3.3 ignore: 5.3.2 merge2: 1.4.1 slash: 3.0.0 @@ -10442,7 +10620,7 @@ snapshots: globby@14.0.2: dependencies: '@sindresorhus/merge-streams': 2.3.0 - fast-glob: 3.3.2 + fast-glob: 3.3.3 ignore: 5.3.2 path-type: 5.0.0 slash: 5.1.0 @@ -10624,7 +10802,7 @@ snapshots: ignore@5.3.2: {} - ignore@6.0.2: {} + ignore@7.0.0: {} immediate@3.0.6: {} @@ -10633,7 +10811,7 @@ snapshots: parent-module: 1.0.1 resolve-from: 4.0.0 - import-from-esm@1.3.4: + import-from-esm@2.0.0: dependencies: debug: 4.4.0 import-meta-resolve: 4.1.0 @@ -10695,11 +10873,18 @@ snapshots: is-alphabetical@1.0.4: {} + is-alphabetical@2.0.1: {} + is-alphanumerical@1.0.4: dependencies: is-alphabetical: 1.0.4 is-decimal: 1.0.4 + is-alphanumerical@2.0.1: + dependencies: + is-alphabetical: 2.0.1 + is-decimal: 2.0.1 + is-arguments@1.2.0: dependencies: call-bound: 1.0.3 @@ -10709,13 +10894,16 @@ snapshots: dependencies: call-bind: 1.0.8 call-bound: 1.0.3 - get-intrinsic: 1.2.6 + get-intrinsic: 1.2.7 is-arrayish@0.2.1: {} - is-async-function@2.0.0: + is-async-function@2.1.0: dependencies: + call-bound: 1.0.3 + get-proto: 1.0.1 has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 is-bigint@1.1.0: dependencies: @@ -10741,7 +10929,7 @@ snapshots: is-data-view@1.0.2: dependencies: call-bound: 1.0.3 - get-intrinsic: 1.2.6 + get-intrinsic: 1.2.7 is-typed-array: 1.1.15 is-date-object@1.1.0: @@ -10751,6 +10939,8 @@ snapshots: is-decimal@1.0.4: {} + is-decimal@2.0.1: {} + is-extglob@2.1.1: {} is-finalizationregistry@1.1.1: @@ -10761,9 +10951,12 @@ snapshots: is-generator-fn@2.1.0: {} - is-generator-function@1.0.10: + is-generator-function@1.1.0: dependencies: + call-bound: 1.0.3 + get-proto: 1.0.1 has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 is-glob@4.0.3: dependencies: @@ -10771,6 +10964,8 @@ snapshots: is-hexadecimal@1.0.4: {} + is-hexadecimal@2.0.1: {} + is-lambda@1.0.1: optional: true @@ -10844,7 +11039,7 @@ snapshots: is-weakset@2.0.4: dependencies: call-bound: 1.0.3 - get-intrinsic: 1.2.6 + get-intrinsic: 1.2.7 is-windows@1.0.2: {} @@ -10873,7 +11068,7 @@ snapshots: istanbul-lib-instrument@5.2.1: dependencies: '@babel/core': 7.26.0 - '@babel/parser': 7.26.3 + '@babel/parser': 7.26.5 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.2 semver: 6.3.1 @@ -10883,7 +11078,7 @@ snapshots: istanbul-lib-instrument@6.0.3: dependencies: '@babel/core': 7.26.0 - '@babel/parser': 7.26.3 + '@babel/parser': 7.26.5 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.2 semver: 7.6.3 @@ -10949,7 +11144,7 @@ snapshots: '@jest/expect': 29.7.0 '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.17.10 + '@types/node': 22.10.5 chalk: 4.1.2 co: 4.6.0 dedent: 1.5.3 @@ -10969,16 +11164,16 @@ snapshots: - babel-plugin-macros - supports-color - jest-cli@29.7.0(@types/node@20.17.10)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@20.17.10)(typescript@5.7.2)): + jest-cli@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)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@20.17.10)(typescript@5.7.2)) + '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.10.7)(@types/node@22.10.5)(typescript@5.7.3)) '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@20.17.10)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@20.17.10)(typescript@5.7.2)) + create-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)) exit: 0.1.2 import-local: 3.2.0 - jest-config: 29.7.0(@types/node@20.17.10)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@20.17.10)(typescript@5.7.2)) + jest-config: 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)) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -10988,7 +11183,7 @@ snapshots: - supports-color - ts-node - jest-config@29.7.0(@types/node@20.17.10)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@20.17.10)(typescript@5.7.2)): + jest-config@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)): dependencies: '@babel/core': 7.26.0 '@jest/test-sequencer': 29.7.0 @@ -11013,8 +11208,8 @@ snapshots: slash: 3.0.0 strip-json-comments: 3.1.1 optionalDependencies: - '@types/node': 20.17.10 - ts-node: 10.9.2(@swc/core@1.10.1)(@types/node@20.17.10)(typescript@5.7.2) + '@types/node': 22.10.5 + ts-node: 10.9.2(@swc/core@1.10.7)(@types/node@22.10.5)(typescript@5.7.3) transitivePeerDependencies: - babel-plugin-macros - supports-color @@ -11043,16 +11238,16 @@ snapshots: '@jest/environment': 29.7.0 '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.17.10 + '@types/node': 22.10.5 jest-mock: 29.7.0 jest-util: 29.7.0 - jest-extended@4.0.2(jest@29.7.0(@types/node@20.17.10)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@20.17.10)(typescript@5.7.2))): + jest-extended@4.0.2(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))): dependencies: jest-diff: 29.7.0 jest-get-type: 29.6.3 optionalDependencies: - jest: 29.7.0(@types/node@20.17.10)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@20.17.10)(typescript@5.7.2)) + 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)) jest-get-type@29.6.3: {} @@ -11060,7 +11255,7 @@ snapshots: dependencies: '@jest/types': 29.6.3 '@types/graceful-fs': 4.1.9 - '@types/node': 20.17.10 + '@types/node': 22.10.5 anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.11 @@ -11103,16 +11298,16 @@ snapshots: slash: 3.0.0 stack-utils: 2.0.6 - jest-mock-extended@3.0.7(jest@29.7.0(@types/node@20.17.10)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@20.17.10)(typescript@5.7.2)))(typescript@5.7.2): + jest-mock-extended@3.0.7(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: - jest: 29.7.0(@types/node@20.17.10)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@20.17.10)(typescript@5.7.2)) - ts-essentials: 10.0.3(typescript@5.7.2) - typescript: 5.7.2 + 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)) + ts-essentials: 10.0.4(typescript@5.7.3) + typescript: 5.7.3 jest-mock@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 20.17.10 + '@types/node': 22.10.5 jest-util: 29.7.0 jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): @@ -11147,7 +11342,7 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.17.10 + '@types/node': 22.10.5 chalk: 4.1.2 emittery: 0.13.1 graceful-fs: 4.2.11 @@ -11175,7 +11370,7 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.17.10 + '@types/node': 22.10.5 chalk: 4.1.2 cjs-module-lexer: 1.4.1 collect-v8-coverage: 1.0.2 @@ -11196,10 +11391,10 @@ snapshots: jest-snapshot@29.7.0: dependencies: '@babel/core': 7.26.0 - '@babel/generator': 7.26.3 + '@babel/generator': 7.26.5 '@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.26.0) '@babel/plugin-syntax-typescript': 7.25.9(@babel/core@7.26.0) - '@babel/types': 7.26.3 + '@babel/types': 7.26.5 '@jest/expect-utils': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 @@ -11221,7 +11416,7 @@ snapshots: jest-util@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 20.17.10 + '@types/node': 22.10.5 chalk: 4.1.2 ci-info: 3.9.0 graceful-fs: 4.2.11 @@ -11240,7 +11435,7 @@ snapshots: dependencies: '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.17.10 + '@types/node': 22.10.5 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.13.1 @@ -11249,17 +11444,17 @@ snapshots: jest-worker@29.7.0: dependencies: - '@types/node': 20.17.10 + '@types/node': 22.10.5 jest-util: 29.7.0 merge-stream: 2.0.0 supports-color: 8.1.1 - jest@29.7.0(@types/node@20.17.10)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@20.17.10)(typescript@5.7.2)): + 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)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@20.17.10)(typescript@5.7.2)) + '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.10.7)(@types/node@22.10.5)(typescript@5.7.3)) '@jest/types': 29.6.3 import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@20.17.10)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@20.17.10)(typescript@5.7.2)) + jest-cli: 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)) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -11337,6 +11532,10 @@ snapshots: jwa: 2.0.0 safe-buffer: 5.2.1 + katex@0.16.19: + dependencies: + commander: 8.3.0 + keybase-ecurve@1.0.1: dependencies: bn: 1.0.5 @@ -11420,7 +11619,7 @@ snapshots: lodash@4.17.21: {} - long@5.2.3: {} + long@5.2.4: {} longest-streak@2.0.4: {} @@ -11489,25 +11688,34 @@ snapshots: dependencies: repeat-string: 1.6.1 - markdownlint-cli2-formatter-default@0.0.5(markdownlint-cli2@0.16.0): + markdownlint-cli2-formatter-default@0.0.5(markdownlint-cli2@0.17.1): dependencies: - markdownlint-cli2: 0.16.0 + markdownlint-cli2: 0.17.1 - markdownlint-cli2@0.16.0: + markdownlint-cli2@0.17.1: dependencies: globby: 14.0.2 js-yaml: 4.1.0 jsonc-parser: 3.3.1 - markdownlint: 0.36.1 - markdownlint-cli2-formatter-default: 0.0.5(markdownlint-cli2@0.16.0) + markdownlint: 0.37.3 + markdownlint-cli2-formatter-default: 0.0.5(markdownlint-cli2@0.17.1) micromatch: 4.0.8 + transitivePeerDependencies: + - supports-color - markdownlint-micromark@0.1.12: {} - - markdownlint@0.36.1: + markdownlint@0.37.3: dependencies: markdown-it: 14.1.0 - markdownlint-micromark: 0.1.12 + micromark: 4.0.1 + micromark-core-commonmark: 2.0.2 + micromark-extension-directive: 3.0.2 + micromark-extension-gfm-autolink-literal: 2.1.0 + micromark-extension-gfm-footnote: 2.1.0 + micromark-extension-gfm-table: 2.1.0 + micromark-extension-math: 3.1.0 + micromark-util-types: 2.0.1 + transitivePeerDependencies: + - supports-color marked-terminal@7.2.1(marked@12.0.2): dependencies: @@ -11559,7 +11767,7 @@ snapshots: mdurl@2.0.0: {} - memfs@4.15.1: + memfs@4.17.0: dependencies: '@jsonjoy.com/json-pack': 1.1.1(tslib@2.8.1) '@jsonjoy.com/util': 1.5.0(tslib@2.8.1) @@ -11602,6 +11810,156 @@ snapshots: merge2@1.4.1: {} + micromark-core-commonmark@2.0.2: + dependencies: + decode-named-character-reference: 1.0.2 + devlop: 1.1.0 + micromark-factory-destination: 2.0.1 + micromark-factory-label: 2.0.1 + micromark-factory-space: 2.0.1 + micromark-factory-title: 2.0.1 + micromark-factory-whitespace: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-html-tag-name: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-subtokenize: 2.0.3 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.1 + + micromark-extension-directive@3.0.2: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-factory-whitespace: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.1 + parse-entities: 4.0.2 + + micromark-extension-gfm-autolink-literal@2.1.0: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.1 + + micromark-extension-gfm-footnote@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-core-commonmark: 2.0.2 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.1 + + micromark-extension-gfm-table@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.1 + + micromark-extension-math@3.1.0: + dependencies: + '@types/katex': 0.16.7 + devlop: 1.1.0 + katex: 0.16.19 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.1 + + micromark-factory-destination@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.1 + + micromark-factory-label@2.0.1: + dependencies: + devlop: 1.1.0 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.1 + + micromark-factory-space@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-types: 2.0.1 + + micromark-factory-title@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.1 + + micromark-factory-whitespace@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.1 + + micromark-util-character@2.1.1: + dependencies: + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.1 + + micromark-util-chunked@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-classify-character@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.1 + + micromark-util-combine-extensions@2.0.1: + dependencies: + micromark-util-chunked: 2.0.1 + micromark-util-types: 2.0.1 + + micromark-util-decode-numeric-character-reference@2.0.2: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-encode@2.0.1: {} + + micromark-util-html-tag-name@2.0.1: {} + + micromark-util-normalize-identifier@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-resolve-all@2.0.1: + dependencies: + micromark-util-types: 2.0.1 + + micromark-util-sanitize-uri@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-encode: 2.0.1 + micromark-util-symbol: 2.0.1 + + micromark-util-subtokenize@2.0.3: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.1 + + micromark-util-symbol@2.0.1: {} + + micromark-util-types@2.0.1: {} + micromark@2.11.4: dependencies: debug: 4.4.0 @@ -11609,6 +11967,28 @@ snapshots: transitivePeerDependencies: - supports-color + micromark@4.0.1: + dependencies: + '@types/debug': 4.1.12 + debug: 4.4.0 + decode-named-character-reference: 1.0.2 + devlop: 1.1.0 + micromark-core-commonmark: 2.0.2 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-combine-extensions: 2.0.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-encode: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-subtokenize: 2.0.3 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.1 + transitivePeerDependencies: + - supports-color + micromatch@4.0.8: dependencies: braces: 3.0.3 @@ -11794,7 +12174,7 @@ snapshots: - supports-color optional: true - node-html-parser@6.1.13: + node-html-parser@7.0.1: dependencies: css-select: 5.1.0 he: 1.2.0 @@ -11921,14 +12301,14 @@ snapshots: dependencies: call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.7 + es-abstract: 1.23.9 es-object-atoms: 1.0.0 object.groupby@1.0.3: dependencies: call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.7 + es-abstract: 1.23.9 object.values@1.2.1: dependencies: @@ -11961,6 +12341,12 @@ snapshots: type-check: 0.4.0 word-wrap: 1.2.5 + own-keys@1.0.1: + dependencies: + get-intrinsic: 1.2.7 + object-keys: 1.1.1 + safe-push-apply: 1.0.0 + p-all@3.0.0: dependencies: p-map: 4.0.0 @@ -12056,6 +12442,16 @@ snapshots: is-decimal: 1.0.4 is-hexadecimal: 1.0.4 + parse-entities@4.0.2: + dependencies: + '@types/unist': 2.0.11 + character-entities-legacy: 3.0.0 + character-reference-invalid: 2.0.1 + decode-named-character-reference: 1.0.2 + is-alphanumerical: 2.0.1 + is-decimal: 2.0.1 + is-hexadecimal: 2.0.1 + parse-json@4.0.0: dependencies: error-ex: 1.3.2 @@ -12072,7 +12468,7 @@ snapshots: dependencies: '@babel/code-frame': 7.26.2 index-to-position: 0.1.2 - type-fest: 4.30.2 + type-fest: 4.32.0 parse-link-header@2.0.0: dependencies: @@ -12221,8 +12617,8 @@ snapshots: '@protobufjs/path': 1.1.2 '@protobufjs/pool': 1.1.0 '@protobufjs/utf8': 1.1.0 - '@types/node': 20.17.10 - long: 5.2.3 + '@types/node': 22.10.5 + long: 5.2.4 protocols@2.0.1: {} @@ -12276,7 +12672,7 @@ snapshots: dependencies: find-up-simple: 1.0.0 read-pkg: 9.0.1 - type-fest: 4.30.2 + type-fest: 4.32.0 read-pkg-up@7.0.1: dependencies: @@ -12296,7 +12692,7 @@ snapshots: '@types/normalize-package-data': 2.4.4 normalize-package-data: 6.0.2 parse-json: 8.1.0 - type-fest: 4.30.2 + type-fest: 4.32.0 unicorn-magic: 0.1.0 read-yaml-file@2.1.0: @@ -12334,24 +12730,26 @@ snapshots: '@redis/search': 1.2.0(@redis/client@1.6.0) '@redis/time-series': 1.1.0(@redis/client@1.6.0) - reflect.getprototypeof@1.0.9: + reflect.getprototypeof@1.0.10: dependencies: call-bind: 1.0.8 define-properties: 1.2.1 - dunder-proto: 1.0.1 - es-abstract: 1.23.7 + es-abstract: 1.23.9 es-errors: 1.3.0 - get-intrinsic: 1.2.6 - gopd: 1.2.0 + es-object-atoms: 1.0.0 + get-intrinsic: 1.2.7 + get-proto: 1.0.1 which-builtin-type: 1.2.1 regenerator-runtime@0.14.1: {} - regexp.prototype.flags@1.5.3: + regexp.prototype.flags@1.5.4: dependencies: call-bind: 1.0.8 define-properties: 1.2.1 es-errors: 1.3.0 + get-proto: 1.0.1 + gopd: 1.2.0 set-function-name: 2.0.2 registry-auth-token@5.0.3: @@ -12439,7 +12837,7 @@ snapshots: rimraf@6.0.1: dependencies: - glob: 11.0.0 + glob: 11.0.1 package-json-from-dist: 1.0.1 roarr@2.15.4: @@ -12459,7 +12857,7 @@ snapshots: dependencies: call-bind: 1.0.8 call-bound: 1.0.3 - get-intrinsic: 1.2.6 + get-intrinsic: 1.2.7 has-symbols: 1.1.0 isarray: 2.0.5 @@ -12467,6 +12865,11 @@ snapshots: safe-buffer@5.2.1: {} + safe-push-apply@1.0.0: + dependencies: + es-errors: 1.3.0 + isarray: 2.0.5 + safe-regex-test@1.1.0: dependencies: call-bound: 1.0.3 @@ -12480,15 +12883,15 @@ snapshots: sax@1.4.1: {} - semantic-release@24.2.0(typescript@5.7.2): + semantic-release@24.2.1(typescript@5.7.3): dependencies: - '@semantic-release/commit-analyzer': 13.0.0(semantic-release@24.2.0(typescript@5.7.2)) + '@semantic-release/commit-analyzer': 13.0.1(semantic-release@24.2.1(typescript@5.7.3)) '@semantic-release/error': 4.0.0 - '@semantic-release/github': 11.0.1(semantic-release@24.2.0(typescript@5.7.2)) - '@semantic-release/npm': 12.0.1(semantic-release@24.2.0(typescript@5.7.2)) - '@semantic-release/release-notes-generator': 14.0.2(semantic-release@24.2.0(typescript@5.7.2)) + '@semantic-release/github': 11.0.1(semantic-release@24.2.1(typescript@5.7.3)) + '@semantic-release/npm': 12.0.1(semantic-release@24.2.1(typescript@5.7.3)) + '@semantic-release/release-notes-generator': 14.0.3(semantic-release@24.2.1(typescript@5.7.3)) aggregate-error: 5.0.0 - cosmiconfig: 9.0.0(typescript@5.7.2) + cosmiconfig: 9.0.0(typescript@5.7.3) debug: 4.4.0 env-ci: 11.1.0 execa: 9.5.2 @@ -12498,7 +12901,7 @@ snapshots: git-log-parser: 1.2.1 hook-std: 3.0.0 hosted-git-info: 8.0.2 - import-from-esm: 1.3.4 + import-from-esm: 2.0.0 lodash-es: 4.17.21 marked: 12.0.2 marked-terminal: 7.2.1(marked@12.0.2) @@ -12546,7 +12949,7 @@ snapshots: define-data-property: 1.1.4 es-errors: 1.3.0 function-bind: 1.1.2 - get-intrinsic: 1.2.6 + get-intrinsic: 1.2.7 gopd: 1.2.0 has-property-descriptors: 1.0.2 @@ -12557,6 +12960,12 @@ snapshots: functions-have-names: 1.2.3 has-property-descriptors: 1.0.2 + set-proto@1.0.0: + dependencies: + dunder-proto: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 @@ -12578,14 +12987,14 @@ snapshots: dependencies: call-bound: 1.0.3 es-errors: 1.3.0 - get-intrinsic: 1.2.6 + get-intrinsic: 1.2.7 object-inspect: 1.13.3 side-channel-weakmap@1.0.2: dependencies: call-bound: 1.0.3 es-errors: 1.3.0 - get-intrinsic: 1.2.6 + get-intrinsic: 1.2.7 object-inspect: 1.13.3 side-channel-map: 1.0.1 @@ -12760,7 +13169,7 @@ snapshots: call-bound: 1.0.3 define-data-property: 1.1.4 define-properties: 1.2.1 - es-abstract: 1.23.7 + es-abstract: 1.23.9 es-object-atoms: 1.0.0 has-property-descriptors: 1.0.2 @@ -12963,26 +13372,26 @@ snapshots: trough@1.0.5: {} - ts-api-utils@1.4.3(typescript@5.7.2): + ts-api-utils@2.0.0(typescript@5.7.3): dependencies: - typescript: 5.7.2 + typescript: 5.7.3 - ts-essentials@10.0.3(typescript@5.7.2): + ts-essentials@10.0.4(typescript@5.7.3): optionalDependencies: - typescript: 5.7.2 + typescript: 5.7.3 - ts-jest@29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(jest@29.7.0(@types/node@20.17.10)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@20.17.10)(typescript@5.7.2)))(typescript@5.7.2): + ts-jest@29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(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: bs-logger: 0.2.6 ejs: 3.1.10 fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@20.17.10)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@20.17.10)(typescript@5.7.2)) + 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)) jest-util: 29.7.0 json5: 2.2.3 lodash.memoize: 4.1.2 make-error: 1.3.6 semver: 7.6.3 - typescript: 5.7.2 + typescript: 5.7.3 yargs-parser: 21.1.1 optionalDependencies: '@babel/core': 7.26.0 @@ -12990,25 +13399,25 @@ snapshots: '@jest/types': 29.6.3 babel-jest: 29.7.0(@babel/core@7.26.0) - ts-node@10.9.2(@swc/core@1.10.1)(@types/node@20.17.10)(typescript@5.7.2): + ts-node@10.9.2(@swc/core@1.10.7)(@types/node@22.10.5)(typescript@5.7.3): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.11 '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 20.17.10 + '@types/node': 22.10.5 acorn: 8.14.0 acorn-walk: 8.3.4 arg: 4.1.3 create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 - typescript: 5.7.2 + typescript: 5.7.3 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 optionalDependencies: - '@swc/core': 1.10.1 + '@swc/core': 1.10.7 tsconfig-paths@3.15.0: dependencies: @@ -13021,10 +13430,10 @@ snapshots: tslib@2.8.1: {} - tsutils@3.21.0(typescript@5.7.2): + tsutils@3.21.0(typescript@5.7.3): dependencies: tslib: 1.14.1 - typescript: 5.7.2 + typescript: 5.7.3 tunnel-agent@0.6.0: dependencies: @@ -13063,7 +13472,7 @@ snapshots: type-fest@2.19.0: {} - type-fest@4.30.2: {} + type-fest@4.32.0: {} typed-array-buffer@1.0.3: dependencies: @@ -13087,7 +13496,7 @@ snapshots: gopd: 1.2.0 has-proto: 1.2.0 is-typed-array: 1.1.15 - reflect.getprototypeof: 1.0.9 + reflect.getprototypeof: 1.0.10 typed-array-length@1.0.7: dependencies: @@ -13096,7 +13505,7 @@ snapshots: gopd: 1.2.0 is-typed-array: 1.1.15 possible-typed-array-names: 1.0.0 - reflect.getprototypeof: 1.0.9 + reflect.getprototypeof: 1.0.10 typed-rest-client@2.1.0: dependencies: @@ -13110,7 +13519,7 @@ snapshots: dependencies: is-typedarray: 1.0.0 - typescript@5.7.2: {} + typescript@5.7.3: {} uc.micro@2.1.0: {} @@ -13127,7 +13536,7 @@ snapshots: underscore@1.13.7: {} - undici-types@6.19.8: {} + undici-types@6.20.0: {} unicode-emoji-modifier-base@1.0.0: {} @@ -13192,9 +13601,9 @@ snapshots: upath@2.0.1: {} - update-browserslist-db@1.1.1(browserslist@4.24.3): + update-browserslist-db@1.1.2(browserslist@4.24.4): dependencies: - browserslist: 4.24.3 + browserslist: 4.24.4 escalade: 3.2.0 picocolors: 1.1.1 @@ -13212,7 +13621,7 @@ snapshots: dependencies: inherits: 2.0.4 is-arguments: 1.2.0 - is-generator-function: 1.0.10 + is-generator-function: 1.1.0 is-typed-array: 1.1.15 which-typed-array: 1.1.18 @@ -13273,10 +13682,10 @@ snapshots: call-bound: 1.0.3 function.prototype.name: 1.1.8 has-tostringtag: 1.0.2 - is-async-function: 2.0.0 + is-async-function: 2.1.0 is-date-object: 1.1.0 is-finalizationregistry: 1.1.1 - is-generator-function: 1.0.10 + is-generator-function: 1.1.0 is-regex: 1.2.1 is-weakref: 1.1.0 isarray: 2.0.5 @@ -13377,7 +13786,7 @@ snapshots: yallist@5.0.0: {} - yaml@2.6.1: {} + yaml@2.7.0: {} yargs-parser@18.1.3: dependencies: diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile index 864130d55fce02..9a695353f488f3 100644 --- a/tools/docker/Dockerfile +++ b/tools/docker/Dockerfile @@ -5,23 +5,23 @@ ARG BASE_IMAGE_TYPE=slim # -------------------------------------- # slim image # -------------------------------------- -FROM ghcr.io/renovatebot/base-image:9.27.10@sha256:bb66c6760180eca52655624f8cfb86e1581ba56ba014d788eb5edddd3fb4405f AS slim-base +FROM ghcr.io/renovatebot/base-image:9.33.2@sha256:8b958697ed82f189abb46c92591cbd96600977696014e971c825d776891aac5a AS slim-base # -------------------------------------- # full image # -------------------------------------- -FROM ghcr.io/renovatebot/base-image:9.27.10-full@sha256:7345a26aba660efc97621a291785e951079f3e03077a6e57b06a022a0cb22c54 AS full-base +FROM ghcr.io/renovatebot/base-image:9.33.2-full@sha256:a0f2a13b6857c9cfba1c810fed13f4ef2c25020645a006bbe80b6f87cfb535e3 AS full-base ENV RENOVATE_BINARY_SOURCE=global # -------------------------------------- # build image # -------------------------------------- -FROM --platform=$BUILDPLATFORM ghcr.io/renovatebot/base-image:9.27.10@sha256:bb66c6760180eca52655624f8cfb86e1581ba56ba014d788eb5edddd3fb4405f AS build +FROM --platform=$BUILDPLATFORM ghcr.io/renovatebot/base-image:9.33.2@sha256:8b958697ed82f189abb46c92591cbd96600977696014e971c825d776891aac5a AS build # We want a specific node version here # renovate: datasource=node-version -RUN install-tool node 22.11.0 +RUN install-tool node 22.13.0 WORKDIR /usr/local/renovate 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', diff --git a/tools/docs/manager.ts b/tools/docs/manager.ts index 73da0d3c09ff04..70b9c0a2435b72 100644 --- a/tools/docs/manager.ts +++ b/tools/docs/manager.ts @@ -48,6 +48,7 @@ export const CategoryNames: Record = { dotnet: '.NET', elixir: 'Elixir', golang: 'Go', + haskell: 'Haskell', helm: 'Helm', iac: 'Infrastructure as Code', java: 'Java', diff --git a/tools/docs/presets.ts b/tools/docs/presets.ts index 7c08b7eccffb1e..3a82d844fc46cd 100644 --- a/tools/docs/presets.ts +++ b/tools/docs/presets.ts @@ -70,7 +70,10 @@ export async function generatePresets(dist: string): Promise { if (presetDescription) { body += `\n\n${presetDescription}\n`; } else { - logger.warn(`Preset ${name}:${preset} has no description`); + logger.warn( + { preset: `${name}:${preset}` }, + 'Preset has no description', + ); } body += '\n```json\n'; body += JSON.stringify(value, null, 2); diff --git a/tools/mkdocs/mkdocs.yml b/tools/mkdocs/mkdocs.yml index cf68267748d9c9..5b8eef98dd2962 100644 --- a/tools/mkdocs/mkdocs.yml +++ b/tools/mkdocs/mkdocs.yml @@ -59,7 +59,7 @@ theme: # The custom_dir points to the overrides folder, this folder has the code for our announcement bar. # The easiest way to disable the announcement bar is to comment out the custom_dir: overrides entry in this mkdocs.yml file. # https://squidfunk.github.io/mkdocs-material/customization/#setup-and-theme-structure - custom_dir: overrides + # custom_dir: overrides logo: 'assets/images/logo.png' favicon: 'assets/images/logo.png'