diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index ff52204e6e3a68..6daf80c6940f4a 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -19,7 +19,8 @@ "dbaeumer.vscode-eslint", "esbenp.prettier-vscode", "orta.vscode-jest", - "EditorConfig.editorconfig" + "editorconfig.editorconfig", + "github.vscode-github-actions" ] } }, diff --git a/.github/label-actions.yml b/.github/label-actions.yml index e0f3205b11fd67..5e85dbe2729290 100644 --- a/.github/label-actions.yml +++ b/.github/label-actions.yml @@ -23,12 +23,12 @@ The Renovate team -'logs:problem': +'needs-logs': comment: > Hi there, - We found a problem with the logs. + This issue or discussion is missing some logs, making it difficult or impossible to help you. Depending on which situation applies follow one, some or all of these instructions. @@ -178,6 +178,26 @@ The Renovate team +'pr:discussion-first': + comment: > + **Please create a GitHub Discussion before continuing with this PR.** + + + Thank you for your PR, but we need to discuss the requirements and implementation first. + This PR will be closed, but you can reopen it after the discussion has been resolved. + + + Thanks, The Renovate team + close: true + +'needs-details': + comment: > + Hi there, + + + This discussion is missing some details, making it difficult or impossible to help you. + Please try again to provide more details. + 'needs-discussion': unlabel: - 'type:bug' @@ -199,9 +219,9 @@ lock: true lock-reason: 'resolved' -'needs-code-formatting': +'format-code-comments': comment: > - Hi, please format your code or logs so they're readable. + Hi, please format any copy/pasted code or logs so they're readable. You can find a Markdown code formatting guide [here](https://www.markdownguide.org/basic-syntax/#code) as well as some GitHub-specific information formatting code blocks [here](https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/creating-and-highlighting-code-blocks). diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8f63d1a60ddb5f..7b3f881a4421d5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -97,7 +97,7 @@ jobs: run: yarn jest --ci --coverage ${{ env.coverage }} - name: Codecov - uses: codecov/codecov-action@894ff025c7b54547a9a2a1e9f228beae737ad3c2 # v3.1.3 + uses: codecov/codecov-action@eaaf4bedf32dbdc6b720b63067d99c4d77d6047d # v3.1.4 if: always() && env.coverage == 'true' - name: E2E Test diff --git a/.github/workflows/label-actions.yml b/.github/workflows/label-actions.yml index fbdde3bb903832..e266ffa46be6e2 100644 --- a/.github/workflows/label-actions.yml +++ b/.github/workflows/label-actions.yml @@ -5,11 +5,14 @@ on: types: [labeled] discussion: types: [labeled] + pull_request_target: + types: [labeled] permissions: contents: read issues: write discussions: write + pull-requests: write jobs: reaction: @@ -18,4 +21,3 @@ jobs: - uses: dessant/label-actions@074b96a62f35c226ecb38e840f44941bde0343a6 # v3.0.0 with: github-token: ${{ github.token }} - process-only: 'issues, discussions' diff --git a/.gitpod.yml b/.gitpod.yml deleted file mode 100644 index 7c7efce0d8beca..00000000000000 --- a/.gitpod.yml +++ /dev/null @@ -1,7 +0,0 @@ -tasks: - - init: > - nvm install 18 && - nvm use 18 && - yarn install && - yarn run build - command: yarn run start diff --git a/.husky/pre-commit b/.husky/pre-commit index 863d3997b02d17..f642535569f8dc 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,7 +1,6 @@ #!/bin/sh . "$(dirname "$0")/_/husky.sh" -yarn lint-staged yarn ls-lint BRANCH_NAME=$(git branch --show-current) diff --git a/.lintstagedrc.json b/.lintstagedrc.json deleted file mode 100644 index 1d133dcf4f16c4..00000000000000 --- a/.lintstagedrc.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "*.md": "markdownlint-cli2-fix", - "**/*.{ts,js,mjs,cjs}": "eslint --cache --fix", - "*": "prettier --cache --ignore-unknown --write" -} diff --git a/.vscode/extensions.json b/.vscode/extensions.json index e569c62d68ba77..a45d022d1c1ebc 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -3,6 +3,7 @@ "dbaeumer.vscode-eslint", "esbenp.prettier-vscode", "orta.vscode-jest", - "EditorConfig.editorconfig" + "editorconfig.editorconfig", + "github.vscode-github-actions" ] } diff --git a/docs/development/remote-development.md b/docs/development/remote-development.md index 24d2ba815b0577..d3f6c4ca0f3683 100644 --- a/docs/development/remote-development.md +++ b/docs/development/remote-development.md @@ -29,77 +29,7 @@ You'll use the same code editor and have the same config as all other developers - Waiting for the remote container to start - If your internet is down you can't work -- If Gitpod or Codespaces is down you can't work - -## Gitpod - -You can use [Gitpod](https://gitpod.io/) for light development work like: - -- Editing the docs -- Running ESLint, Prettier - -For proper development, use GitHub Codespaces. - -The config file for Gitpod is `.gitpod.yml` in the root of the repository. - -Gitpod gives you 500 free credits each month, which is enough for about 50 hours of work. - -### Gitpod tips - -- Use `yarn jest` to run the tests on Gitpod - -### Known problems with Gitpod - -There are two failing tests when running `yarn jest` on Gitpod: - -```bash -Summary of all failing tests - FAIL lib/util/git/index.spec.ts (635.102 s, 319 MB heap size) - ● util/git/index › isBranchModified() › should return false when author matches - - expected true to be false or Boolean(false) - - 283 | - 284 | it('should return false when author matches', async () => { - > 285 | expect(await git.isBranchModified('renovate/future_branch')).toBeFalse(); - | ^ - 286 | expect(await git.isBranchModified('renovate/future_branch')).toBeFalse(); - 287 | }); - 288 | - - at Object. (lib/util/git/index.spec.ts:285:68) - - ● util/git/index › isBranchModified() › should return false when author is ignored - - expected true to be false or Boolean(false) - - 291 | gitIgnoredAuthors: ['custom@example.com'], - 292 | }); - > 293 | expect(await git.isBranchModified('renovate/custom_author')).toBeFalse(); - | ^ - 294 | }); - 295 | - 296 | it('should return true when custom author is unknown', async () => { - - at Object. (lib/util/git/index.spec.ts:293:68) - - FAIL test/static-files.spec.ts (14.506 s, 288 MB heap size) - ● static-files › has same static files in lib and dist - - thrown: "Exceeded timeout of 10000 ms for a test. - Use jest.setTimeout(newTimeout) to increase the timeout value, if this is a long-running test." - - 36 | jest.setTimeout(10 * 1000); - 37 | - > 38 | it('has same static files in lib and dist', async () => { - | ^ - 39 | expect(await getFiles('dist')).toEqual(await getFiles('lib')); - 40 | }); - 41 | }); - - at test/static-files.spec.ts:38:3 - at Object. (test/static-files.spec.ts:34:1) -``` +- If Codespaces is down you can't work ## GitHub Codespaces diff --git a/docs/usage/configuration-options.md b/docs/usage/configuration-options.md index 6b01f12bebe36b..223da36102ff8a 100644 --- a/docs/usage/configuration-options.md +++ b/docs/usage/configuration-options.md @@ -448,6 +448,11 @@ Check out the default value for `commitMessage` to understand how this field is This is used to alter `commitMessage` and `prTitle` without needing to copy/paste the whole string. The "extra" is usually an identifier of the new version, e.g. "to v1.3.2" or "to tag 9.2". +## commitMessageLowerCase + +With `semanticCommits` pr- and commit-titles will by default (`"auto"`) be converted to all-lowercase. +Set this to `"never"` to leave the titles untouched, allowing uppercase characters in semantic commit titles. + ## commitMessagePrefix This is used to alter `commitMessage` and `prTitle` without needing to copy/paste the whole string. @@ -698,6 +703,19 @@ You can configure this to `true` if you prefer Renovate to close an existing Dep The labels only get updated when the Dependency Dashboard issue updates its content and/or title. It is pointless to edit the labels, as Renovate bot restores the labels on each run. +## dependencyDashboardOSVVulnerabilitySummary + +Use this option to control if the Dependency Dashboard lists the OSV-sourced CVEs for your repository. +You can choose from: + +- `none` (default) do not list any CVEs +- `unresolved` list CVEs that have no fixes +- `all` list all CVEs + +This feature is independent of the `osvVulnerabilityAlerts` option. + +The source of these CVEs is [OSV.dev](https://osv.dev/). + ## dependencyDashboardTitle Configure this option if you prefer a different title for the Dependency Dashboard. @@ -1190,6 +1208,23 @@ A preset alternative to the above is: } ``` +To match specific ports you have to add a protocol to `matchHost`: + +```json +{ + "hostRules": [ + { + "matchHost": "https://domain.com:9118", + "enabled": false + } + ] +} +``` + + +!!! warning + Using `matchHost` without a protocol behaves the same as if you had set no `matchHost` configuration. + !!! note Disabling a host is only 100% effective if added to self-hosted config. @@ -3140,6 +3175,7 @@ This feature works with the following managers: - [`kubernetes`](/modules/manager/kubernetes) - [`ansible`](/modules/manager/ansible) - [`droneci`](/modules/manager/droneci) +- [`terraform`](/modules/manager/terraform) ## registryUrls diff --git a/docs/usage/configuration-templates.md b/docs/usage/configuration-templates.md index d20c501df41b9e..ae35c8b6a8194a 100644 --- a/docs/usage/configuration-templates.md +++ b/docs/usage/configuration-templates.md @@ -14,8 +14,8 @@ If you change the `branchPrefix` while you have ignored some upgrades (closed PR `branchName` default value is `{{{branchPrefix}}}{{{additionalBranchPrefix}}}{{{branchTopic}}}`. -The most common branch name you will see looks like this: `renovate/react-17.x`. -In this example, the `branchPrefix` is the default `renovate/`, `additionalBranchPrefix` is empty, and `branchTopic` is `react-17.x`. +The most common branch name you will see looks like this: `renovate/react-18.x`. +In this example, the `branchPrefix` is the default `renovate/`, `additionalBranchPrefix` is empty, and `branchTopic` is `react-18.x`. Most users will be happy with the default `branchPrefix` of `renovate/`, but you can change this if you don't like the default. Say you don't want the forward slashes, in that case you would use `renovate-` as your `branchPrefix`. @@ -47,7 +47,7 @@ You may want to edit this. If you think your new `commitMessageTopic` is helpful for others, please [open a PR](https://github.com/renovatebot/renovate/pulls). `commitMessageExtra` refers to the version being updated to. -e.g. `to v17` for a major upgrade, or `to v17.0.2` for a patch update. +e.g. `to v18` for a major upgrade, or `to v18.0.2` for a patch update. It can be empty in some cases, like if the action/topic doesn't change a package version, e.g. `Pin Docker digests`. `commitMessageSuffix` defaults to empty but is currently used in two cases: diff --git a/docs/usage/docker.md b/docs/usage/docker.md index c28ce0c59b73ee..be4ba4f94da90b 100644 --- a/docs/usage/docker.md +++ b/docs/usage/docker.md @@ -388,7 +388,7 @@ To get access to the token a custom Renovate Docker image is needed that include The Dockerfile to create such an image can look like this: ```Dockerfile -FROM renovate/renovate:35.73.0 +FROM renovate/renovate:35.82.0 # 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/lib/config/index.spec.ts b/lib/config/index.spec.ts index 41deb82830f776..001ea8c8b53488 100644 --- a/lib/config/index.spec.ts +++ b/lib/config/index.spec.ts @@ -1,4 +1,5 @@ import { getConfig } from './defaults'; +import { filterConfig, getManagerConfig, mergeChildConfig } from './index'; jest.mock('../modules/datasource/npm'); try { @@ -11,7 +12,7 @@ const defaultConfig = getConfig(); describe('config/index', () => { describe('mergeChildConfig(parentConfig, childConfig)', () => { - it('merges', async () => { + it('merges', () => { const parentConfig = { ...defaultConfig }; const childConfig = { foo: 'bar', @@ -20,15 +21,14 @@ describe('config/index', () => { schedule: ['on monday'], }, }; - const configParser = await import('./index'); - const config = configParser.mergeChildConfig(parentConfig, childConfig); + const config = mergeChildConfig(parentConfig, childConfig); expect(config.foo).toBe('bar'); expect(config.rangeStrategy).toBe('replace'); expect(config.lockFileMaintenance.schedule).toEqual(['on monday']); expect(config.lockFileMaintenance).toMatchSnapshot(); }); - it('merges packageRules', async () => { + it('merges packageRules', () => { const parentConfig = { ...defaultConfig }; Object.assign(parentConfig, { packageRules: [{ a: 1 }, { a: 2 }], @@ -36,14 +36,13 @@ describe('config/index', () => { const childConfig = { packageRules: [{ a: 3 }, { a: 4 }], }; - const configParser = await import('./index'); - const config = configParser.mergeChildConfig(parentConfig, childConfig); + const config = mergeChildConfig(parentConfig, childConfig); expect(config.packageRules.map((rule) => rule.a)).toMatchObject([ 1, 2, 3, 4, ]); }); - it('merges constraints', async () => { + it('merges constraints', () => { const parentConfig = { ...defaultConfig }; Object.assign(parentConfig, { constraints: { @@ -56,8 +55,7 @@ describe('config/index', () => { node: '<15', }, }; - const configParser = await import('./index'); - const config = configParser.mergeChildConfig(parentConfig, childConfig); + const config = mergeChildConfig(parentConfig, childConfig); expect(config.constraints).toMatchSnapshot(); expect(config.constraints.node).toBe('<15'); }); @@ -75,39 +73,48 @@ describe('config/index', () => { expect(config.packageRules).toHaveLength(2); }); - it('handles null child packageRules', async () => { + it('handles null child packageRules', () => { const parentConfig = { ...defaultConfig }; parentConfig.packageRules = [{ a: 3 }, { a: 4 }]; - const configParser = await import('./index'); - const config = configParser.mergeChildConfig(parentConfig, {}); + const config = mergeChildConfig(parentConfig, {}); expect(config.packageRules).toHaveLength(2); }); - it('handles undefined childConfig', async () => { + it('handles undefined childConfig', () => { const parentConfig = { ...defaultConfig }; - const configParser = await import('./index'); - const config = configParser.mergeChildConfig(parentConfig, undefined); + const config = mergeChildConfig(parentConfig, undefined); expect(config).toMatchObject(parentConfig); }); - it('getManagerConfig()', async () => { + it('getManagerConfig()', () => { const parentConfig = { ...defaultConfig }; - const configParser = await import('./index'); - const config = configParser.getManagerConfig(parentConfig, 'npm'); + const config = getManagerConfig(parentConfig, 'npm'); expect(config).toContainEntries([ ['fileMatch', ['(^|/)package\\.json$']], ['rollbackPrs', true], ]); - expect( - configParser.getManagerConfig(parentConfig, 'html') - ).toContainEntries([['fileMatch', ['\\.html?$']]]); + expect(getManagerConfig(parentConfig, 'html')).toContainEntries([ + ['fileMatch', ['\\.html?$']], + ]); }); - it('filterConfig()', async () => { + it('filterConfig()', () => { const parentConfig = { ...defaultConfig }; - const configParser = await import('./index'); - const config = configParser.filterConfig(parentConfig, 'pr'); + const config = filterConfig(parentConfig, 'pr'); expect(config).toBeObject(); }); + + it('highest vulnerabilitySeverity maintained when config is vulnerability alert', () => { + const parentConfig = { ...defaultConfig }; + Object.assign(parentConfig, { + isVulnerabilityAlert: true, + vulnerabilitySeverity: 'HIGH', + }); + const childConfig = { + vulnerabilitySeverity: 'CRITICAL', + }; + const config = mergeChildConfig(parentConfig, childConfig); + expect(config.vulnerabilitySeverity).toBe('CRITICAL'); + }); }); }); diff --git a/lib/config/options/index.ts b/lib/config/options/index.ts index a020d9dae72157..a41fb0fdd7056b 100644 --- a/lib/config/options/index.ts +++ b/lib/config/options/index.ts @@ -520,6 +520,15 @@ const options: RenovateOptions[] = [ subType: 'string', default: null, }, + { + name: 'dependencyDashboardOSVVulnerabilitySummary', + description: + 'Control if the Dependency Dashboard issue lists CVEs supplied by [osv.dev](https://osv.dev).', + type: 'string', + allowedValues: ['none', 'all', 'unresolved'], + default: 'none', + experimental: true, + }, { name: 'configWarningReuseIssue', description: @@ -1549,6 +1558,13 @@ const options: RenovateOptions[] = [ type: 'string', default: 'deps', }, + { + name: 'commitMessageLowerCase', + description: 'Lowercase PR- and commit titles.', + type: 'string', + allowedValues: ['auto', 'never'], + default: 'auto', + }, // PR Behaviour { name: 'rollbackPrs', diff --git a/lib/config/presets/internal/default.ts b/lib/config/presets/internal/default.ts index 0c4340b17f996e..4a7ca0f2577a20 100644 --- a/lib/config/presets/internal/default.ts +++ b/lib/config/presets/internal/default.ts @@ -2,6 +2,15 @@ import type { Preset } from '../types'; /* eslint sort-keys: ["error", "asc", {caseSensitive: false, natural: true}] */ export const presets: Record = { + approveMajorUpdates: { + description: 'Require dependency dashboard approval for `major` updates.', + packageRules: [ + { + dependencyDashboardApproval: true, + matchUpdateTypes: ['major'], + }, + ], + }, assignAndReview: { description: 'Set `{{arg0}}` as assignee and reviewer of PRs.', extends: [':assignee({{arg0}})', ':reviewer({{arg0}})'], diff --git a/lib/config/presets/internal/monorepo.ts b/lib/config/presets/internal/monorepo.ts index 122df520a6aec5..2ffd34584f2e7b 100644 --- a/lib/config/presets/internal/monorepo.ts +++ b/lib/config/presets/internal/monorepo.ts @@ -73,7 +73,9 @@ const repoGroups = { 'https://github.com/dotnet/aspnetcore', 'https://github.com/dotnet/efcore', 'https://github.com/dotnet/extensions', + 'https://github.com/dotnet/maui', 'https://github.com/dotnet/runtime', + 'https://github.com/dotnet/sdk', ], 'dotnet-azure-ad-identitymodel-extensions': 'https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet', @@ -206,6 +208,7 @@ const repoGroups = { 'reg-suit': 'https://github.com/reg-viz/reg-suit', remark: 'https://github.com/remarkjs/remark', remix: 'https://github.com/remix-run/remix', + rjsf: 'https://github.com/rjsf-team/react-jsonschema-form', router5: 'https://github.com/router5/router5', 'rust-futures': 'https://github.com/rust-lang/futures-rs', 'rust-wasm-bindgen': 'https://github.com/rustwasm/wasm-bindgen', diff --git a/lib/config/presets/internal/regex-managers.ts b/lib/config/presets/internal/regex-managers.ts index d3021f96ee7649..c4574bcc09ac44 100644 --- a/lib/config/presets/internal/regex-managers.ts +++ b/lib/config/presets/internal/regex-managers.ts @@ -7,7 +7,10 @@ export const presets: Record = { description: 'Update `_VERSION` variables in Dockerfiles.', regexManagers: [ { - fileMatch: ['(^|/|\\.)Dockerfile$', '(^|/)Dockerfile[^/]*$'], + fileMatch: [ + '(^|/|\\.)([Dd]ocker|[Cc]ontainer)file$', + '(^|/)([Dd]ocker|[Cc]ontainer)file[^/]*$', + ], matchStrings: [ '# renovate: datasource=(?[a-z-]+?) depName=(?[^\\s]+?)(?: (lookupName|packageName)=(?[^\\s]+?))?(?: versioning=(?[^\\s]+?))?(?: registryUrl=(?[^\\s]+?))?\\s(?:ENV|ARG) .+?_VERSION[ =]"?(?.+?)"?\\s', ], diff --git a/lib/config/presets/local/index.ts b/lib/config/presets/local/index.ts index ac8e2a69703049..6f99390a6c676d 100644 --- a/lib/config/presets/local/index.ts +++ b/lib/config/presets/local/index.ts @@ -24,6 +24,7 @@ const resolvers = { gitea, github, gitlab, + local: null, } satisfies Record; export function getPreset({ diff --git a/lib/config/types.ts b/lib/config/types.ts index 0df00b27a9a688..5c390b09c825a0 100644 --- a/lib/config/types.ts +++ b/lib/config/types.ts @@ -78,6 +78,7 @@ export interface RenovateSharedConfig { automergeSchedule?: string[]; semanticCommits?: 'auto' | 'enabled' | 'disabled'; semanticCommitScope?: string | null; + commitMessageLowerCase?: 'auto' | 'never'; semanticCommitType?: string; suppressNotifications?: string[]; timezone?: string; @@ -231,6 +232,7 @@ export interface RenovateConfig dependencyDashboardHeader?: string; dependencyDashboardFooter?: string; dependencyDashboardLabels?: string[]; + dependencyDashboardOSVVulnerabilitySummary?: 'none' | 'all' | 'unresolved'; packageFile?: string; packageRules?: PackageRule[]; postUpdateOptions?: string[]; @@ -251,6 +253,7 @@ export interface RenovateConfig warnings?: ValidationMessage[]; vulnerabilityAlerts?: RenovateSharedConfig; osvVulnerabilityAlerts?: boolean; + vulnerabilitySeverity?: string; regexManagers?: RegExManager[]; fetchReleaseNotes?: boolean; @@ -309,6 +312,7 @@ export interface PackageRule UpdateConfig, Record { description?: string | string[]; + isVulnerabilityAlert?: boolean; matchFiles?: string[]; matchPaths?: string[]; matchLanguages?: string[]; @@ -333,6 +337,7 @@ export interface PackageRule matchUpdateTypes?: UpdateType[]; matchConfidence?: MergeConfidence[]; registryUrls?: string[] | null; + vulnerabilitySeverity?: string; } export interface ValidationMessage { diff --git a/lib/config/utils.ts b/lib/config/utils.ts index 106d9e168f1453..140d5f0df030a6 100644 --- a/lib/config/utils.ts +++ b/lib/config/utils.ts @@ -1,4 +1,5 @@ import { logger } from '../logger'; +import { getHighestVulnerabilitySeverity } from '../util/vulnerability/utils'; import * as options from './options'; import type { RenovateConfig } from './types'; @@ -13,6 +14,15 @@ export function mergeChildConfig< const parentConfig = structuredClone(parent); const childConfig = structuredClone(child); const config: Record = { ...parentConfig, ...childConfig }; + + // Ensure highest severity survives parent / child merge + if (config?.isVulnerabilityAlert) { + config.vulnerabilitySeverity = getHighestVulnerabilitySeverity( + parent, + child + ); + } + for (const option of options.getOptions()) { if ( option.mergeable && @@ -20,6 +30,7 @@ export function mergeChildConfig< parentConfig[option.name] ) { logger.trace(`mergeable option: ${option.name}`); + if (option.name === 'constraints') { config[option.name] = { ...parentConfig[option.name], diff --git a/lib/constants/platforms.ts b/lib/constants/platforms.ts index f3a1e71ac8b7ba..049155bd3ba43c 100644 --- a/lib/constants/platforms.ts +++ b/lib/constants/platforms.ts @@ -5,7 +5,8 @@ export type PlatformId = | 'bitbucket-server' | 'gitea' | 'github' - | 'gitlab'; + | 'gitlab' + | 'local'; export const GITHUB_API_USING_HOST_TYPES = [ 'github', diff --git a/lib/logger/utils.spec.ts b/lib/logger/utils.spec.ts index 376584700b8f40..ac944c5ad2ca9c 100644 --- a/lib/logger/utils.spec.ts +++ b/lib/logger/utils.spec.ts @@ -1,4 +1,9 @@ -import { sanitizeValue, validateLogLevel } from './utils'; +import { z } from 'zod'; +import prepareError, { + prepareZodIssues, + sanitizeValue, + validateLogLevel, +} from './utils'; describe('logger/utils', () => { afterEach(() => { @@ -46,4 +51,138 @@ describe('logger/utils', () => { `('sanitizeValue("$input") == "$output"', ({ input, output }) => { expect(sanitizeValue(input)).toBe(output); }); + + describe('prepareError', () => { + function getError( + schema: T, + input: unknown + ): z.ZodError | null { + try { + schema.parse(input); + } catch (error) { + if (error instanceof z.ZodError) { + return error; + } + } + throw new Error('Expected error'); + } + + function prepareIssues( + schema: T, + input: unknown + ): unknown | null { + const error = getError(schema, input); + return error ? prepareZodIssues(error.format()) : null; + } + + it('prepareZodIssues', () => { + expect(prepareIssues(z.string(), 42)).toBe( + 'Expected string, received number' + ); + + expect(prepareIssues(z.string().array(), 42)).toBe( + 'Expected array, received number' + ); + + expect( + prepareIssues(z.string().array(), ['foo', 'bar', 42, 42, 42, 42, 42]) + ).toEqual({ + '2': 'Expected string, received number', + '3': 'Expected string, received number', + '4': 'Expected string, received number', + ___: '... 2 more', + }); + + expect( + prepareIssues(z.record(z.string()), { + foo: 'foo', + bar: 'bar', + key1: 42, + key2: 42, + key3: 42, + key4: 42, + key5: 42, + }) + ).toEqual({ + key1: 'Expected string, received number', + key2: 'Expected string, received number', + key3: 'Expected string, received number', + ___: '... 2 more', + }); + + expect( + prepareIssues( + z.object({ + foo: z.object({ + bar: z.string(), + }), + }), + { foo: { bar: [], baz: 42 } } + ) + ).toEqual({ + foo: { + bar: 'Expected string, received array', + }, + }); + + expect( + prepareIssues( + z.discriminatedUnion('type', [ + z.object({ type: z.literal('foo') }), + z.object({ type: z.literal('bar') }), + ]), + { type: 'baz' } + ) + ).toEqual({ + type: "Invalid discriminator value. Expected 'foo' | 'bar'", + }); + + expect( + prepareIssues( + z.discriminatedUnion('type', [ + z.object({ type: z.literal('foo') }), + z.object({ type: z.literal('bar') }), + ]), + {} + ) + ).toEqual({ + type: "Invalid discriminator value. Expected 'foo' | 'bar'", + }); + + expect( + prepareIssues( + z.discriminatedUnion('type', [ + z.object({ type: z.literal('foo') }), + z.object({ type: z.literal('bar') }), + ]), + 42 + ) + ).toBe('Expected object, received number'); + }); + + it('prepareError', () => { + const err = getError( + z.object({ + foo: z.object({ + bar: z.object({ + baz: z.string(), + }), + }), + }), + { foo: { bar: { baz: 42 } } } + ); + + expect(prepareError(err!)).toEqual({ + issues: { + foo: { + bar: { + baz: 'Expected string, received number', + }, + }, + }, + message: 'Schema error', + stack: expect.stringMatching(/^ZodError: Schema error/), + }); + }); + }); }); diff --git a/lib/logger/utils.ts b/lib/logger/utils.ts index 4d0297cedb823b..84144229650e37 100644 --- a/lib/logger/utils.ts +++ b/lib/logger/utils.ts @@ -3,6 +3,7 @@ import is from '@sindresorhus/is'; import bunyan from 'bunyan'; import fs from 'fs-extra'; import { RequestError as HttpError } from 'got'; +import { ZodError } from 'zod'; import { redactedFields, sanitize } from '../util/sanitize'; import type { BunyanRecord, BunyanStream } from './types'; @@ -46,7 +47,74 @@ const contentFields = [ 'yarnLockParsed', ]; +type ZodShortenedIssue = + | null + | string + | string[] + | { + [key: string]: ZodShortenedIssue; + }; + +export function prepareZodIssues(input: unknown): ZodShortenedIssue { + // istanbul ignore if + if (!is.plainObject(input)) { + return null; + } + + let err: null | string | string[] = null; + if (is.array(input._errors, is.string)) { + // istanbul ignore else + if (input._errors.length === 1) { + err = input._errors[0]; + } else if (input._errors.length > 1) { + err = input._errors; + } else { + err = null; + } + } + delete input._errors; + + if (is.emptyObject(input)) { + return err; + } + + const output: Record = {}; + const entries = Object.entries(input); + for (const [key, value] of entries.slice(0, 3)) { + const child = prepareZodIssues(value); + if (child !== null) { + output[key] = child; + } + } + + if (entries.length > 3) { + output['___'] = `... ${entries.length - 3} more`; + } + + return output; +} + +export function prepareZodError(err: ZodError): Record { + // istanbul ignore next + Object.defineProperty(err, 'message', { + get: () => 'Schema error', + set: (_) => { + _; + }, + }); + + return { + message: err.message, + stack: err.stack, + issues: prepareZodIssues(err.format()), + }; +} + export default function prepareError(err: Error): Record { + if (err instanceof ZodError) { + return prepareZodError(err); + } + const response: Record = { ...err, }; diff --git a/lib/modules/datasource/metadata-manual.ts b/lib/modules/datasource/metadata-manual.ts index 84ead99902cdba..f475f5e8072cbe 100644 --- a/lib/modules/datasource/metadata-manual.ts +++ b/lib/modules/datasource/metadata-manual.ts @@ -94,6 +94,10 @@ export const manualSourceUrls: Record> = { kubernetes: { node: 'https://github.com/nodejs/node', }, + maven: { + 'com.figure.gradle.semver-plugin:com.figure.gradle.semver-plugin.gradle.plugin': + 'https://github.com/FigureTechnologies/gradle-semver-plugin', + }, npm: { node: 'https://github.com/nodejs/node', }, diff --git a/lib/modules/datasource/pypi/index.ts b/lib/modules/datasource/pypi/index.ts index 44acf798b116db..6757b39e594391 100644 --- a/lib/modules/datasource/pypi/index.ts +++ b/lib/modules/datasource/pypi/index.ts @@ -21,9 +21,9 @@ export class PypiDatasource extends Datasource { override readonly customRegistrySupport = true; - override readonly defaultRegistryUrls = [ - process.env.PIP_INDEX_URL ?? 'https://pypi.org/pypi/', - ]; + static readonly defaultURL = + process.env.PIP_INDEX_URL ?? 'https://pypi.org/pypi/'; + override readonly defaultRegistryUrls = [PypiDatasource.defaultURL]; override readonly defaultVersioning = pep440.id; diff --git a/lib/modules/datasource/rubygems/__fixtures__/rails/info.json b/lib/modules/datasource/rubygems/__fixtures__/rails/info.json index 844ef31bf05509..40b11b0cd0d43c 100644 --- a/lib/modules/datasource/rubygems/__fixtures__/rails/info.json +++ b/lib/modules/datasource/rubygems/__fixtures__/rails/info.json @@ -1 +1 @@ -{"name":"rails","downloads":156058530,"version":"5.2.2","version_downloads":385084,"platform":"ruby","authors":"David Heinemeier Hansson","info":"Ruby on Rails is a full-stack web framework optimized for programmer happiness and sustainable productivity. It encourages beautiful code by favoring convention over configuration.","licenses":["MIT"],"metadata":{},"sha":"d9ff5d9be16ee277dfc8f3c760bf171aa497d8685ec5c8988fba21a3dbd72cd5","project_uri":"https://rubygems.org/gems/rails","gem_uri":"https://rubygems.org/gems/rails-5.2.2.gem","homepage_uri":"http://rubyonrails.org","wiki_uri":"","documentation_uri":"http://api.rubyonrails.org","mailing_list_uri":"http://groups.google.com/group/rubyonrails-talk","source_code_uri":"http://github.com/rails/rails","bug_tracker_uri":"http://github.com/rails/rails/issues","changelog_uri":null,"dependencies":{"development":[],"runtime":[{"name":"actioncable","requirements":"= 5.2.2"},{"name":"actionmailer","requirements":"= 5.2.2"},{"name":"actionpack","requirements":"= 5.2.2"},{"name":"actionview","requirements":"= 5.2.2"},{"name":"activejob","requirements":"= 5.2.2"},{"name":"activemodel","requirements":"= 5.2.2"},{"name":"activerecord","requirements":"= 5.2.2"},{"name":"activestorage","requirements":"= 5.2.2"},{"name":"activesupport","requirements":"= 5.2.2"},{"name":"bundler","requirements":"\u003e= 1.3.0"},{"name":"railties","requirements":"= 5.2.2"},{"name":"sprockets-rails","requirements":"\u003e= 2.0.0"}]}} +{"name":"rails","downloads":156058530,"version":"5.2.2","version_downloads":385084,"platform":"ruby","authors":"David Heinemeier Hansson","info":"Ruby on Rails is a full-stack web framework optimized for programmer happiness and sustainable productivity. It encourages beautiful code by favoring convention over configuration.","licenses":["MIT"],"metadata":{},"sha":"d9ff5d9be16ee277dfc8f3c760bf171aa497d8685ec5c8988fba21a3dbd72cd5","project_uri":"https://rubygems.org/gems/rails","gem_uri":"https://rubygems.org/gems/rails-5.2.2.gem","homepage_uri":"http://rubyonrails.org","wiki_uri":"","documentation_uri":"http://api.rubyonrails.org","mailing_list_uri":"http://groups.google.com/group/rubyonrails-talk","source_code_uri":"http://github.com/rails/rails","bug_tracker_uri":"http://github.com/rails/rails/issues","changelog_uri":"https://www.railschangelog.com/","dependencies":{"development":[],"runtime":[{"name":"actioncable","requirements":"= 5.2.2"},{"name":"actionmailer","requirements":"= 5.2.2"},{"name":"actionpack","requirements":"= 5.2.2"},{"name":"actionview","requirements":"= 5.2.2"},{"name":"activejob","requirements":"= 5.2.2"},{"name":"activemodel","requirements":"= 5.2.2"},{"name":"activerecord","requirements":"= 5.2.2"},{"name":"activestorage","requirements":"= 5.2.2"},{"name":"activesupport","requirements":"= 5.2.2"},{"name":"bundler","requirements":"\u003e= 1.3.0"},{"name":"railties","requirements":"= 5.2.2"},{"name":"sprockets-rails","requirements":"\u003e= 2.0.0"}]}} diff --git a/lib/modules/datasource/rubygems/__snapshots__/index.spec.ts.snap b/lib/modules/datasource/rubygems/__snapshots__/index.spec.ts.snap index 2233e2de00dcf0..523f011b849207 100644 --- a/lib/modules/datasource/rubygems/__snapshots__/index.spec.ts.snap +++ b/lib/modules/datasource/rubygems/__snapshots__/index.spec.ts.snap @@ -5,1359 +5,1020 @@ exports[`modules/datasource/rubygems/index getReleases returns a dep for GitHub "registryUrl": "https://rubygems.pkg.github.com/example", "releases": [ { - "rubyPlatform": "ruby", "version": "0.8.0", }, { - "rubyPlatform": "ruby", "version": "0.8.5", }, { - "rubyPlatform": "ruby", "version": "0.9.0", }, { - "rubyPlatform": "ruby", "version": "0.9.1", }, { - "rubyPlatform": "ruby", "version": "0.9.2", }, { - "rubyPlatform": "ruby", "version": "0.9.3", }, { - "rubyPlatform": "ruby", "version": "0.9.4", }, { - "rubyPlatform": "ruby", "version": "0.9.4.1", }, { - "rubyPlatform": "ruby", "version": "0.9.5", }, { - "rubyPlatform": "ruby", "version": "0.10.0", }, { - "rubyPlatform": "ruby", "version": "0.10.1", }, { - "rubyPlatform": "ruby", "version": "0.11.0", }, { - "rubyPlatform": "ruby", "version": "0.11.1", }, { - "rubyPlatform": "ruby", "version": "0.12.0", }, { - "rubyPlatform": "ruby", "version": "0.12.1", }, { - "rubyPlatform": "ruby", "version": "0.13.0", }, { - "rubyPlatform": "ruby", "version": "0.13.1", }, { - "rubyPlatform": "ruby", "version": "0.14.1", }, { - "rubyPlatform": "ruby", "version": "0.14.2", }, { - "rubyPlatform": "ruby", "version": "0.14.3", }, { - "rubyPlatform": "ruby", "version": "0.14.4", }, { - "rubyPlatform": "ruby", "version": "1.0.0", }, { - "rubyPlatform": "ruby", "version": "1.1.0", }, { - "rubyPlatform": "ruby", "version": "1.1.1", }, { - "rubyPlatform": "ruby", "version": "1.1.2", }, { - "rubyPlatform": "ruby", "version": "1.1.3", }, { - "rubyPlatform": "ruby", "version": "1.1.4", }, { - "rubyPlatform": "ruby", "version": "1.1.5", }, { - "rubyPlatform": "ruby", "version": "1.1.6", }, { - "rubyPlatform": "ruby", "version": "1.2.0", }, { - "rubyPlatform": "ruby", "version": "1.2.1", }, { - "rubyPlatform": "ruby", "version": "1.2.2", }, { - "rubyPlatform": "ruby", "version": "1.2.3", }, { - "rubyPlatform": "ruby", "version": "1.2.4", }, { - "rubyPlatform": "ruby", "version": "1.2.5", }, { - "rubyPlatform": "ruby", "version": "1.2.6", }, { - "rubyPlatform": "ruby", "version": "2.0.0", }, { - "rubyPlatform": "ruby", "version": "2.0.1", }, { - "rubyPlatform": "ruby", "version": "2.0.2", }, { - "rubyPlatform": "ruby", "version": "2.0.4", }, { - "rubyPlatform": "ruby", "version": "2.0.5", }, { - "rubyPlatform": "ruby", "version": "2.1.0", }, { - "rubyPlatform": "ruby", "version": "2.1.1", }, { - "rubyPlatform": "ruby", "version": "2.1.2", }, { - "rubyPlatform": "ruby", "version": "2.2.2", }, { - "rubyPlatform": "ruby", "version": "2.2.3", }, { - "rubyPlatform": "ruby", "version": "2.3.2", }, { - "rubyPlatform": "ruby", "version": "2.3.3", }, { - "rubyPlatform": "ruby", "version": "2.3.4", }, { - "rubyPlatform": "ruby", "version": "2.3.5", }, { - "rubyPlatform": "ruby", "version": "2.3.6", }, { - "rubyPlatform": "ruby", "version": "2.3.7", }, { - "rubyPlatform": "ruby", "version": "2.3.8.pre1", }, { - "rubyPlatform": "ruby", "version": "2.3.8", }, { - "rubyPlatform": "ruby", "version": "2.3.9.pre", }, { - "rubyPlatform": "ruby", "version": "2.3.9", }, { - "rubyPlatform": "ruby", "version": "2.3.10", }, { - "rubyPlatform": "ruby", "version": "2.3.11", }, { - "rubyPlatform": "ruby", "version": "2.3.12", }, { - "rubyPlatform": "ruby", "version": "2.3.14", }, { - "rubyPlatform": "ruby", "version": "2.3.15", }, { - "rubyPlatform": "ruby", "version": "2.3.16", }, { - "rubyPlatform": "ruby", "version": "2.3.17", }, { - "rubyPlatform": "ruby", "version": "2.3.18", }, { - "rubyPlatform": "ruby", "version": "3.0.0.beta", }, { - "rubyPlatform": "ruby", "version": "3.0.0.beta2", }, { - "rubyPlatform": "ruby", "version": "3.0.0.beta3", }, { - "rubyPlatform": "ruby", "version": "3.0.0.beta4", }, { - "rubyPlatform": "ruby", "version": "3.0.0.rc", }, { - "rubyPlatform": "ruby", "version": "3.0.0.rc2", }, { - "rubyPlatform": "ruby", "version": "3.0.0", }, { - "rubyPlatform": "ruby", "version": "3.0.1", }, { - "rubyPlatform": "ruby", "version": "3.0.2", }, { - "rubyPlatform": "ruby", "version": "3.0.3", }, { - "rubyPlatform": "ruby", "version": "3.0.4.rc1", }, { - "rubyPlatform": "ruby", "version": "3.0.4", }, { - "rubyPlatform": "ruby", "version": "3.0.5.rc1", }, { - "rubyPlatform": "ruby", "version": "3.0.5", }, { - "rubyPlatform": "ruby", "version": "3.0.6.rc1", }, { - "rubyPlatform": "ruby", "version": "3.0.6.rc2", }, { - "rubyPlatform": "ruby", "version": "3.0.6", }, { - "rubyPlatform": "ruby", "version": "3.0.7.rc1", }, { - "rubyPlatform": "ruby", "version": "3.0.7.rc2", }, { - "rubyPlatform": "ruby", "version": "3.0.7", }, { - "rubyPlatform": "ruby", "version": "3.0.8.rc1", }, { - "rubyPlatform": "ruby", "version": "3.0.8.rc2", }, { - "rubyPlatform": "ruby", "version": "3.0.8.rc4", }, { - "rubyPlatform": "ruby", "version": "3.0.8", }, { - "rubyPlatform": "ruby", "version": "3.0.9.rc1", }, { - "rubyPlatform": "ruby", "version": "3.0.9.rc3", }, { - "rubyPlatform": "ruby", "version": "3.0.9.rc4", }, { - "rubyPlatform": "ruby", "version": "3.0.9.rc5", }, { - "rubyPlatform": "ruby", "version": "3.0.9", }, { - "rubyPlatform": "ruby", "version": "3.0.10.rc1", }, { - "rubyPlatform": "ruby", "version": "3.0.10", }, { - "rubyPlatform": "ruby", "version": "3.0.11", }, { - "rubyPlatform": "ruby", "version": "3.0.12.rc1", }, { - "rubyPlatform": "ruby", "version": "3.0.12", }, { - "rubyPlatform": "ruby", "version": "3.0.13.rc1", }, { - "rubyPlatform": "ruby", "version": "3.0.13", }, { - "rubyPlatform": "ruby", "version": "3.0.14", }, { - "rubyPlatform": "ruby", "version": "3.0.15", }, { - "rubyPlatform": "ruby", "version": "3.0.16", }, { - "rubyPlatform": "ruby", "version": "3.0.17", }, { - "rubyPlatform": "ruby", "version": "3.0.18", }, { - "rubyPlatform": "ruby", "version": "3.0.19", }, { - "rubyPlatform": "ruby", "version": "3.0.20", }, { - "rubyPlatform": "ruby", "version": "3.1.0.beta1", }, { - "rubyPlatform": "ruby", "version": "3.1.0.rc1", }, { - "rubyPlatform": "ruby", "version": "3.1.0.rc2", }, { - "rubyPlatform": "ruby", "version": "3.1.0.rc3", }, { - "rubyPlatform": "ruby", "version": "3.1.0.rc4", }, { - "rubyPlatform": "ruby", "version": "3.1.0.rc5", }, { - "rubyPlatform": "ruby", "version": "3.1.0.rc6", }, { - "rubyPlatform": "ruby", "version": "3.1.0.rc8", }, { - "rubyPlatform": "ruby", "version": "3.1.0", }, { - "rubyPlatform": "ruby", "version": "3.1.1.rc1", }, { - "rubyPlatform": "ruby", "version": "3.1.1.rc2", }, { - "rubyPlatform": "ruby", "version": "3.1.1.rc3", }, { - "rubyPlatform": "ruby", "version": "3.1.1", }, { - "rubyPlatform": "ruby", "version": "3.1.2.rc1", }, { - "rubyPlatform": "ruby", "version": "3.1.2.rc2", }, { - "rubyPlatform": "ruby", "version": "3.1.2", }, { - "rubyPlatform": "ruby", "version": "3.1.3", }, { - "rubyPlatform": "ruby", "version": "3.1.4.rc1", }, { - "rubyPlatform": "ruby", "version": "3.1.4", }, { - "rubyPlatform": "ruby", "version": "3.1.5.rc1", }, { - "rubyPlatform": "ruby", "version": "3.1.5", }, { - "rubyPlatform": "ruby", "version": "3.1.6", }, { - "rubyPlatform": "ruby", "version": "3.1.7", }, { - "rubyPlatform": "ruby", "version": "3.1.8", }, { - "rubyPlatform": "ruby", "version": "3.1.9", }, { - "rubyPlatform": "ruby", "version": "3.1.10", }, { - "rubyPlatform": "ruby", "version": "3.1.11", }, { - "rubyPlatform": "ruby", "version": "3.1.12", }, { - "rubyPlatform": "ruby", "version": "3.2.0.rc1", }, { - "rubyPlatform": "ruby", "version": "3.2.0.rc2", }, { - "rubyPlatform": "ruby", "version": "3.2.0", }, { - "rubyPlatform": "ruby", "version": "3.2.1", }, { - "rubyPlatform": "ruby", "version": "3.2.2.rc1", }, { - "rubyPlatform": "ruby", "version": "3.2.2", }, { - "rubyPlatform": "ruby", "version": "3.2.3.rc1", }, { - "rubyPlatform": "ruby", "version": "3.2.3.rc2", }, { - "rubyPlatform": "ruby", "version": "3.2.3", }, { - "rubyPlatform": "ruby", "version": "3.2.4.rc1", }, { - "rubyPlatform": "ruby", "version": "3.2.4", }, { - "rubyPlatform": "ruby", "version": "3.2.5", }, { - "rubyPlatform": "ruby", "version": "3.2.6", }, { - "rubyPlatform": "ruby", "version": "3.2.7.rc1", }, { - "rubyPlatform": "ruby", "version": "3.2.7", }, { - "rubyPlatform": "ruby", "version": "3.2.8.rc1", }, { - "rubyPlatform": "ruby", "version": "3.2.8.rc2", }, { - "rubyPlatform": "ruby", "version": "3.2.8", }, { - "rubyPlatform": "ruby", "version": "3.2.9.rc1", }, { - "rubyPlatform": "ruby", "version": "3.2.9.rc2", }, { - "rubyPlatform": "ruby", "version": "3.2.9.rc3", }, { - "rubyPlatform": "ruby", "version": "3.2.9", }, { - "rubyPlatform": "ruby", "version": "3.2.10", }, { - "rubyPlatform": "ruby", "version": "3.2.11", }, { - "rubyPlatform": "ruby", "version": "3.2.12", }, { - "rubyPlatform": "ruby", "version": "3.2.13.rc1", }, { - "rubyPlatform": "ruby", "version": "3.2.13.rc2", }, { - "rubyPlatform": "ruby", "version": "3.2.13", }, { - "rubyPlatform": "ruby", "version": "3.2.14.rc1", }, { - "rubyPlatform": "ruby", "version": "3.2.14.rc2", }, { - "rubyPlatform": "ruby", "version": "3.2.14", }, { - "rubyPlatform": "ruby", "version": "3.2.15.rc1", }, { - "rubyPlatform": "ruby", "version": "3.2.15.rc2", }, { - "rubyPlatform": "ruby", "version": "3.2.15.rc3", }, { - "rubyPlatform": "ruby", "version": "3.2.15", }, { - "rubyPlatform": "ruby", "version": "3.2.16", }, { - "rubyPlatform": "ruby", "version": "3.2.17", }, { - "rubyPlatform": "ruby", "version": "3.2.18", }, { - "rubyPlatform": "ruby", "version": "3.2.19", }, { - "rubyPlatform": "ruby", "version": "3.2.20", }, { - "rubyPlatform": "ruby", "version": "3.2.21", }, { - "rubyPlatform": "ruby", "version": "3.2.22", }, { - "rubyPlatform": "ruby", "version": "3.2.22.1", }, { - "rubyPlatform": "ruby", "version": "3.2.22.2", }, { - "rubyPlatform": "ruby", "version": "3.2.22.3", }, { - "rubyPlatform": "ruby", "version": "3.2.22.4", }, { - "rubyPlatform": "ruby", "version": "3.2.22.5", }, { - "rubyPlatform": "ruby", "version": "4.0.0.beta1", }, { - "rubyPlatform": "ruby", "version": "4.0.0.rc1", }, { - "rubyPlatform": "ruby", "version": "4.0.0.rc2", }, { - "rubyPlatform": "ruby", "version": "4.0.0", }, { - "rubyPlatform": "ruby", "version": "4.0.1.rc1", }, { - "rubyPlatform": "ruby", "version": "4.0.1.rc2", }, { - "rubyPlatform": "ruby", "version": "4.0.1.rc3", }, { - "rubyPlatform": "ruby", "version": "4.0.1.rc4", }, { - "rubyPlatform": "ruby", "version": "4.0.1", }, { - "rubyPlatform": "ruby", "version": "4.0.2", }, { - "rubyPlatform": "ruby", "version": "4.0.3", }, { - "rubyPlatform": "ruby", "version": "4.0.4.rc1", }, { - "rubyPlatform": "ruby", "version": "4.0.4", }, { - "rubyPlatform": "ruby", "version": "4.0.5", }, { - "rubyPlatform": "ruby", "version": "4.0.6.rc1", }, { - "rubyPlatform": "ruby", "version": "4.0.6.rc2", }, { - "rubyPlatform": "ruby", "version": "4.0.6.rc3", }, { - "rubyPlatform": "ruby", "version": "4.0.6", }, { - "rubyPlatform": "ruby", "version": "4.0.7", }, { - "rubyPlatform": "ruby", "version": "4.0.8", }, { - "rubyPlatform": "ruby", "version": "4.0.9", }, { - "rubyPlatform": "ruby", "version": "4.0.10.rc1", }, { - "rubyPlatform": "ruby", "version": "4.0.10.rc2", }, { - "rubyPlatform": "ruby", "version": "4.0.10", }, { - "rubyPlatform": "ruby", "version": "4.0.11", }, { - "rubyPlatform": "ruby", "version": "4.0.11.1", }, { - "rubyPlatform": "ruby", "version": "4.0.12", }, { - "rubyPlatform": "ruby", "version": "4.0.13.rc1", }, { - "rubyPlatform": "ruby", "version": "4.0.13", }, { - "rubyPlatform": "ruby", "version": "4.1.0.beta1", }, { - "rubyPlatform": "ruby", "version": "4.1.0.beta2", }, { - "rubyPlatform": "ruby", "version": "4.1.0.rc1", }, { - "rubyPlatform": "ruby", "version": "4.1.0.rc2", }, { - "rubyPlatform": "ruby", "version": "4.1.0", }, { - "rubyPlatform": "ruby", "version": "4.1.1", }, { - "rubyPlatform": "ruby", "version": "4.1.2.rc1", }, { - "rubyPlatform": "ruby", "version": "4.1.2.rc2", }, { - "rubyPlatform": "ruby", "version": "4.1.2.rc3", }, { - "rubyPlatform": "ruby", "version": "4.1.2", }, { - "rubyPlatform": "ruby", "version": "4.1.3", }, { - "rubyPlatform": "ruby", "version": "4.1.4", }, { - "rubyPlatform": "ruby", "version": "4.1.5", }, { - "rubyPlatform": "ruby", "version": "4.1.6.rc1", }, { - "rubyPlatform": "ruby", "version": "4.1.6.rc2", }, { - "rubyPlatform": "ruby", "version": "4.1.6", }, { - "rubyPlatform": "ruby", "version": "4.1.7", }, { - "rubyPlatform": "ruby", "version": "4.1.7.1", }, { - "rubyPlatform": "ruby", "version": "4.1.8", }, { - "rubyPlatform": "ruby", "version": "4.1.9.rc1", }, { - "rubyPlatform": "ruby", "version": "4.1.9", }, { - "rubyPlatform": "ruby", "version": "4.1.10.rc1", }, { - "rubyPlatform": "ruby", "version": "4.1.10.rc2", }, { - "rubyPlatform": "ruby", "version": "4.1.10.rc3", }, { - "rubyPlatform": "ruby", "version": "4.1.10.rc4", }, { - "rubyPlatform": "ruby", "version": "4.1.10", }, { - "rubyPlatform": "ruby", "version": "4.1.11", }, { - "rubyPlatform": "ruby", "version": "4.1.12.rc1", }, { - "rubyPlatform": "ruby", "version": "4.1.12", }, { - "rubyPlatform": "ruby", "version": "4.1.13.rc1", }, { - "rubyPlatform": "ruby", "version": "4.1.13", }, { - "rubyPlatform": "ruby", "version": "4.1.14.rc1", }, { - "rubyPlatform": "ruby", "version": "4.1.14.rc2", }, { - "rubyPlatform": "ruby", "version": "4.1.14", }, { - "rubyPlatform": "ruby", "version": "4.1.14.1", }, { - "rubyPlatform": "ruby", "version": "4.1.14.2", }, { - "rubyPlatform": "ruby", "version": "4.1.15.rc1", }, { - "rubyPlatform": "ruby", "version": "4.1.15", }, { - "rubyPlatform": "ruby", "version": "4.1.16.rc1", }, { - "rubyPlatform": "ruby", "version": "4.1.16", }, { - "rubyPlatform": "ruby", "version": "4.2.0.beta1", }, { - "rubyPlatform": "ruby", "version": "4.2.0.beta2", }, { - "rubyPlatform": "ruby", "version": "4.2.0.beta3", }, { - "rubyPlatform": "ruby", "version": "4.2.0.beta4", }, { - "rubyPlatform": "ruby", "version": "4.2.0.rc1", }, { - "rubyPlatform": "ruby", "version": "4.2.0.rc2", }, { - "rubyPlatform": "ruby", "version": "4.2.0.rc3", }, { - "rubyPlatform": "ruby", "version": "4.2.0", }, { - "rubyPlatform": "ruby", "version": "4.2.1.rc1", }, { - "rubyPlatform": "ruby", "version": "4.2.1.rc2", }, { - "rubyPlatform": "ruby", "version": "4.2.1.rc3", }, { - "rubyPlatform": "ruby", "version": "4.2.1.rc4", }, { - "rubyPlatform": "ruby", "version": "4.2.1", }, { - "rubyPlatform": "ruby", "version": "4.2.2", }, { - "rubyPlatform": "ruby", "version": "4.2.3.rc1", }, { - "rubyPlatform": "ruby", "version": "4.2.3", }, { - "rubyPlatform": "ruby", "version": "4.2.4.rc1", }, { - "rubyPlatform": "ruby", "version": "4.2.4", }, { - "rubyPlatform": "ruby", "version": "4.2.5.rc1", }, { - "rubyPlatform": "ruby", "version": "4.2.5.rc2", }, { - "rubyPlatform": "ruby", "version": "4.2.5", }, { - "rubyPlatform": "ruby", "version": "4.2.5.1", }, { - "rubyPlatform": "ruby", "version": "4.2.5.2", }, { - "rubyPlatform": "ruby", "version": "4.2.6.rc1", }, { - "rubyPlatform": "ruby", "version": "4.2.6", }, { - "rubyPlatform": "ruby", "version": "4.2.7.rc1", }, { - "rubyPlatform": "ruby", "version": "4.2.7", }, { - "rubyPlatform": "ruby", "version": "4.2.7.1", }, { - "rubyPlatform": "ruby", "version": "4.2.8.rc1", }, { - "rubyPlatform": "ruby", "version": "4.2.8", }, { - "rubyPlatform": "ruby", "version": "4.2.9.rc1", }, { - "rubyPlatform": "ruby", "version": "4.2.9.rc2", }, { - "rubyPlatform": "ruby", "version": "4.2.9", }, { - "rubyPlatform": "ruby", "version": "4.2.10.rc1", }, { - "rubyPlatform": "ruby", "version": "4.2.10", }, { - "rubyPlatform": "ruby", "version": "4.2.11", }, { - "rubyPlatform": "ruby", "version": "5.0.0.beta1", }, { - "rubyPlatform": "ruby", "version": "5.0.0.beta1.1", }, { - "rubyPlatform": "ruby", "version": "5.0.0.beta2", }, { - "rubyPlatform": "ruby", "version": "5.0.0.beta3", }, { - "rubyPlatform": "ruby", "version": "5.0.0.beta4", }, { - "rubyPlatform": "ruby", "version": "5.0.0.racecar1", }, { - "rubyPlatform": "ruby", "version": "5.0.0.rc1", }, { - "rubyPlatform": "ruby", "version": "5.0.0.rc2", }, { - "rubyPlatform": "ruby", "version": "5.0.0", }, { - "rubyPlatform": "ruby", "version": "5.0.0.1", }, { - "rubyPlatform": "ruby", "version": "5.0.1.rc1", }, { - "rubyPlatform": "ruby", "version": "5.0.1.rc2", }, { - "rubyPlatform": "ruby", "version": "5.0.1", }, { - "rubyPlatform": "ruby", "version": "5.0.2.rc1", }, { - "rubyPlatform": "ruby", "version": "5.0.2", }, { - "rubyPlatform": "ruby", "version": "5.0.3", }, { - "rubyPlatform": "ruby", "version": "5.0.4.rc1", }, { - "rubyPlatform": "ruby", "version": "5.0.4", }, { - "rubyPlatform": "ruby", "version": "5.0.5.rc1", }, { - "rubyPlatform": "ruby", "version": "5.0.5.rc2", }, { - "rubyPlatform": "ruby", "version": "5.0.5", }, { - "rubyPlatform": "ruby", "version": "5.0.6.rc1", }, { - "rubyPlatform": "ruby", "version": "5.0.6", }, { - "rubyPlatform": "ruby", "version": "5.0.7", }, { - "rubyPlatform": "ruby", "version": "5.0.7.1", }, { - "rubyPlatform": "ruby", "version": "5.1.0.beta1", }, { - "rubyPlatform": "ruby", "version": "5.1.0.rc1", }, { - "rubyPlatform": "ruby", "version": "5.1.0.rc2", }, { - "rubyPlatform": "ruby", "version": "5.1.0", }, { - "rubyPlatform": "ruby", "version": "5.1.1", }, { - "rubyPlatform": "ruby", "version": "5.1.2.rc1", }, { - "rubyPlatform": "ruby", "version": "5.1.2", }, { - "rubyPlatform": "ruby", "version": "5.1.3.rc1", }, { - "rubyPlatform": "ruby", "version": "5.1.3.rc2", }, { - "rubyPlatform": "ruby", "version": "5.1.3.rc3", }, { - "rubyPlatform": "ruby", "version": "5.1.3", }, { - "rubyPlatform": "ruby", "version": "5.1.4.rc1", }, { - "rubyPlatform": "ruby", "version": "5.1.4", }, { - "rubyPlatform": "ruby", "version": "5.1.5.rc1", }, { - "rubyPlatform": "ruby", "version": "5.1.5", }, { - "rubyPlatform": "ruby", "version": "5.1.6", }, { - "rubyPlatform": "ruby", "version": "5.1.6.1", }, { - "rubyPlatform": "ruby", "version": "5.2.0.beta1", }, { - "rubyPlatform": "ruby", "version": "5.2.0.beta2", }, { - "rubyPlatform": "ruby", "version": "5.2.0.rc1", }, { - "rubyPlatform": "ruby", "version": "5.2.0.rc2", }, { - "rubyPlatform": "ruby", "version": "5.2.0", }, { - "rubyPlatform": "ruby", "version": "5.2.1.rc1", }, { - "rubyPlatform": "ruby", "version": "5.2.1", }, { - "rubyPlatform": "ruby", "version": "5.2.1.1", }, { - "rubyPlatform": "ruby", "version": "5.2.2.rc1", }, { - "rubyPlatform": "ruby", "version": "5.2.2", }, ], @@ -1380,2380 +1041,1364 @@ exports[`modules/datasource/rubygems/index getReleases returns a dep for rubygem exports[`modules/datasource/rubygems/index getReleases uses multiple source urls 1`] = ` { + "changelogUrl": "https://www.railschangelog.com/", "homepage": "http://rubyonrails.org", "registryUrl": "https://firstparty.com/basepath", "releases": [ { "releaseTimestamp": "2009-07-25T18:01:56.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "0.8.0", }, { "releaseTimestamp": "2009-07-25T18:01:56.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "0.8.5", }, { "releaseTimestamp": "2009-07-25T18:01:56.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "0.9.0", }, { "releaseTimestamp": "2009-07-25T18:01:56.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "0.9.1", }, { "releaseTimestamp": "2009-07-25T18:01:56.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "0.9.2", }, { "releaseTimestamp": "2009-07-25T18:01:55.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "0.9.3", }, { "releaseTimestamp": "2009-07-25T18:01:55.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "0.9.4", }, { "releaseTimestamp": "2009-07-25T18:01:55.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "0.9.4.1", }, { "releaseTimestamp": "2009-07-25T18:01:55.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "0.9.5", }, { "releaseTimestamp": "2009-07-25T18:01:58.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "0.10.0", }, { "releaseTimestamp": "2009-07-25T18:01:58.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "0.10.1", }, { "releaseTimestamp": "2009-07-25T18:01:58.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "0.11.0", }, { "releaseTimestamp": "2009-07-25T18:01:58.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "0.11.1", }, { "releaseTimestamp": "2009-07-25T18:01:58.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "0.12.0", }, { "releaseTimestamp": "2009-07-25T18:01:57.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "0.12.1", }, { "releaseTimestamp": "2009-07-25T18:01:57.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "0.13.0", }, { "releaseTimestamp": "2009-07-25T18:01:57.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "0.13.1", }, { "releaseTimestamp": "2009-07-25T18:01:57.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "0.14.1", }, { "releaseTimestamp": "2009-07-25T18:01:57.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "0.14.2", }, { "releaseTimestamp": "2009-07-25T18:01:56.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "0.14.3", }, { "releaseTimestamp": "2009-07-25T18:01:56.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "0.14.4", }, { "releaseTimestamp": "2009-07-25T18:01:55.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "1.0.0", }, { "releaseTimestamp": "2009-07-25T18:01:55.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "1.1.0", }, { "releaseTimestamp": "2009-07-25T18:01:55.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "1.1.1", }, { "releaseTimestamp": "2009-07-25T18:01:54.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "1.1.2", }, { "releaseTimestamp": "2009-07-25T18:01:54.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "1.1.3", }, { "releaseTimestamp": "2009-07-25T18:01:54.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "1.1.4", }, { "releaseTimestamp": "2009-07-25T18:01:54.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "1.1.5", }, { "releaseTimestamp": "2009-07-25T18:01:54.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "1.1.6", }, { "releaseTimestamp": "2009-07-25T18:01:53.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "1.2.0", }, { "releaseTimestamp": "2009-07-25T18:01:52.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "1.2.1", }, { "releaseTimestamp": "2009-07-25T18:01:52.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "1.2.2", }, { "releaseTimestamp": "2009-07-25T18:01:52.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "1.2.3", }, { "releaseTimestamp": "2009-07-25T18:01:52.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "1.2.4", }, { "releaseTimestamp": "2009-07-25T18:01:52.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "1.2.5", }, { "releaseTimestamp": "2009-07-25T18:01:51.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "1.2.6", }, { "releaseTimestamp": "2009-07-25T18:01:51.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "2.0.0", }, { "releaseTimestamp": "2009-07-25T18:01:51.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "2.0.1", }, { "releaseTimestamp": "2009-07-25T18:01:51.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "2.0.2", }, { "releaseTimestamp": "2009-07-25T18:01:51.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "2.0.4", }, { "releaseTimestamp": "2009-07-25T18:01:50.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "2.0.5", }, { "releaseTimestamp": "2009-07-25T18:01:50.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "2.1.0", }, { "releaseTimestamp": "2009-07-25T18:01:50.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "2.1.1", }, { "releaseTimestamp": "2009-07-25T18:01:50.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "2.1.2", }, { "releaseTimestamp": "2009-07-25T18:01:49.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "2.2.2", }, { "releaseTimestamp": "2009-09-28T09:25:13.132Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "2.2.3", }, { "releaseTimestamp": "2009-07-25T18:01:49.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "2.3.2", }, { "releaseTimestamp": "2009-08-05T13:21:07.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "2.3.3", }, { "releaseTimestamp": "2009-09-04T17:33:48.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "2.3.4", }, { "releaseTimestamp": "2009-11-27T00:12:56.921Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "2.3.5", }, { "releaseTimestamp": "2010-05-23T07:49:23.602Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "2.3.6", }, { "releaseTimestamp": "2010-05-24T08:23:05.731Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "2.3.7", }, { "releaseTimestamp": "2010-05-24T21:17:25.987Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": "> 1.3.1", "version": "2.3.8.pre1", }, { "releaseTimestamp": "2010-05-25T04:53:06.895Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "2.3.8", }, { "releaseTimestamp": "2010-08-30T03:32:34.689Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": "> 1.3.1", "version": "2.3.9.pre", }, { "releaseTimestamp": "2010-09-04T21:54:41.257Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "2.3.9", }, { "releaseTimestamp": "2010-10-14T20:53:17.413Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "2.3.10", }, { "releaseTimestamp": "2011-02-08T21:17:36.254Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "2.3.11", }, { "releaseTimestamp": "2011-06-08T00:22:06.357Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "2.3.12", }, { "releaseTimestamp": "2011-08-16T22:01:21.962Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "2.3.14", }, { "releaseTimestamp": "2013-01-08T20:08:28.812Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "2.3.15", }, { "releaseTimestamp": "2013-01-28T21:01:30.451Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "2.3.16", }, { "releaseTimestamp": "2013-02-11T18:17:30.726Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "2.3.17", }, { "releaseTimestamp": "2013-03-18T17:13:25.422Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "2.3.18", }, { "releaseTimestamp": "2010-02-05T03:02:19.496Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": "> 1.3.1", "version": "3.0.0.beta", }, { "releaseTimestamp": "2010-04-01T21:26:26.222Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.0.beta2", }, { "releaseTimestamp": "2010-04-13T19:23:14.932Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.0.beta3", }, { "releaseTimestamp": "2010-06-08T22:33:16.046Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.0.beta4", }, { "releaseTimestamp": "2010-07-26T21:43:12.765Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.0.rc", }, { "releaseTimestamp": "2010-08-24T03:04:45.033Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.0.rc2", }, { "releaseTimestamp": "2010-08-29T23:11:11.490Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.0", }, { "releaseTimestamp": "2010-10-14T20:55:44.846Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.1", }, { "releaseTimestamp": "2010-11-15T19:33:41.460Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.2", }, { "releaseTimestamp": "2010-11-16T16:29:00.892Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.3", }, { "releaseTimestamp": "2011-01-30T23:00:37.572Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.4.rc1", }, { "releaseTimestamp": "2011-02-08T21:17:48.221Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.4", }, { "releaseTimestamp": "2011-02-23T19:08:34.691Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.5.rc1", }, { "releaseTimestamp": "2011-02-27T02:30:55.377Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.5", }, { "releaseTimestamp": "2011-03-29T20:47:15.107Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.6.rc1", }, { "releaseTimestamp": "2011-03-31T05:28:51.216Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.6.rc2", }, { "releaseTimestamp": "2011-04-05T23:05:21.745Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.6", }, { "releaseTimestamp": "2011-04-14T21:57:06.386Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.7.rc1", }, { "releaseTimestamp": "2011-04-15T17:33:53.132Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.7.rc2", }, { "releaseTimestamp": "2011-04-18T21:05:54.308Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.7", }, { "releaseTimestamp": "2011-05-26T00:11:36.891Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.8.rc1", }, { "releaseTimestamp": "2011-05-27T16:32:24.502Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.8.rc2", }, { "releaseTimestamp": "2011-05-31T00:08:18.745Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.8.rc4", }, { "releaseTimestamp": "2011-06-08T00:16:45.270Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.8", }, { "releaseTimestamp": "2011-06-08T21:20:17.404Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.9.rc1", }, { "releaseTimestamp": "2011-06-09T22:51:39.349Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.9.rc3", }, { "releaseTimestamp": "2011-06-12T21:24:34.980Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.9.rc4", }, { "releaseTimestamp": "2011-06-12T21:30:07.555Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.9.rc5", }, { "releaseTimestamp": "2011-06-16T10:05:11.080Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.9", }, { "releaseTimestamp": "2011-08-05T00:12:05.290Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.10.rc1", }, { "releaseTimestamp": "2011-08-16T22:14:17.045Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.10", }, { "releaseTimestamp": "2011-11-18T01:23:23.249Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.11", }, { "releaseTimestamp": "2012-02-22T21:39:19.764Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.12.rc1", }, { "releaseTimestamp": "2012-03-01T17:52:15.609Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.12", }, { "releaseTimestamp": "2012-05-28T19:01:47.715Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.13.rc1", }, { "releaseTimestamp": "2012-05-31T18:24:59.747Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.13", }, { "releaseTimestamp": "2012-06-12T21:26:07.460Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.14", }, { "releaseTimestamp": "2012-06-13T03:07:06.509Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.15", }, { "releaseTimestamp": "2012-07-26T22:08:54.212Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.16", }, { "releaseTimestamp": "2012-08-09T21:16:44.882Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.17", }, { "releaseTimestamp": "2013-01-02T21:19:52.960Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.18", }, { "releaseTimestamp": "2013-01-08T20:08:33.922Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.19", }, { "releaseTimestamp": "2013-01-28T21:01:34.374Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.20", }, { "releaseTimestamp": "2011-05-05T01:23:18.105Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.0.beta1", }, { "releaseTimestamp": "2011-05-22T02:26:25.383Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.0.rc1", }, { "releaseTimestamp": "2011-06-08T00:16:57.976Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.0.rc2", }, { "releaseTimestamp": "2011-06-08T21:27:28.270Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.0.rc3", }, { "releaseTimestamp": "2011-06-09T22:56:24.880Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.0.rc4", }, { "releaseTimestamp": "2011-07-25T23:05:19.817Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.0.rc5", }, { "releaseTimestamp": "2011-08-16T22:33:32.921Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.0.rc6", }, { "releaseTimestamp": "2011-08-29T03:27:19.194Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.0.rc8", }, { "releaseTimestamp": "2011-08-31T02:18:30.035Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.0", }, { "releaseTimestamp": "2011-09-15T00:27:03.617Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.1.rc1", }, { "releaseTimestamp": "2011-09-29T22:17:03.417Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.1.rc2", }, { "releaseTimestamp": "2011-10-06T02:31:00.452Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.1.rc3", }, { "releaseTimestamp": "2011-10-07T15:30:09.628Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.1", }, { "releaseTimestamp": "2011-11-14T14:17:34.523Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.2.rc1", }, { "releaseTimestamp": "2011-11-14T15:49:20.198Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.2.rc2", }, { "releaseTimestamp": "2011-11-18T01:33:32.509Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.2", }, { "releaseTimestamp": "2011-11-20T22:52:57.492Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.3", }, { "releaseTimestamp": "2012-02-22T21:39:29.633Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.4.rc1", }, { "releaseTimestamp": "2012-03-01T17:52:28.342Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.4", }, { "releaseTimestamp": "2012-05-28T19:01:51.050Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.5.rc1", }, { "releaseTimestamp": "2012-05-31T18:25:06.617Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.5", }, { "releaseTimestamp": "2012-06-12T21:26:16.856Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.6", }, { "releaseTimestamp": "2012-07-26T22:09:00.975Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.7", }, { "releaseTimestamp": "2012-08-09T21:20:27.129Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.8", }, { "releaseTimestamp": "2013-01-02T21:19:56.845Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.9", }, { "releaseTimestamp": "2013-01-08T20:08:37.727Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.10", }, { "releaseTimestamp": "2013-02-11T18:17:37.200Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.11", }, { "releaseTimestamp": "2013-03-18T17:13:29.344Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.12", }, { "releaseTimestamp": "2011-12-20T00:41:10.661Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.0.rc1", }, { "releaseTimestamp": "2012-01-04T21:05:27.454Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.0.rc2", }, { "releaseTimestamp": "2012-01-20T16:47:48.848Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.0", }, { "releaseTimestamp": "2012-01-26T23:09:41.494Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.1", }, { "releaseTimestamp": "2012-02-22T21:39:35.308Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.2.rc1", }, { "releaseTimestamp": "2012-03-01T17:52:33.094Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.2", }, { "releaseTimestamp": "2012-03-27T17:11:24.443Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.3.rc1", }, { "releaseTimestamp": "2012-03-29T16:14:14.715Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.3.rc2", }, { "releaseTimestamp": "2012-03-30T22:26:20.685Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.3", }, { "releaseTimestamp": "2012-05-28T19:01:55.834Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.4.rc1", }, { "releaseTimestamp": "2012-05-31T18:25:13.532Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.4", }, { "releaseTimestamp": "2012-06-01T03:39:04.678Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.5", }, { "releaseTimestamp": "2012-06-12T21:26:21.434Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.6", }, { "releaseTimestamp": "2012-07-23T21:45:55.204Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.7.rc1", }, { "releaseTimestamp": "2012-07-26T22:09:06.275Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.7", }, { "releaseTimestamp": "2012-08-01T20:57:56.061Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.8.rc1", }, { "releaseTimestamp": "2012-08-03T14:29:05.254Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.8.rc2", }, { "releaseTimestamp": "2012-08-09T21:23:34.632Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.8", }, { "releaseTimestamp": "2012-10-29T17:07:08.109Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.9.rc1", }, { "releaseTimestamp": "2012-11-01T17:39:37.178Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.9.rc2", }, { "releaseTimestamp": "2012-11-09T18:00:50.077Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.9.rc3", }, { "releaseTimestamp": "2012-11-12T15:21:34.822Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.9", }, { "releaseTimestamp": "2013-01-02T21:20:01.186Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.10", }, { "releaseTimestamp": "2013-01-08T20:08:45.798Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.11", }, { "releaseTimestamp": "2013-02-11T18:17:41.481Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.12", }, { "releaseTimestamp": "2013-02-27T20:25:46.062Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.13.rc1", }, { "releaseTimestamp": "2013-03-06T23:06:19.052Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.13.rc2", }, { "releaseTimestamp": "2013-03-18T17:13:33.058Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.13", }, { "releaseTimestamp": "2013-07-13T00:25:39.110Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.14.rc1", }, { "releaseTimestamp": "2013-07-16T16:13:33.339Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.14.rc2", }, { "releaseTimestamp": "2013-07-22T16:44:50.870Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.14", }, { "releaseTimestamp": "2013-10-03T18:54:09.709Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.15.rc1", }, { "releaseTimestamp": "2013-10-04T20:48:45.484Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.15.rc2", }, { "releaseTimestamp": "2013-10-11T21:17:17.374Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.15.rc3", }, { "releaseTimestamp": "2013-10-16T17:23:10.503Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.15", }, { "releaseTimestamp": "2013-12-03T19:01:19.549Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.16", }, { "releaseTimestamp": "2014-02-18T18:54:56.443Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.17", }, { "releaseTimestamp": "2014-05-06T16:17:02.829Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.8.7", - "rubygemsVersion": ">= 1.3.6", "version": "3.2.18", }, { "releaseTimestamp": "2014-07-02T17:02:48.733Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.8.7", - "rubygemsVersion": ">= 1.3.6", "version": "3.2.19", }, { "releaseTimestamp": "2014-10-30T18:37:26.434Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.8.7", - "rubygemsVersion": ">= 1.3.6", "version": "3.2.20", }, { "releaseTimestamp": "2014-11-17T16:00:44.994Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.8.7", - "rubygemsVersion": ">= 1.3.6", "version": "3.2.21", }, { "releaseTimestamp": "2015-06-16T18:06:38.294Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.8.7", - "rubygemsVersion": ">= 1.3.6", "version": "3.2.22", }, { "releaseTimestamp": "2016-01-25T19:26:12.364Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.8.7", - "rubygemsVersion": ">= 1.3.6", "version": "3.2.22.1", }, { "releaseTimestamp": "2016-02-29T19:24:19.757Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.8.7", - "rubygemsVersion": ">= 1.3.6", "version": "3.2.22.2", }, { "releaseTimestamp": "2016-08-11T17:34:59.710Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.8.7", - "rubygemsVersion": ">= 1.3.6", "version": "3.2.22.3", }, { "releaseTimestamp": "2016-08-11T19:20:46.883Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.8.7", - "rubygemsVersion": ">= 1.3.6", "version": "3.2.22.4", }, { "releaseTimestamp": "2016-09-14T21:19:01.962Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.8.7", - "rubygemsVersion": ">= 1.3.6", "version": "3.2.22.5", }, { "releaseTimestamp": "2013-02-26T00:05:43.566Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.8.11", "version": "4.0.0.beta1", }, { "releaseTimestamp": "2013-04-29T15:39:05.085Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.8.11", "version": "4.0.0.rc1", }, { "releaseTimestamp": "2013-06-11T20:26:00.144Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.8.11", "version": "4.0.0.rc2", }, { "releaseTimestamp": "2013-06-25T14:32:58.526Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.8.11", "version": "4.0.0", }, { "releaseTimestamp": "2013-10-17T16:46:23.993Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.8.11", "version": "4.0.1.rc1", }, { "releaseTimestamp": "2013-10-21T22:01:19.341Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.8.11", "version": "4.0.1.rc2", }, { "releaseTimestamp": "2013-10-23T21:41:08.791Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.8.11", "version": "4.0.1.rc3", }, { "releaseTimestamp": "2013-10-30T20:49:25.297Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.8.11", "version": "4.0.1.rc4", }, { "releaseTimestamp": "2013-11-01T19:08:16.307Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.8.11", "version": "4.0.1", }, { "releaseTimestamp": "2013-12-03T19:01:29.867Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.8.11", "version": "4.0.2", }, { "releaseTimestamp": "2014-02-18T18:49:43.150Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.8.11", "version": "4.0.3", }, { "releaseTimestamp": "2014-03-11T17:31:18.568Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.8.11", "version": "4.0.4.rc1", }, { "releaseTimestamp": "2014-03-14T17:37:07.331Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.8.11", "version": "4.0.4", }, { "releaseTimestamp": "2014-05-06T16:13:27.132Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.0.5", }, { "releaseTimestamp": "2014-05-27T16:06:55.364Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.0.6.rc1", }, { "releaseTimestamp": "2014-06-16T16:16:01.642Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.0.6.rc2", }, { "releaseTimestamp": "2014-06-23T17:24:41.466Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.0.6.rc3", }, { "releaseTimestamp": "2014-06-26T16:30:13.579Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.0.6", }, { "releaseTimestamp": "2014-07-02T17:04:32.418Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.0.7", }, { "releaseTimestamp": "2014-07-02T19:42:37.603Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.0.8", }, { "releaseTimestamp": "2014-08-18T17:03:01.087Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.0.9", }, { "releaseTimestamp": "2014-08-19T20:48:29.471Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.0.10.rc1", }, { "releaseTimestamp": "2014-09-08T17:55:45.314Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.0.10.rc2", }, { "releaseTimestamp": "2014-09-11T17:33:15.455Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.0.10", }, { "releaseTimestamp": "2014-10-30T18:37:38.192Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.0.11", }, { "releaseTimestamp": "2014-11-19T19:09:54.075Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.0.11.1", }, { "releaseTimestamp": "2014-11-17T16:01:00.306Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.0.12", }, { "releaseTimestamp": "2015-01-02T00:54:54.587Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.0.13.rc1", }, { "releaseTimestamp": "2015-01-06T20:08:59.935Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.0.13", }, { "releaseTimestamp": "2013-12-18T00:15:16.640Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.8.11", "version": "4.1.0.beta1", }, { "releaseTimestamp": "2014-02-18T18:52:57.614Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.8.11", "version": "4.1.0.beta2", }, { "releaseTimestamp": "2014-02-18T20:59:23.632Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.8.11", "version": "4.1.0.rc1", }, { "releaseTimestamp": "2014-03-25T20:12:47.195Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.0.rc2", }, { "releaseTimestamp": "2014-04-08T19:21:51.275Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.0", }, { "releaseTimestamp": "2014-05-06T16:11:31.458Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.1", }, { "releaseTimestamp": "2014-05-27T16:12:48.106Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.2.rc1", }, { "releaseTimestamp": "2014-06-16T16:30:46.332Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.2.rc2", }, { "releaseTimestamp": "2014-06-23T17:28:46.002Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.2.rc3", }, { "releaseTimestamp": "2014-06-26T14:50:09.079Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.2", }, { "releaseTimestamp": "2014-07-02T17:06:42.181Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.3", }, { "releaseTimestamp": "2014-07-02T19:53:35.556Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.4", }, { "releaseTimestamp": "2014-08-18T17:01:03.727Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.5", }, { "releaseTimestamp": "2014-08-19T20:52:47.110Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.6.rc1", }, { "releaseTimestamp": "2014-09-08T18:13:12.723Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.6.rc2", }, { "releaseTimestamp": "2014-09-11T17:26:04.576Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.6", }, { "releaseTimestamp": "2014-10-30T18:37:49.213Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.7", }, { "releaseTimestamp": "2014-11-19T19:12:12.692Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.7.1", }, { "releaseTimestamp": "2014-11-17T16:01:13.385Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.8", }, { "releaseTimestamp": "2015-01-02T01:11:10.973Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.9.rc1", }, { "releaseTimestamp": "2015-01-06T20:04:31.185Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.9", }, { "releaseTimestamp": "2015-02-20T22:25:09.666Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.10.rc1", }, { "releaseTimestamp": "2015-02-25T22:22:40.645Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.10.rc2", }, { "releaseTimestamp": "2015-03-02T21:39:47.964Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.10.rc3", }, { "releaseTimestamp": "2015-03-12T21:32:52.724Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.10.rc4", }, { "releaseTimestamp": "2015-03-19T16:50:27.388Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.10", }, { "releaseTimestamp": "2015-06-16T18:00:13.043Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.11", }, { "releaseTimestamp": "2015-06-22T14:05:08.486Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.12.rc1", }, { "releaseTimestamp": "2015-06-25T21:26:08.544Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.12", }, { "releaseTimestamp": "2015-08-14T15:13:26.943Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.13.rc1", }, { "releaseTimestamp": "2015-08-24T18:02:56.741Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.13", }, { "releaseTimestamp": "2015-10-30T20:45:42.801Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.14.rc1", }, { "releaseTimestamp": "2015-11-05T02:55:44.276Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.14.rc2", }, { "releaseTimestamp": "2015-11-12T18:20:40.613Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.14", }, { "releaseTimestamp": "2016-01-25T19:26:27.339Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.14.1", }, { "releaseTimestamp": "2016-02-29T19:19:55.523Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.14.2", }, { "releaseTimestamp": "2016-03-01T18:43:40.764Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.15.rc1", }, { "releaseTimestamp": "2016-03-07T22:37:14.594Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.15", }, { "releaseTimestamp": "2016-07-02T02:15:20.923Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.16.rc1", }, { "releaseTimestamp": "2016-07-12T22:20:56.527Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.16", }, { "releaseTimestamp": "2014-08-20T02:34:44.046Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.0.beta1", }, { "releaseTimestamp": "2014-09-29T17:16:38.761Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.0.beta2", }, { "releaseTimestamp": "2014-10-30T18:37:59.690Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.0.beta3", }, { "releaseTimestamp": "2014-10-30T22:13:30.689Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.0.beta4", }, { "releaseTimestamp": "2014-11-28T17:53:27.822Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.0.rc1", }, { "releaseTimestamp": "2014-12-05T23:20:12.824Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.0.rc2", }, { "releaseTimestamp": "2014-12-13T02:58:44.762Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.0.rc3", }, { "releaseTimestamp": "2014-12-20T00:15:37.476Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.0", }, { "releaseTimestamp": "2015-02-20T22:21:34.214Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.1.rc1", }, { "releaseTimestamp": "2015-02-25T22:19:50.245Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.1.rc2", }, { "releaseTimestamp": "2015-03-02T21:35:50.169Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.1.rc3", }, { "releaseTimestamp": "2015-03-12T21:25:52.551Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.1.rc4", }, { "releaseTimestamp": "2015-03-19T16:42:01.191Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.1", }, { "releaseTimestamp": "2015-06-16T18:03:17.061Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.2", }, { "releaseTimestamp": "2015-06-22T14:23:17.788Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.3.rc1", }, { "releaseTimestamp": "2015-06-25T21:30:57.890Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.3", }, { "releaseTimestamp": "2015-08-14T15:21:15.566Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.4.rc1", }, { "releaseTimestamp": "2015-08-24T18:27:12.716Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.4", }, { "releaseTimestamp": "2015-10-30T20:47:59.397Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.5.rc1", }, { "releaseTimestamp": "2015-11-05T03:02:33.340Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.5.rc2", }, { "releaseTimestamp": "2015-11-12T17:06:55.226Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.5", }, { "releaseTimestamp": "2016-01-25T19:26:41.410Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.5.1", }, { "releaseTimestamp": "2016-02-29T19:17:10.564Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.5.2", }, { "releaseTimestamp": "2016-03-01T18:37:54.172Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.6.rc1", }, { "releaseTimestamp": "2016-03-07T22:33:22.563Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.6", }, { "releaseTimestamp": "2016-07-01T00:33:36.424Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.7.rc1", }, { "releaseTimestamp": "2016-07-13T02:57:05.601Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.7", }, { "releaseTimestamp": "2016-08-11T17:35:16.160Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.7.1", }, { "releaseTimestamp": "2017-02-10T02:46:51.222Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.8.rc1", }, { "releaseTimestamp": "2017-02-21T16:08:53.220Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.8", }, { "releaseTimestamp": "2017-06-13T18:50:29.897Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.9.rc1", }, { "releaseTimestamp": "2017-06-19T22:28:22.086Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.9.rc2", }, { "releaseTimestamp": "2017-06-26T21:30:56.077Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.9", }, { "releaseTimestamp": "2017-09-20T19:42:33.297Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.10.rc1", }, { "releaseTimestamp": "2017-09-27T14:29:42.567Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.10", }, { "releaseTimestamp": "2018-11-27T20:07:25.845Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.11", }, { "releaseTimestamp": "2015-12-18T21:18:13.306Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.0.0.beta1", }, { "releaseTimestamp": "2016-01-25T19:26:49.903Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.0.0.beta1.1", }, { "releaseTimestamp": "2016-02-01T22:06:25.279Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.0.0.beta2", }, { "releaseTimestamp": "2016-02-24T16:16:22.722Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.0.0.beta3", }, { "releaseTimestamp": "2016-04-27T20:55:26.508Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.0.0.beta4", }, { "releaseTimestamp": "2016-05-06T22:02:43.345Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.0.0.racecar1", }, { "releaseTimestamp": "2016-05-06T21:57:46.793Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.0.0.rc1", }, { "releaseTimestamp": "2016-06-22T20:03:41.237Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.0.0.rc2", }, { "releaseTimestamp": "2016-06-30T21:32:45.255Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.0.0", }, { "releaseTimestamp": "2016-08-11T17:35:27.196Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.0.0.1", }, { "releaseTimestamp": "2016-11-30T20:02:44.553Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.0.1.rc1", }, { "releaseTimestamp": "2016-12-09T19:13:12.953Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.0.1.rc2", }, { "releaseTimestamp": "2016-12-21T00:07:46.527Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.0.1", }, { "releaseTimestamp": "2017-02-25T00:55:48.618Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.0.2.rc1", }, { "releaseTimestamp": "2017-03-01T23:13:53.219Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.0.2", }, { "releaseTimestamp": "2017-05-12T20:08:33.226Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.0.3", }, { "releaseTimestamp": "2017-06-14T20:49:29.610Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.0.4.rc1", }, { "releaseTimestamp": "2017-06-19T21:58:56.501Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.0.4", }, { "releaseTimestamp": "2017-07-19T19:43:58.280Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.0.5.rc1", }, { "releaseTimestamp": "2017-07-25T20:26:10.369Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.0.5.rc2", }, { "releaseTimestamp": "2017-07-31T19:05:29.060Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.0.5", }, { "releaseTimestamp": "2017-08-24T19:21:20.599Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.0.6.rc1", }, { "releaseTimestamp": "2017-09-08T00:47:42.201Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.0.6", }, { "releaseTimestamp": "2018-03-29T18:18:14.388Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.0.7", }, { "releaseTimestamp": "2018-11-27T20:09:36.347Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.0.7.1", }, { "releaseTimestamp": "2017-02-23T20:00:44.720Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.1.0.beta1", }, { "releaseTimestamp": "2017-03-20T18:57:56.595Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.1.0.rc1", }, { "releaseTimestamp": "2017-04-21T01:31:13.442Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.1.0.rc2", }, { "releaseTimestamp": "2017-04-27T21:00:47.670Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.1.0", }, { "releaseTimestamp": "2017-05-12T20:11:39.743Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.1.1", }, { "releaseTimestamp": "2017-06-20T17:03:49.322Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.1.2.rc1", }, { "releaseTimestamp": "2017-06-26T21:51:41.161Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.1.2", }, { "releaseTimestamp": "2017-07-19T19:38:05.393Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.1.3.rc1", }, { "releaseTimestamp": "2017-07-25T20:18:18.420Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.1.3.rc2", }, { "releaseTimestamp": "2017-07-31T19:12:53.241Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.1.3.rc3", }, { "releaseTimestamp": "2017-08-03T19:15:15.370Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.1.3", }, { "releaseTimestamp": "2017-08-24T19:37:37.728Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.1.4.rc1", }, { "releaseTimestamp": "2017-09-08T00:52:07.791Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.1.4", }, { "releaseTimestamp": "2018-02-01T19:00:37.520Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.1.5.rc1", }, { "releaseTimestamp": "2018-02-14T20:02:02.541Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.1.5", }, { "releaseTimestamp": "2018-03-29T18:29:03.149Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.1.6", }, { "releaseTimestamp": "2018-11-27T20:11:47.585Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.1.6.1", }, { "releaseTimestamp": "2017-11-27T19:19:13.809Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.2.0.beta1", }, { "releaseTimestamp": "2017-11-28T05:04:37.765Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.2.0.beta2", }, { "releaseTimestamp": "2018-01-30T23:38:56.843Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.2.0.rc1", }, { "releaseTimestamp": "2018-03-20T17:54:58.165Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.2.0.rc2", }, { "releaseTimestamp": "2018-04-09T20:07:04.834Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.2.0", }, { "releaseTimestamp": "2018-07-30T20:22:38.749Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.2.1.rc1", }, { "releaseTimestamp": "2018-08-07T21:44:52.020Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.2.1", }, { "releaseTimestamp": "2018-11-27T20:14:16.796Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.2.1.1", }, { "releaseTimestamp": "2018-11-28T22:55:23.827Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.2.2.rc1", }, { "releaseTimestamp": "2018-12-04T18:15:02.233Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.2.2", }, ], @@ -3777,2380 +2422,1364 @@ exports[`modules/datasource/rubygems/index getReleases uses rubygems.org if no r exports[`modules/datasource/rubygems/index getReleases works with real data 1`] = ` { + "changelogUrl": "https://www.railschangelog.com/", "homepage": "http://rubyonrails.org", "registryUrl": "https://thirdparty.com", "releases": [ { "releaseTimestamp": "2009-07-25T18:01:56.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "0.8.0", }, { "releaseTimestamp": "2009-07-25T18:01:56.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "0.8.5", }, { "releaseTimestamp": "2009-07-25T18:01:56.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "0.9.0", }, { "releaseTimestamp": "2009-07-25T18:01:56.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "0.9.1", }, { "releaseTimestamp": "2009-07-25T18:01:56.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "0.9.2", }, { "releaseTimestamp": "2009-07-25T18:01:55.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "0.9.3", }, { "releaseTimestamp": "2009-07-25T18:01:55.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "0.9.4", }, { "releaseTimestamp": "2009-07-25T18:01:55.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "0.9.4.1", }, { "releaseTimestamp": "2009-07-25T18:01:55.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "0.9.5", }, { "releaseTimestamp": "2009-07-25T18:01:58.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "0.10.0", }, { "releaseTimestamp": "2009-07-25T18:01:58.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "0.10.1", }, { "releaseTimestamp": "2009-07-25T18:01:58.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "0.11.0", }, { "releaseTimestamp": "2009-07-25T18:01:58.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "0.11.1", }, { "releaseTimestamp": "2009-07-25T18:01:58.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "0.12.0", }, { "releaseTimestamp": "2009-07-25T18:01:57.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "0.12.1", }, { "releaseTimestamp": "2009-07-25T18:01:57.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "0.13.0", }, { "releaseTimestamp": "2009-07-25T18:01:57.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "0.13.1", }, { "releaseTimestamp": "2009-07-25T18:01:57.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "0.14.1", }, { "releaseTimestamp": "2009-07-25T18:01:57.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "0.14.2", }, { "releaseTimestamp": "2009-07-25T18:01:56.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "0.14.3", }, { "releaseTimestamp": "2009-07-25T18:01:56.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "0.14.4", }, { "releaseTimestamp": "2009-07-25T18:01:55.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "1.0.0", }, { "releaseTimestamp": "2009-07-25T18:01:55.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "1.1.0", }, { "releaseTimestamp": "2009-07-25T18:01:55.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "1.1.1", }, { "releaseTimestamp": "2009-07-25T18:01:54.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "1.1.2", }, { "releaseTimestamp": "2009-07-25T18:01:54.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "1.1.3", }, { "releaseTimestamp": "2009-07-25T18:01:54.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "1.1.4", }, { "releaseTimestamp": "2009-07-25T18:01:54.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "1.1.5", }, { "releaseTimestamp": "2009-07-25T18:01:54.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "1.1.6", }, { "releaseTimestamp": "2009-07-25T18:01:53.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "1.2.0", }, { "releaseTimestamp": "2009-07-25T18:01:52.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "1.2.1", }, { "releaseTimestamp": "2009-07-25T18:01:52.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "1.2.2", }, { "releaseTimestamp": "2009-07-25T18:01:52.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "1.2.3", }, { "releaseTimestamp": "2009-07-25T18:01:52.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "1.2.4", }, { "releaseTimestamp": "2009-07-25T18:01:52.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "1.2.5", }, { "releaseTimestamp": "2009-07-25T18:01:51.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "1.2.6", }, { "releaseTimestamp": "2009-07-25T18:01:51.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "2.0.0", }, { "releaseTimestamp": "2009-07-25T18:01:51.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "2.0.1", }, { "releaseTimestamp": "2009-07-25T18:01:51.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "2.0.2", }, { "releaseTimestamp": "2009-07-25T18:01:51.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "2.0.4", }, { "releaseTimestamp": "2009-07-25T18:01:50.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "2.0.5", }, { "releaseTimestamp": "2009-07-25T18:01:50.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "2.1.0", }, { "releaseTimestamp": "2009-07-25T18:01:50.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "2.1.1", }, { "releaseTimestamp": "2009-07-25T18:01:50.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "2.1.2", }, { "releaseTimestamp": "2009-07-25T18:01:49.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "2.2.2", }, { "releaseTimestamp": "2009-09-28T09:25:13.132Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "2.2.3", }, { "releaseTimestamp": "2009-07-25T18:01:49.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "2.3.2", }, { "releaseTimestamp": "2009-08-05T13:21:07.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "2.3.3", }, { "releaseTimestamp": "2009-09-04T17:33:48.000Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "2.3.4", }, { "releaseTimestamp": "2009-11-27T00:12:56.921Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "2.3.5", }, { "releaseTimestamp": "2010-05-23T07:49:23.602Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "2.3.6", }, { "releaseTimestamp": "2010-05-24T08:23:05.731Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "2.3.7", }, { "releaseTimestamp": "2010-05-24T21:17:25.987Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": "> 1.3.1", "version": "2.3.8.pre1", }, { "releaseTimestamp": "2010-05-25T04:53:06.895Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "2.3.8", }, { "releaseTimestamp": "2010-08-30T03:32:34.689Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": "> 1.3.1", "version": "2.3.9.pre", }, { "releaseTimestamp": "2010-09-04T21:54:41.257Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "2.3.9", }, { "releaseTimestamp": "2010-10-14T20:53:17.413Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "2.3.10", }, { "releaseTimestamp": "2011-02-08T21:17:36.254Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "2.3.11", }, { "releaseTimestamp": "2011-06-08T00:22:06.357Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "2.3.12", }, { "releaseTimestamp": "2011-08-16T22:01:21.962Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "2.3.14", }, { "releaseTimestamp": "2013-01-08T20:08:28.812Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "2.3.15", }, { "releaseTimestamp": "2013-01-28T21:01:30.451Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "2.3.16", }, { "releaseTimestamp": "2013-02-11T18:17:30.726Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "2.3.17", }, { "releaseTimestamp": "2013-03-18T17:13:25.422Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 0", "version": "2.3.18", }, { "releaseTimestamp": "2010-02-05T03:02:19.496Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": "> 1.3.1", "version": "3.0.0.beta", }, { "releaseTimestamp": "2010-04-01T21:26:26.222Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.0.beta2", }, { "releaseTimestamp": "2010-04-13T19:23:14.932Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.0.beta3", }, { "releaseTimestamp": "2010-06-08T22:33:16.046Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.0.beta4", }, { "releaseTimestamp": "2010-07-26T21:43:12.765Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.0.rc", }, { "releaseTimestamp": "2010-08-24T03:04:45.033Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.0.rc2", }, { "releaseTimestamp": "2010-08-29T23:11:11.490Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.0", }, { "releaseTimestamp": "2010-10-14T20:55:44.846Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.1", }, { "releaseTimestamp": "2010-11-15T19:33:41.460Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.2", }, { "releaseTimestamp": "2010-11-16T16:29:00.892Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.3", }, { "releaseTimestamp": "2011-01-30T23:00:37.572Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.4.rc1", }, { "releaseTimestamp": "2011-02-08T21:17:48.221Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.4", }, { "releaseTimestamp": "2011-02-23T19:08:34.691Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.5.rc1", }, { "releaseTimestamp": "2011-02-27T02:30:55.377Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.5", }, { "releaseTimestamp": "2011-03-29T20:47:15.107Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.6.rc1", }, { "releaseTimestamp": "2011-03-31T05:28:51.216Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.6.rc2", }, { "releaseTimestamp": "2011-04-05T23:05:21.745Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.6", }, { "releaseTimestamp": "2011-04-14T21:57:06.386Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.7.rc1", }, { "releaseTimestamp": "2011-04-15T17:33:53.132Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.7.rc2", }, { "releaseTimestamp": "2011-04-18T21:05:54.308Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.7", }, { "releaseTimestamp": "2011-05-26T00:11:36.891Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.8.rc1", }, { "releaseTimestamp": "2011-05-27T16:32:24.502Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.8.rc2", }, { "releaseTimestamp": "2011-05-31T00:08:18.745Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.8.rc4", }, { "releaseTimestamp": "2011-06-08T00:16:45.270Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.8", }, { "releaseTimestamp": "2011-06-08T21:20:17.404Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.9.rc1", }, { "releaseTimestamp": "2011-06-09T22:51:39.349Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.9.rc3", }, { "releaseTimestamp": "2011-06-12T21:24:34.980Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.9.rc4", }, { "releaseTimestamp": "2011-06-12T21:30:07.555Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.9.rc5", }, { "releaseTimestamp": "2011-06-16T10:05:11.080Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.9", }, { "releaseTimestamp": "2011-08-05T00:12:05.290Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.10.rc1", }, { "releaseTimestamp": "2011-08-16T22:14:17.045Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.10", }, { "releaseTimestamp": "2011-11-18T01:23:23.249Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.11", }, { "releaseTimestamp": "2012-02-22T21:39:19.764Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.12.rc1", }, { "releaseTimestamp": "2012-03-01T17:52:15.609Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.12", }, { "releaseTimestamp": "2012-05-28T19:01:47.715Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.13.rc1", }, { "releaseTimestamp": "2012-05-31T18:24:59.747Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.13", }, { "releaseTimestamp": "2012-06-12T21:26:07.460Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.14", }, { "releaseTimestamp": "2012-06-13T03:07:06.509Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.15", }, { "releaseTimestamp": "2012-07-26T22:08:54.212Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.16", }, { "releaseTimestamp": "2012-08-09T21:16:44.882Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.17", }, { "releaseTimestamp": "2013-01-02T21:19:52.960Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.18", }, { "releaseTimestamp": "2013-01-08T20:08:33.922Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.19", }, { "releaseTimestamp": "2013-01-28T21:01:34.374Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.0.20", }, { "releaseTimestamp": "2011-05-05T01:23:18.105Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.0.beta1", }, { "releaseTimestamp": "2011-05-22T02:26:25.383Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.0.rc1", }, { "releaseTimestamp": "2011-06-08T00:16:57.976Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.0.rc2", }, { "releaseTimestamp": "2011-06-08T21:27:28.270Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.0.rc3", }, { "releaseTimestamp": "2011-06-09T22:56:24.880Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.0.rc4", }, { "releaseTimestamp": "2011-07-25T23:05:19.817Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.0.rc5", }, { "releaseTimestamp": "2011-08-16T22:33:32.921Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.0.rc6", }, { "releaseTimestamp": "2011-08-29T03:27:19.194Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.0.rc8", }, { "releaseTimestamp": "2011-08-31T02:18:30.035Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.0", }, { "releaseTimestamp": "2011-09-15T00:27:03.617Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.1.rc1", }, { "releaseTimestamp": "2011-09-29T22:17:03.417Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.1.rc2", }, { "releaseTimestamp": "2011-10-06T02:31:00.452Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.1.rc3", }, { "releaseTimestamp": "2011-10-07T15:30:09.628Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.1", }, { "releaseTimestamp": "2011-11-14T14:17:34.523Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.2.rc1", }, { "releaseTimestamp": "2011-11-14T15:49:20.198Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.2.rc2", }, { "releaseTimestamp": "2011-11-18T01:33:32.509Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.2", }, { "releaseTimestamp": "2011-11-20T22:52:57.492Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.3", }, { "releaseTimestamp": "2012-02-22T21:39:29.633Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.4.rc1", }, { "releaseTimestamp": "2012-03-01T17:52:28.342Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.4", }, { "releaseTimestamp": "2012-05-28T19:01:51.050Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.5.rc1", }, { "releaseTimestamp": "2012-05-31T18:25:06.617Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.5", }, { "releaseTimestamp": "2012-06-12T21:26:16.856Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.6", }, { "releaseTimestamp": "2012-07-26T22:09:00.975Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.7", }, { "releaseTimestamp": "2012-08-09T21:20:27.129Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.8", }, { "releaseTimestamp": "2013-01-02T21:19:56.845Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.9", }, { "releaseTimestamp": "2013-01-08T20:08:37.727Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.10", }, { "releaseTimestamp": "2013-02-11T18:17:37.200Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.11", }, { "releaseTimestamp": "2013-03-18T17:13:29.344Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.1.12", }, { "releaseTimestamp": "2011-12-20T00:41:10.661Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.0.rc1", }, { "releaseTimestamp": "2012-01-04T21:05:27.454Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.0.rc2", }, { "releaseTimestamp": "2012-01-20T16:47:48.848Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.0", }, { "releaseTimestamp": "2012-01-26T23:09:41.494Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.1", }, { "releaseTimestamp": "2012-02-22T21:39:35.308Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.2.rc1", }, { "releaseTimestamp": "2012-03-01T17:52:33.094Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.2", }, { "releaseTimestamp": "2012-03-27T17:11:24.443Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.3.rc1", }, { "releaseTimestamp": "2012-03-29T16:14:14.715Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.3.rc2", }, { "releaseTimestamp": "2012-03-30T22:26:20.685Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.3", }, { "releaseTimestamp": "2012-05-28T19:01:55.834Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.4.rc1", }, { "releaseTimestamp": "2012-05-31T18:25:13.532Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.4", }, { "releaseTimestamp": "2012-06-01T03:39:04.678Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.5", }, { "releaseTimestamp": "2012-06-12T21:26:21.434Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.6", }, { "releaseTimestamp": "2012-07-23T21:45:55.204Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.7.rc1", }, { "releaseTimestamp": "2012-07-26T22:09:06.275Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.7", }, { "releaseTimestamp": "2012-08-01T20:57:56.061Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.8.rc1", }, { "releaseTimestamp": "2012-08-03T14:29:05.254Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.8.rc2", }, { "releaseTimestamp": "2012-08-09T21:23:34.632Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.8", }, { "releaseTimestamp": "2012-10-29T17:07:08.109Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.9.rc1", }, { "releaseTimestamp": "2012-11-01T17:39:37.178Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.9.rc2", }, { "releaseTimestamp": "2012-11-09T18:00:50.077Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.9.rc3", }, { "releaseTimestamp": "2012-11-12T15:21:34.822Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.9", }, { "releaseTimestamp": "2013-01-02T21:20:01.186Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.10", }, { "releaseTimestamp": "2013-01-08T20:08:45.798Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.11", }, { "releaseTimestamp": "2013-02-11T18:17:41.481Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.12", }, { "releaseTimestamp": "2013-02-27T20:25:46.062Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.13.rc1", }, { "releaseTimestamp": "2013-03-06T23:06:19.052Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.13.rc2", }, { "releaseTimestamp": "2013-03-18T17:13:33.058Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.13", }, { "releaseTimestamp": "2013-07-13T00:25:39.110Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.14.rc1", }, { "releaseTimestamp": "2013-07-16T16:13:33.339Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.14.rc2", }, { "releaseTimestamp": "2013-07-22T16:44:50.870Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.14", }, { "releaseTimestamp": "2013-10-03T18:54:09.709Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.15.rc1", }, { "releaseTimestamp": "2013-10-04T20:48:45.484Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.15.rc2", }, { "releaseTimestamp": "2013-10-11T21:17:17.374Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.15.rc3", }, { "releaseTimestamp": "2013-10-16T17:23:10.503Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.15", }, { "releaseTimestamp": "2013-12-03T19:01:19.549Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.16", }, { "releaseTimestamp": "2014-02-18T18:54:56.443Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.3.6", "version": "3.2.17", }, { "releaseTimestamp": "2014-05-06T16:17:02.829Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.8.7", - "rubygemsVersion": ">= 1.3.6", "version": "3.2.18", }, { "releaseTimestamp": "2014-07-02T17:02:48.733Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.8.7", - "rubygemsVersion": ">= 1.3.6", "version": "3.2.19", }, { "releaseTimestamp": "2014-10-30T18:37:26.434Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.8.7", - "rubygemsVersion": ">= 1.3.6", "version": "3.2.20", }, { "releaseTimestamp": "2014-11-17T16:00:44.994Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.8.7", - "rubygemsVersion": ">= 1.3.6", "version": "3.2.21", }, { "releaseTimestamp": "2015-06-16T18:06:38.294Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.8.7", - "rubygemsVersion": ">= 1.3.6", "version": "3.2.22", }, { "releaseTimestamp": "2016-01-25T19:26:12.364Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.8.7", - "rubygemsVersion": ">= 1.3.6", "version": "3.2.22.1", }, { "releaseTimestamp": "2016-02-29T19:24:19.757Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.8.7", - "rubygemsVersion": ">= 1.3.6", "version": "3.2.22.2", }, { "releaseTimestamp": "2016-08-11T17:34:59.710Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.8.7", - "rubygemsVersion": ">= 1.3.6", "version": "3.2.22.3", }, { "releaseTimestamp": "2016-08-11T19:20:46.883Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.8.7", - "rubygemsVersion": ">= 1.3.6", "version": "3.2.22.4", }, { "releaseTimestamp": "2016-09-14T21:19:01.962Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.8.7", - "rubygemsVersion": ">= 1.3.6", "version": "3.2.22.5", }, { "releaseTimestamp": "2013-02-26T00:05:43.566Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.8.11", "version": "4.0.0.beta1", }, { "releaseTimestamp": "2013-04-29T15:39:05.085Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.8.11", "version": "4.0.0.rc1", }, { "releaseTimestamp": "2013-06-11T20:26:00.144Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.8.11", "version": "4.0.0.rc2", }, { "releaseTimestamp": "2013-06-25T14:32:58.526Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.8.11", "version": "4.0.0", }, { "releaseTimestamp": "2013-10-17T16:46:23.993Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.8.11", "version": "4.0.1.rc1", }, { "releaseTimestamp": "2013-10-21T22:01:19.341Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.8.11", "version": "4.0.1.rc2", }, { "releaseTimestamp": "2013-10-23T21:41:08.791Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.8.11", "version": "4.0.1.rc3", }, { "releaseTimestamp": "2013-10-30T20:49:25.297Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.8.11", "version": "4.0.1.rc4", }, { "releaseTimestamp": "2013-11-01T19:08:16.307Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.8.11", "version": "4.0.1", }, { "releaseTimestamp": "2013-12-03T19:01:29.867Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.8.11", "version": "4.0.2", }, { "releaseTimestamp": "2014-02-18T18:49:43.150Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.8.11", "version": "4.0.3", }, { "releaseTimestamp": "2014-03-11T17:31:18.568Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.8.11", "version": "4.0.4.rc1", }, { "releaseTimestamp": "2014-03-14T17:37:07.331Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.8.11", "version": "4.0.4", }, { "releaseTimestamp": "2014-05-06T16:13:27.132Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.0.5", }, { "releaseTimestamp": "2014-05-27T16:06:55.364Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.0.6.rc1", }, { "releaseTimestamp": "2014-06-16T16:16:01.642Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.0.6.rc2", }, { "releaseTimestamp": "2014-06-23T17:24:41.466Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.0.6.rc3", }, { "releaseTimestamp": "2014-06-26T16:30:13.579Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.0.6", }, { "releaseTimestamp": "2014-07-02T17:04:32.418Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.0.7", }, { "releaseTimestamp": "2014-07-02T19:42:37.603Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.0.8", }, { "releaseTimestamp": "2014-08-18T17:03:01.087Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.0.9", }, { "releaseTimestamp": "2014-08-19T20:48:29.471Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.0.10.rc1", }, { "releaseTimestamp": "2014-09-08T17:55:45.314Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.0.10.rc2", }, { "releaseTimestamp": "2014-09-11T17:33:15.455Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.0.10", }, { "releaseTimestamp": "2014-10-30T18:37:38.192Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.0.11", }, { "releaseTimestamp": "2014-11-19T19:09:54.075Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.0.11.1", }, { "releaseTimestamp": "2014-11-17T16:01:00.306Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.0.12", }, { "releaseTimestamp": "2015-01-02T00:54:54.587Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.0.13.rc1", }, { "releaseTimestamp": "2015-01-06T20:08:59.935Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.0.13", }, { "releaseTimestamp": "2013-12-18T00:15:16.640Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.8.11", "version": "4.1.0.beta1", }, { "releaseTimestamp": "2014-02-18T18:52:57.614Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.8.11", "version": "4.1.0.beta2", }, { "releaseTimestamp": "2014-02-18T20:59:23.632Z", - "rubyPlatform": "ruby", - "rubyVersion": null, - "rubygemsVersion": ">= 1.8.11", "version": "4.1.0.rc1", }, { "releaseTimestamp": "2014-03-25T20:12:47.195Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.0.rc2", }, { "releaseTimestamp": "2014-04-08T19:21:51.275Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.0", }, { "releaseTimestamp": "2014-05-06T16:11:31.458Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.1", }, { "releaseTimestamp": "2014-05-27T16:12:48.106Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.2.rc1", }, { "releaseTimestamp": "2014-06-16T16:30:46.332Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.2.rc2", }, { "releaseTimestamp": "2014-06-23T17:28:46.002Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.2.rc3", }, { "releaseTimestamp": "2014-06-26T14:50:09.079Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.2", }, { "releaseTimestamp": "2014-07-02T17:06:42.181Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.3", }, { "releaseTimestamp": "2014-07-02T19:53:35.556Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.4", }, { "releaseTimestamp": "2014-08-18T17:01:03.727Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.5", }, { "releaseTimestamp": "2014-08-19T20:52:47.110Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.6.rc1", }, { "releaseTimestamp": "2014-09-08T18:13:12.723Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.6.rc2", }, { "releaseTimestamp": "2014-09-11T17:26:04.576Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.6", }, { "releaseTimestamp": "2014-10-30T18:37:49.213Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.7", }, { "releaseTimestamp": "2014-11-19T19:12:12.692Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.7.1", }, { "releaseTimestamp": "2014-11-17T16:01:13.385Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.8", }, { "releaseTimestamp": "2015-01-02T01:11:10.973Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.9.rc1", }, { "releaseTimestamp": "2015-01-06T20:04:31.185Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.9", }, { "releaseTimestamp": "2015-02-20T22:25:09.666Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.10.rc1", }, { "releaseTimestamp": "2015-02-25T22:22:40.645Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.10.rc2", }, { "releaseTimestamp": "2015-03-02T21:39:47.964Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.10.rc3", }, { "releaseTimestamp": "2015-03-12T21:32:52.724Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.10.rc4", }, { "releaseTimestamp": "2015-03-19T16:50:27.388Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.10", }, { "releaseTimestamp": "2015-06-16T18:00:13.043Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.11", }, { "releaseTimestamp": "2015-06-22T14:05:08.486Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.12.rc1", }, { "releaseTimestamp": "2015-06-25T21:26:08.544Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.12", }, { "releaseTimestamp": "2015-08-14T15:13:26.943Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.13.rc1", }, { "releaseTimestamp": "2015-08-24T18:02:56.741Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.13", }, { "releaseTimestamp": "2015-10-30T20:45:42.801Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.14.rc1", }, { "releaseTimestamp": "2015-11-05T02:55:44.276Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.14.rc2", }, { "releaseTimestamp": "2015-11-12T18:20:40.613Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.14", }, { "releaseTimestamp": "2016-01-25T19:26:27.339Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.14.1", }, { "releaseTimestamp": "2016-02-29T19:19:55.523Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.14.2", }, { "releaseTimestamp": "2016-03-01T18:43:40.764Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.15.rc1", }, { "releaseTimestamp": "2016-03-07T22:37:14.594Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.15", }, { "releaseTimestamp": "2016-07-02T02:15:20.923Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.16.rc1", }, { "releaseTimestamp": "2016-07-12T22:20:56.527Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.1.16", }, { "releaseTimestamp": "2014-08-20T02:34:44.046Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.0.beta1", }, { "releaseTimestamp": "2014-09-29T17:16:38.761Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.0.beta2", }, { "releaseTimestamp": "2014-10-30T18:37:59.690Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.0.beta3", }, { "releaseTimestamp": "2014-10-30T22:13:30.689Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.0.beta4", }, { "releaseTimestamp": "2014-11-28T17:53:27.822Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.0.rc1", }, { "releaseTimestamp": "2014-12-05T23:20:12.824Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.0.rc2", }, { "releaseTimestamp": "2014-12-13T02:58:44.762Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.0.rc3", }, { "releaseTimestamp": "2014-12-20T00:15:37.476Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.0", }, { "releaseTimestamp": "2015-02-20T22:21:34.214Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.1.rc1", }, { "releaseTimestamp": "2015-02-25T22:19:50.245Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.1.rc2", }, { "releaseTimestamp": "2015-03-02T21:35:50.169Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.1.rc3", }, { "releaseTimestamp": "2015-03-12T21:25:52.551Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.1.rc4", }, { "releaseTimestamp": "2015-03-19T16:42:01.191Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.1", }, { "releaseTimestamp": "2015-06-16T18:03:17.061Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.2", }, { "releaseTimestamp": "2015-06-22T14:23:17.788Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.3.rc1", }, { "releaseTimestamp": "2015-06-25T21:30:57.890Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.3", }, { "releaseTimestamp": "2015-08-14T15:21:15.566Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.4.rc1", }, { "releaseTimestamp": "2015-08-24T18:27:12.716Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.4", }, { "releaseTimestamp": "2015-10-30T20:47:59.397Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.5.rc1", }, { "releaseTimestamp": "2015-11-05T03:02:33.340Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.5.rc2", }, { "releaseTimestamp": "2015-11-12T17:06:55.226Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.5", }, { "releaseTimestamp": "2016-01-25T19:26:41.410Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.5.1", }, { "releaseTimestamp": "2016-02-29T19:17:10.564Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.5.2", }, { "releaseTimestamp": "2016-03-01T18:37:54.172Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.6.rc1", }, { "releaseTimestamp": "2016-03-07T22:33:22.563Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.6", }, { "releaseTimestamp": "2016-07-01T00:33:36.424Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.7.rc1", }, { "releaseTimestamp": "2016-07-13T02:57:05.601Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.7", }, { "releaseTimestamp": "2016-08-11T17:35:16.160Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.7.1", }, { "releaseTimestamp": "2017-02-10T02:46:51.222Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.8.rc1", }, { "releaseTimestamp": "2017-02-21T16:08:53.220Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.8", }, { "releaseTimestamp": "2017-06-13T18:50:29.897Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.9.rc1", }, { "releaseTimestamp": "2017-06-19T22:28:22.086Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.9.rc2", }, { "releaseTimestamp": "2017-06-26T21:30:56.077Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.9", }, { "releaseTimestamp": "2017-09-20T19:42:33.297Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.10.rc1", }, { "releaseTimestamp": "2017-09-27T14:29:42.567Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.10", }, { "releaseTimestamp": "2018-11-27T20:07:25.845Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 1.9.3", - "rubygemsVersion": ">= 1.8.11", "version": "4.2.11", }, { "releaseTimestamp": "2015-12-18T21:18:13.306Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.0.0.beta1", }, { "releaseTimestamp": "2016-01-25T19:26:49.903Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.0.0.beta1.1", }, { "releaseTimestamp": "2016-02-01T22:06:25.279Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.0.0.beta2", }, { "releaseTimestamp": "2016-02-24T16:16:22.722Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.0.0.beta3", }, { "releaseTimestamp": "2016-04-27T20:55:26.508Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.0.0.beta4", }, { "releaseTimestamp": "2016-05-06T22:02:43.345Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.0.0.racecar1", }, { "releaseTimestamp": "2016-05-06T21:57:46.793Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.0.0.rc1", }, { "releaseTimestamp": "2016-06-22T20:03:41.237Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.0.0.rc2", }, { "releaseTimestamp": "2016-06-30T21:32:45.255Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.0.0", }, { "releaseTimestamp": "2016-08-11T17:35:27.196Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.0.0.1", }, { "releaseTimestamp": "2016-11-30T20:02:44.553Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.0.1.rc1", }, { "releaseTimestamp": "2016-12-09T19:13:12.953Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.0.1.rc2", }, { "releaseTimestamp": "2016-12-21T00:07:46.527Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.0.1", }, { "releaseTimestamp": "2017-02-25T00:55:48.618Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.0.2.rc1", }, { "releaseTimestamp": "2017-03-01T23:13:53.219Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.0.2", }, { "releaseTimestamp": "2017-05-12T20:08:33.226Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.0.3", }, { "releaseTimestamp": "2017-06-14T20:49:29.610Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.0.4.rc1", }, { "releaseTimestamp": "2017-06-19T21:58:56.501Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.0.4", }, { "releaseTimestamp": "2017-07-19T19:43:58.280Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.0.5.rc1", }, { "releaseTimestamp": "2017-07-25T20:26:10.369Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.0.5.rc2", }, { "releaseTimestamp": "2017-07-31T19:05:29.060Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.0.5", }, { "releaseTimestamp": "2017-08-24T19:21:20.599Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.0.6.rc1", }, { "releaseTimestamp": "2017-09-08T00:47:42.201Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.0.6", }, { "releaseTimestamp": "2018-03-29T18:18:14.388Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.0.7", }, { "releaseTimestamp": "2018-11-27T20:09:36.347Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.0.7.1", }, { "releaseTimestamp": "2017-02-23T20:00:44.720Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.1.0.beta1", }, { "releaseTimestamp": "2017-03-20T18:57:56.595Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.1.0.rc1", }, { "releaseTimestamp": "2017-04-21T01:31:13.442Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.1.0.rc2", }, { "releaseTimestamp": "2017-04-27T21:00:47.670Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.1.0", }, { "releaseTimestamp": "2017-05-12T20:11:39.743Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.1.1", }, { "releaseTimestamp": "2017-06-20T17:03:49.322Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.1.2.rc1", }, { "releaseTimestamp": "2017-06-26T21:51:41.161Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.1.2", }, { "releaseTimestamp": "2017-07-19T19:38:05.393Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.1.3.rc1", }, { "releaseTimestamp": "2017-07-25T20:18:18.420Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.1.3.rc2", }, { "releaseTimestamp": "2017-07-31T19:12:53.241Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.1.3.rc3", }, { "releaseTimestamp": "2017-08-03T19:15:15.370Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.1.3", }, { "releaseTimestamp": "2017-08-24T19:37:37.728Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.1.4.rc1", }, { "releaseTimestamp": "2017-09-08T00:52:07.791Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.1.4", }, { "releaseTimestamp": "2018-02-01T19:00:37.520Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.1.5.rc1", }, { "releaseTimestamp": "2018-02-14T20:02:02.541Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.1.5", }, { "releaseTimestamp": "2018-03-29T18:29:03.149Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.1.6", }, { "releaseTimestamp": "2018-11-27T20:11:47.585Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.1.6.1", }, { "releaseTimestamp": "2017-11-27T19:19:13.809Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.2.0.beta1", }, { "releaseTimestamp": "2017-11-28T05:04:37.765Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.2.0.beta2", }, { "releaseTimestamp": "2018-01-30T23:38:56.843Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.2.0.rc1", }, { "releaseTimestamp": "2018-03-20T17:54:58.165Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.2.0.rc2", }, { "releaseTimestamp": "2018-04-09T20:07:04.834Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.2.0", }, { "releaseTimestamp": "2018-07-30T20:22:38.749Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.2.1.rc1", }, { "releaseTimestamp": "2018-08-07T21:44:52.020Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.2.1", }, { "releaseTimestamp": "2018-11-27T20:14:16.796Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.2.1.1", }, { "releaseTimestamp": "2018-11-28T22:55:23.827Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.2.2.rc1", }, { "releaseTimestamp": "2018-12-04T18:15:02.233Z", - "rubyPlatform": "ruby", - "rubyVersion": ">= 2.2.2", - "rubygemsVersion": ">= 1.8.11", "version": "5.2.2", }, ], diff --git a/lib/modules/datasource/rubygems/get.ts b/lib/modules/datasource/rubygems/get.ts index 064fa275c01477..87e658b86fc3c9 100644 --- a/lib/modules/datasource/rubygems/get.ts +++ b/lib/modules/datasource/rubygems/get.ts @@ -1,185 +1,208 @@ import { Marshal } from '@qnighy/marshal'; +import is from '@sindresorhus/is'; +import { z } from 'zod'; import { logger } from '../../../logger'; import { HttpError } from '../../../util/http'; +import { LooseArray } from '../../../util/schema-utils'; import { getQueryString, joinUrlParts, parseUrl } from '../../../util/url'; import { Datasource } from '../datasource'; import type { GetReleasesConfig, Release, ReleaseResult } from '../types'; -import type { - JsonGemVersions, - JsonGemsInfo, - MarshalledVersionInfo, -} from './types'; -const INFO_PATH = '/api/v1/gems'; -const VERSIONS_PATH = '/api/v1/versions'; -const DEPENDENCIES_PATH = '/api/v1/dependencies'; +const MarshalledVersionInfo = LooseArray( + z + .object({ + number: z.string(), + }) + .transform(({ number: version }) => ({ version })) +) + .transform((releases) => (releases.length === 0 ? null : { releases })) + .nullable() + .catch(null); + +const GemsInfo = z + .object({ + name: z.string().transform((x) => x.toLowerCase()), + version: z.string().nullish().catch(null), + changelog_uri: z.string().nullish().catch(null), + homepage_uri: z.string().nullish().catch(null), + source_code_uri: z.string().nullish().catch(null), + }) + .transform( + ({ + name: packageName, + version, + changelog_uri: changelogUrl, + homepage_uri: homepage, + source_code_uri: sourceUrl, + }) => ({ + packageName, + version, + changelogUrl, + homepage, + sourceUrl, + }) + ); +type GemsInfo = z.infer; + +const GemVersions = LooseArray( + z + .object({ + number: z.string(), + created_at: z.string(), + platform: z.string().nullable().catch(null), + ruby_version: z.string().nullable().catch(null), + rubygems_version: z.string().nullable().catch(null), + }) + .transform( + ({ + number: version, + created_at: releaseTimestamp, + platform, + ruby_version: rubyVersion, + rubygems_version: rubygemsVersion, + }): Release => { + const result: Release = { version, releaseTimestamp }; + const constraints: Record = {}; + + if (platform) { + constraints.platform = [platform]; + } + + if (rubyVersion) { + constraints.ruby = [rubyVersion]; + } + + if (rubygemsVersion) { + constraints.rubygems = [rubygemsVersion]; + } + + if (!is.emptyObject(constraints)) { + result.constraints = constraints; + } + + return result; + } + ) +); +type GemVersions = z.infer; export class InternalRubyGemsDatasource extends Datasource { constructor(override readonly id: string) { super(id); } - private knownFallbackHosts = ['rubygems.pkg.github.com', 'gitlab.com']; - - override getReleases({ - packageName, - registryUrl, - }: GetReleasesConfig): Promise { + async getReleases(config: GetReleasesConfig): Promise { + const registryUrl = config.registryUrl; // istanbul ignore if if (!registryUrl) { - return Promise.resolve(null); + return null; } + + const packageName = config.packageName.toLowerCase(); + const hostname = parseUrl(registryUrl)?.hostname; - if (hostname && this.knownFallbackHosts.includes(hostname)) { - return this.getDependencyFallback(packageName, registryUrl); - } - return this.getDependency(packageName, registryUrl); + return hostname === 'rubygems.pkg.github.com' || hostname === 'gitlab.com' + ? await this.getDependencyFallback(registryUrl, packageName) + : await this.getDependency(registryUrl, packageName); } async getDependencyFallback( - dependency: string, - registry: string + registryUrl: string, + packageName: string ): Promise { - logger.debug( - { dependency, api: DEPENDENCIES_PATH }, - 'RubyGems lookup for dependency' - ); - const info = await this.fetchBuffer( - dependency, - registry, - DEPENDENCIES_PATH - ); - if (!info || info.length === 0) { - return null; - } - const releases = info.map( - ({ number: version, platform: rubyPlatform }) => ({ - version, - rubyPlatform, - }) - ); - return { - releases, - sourceUrl: null, - }; + const path = joinUrlParts(registryUrl, `/api/v1/dependencies`); + const query = getQueryString({ gems: packageName }); + const url = `${path}?${query}`; + const { body: buffer } = await this.http.getBuffer(url); + const data = Marshal.parse(buffer); + return MarshalledVersionInfo.parse(data); } - async getDependency( - dependency: string, - registry: string - ): Promise { - logger.debug( - { dependency, api: INFO_PATH }, - 'RubyGems lookup for dependency' - ); - let info: JsonGemsInfo; - + async fetchGemsInfo( + registryUrl: string, + packageName: string + ): Promise { try { - info = await this.fetchJson(dependency, registry, INFO_PATH); - } catch (error) { + const { body } = await this.http.getJson( + joinUrlParts(registryUrl, '/api/v1/gems', `${packageName}.json`), + GemsInfo + ); + return body; + } catch (err) { // fallback to deps api on 404 - if (error instanceof HttpError && error.response?.statusCode === 404) { - return await this.getDependencyFallback(dependency, registry); + if (err instanceof HttpError && err.response?.statusCode === 404) { + return null; } - throw error; - } - - if (!info) { - logger.debug(`RubyGems package not found packageName: ${dependency} `); - return null; - } - - if (dependency.toLowerCase() !== info.name.toLowerCase()) { - logger.warn( - { lookup: dependency, returned: info.name }, - 'Lookup name does not match with returned.' - ); - return null; + throw err; } + } - let versions: JsonGemVersions[] = []; - let releases: Release[] = []; + async fetchGemVersions( + registryUrl: string, + packageName: string + ): Promise { try { - versions = await this.fetchJson(dependency, registry, VERSIONS_PATH); + const { body } = await this.http.getJson( + joinUrlParts(registryUrl, '/api/v1/versions', `${packageName}.json`), + GemVersions + ); + return body; } catch (err) { if (err.statusCode === 400 || err.statusCode === 404) { logger.debug( - { registry }, + { registry: registryUrl }, 'versions endpoint returns error - falling back to info endpoint' ); + return null; } else { throw err; } } + } - // TODO: invalid properties for `Release` see #11312 - - if (versions.length === 0 && info.version) { - logger.warn('falling back to the version from the info endpoint'); - releases = [ - { - version: info.version, - rubyPlatform: info.platform, - } as Release, - ]; - } else { - releases = versions.map( - ({ - number: version, - platform: rubyPlatform, - created_at: releaseTimestamp, - rubygems_version: rubygemsVersion, - ruby_version: rubyVersion, - }) => ({ - version, - rubyPlatform, - releaseTimestamp, - rubygemsVersion, - rubyVersion, - }) - ); + async getDependency( + registryUrl: string, + packageName: string + ): Promise { + const info = await this.fetchGemsInfo(registryUrl, packageName); + if (!info) { + return await this.getDependencyFallback(registryUrl, packageName); } - return { - releases, - homepage: info.homepage_uri, - sourceUrl: info.source_code_uri, - changelogUrl: info.changelog_uri, - }; - } + if (info.packageName !== packageName) { + logger.warn( + { lookup: packageName, returned: info.packageName }, + 'Lookup name does not match the returned name.' + ); + return null; + } - private async fetchJson( - dependency: string, - registry: string, - path: string - ): Promise { - const url = joinUrlParts(registry, path, `${dependency}.json`); + let releases: Release[] | null = null; + const gemVersions = await this.fetchGemVersions(registryUrl, packageName); + if (gemVersions?.length) { + releases = gemVersions; + } else if (info.version) { + releases = [{ version: info.version }]; + } - logger.trace({ registry, dependency, url }, `RubyGems lookup request`); - const response = (await this.http.getJson(url)) || { - body: undefined, - }; + if (!releases) { + return null; + } - return response.body; - } + const result: ReleaseResult = { releases }; - private async fetchBuffer( - dependency: string, - registry: string, - path: string - ): Promise { - const url = `${joinUrlParts(registry, path)}?${getQueryString({ - gems: dependency, - })}`; + if (info.changelogUrl) { + result.changelogUrl = info.changelogUrl; + } - logger.trace({ registry, dependency, url }, `RubyGems lookup request`); - const response = await this.http.getBuffer(url); + if (info.homepage) { + result.homepage = info.homepage; + } - // istanbul ignore if: needs tests - if (!response) { - return null; + if (info.sourceUrl) { + result.sourceUrl = info.sourceUrl; } - return Marshal.parse(response.body) as T; + return result; } } diff --git a/lib/modules/datasource/rubygems/index.spec.ts b/lib/modules/datasource/rubygems/index.spec.ts index 3f62ca70cb9014..6c7a23804c457e 100644 --- a/lib/modules/datasource/rubygems/index.spec.ts +++ b/lib/modules/datasource/rubygems/index.spec.ts @@ -26,12 +26,16 @@ describe('modules/datasource/rubygems/index', () => { httpMock .scope('https://firstparty.com') .get('/basepath/api/v1/gems/rails.json') - .reply(200); + .reply(200, { name: 'rails' }) + .get('/basepath/api/v1/versions/rails.json') + .reply(200, []); httpMock.scope('https://thirdparty.com').get('/versions').reply(404); httpMock .scope('https://thirdparty.com') .get('/api/v1/gems/rails.json') - .reply(200); + .reply(200, { name: 'rails' }) + .get('/api/v1/versions/rails.json') + .reply(200, []); expect( await getPkgReleases({ versioning: rubyVersioning.id, diff --git a/lib/modules/datasource/rubygems/types.ts b/lib/modules/datasource/rubygems/types.ts deleted file mode 100644 index 907ec3620f361e..00000000000000 --- a/lib/modules/datasource/rubygems/types.ts +++ /dev/null @@ -1,44 +0,0 @@ -/** - * see https://guides.rubygems.org/rubygems-org-api/#get---apiv1dependenciesgemscomma-delimited-gem-names - */ -export interface MarshalledVersionInfo { - name: string; - number: string; - platform: string; - dependencies: MarshalledDependency[]; -} - -export type MarshalledDependency = [name: string, version: string]; - -export interface JsonGemDependency { - name: string; - requirements: string; -} - -/** - * see https://guides.rubygems.org/rubygems-org-api/#get---apiv1gemsgem-namejsonyaml - */ -export interface JsonGemsInfo { - // FIXME: This property doesn't exist in api - changelog_uri: string; - dependencies: { - development: JsonGemDependency; - runtime: JsonGemDependency; - }; - homepage_uri: string; - name: string; - platform?: string; - source_code_uri: string; - version?: string; -} - -/** - * see https://guides.rubygems.org/rubygems-org-api/#get---apiv1versionsgem-namejsonyaml - */ -export interface JsonGemVersions { - created_at: string; - number: string; - platform: string; - rubygems_version: string; - ruby_version: string; -} diff --git a/lib/modules/datasource/rubygems/versions-datasource.ts b/lib/modules/datasource/rubygems/versions-datasource.ts index 5122bd759a8b36..1e56a5d89958e8 100644 --- a/lib/modules/datasource/rubygems/versions-datasource.ts +++ b/lib/modules/datasource/rubygems/versions-datasource.ts @@ -45,15 +45,7 @@ const Lines = z } } return { packageName, deletedVersions, addedVersions }; - }), - { - onError: ({ error: err, input }) => { - logger.debug( - { err, input }, - 'Rubygems: failed to parse some version lines' - ); - }, - } + }) ) ); type Lines = z.infer; diff --git a/lib/modules/manager/api.ts b/lib/modules/manager/api.ts index 41dc108d9d1d8c..939a55fe1c58d6 100644 --- a/lib/modules/manager/api.ts +++ b/lib/modules/manager/api.ts @@ -19,6 +19,7 @@ import * as cloudbuild from './cloudbuild'; import * as cocoapods from './cocoapods'; import * as composer from './composer'; import * as conan from './conan'; +import * as cpanfile from './cpanfile'; import * as depsEdn from './deps-edn'; import * as dockerCompose from './docker-compose'; import * as dockerfile from './dockerfile'; @@ -58,6 +59,7 @@ import * as npm from './npm'; import * as nuget from './nuget'; import * as nvm from './nvm'; import * as osgi from './osgi'; +import * as pep621 from './pep621'; import * as pipCompile from './pip-compile'; import * as pip_requirements from './pip_requirements'; import * as pip_setup from './pip_setup'; @@ -107,6 +109,7 @@ api.set('cloudbuild', cloudbuild); api.set('cocoapods', cocoapods); api.set('composer', composer); api.set('conan', conan); +api.set('cpanfile', cpanfile); api.set('deps-edn', depsEdn); api.set('docker-compose', dockerCompose); api.set('dockerfile', dockerfile); @@ -146,6 +149,7 @@ api.set('npm', npm); api.set('nuget', nuget); api.set('nvm', nvm); api.set('osgi', osgi); +api.set('pep621', pep621); api.set('pip-compile', pipCompile); api.set('pip_requirements', pip_requirements); api.set('pip_setup', pip_setup); diff --git a/lib/modules/manager/asdf/extract.spec.ts b/lib/modules/manager/asdf/extract.spec.ts index 4b9e67bf232326..cb4e6b963383d2 100644 --- a/lib/modules/manager/asdf/extract.spec.ts +++ b/lib/modules/manager/asdf/extract.spec.ts @@ -43,10 +43,13 @@ describe('modules/manager/asdf/extract', () => { it('can handle multiple tools in one file', () => { const res = extractPackageFile( - codeBlock`argocd 2.5.4 + codeBlock` +adr-tools 3.0.0 +argocd 2.5.4 awscli 2.8.6 bun 0.2.2 cargo-make 0.36.2 +checkov 2.3.3 clojure 1.11.1.1182 crystal 1.6.1 dart 2.19.3 @@ -57,10 +60,13 @@ ecspresso 2.1.0 elixir 1.14.1 elm 0.19.1 erlang 25.1.2 -flutter 3.7.6 +flutter 3.7.6-stable +flux2 0.41.2 gauche 0.9.12 gohugo extended_0.104.3 golang 1.19.2 +golangci-lint 1.52.2 +hadolint 2.12.0 haskell 9.4.2 helm 3.10.1 helmfile 0.147.0 @@ -70,6 +76,7 @@ java adoptopenjdk-16.0.0+36 julia 1.8.2 just 1.7.0 kotlin 1.7.20 +kubectl 1.26.3 kustomize 4.5.7 lua 5.4.4 nim 1.6.8 @@ -79,6 +86,7 @@ perl 5.37.5 php 8.1.12 pnpm 7.26.2 poetry 1.3.2 +pre-commit 3.3.1 pulumi 3.57.1 python 3.11.0 ruby 3.1.2 @@ -87,7 +95,10 @@ scala 3.2.1 shellcheck 0.8.0 shfmt 3.5.1 terraform 1.3.3 +terraform-docs 0.16.0 terragrunt 0.43.2 +tflint 0.44.1 +tfsec 1.28.1 trivy 0.33.0 zig 0.9.1 maestro 1.24.0 @@ -98,6 +109,12 @@ dummy 1.2.3 ); expect(res).toEqual({ deps: [ + { + currentValue: '3.0.0', + datasource: 'github-tags', + packageName: 'npryce/adr-tools', + depName: 'adr-tools', + }, { currentValue: '2.5.4', datasource: 'github-releases', @@ -124,6 +141,12 @@ dummy 1.2.3 packageName: 'sagiegurari/cargo-make', depName: 'cargo-make', }, + { + currentValue: '2.3.3', + datasource: 'github-tags', + packageName: 'bridgecrewio/checkov', + depName: 'checkov', + }, { currentValue: '1.11.1.1182', datasource: 'github-tags', @@ -195,6 +218,13 @@ dummy 1.2.3 datasource: 'flutter-version', depName: 'flutter', }, + { + currentValue: '0.41.2', + datasource: 'github-tags', + packageName: 'fluxcd/flux2', + depName: 'flux2', + extractVersion: '^v(?.+)', + }, { currentValue: '0.9.12', datasource: 'docker', @@ -215,6 +245,20 @@ dummy 1.2.3 depName: 'golang', extractVersion: '^go(?\\S+)', }, + { + currentValue: '1.52.2', + datasource: 'github-tags', + packageName: 'golangci/golangci-lint', + depName: 'golangci-lint', + extractVersion: '^v(?.+)', + }, + { + currentValue: '2.12.0', + datasource: 'github-tags', + packageName: 'hadolint/hadolint', + depName: 'hadolint', + extractVersion: '^v(?.+)', + }, { currentValue: '9.4.2', datasource: 'github-tags', @@ -276,6 +320,13 @@ dummy 1.2.3 depName: 'kotlin', extractVersion: '^(Kotlin |v)(?\\S+)', }, + { + currentValue: '1.26.3', + datasource: 'github-tags', + packageName: 'kubernetes/kubernetes', + depName: 'kubectl', + extractVersion: '^v(?.+)', + }, { currentValue: '4.5.7', datasource: 'github-releases', @@ -335,6 +386,13 @@ dummy 1.2.3 packageName: 'poetry', depName: 'poetry', }, + { + currentValue: '3.3.1', + datasource: 'github-tags', + packageName: 'pre-commit/pre-commit', + depName: 'pre-commit', + extractVersion: '^v(?.+)', + }, { currentValue: '3.57.1', datasource: 'github-releases', @@ -389,6 +447,13 @@ dummy 1.2.3 depName: 'terraform', extractVersion: '^v(?\\S+)', }, + { + currentValue: '0.16.0', + datasource: 'github-tags', + packageName: 'terraform-docs/terraform-docs', + depName: 'terraform-docs', + extractVersion: '^v(?.+)', + }, { currentValue: '0.43.2', datasource: 'github-releases', @@ -396,6 +461,20 @@ dummy 1.2.3 depName: 'terragrunt', extractVersion: '^v(?\\S+)', }, + { + currentValue: '0.44.1', + datasource: 'github-tags', + packageName: 'terraform-linters/tflint', + depName: 'tflint', + extractVersion: '^v(?.+)', + }, + { + currentValue: '1.28.1', + datasource: 'github-tags', + packageName: 'aquasecurity/tfsec', + depName: 'tfsec', + extractVersion: '^v(?.+)', + }, { currentValue: '0.33.0', datasource: 'github-releases', @@ -437,6 +516,29 @@ dummy 1.2.3 }); }); + it('can handle flutter version channel', () => { + const withChannel = extractPackageFile('flutter 3.10.0-stable'); + expect(withChannel).toEqual({ + deps: [ + { + currentValue: '3.10.0', + datasource: 'flutter-version', + depName: 'flutter', + }, + ], + }); + const withoutChannel = extractPackageFile('flutter 3.10.0'); + expect(withoutChannel).toEqual({ + deps: [ + { + currentValue: '3.10.0', + datasource: 'flutter-version', + depName: 'flutter', + }, + ], + }); + }); + it('can handle java jre / jdk', () => { const jdkRes = extractPackageFile('java adoptopenjdk-16.0.0+36'); expect(jdkRes).toEqual({ diff --git a/lib/modules/manager/asdf/upgradeable-tooling.ts b/lib/modules/manager/asdf/upgradeable-tooling.ts index 921d1274af0276..a80a884030295d 100644 --- a/lib/modules/manager/asdf/upgradeable-tooling.ts +++ b/lib/modules/manager/asdf/upgradeable-tooling.ts @@ -1,3 +1,4 @@ +import { regEx } from '../../../util/regex'; import { DartVersionDatasource } from '../../datasource/dart-version'; import { DockerDatasource } from '../../datasource/docker'; import { FlutterVersionDatasource } from '../../datasource/flutter-version'; @@ -38,6 +39,13 @@ const hugoDefinition: ToolingDefinition = { }; export const upgradeableTooling: Record = { + 'adr-tools': { + asdfPluginUrl: 'https://gitlab.com/td7x/asdf/adr-tools.git', + config: { + datasource: GithubTagsDatasource.id, + packageName: 'npryce/adr-tools', + }, + }, argocd: { asdfPluginUrl: 'https://github.com/beardix/asdf-argocd', config: { @@ -68,6 +76,13 @@ export const upgradeableTooling: Record = { packageName: 'sagiegurari/cargo-make', }, }, + checkov: { + asdfPluginUrl: 'https://github.com/bosmak/asdf-checkov.git', + config: { + datasource: GithubTagsDatasource.id, + packageName: 'bridgecrewio/checkov', + }, + }, clojure: { asdfPluginUrl: 'https://github.com/asdf-community/asdf-clojure', config: { @@ -144,8 +159,18 @@ export const upgradeableTooling: Record = { }, flutter: { asdfPluginUrl: 'https://github.com/oae/asdf-flutter', - config: { + config: (version) => ({ datasource: FlutterVersionDatasource.id, + // asdf-flutter plugin supports channel on version suffix. + currentValue: version.replace(regEx(/-(stable|beta|dev)$/), ''), + }), + }, + flux2: { + asdfPluginUrl: 'https://github.com/tablexi/asdf-flux2.git', + config: { + datasource: GithubTagsDatasource.id, + packageName: 'fluxcd/flux2', + extractVersion: '^v(?.+)', }, }, gauche: { @@ -164,6 +189,22 @@ export const upgradeableTooling: Record = { extractVersion: '^go(?\\S+)', }, }, + 'golangci-lint': { + asdfPluginUrl: 'https://github.com/hypnoglow/asdf-golangci-lint.git', + config: { + datasource: GithubTagsDatasource.id, + packageName: 'golangci/golangci-lint', + extractVersion: '^v(?.+)', + }, + }, + hadolint: { + asdfPluginUrl: 'https://github.com/looztra/asdf-hadolint.git', + config: { + datasource: GithubTagsDatasource.id, + packageName: 'hadolint/hadolint', + extractVersion: '^v(?.+)', + }, + }, haskell: { asdfPluginUrl: 'https://github.com/asdf-community/asdf-haskell', config: { @@ -247,6 +288,14 @@ export const upgradeableTooling: Record = { extractVersion: '^(Kotlin |v)(?\\S+)', }, }, + kubectl: { + asdfPluginUrl: 'https://github.com/Banno/asdf-kubectl.git', + config: { + datasource: GithubTagsDatasource.id, + packageName: 'kubernetes/kubernetes', + extractVersion: '^v(?.+)', + }, + }, kustomize: { asdfPluginUrl: 'https://github.com/Banno/asdf-kustomize', config: { @@ -316,6 +365,14 @@ export const upgradeableTooling: Record = { packageName: 'poetry', }, }, + 'pre-commit': { + asdfPluginUrl: 'https://github.com/jonathanmorley/asdf-pre-commit.git', + config: { + datasource: GithubTagsDatasource.id, + packageName: 'pre-commit/pre-commit', + extractVersion: '^v(?.+)', + }, + }, pulumi: { asdfPluginUrl: 'https://github.com/canha/asdf-pulumi.git', config: { @@ -399,6 +456,14 @@ export const upgradeableTooling: Record = { extractVersion: '^v(?\\S+)', }, }, + 'terraform-docs': { + asdfPluginUrl: 'https://github.com/looztra/asdf-terraform-docs.git', + config: { + datasource: GithubTagsDatasource.id, + packageName: 'terraform-docs/terraform-docs', + extractVersion: '^v(?.+)', + }, + }, terragrunt: { asdfPluginUrl: 'https://github.com/ohmer/asdf-terragrunt', config: { @@ -407,6 +472,22 @@ export const upgradeableTooling: Record = { extractVersion: '^v(?\\S+)', }, }, + tflint: { + asdfPluginUrl: 'https://github.com/skyzyx/asdf-tflint.git', + config: { + datasource: GithubTagsDatasource.id, + packageName: 'terraform-linters/tflint', + extractVersion: '^v(?.+)', + }, + }, + tfsec: { + asdfPluginUrl: 'https://github.com/woneill/asdf-tfsec.git', + config: { + datasource: GithubTagsDatasource.id, + packageName: 'aquasecurity/tfsec', + extractVersion: '^v(?.+)', + }, + }, trivy: { asdfPluginUrl: 'https://github.com/zufardhiyaulhaq/asdf-trivy', config: { diff --git a/lib/modules/manager/composer/schema.ts b/lib/modules/manager/composer/schema.ts index fb8c2a8af2c9d7..5d0ac8e7e4f817 100644 --- a/lib/modules/manager/composer/schema.ts +++ b/lib/modules/manager/composer/schema.ts @@ -26,19 +26,26 @@ export type ComposerRepo = z.infer; export const GitRepo = z.object({ type: z.enum(['vcs', 'git']).transform(() => 'git' as const), url: z.string(), + name: z.string().optional(), }); export type GitRepo = z.infer; export const PathRepo = z.object({ type: z.literal('path'), url: z.string(), + name: z.string().optional(), }); export type PathRepo = z.infer; +export const PackageRepo = z.object({ + type: z.literal('package'), +}); + export const Repo = z.discriminatedUnion('type', [ ComposerRepo, GitRepo, PathRepo, + PackageRepo, ]); export type Repo = z.infer; @@ -46,6 +53,7 @@ export const NamedRepo = z.discriminatedUnion('type', [ ComposerRepo, GitRepo.extend({ name: z.string() }), PathRepo.extend({ name: z.string() }), + PackageRepo, ]); export type NamedRepo = z.infer; @@ -54,7 +62,7 @@ export type DisablePackagist = z.infer; export const ReposRecord = LooseRecord(z.union([Repo, z.literal(false)]), { onError: ({ error: err }) => { - logger.warn({ err }, 'Composer: error parsing repositories object'); + logger.debug({ err }, 'Composer: error parsing repositories object'); }, }).transform((repos) => { const result: (NamedRepo | DisablePackagist)[] = []; @@ -83,7 +91,7 @@ export type ReposRecord = z.infer; export const ReposArray = LooseArray( z.union([ - NamedRepo, + Repo, z .union([ z.object({ packagist: z.literal(false) }), @@ -93,17 +101,28 @@ export const ReposArray = LooseArray( ]), { onError: ({ error: err }) => { - logger.warn({ err }, 'Composer: error parsing repositories array'); + logger.debug({ err }, 'Composer: error parsing repositories array'); }, } -).transform((repos) => repos.filter((x): x is NamedRepo => x !== null)); +).transform((repos) => { + const result: (NamedRepo | DisablePackagist)[] = []; + for (let idx = 0; idx < repos.length; idx++) { + const repo = repos[idx]; + if (repo.type === 'path' || repo.type === 'git') { + result.push({ name: `__${idx}`, ...repo }); + } else { + result.push(repo); + } + } + return result; +}); export type ReposArray = z.infer; export const Repos = z .union([ReposRecord, ReposArray]) .default([]) // Prevents warnings for packages without repositories field .catch(({ error: err }) => { - logger.warn({ err }, 'Composer: repositories parsing error'); + logger.debug({ err }, 'Composer: invalid "repositories" field'); return []; }) .transform((repos) => { @@ -210,13 +229,20 @@ export const ComposerExtract = z lockfile: z .string() .transform((lockfileName) => readLocalFile(lockfileName, 'utf8')) - .pipe(Json) - .pipe(Lockfile) - .nullable() - .catch(({ error: err }) => { - logger.warn({ err }, 'Composer: lockfile parsing error'); - return null; - }), + .pipe( + z.union([ + z.null(), + z + .string() + .pipe(Json) + .pipe(Lockfile) + .nullable() + .catch(({ error: err }) => { + logger.debug({ err }, 'Composer: lockfile parsing error'); + return null; + }), + ]) + ), }) ) .transform(({ file, lockfile, lockfileName }) => { diff --git a/lib/modules/manager/cpanfile/extract.spec.ts b/lib/modules/manager/cpanfile/extract.spec.ts new file mode 100644 index 00000000000000..29d0042c3bdcd5 --- /dev/null +++ b/lib/modules/manager/cpanfile/extract.spec.ts @@ -0,0 +1,322 @@ +import { codeBlock } from 'common-tags'; +import { extractPackageFile } from './extract'; + +describe('modules/manager/cpanfile/extract', () => { + describe('extractPackageFile()', () => { + it('returns null for empty', () => { + expect(extractPackageFile('', 'cpanfile')).toBeNull(); + expect(extractPackageFile('nothing here', 'cpanfile')).toBeNull(); + }); + + describe('parse perl', () => { + test.each` + version | expected + ${'5.012005'} | ${'5.012005'} + ${`'5.008001'`} | ${'5.008001'} + ${`"5.008001"`} | ${'5.008001'} + `('$version', ({ version, expected }) => { + expect( + extractPackageFile( + `requires 'perl', ${version as string};`, + 'cpanfile' + ) + ).toEqual({ + deps: [ + { + versioning: 'perl', + depName: 'perl', + packageName: 'Perl/perl5', + currentValue: expected, + datasource: 'github-tags', + extractVersion: '^v(?\\S+)', + }, + ], + extractedConstraints: { perl: expected }, + }); + }); + }); + + it('parse modules with requires', () => { + expect( + extractPackageFile( + codeBlock` + requires 'Try::Tiny'; + requires 'URI', '1.59'; + requires 'HTTP::Tiny', 0.034; + requires "Capture::Tiny" => "0"; + + requires 'A', '== 1.1'; + requires 'AA', '== v1.1'; + requires 'B', '>= 1.2'; + requires 'BB', '>= v1.2'; + requires 'C', '> 1.3'; + requires 'CC', '> v1.3'; + `, + 'cpanfile' + ) + ).toEqual({ + deps: [ + { + datasource: 'cpan', + depName: 'Try::Tiny', + skipReason: 'no-version', + }, + { + datasource: 'cpan', + depName: 'URI', + currentValue: '1.59', + }, + { + datasource: 'cpan', + depName: 'HTTP::Tiny', + currentValue: '0.034', + }, + { + datasource: 'cpan', + depName: 'Capture::Tiny', + currentValue: '0', + }, + { + datasource: 'cpan', + depName: 'A', + currentValue: '1.1', + }, + { + datasource: 'cpan', + depName: 'AA', + currentValue: '1.1', + }, + { + datasource: 'cpan', + depName: 'B', + currentValue: '1.2', + }, + { + datasource: 'cpan', + depName: 'BB', + currentValue: '1.2', + }, + { + datasource: 'cpan', + depName: 'C', + currentValue: '1.3', + }, + { + datasource: 'cpan', + depName: 'CC', + currentValue: '1.3', + }, + ], + }); + }); + + it('parse modules with recommends', () => { + expect( + extractPackageFile( + codeBlock` + recommends 'Crypt::URandom'; + recommends 'HTTP::XSCookies', '0.000015'; + `, + 'cpanfile' + ) + ).toEqual({ + deps: [ + { + datasource: 'cpan', + depName: 'Crypt::URandom', + skipReason: 'no-version', + }, + { + datasource: 'cpan', + depName: 'HTTP::XSCookies', + currentValue: '0.000015', + }, + ], + }); + }); + + it('parse modules with suggests', () => { + expect( + extractPackageFile( + codeBlock` + suggests 'Test::MockTime::HiRes', '0.06'; + suggests 'Authen::Simple::Passwd'; + `, + 'cpanfile' + ) + ).toEqual({ + deps: [ + { + datasource: 'cpan', + depName: 'Test::MockTime::HiRes', + currentValue: '0.06', + }, + { + datasource: 'cpan', + depName: 'Authen::Simple::Passwd', + skipReason: 'no-version', + }, + ], + }); + }); + + describe('parse modules with phases', () => { + test('configure phase', () => { + expect( + extractPackageFile( + codeBlock` + on 'configure' => sub { + requires "ExtUtils::MakeMaker" => "0"; + }; + `, + 'cpanfile' + ) + ).toEqual({ + deps: [ + { + datasource: 'cpan', + depName: 'ExtUtils::MakeMaker', + currentValue: '0', + depType: 'configure', + }, + ], + }); + }); + + test('build phase', () => { + expect( + extractPackageFile( + codeBlock` + on build => sub { + requires 'Test::More', '0.98'; + }; + `, + 'cpanfile' + ) + ).toEqual({ + deps: [ + { + datasource: 'cpan', + depName: 'Test::More', + currentValue: '0.98', + depType: 'build', + }, + ], + }); + }); + + test('test phase', () => { + expect( + extractPackageFile( + codeBlock` + on test => sub { + requires 'Test::More', '0.88'; + requires 'Test::Requires'; + }; + `, + 'cpanfile' + ) + ).toEqual({ + deps: [ + { + datasource: 'cpan', + depName: 'Test::More', + currentValue: '0.88', + depType: 'test', + }, + { + datasource: 'cpan', + depName: 'Test::Requires', + depType: 'test', + skipReason: 'no-version', + }, + ], + }); + }); + + test('runtime phase', () => { + expect( + extractPackageFile( + codeBlock` + on runtime => sub { + suggests 'FCGI'; + suggests 'FCGI::ProcManager'; + }; + `, + 'cpanfile' + ) + ).toEqual({ + deps: [ + { + datasource: 'cpan', + depName: 'FCGI', + depType: 'runtime', + skipReason: 'no-version', + }, + { + datasource: 'cpan', + depName: 'FCGI::ProcManager', + depType: 'runtime', + skipReason: 'no-version', + }, + ], + }); + }); + + test('develop phase', () => { + expect( + extractPackageFile( + codeBlock` + on 'develop' => sub { + requires "IPC::Open3" => "0"; + requires "Term::Table" => "0.013"; + }; + `, + 'cpanfile' + ) + ).toEqual({ + deps: [ + { + datasource: 'cpan', + depName: 'IPC::Open3', + currentValue: '0', + depType: 'develop', + }, + { + datasource: 'cpan', + depName: 'Term::Table', + currentValue: '0.013', + depType: 'develop', + }, + ], + }); + }); + }); + + describe('parse modules with phase shortcuts', () => { + test.each` + shortcut | phase + ${'configure_requires'} | ${'configure'} + ${'build_requires'} | ${'build'} + ${'test_requires'} | ${'test'} + ${'author_requires'} | ${'develop'} + `('$shortcut', ({ shortcut, phase }) => { + expect( + extractPackageFile( + `${shortcut as string} 'Capture::Tiny', '0.12';`, + 'cpanfile' + ) + ).toEqual({ + deps: [ + { + datasource: 'cpan', + depName: 'Capture::Tiny', + currentValue: '0.12', + depType: phase, + }, + ], + }); + }); + }); + }); +}); diff --git a/lib/modules/manager/cpanfile/extract.ts b/lib/modules/manager/cpanfile/extract.ts new file mode 100644 index 00000000000000..6caee1cc7ca16d --- /dev/null +++ b/lib/modules/manager/cpanfile/extract.ts @@ -0,0 +1,16 @@ +import type { PackageFileContent } from '../types'; +import { parse } from './parser'; + +export function extractPackageFile( + content: string, + packageFile?: string +): PackageFileContent | null { + const result = parse(content); + if (!result?.deps.length) { + return null; + } + + const { deps, perlVersion } = result; + const extractedConstraints = perlVersion ? { perl: perlVersion } : undefined; + return { deps, ...(extractedConstraints && { extractedConstraints }) }; +} diff --git a/lib/modules/manager/cpanfile/index.ts b/lib/modules/manager/cpanfile/index.ts new file mode 100644 index 00000000000000..3d09e935f5b5c3 --- /dev/null +++ b/lib/modules/manager/cpanfile/index.ts @@ -0,0 +1,17 @@ +import { CpanDatasource } from '../../datasource/cpan'; +import { GithubTagsDatasource } from '../../datasource/github-tags'; + +export { extractPackageFile } from './extract'; + +export const displayName = 'cpanfile'; +export const url = + 'https://metacpan.org/dist/Module-CPANfile/view/lib/cpanfile.pod'; + +export const defaultConfig = { + fileMatch: ['(^|/)cpanfile$'], +}; + +export const supportedDatasources = [ + CpanDatasource.id, + GithubTagsDatasource.id, +]; diff --git a/lib/modules/manager/cpanfile/language.ts b/lib/modules/manager/cpanfile/language.ts new file mode 100644 index 00000000000000..9a7f00a31d365f --- /dev/null +++ b/lib/modules/manager/cpanfile/language.ts @@ -0,0 +1,44 @@ +import { lexer as l, lang, parser as p } from 'good-enough-parser'; + +/** + * @see https://perldoc.perl.org/perldata#Scalar-value-constructors + */ +const bindigit = '[01]'; +const octdigit = '[0-7]'; +const digit = '[0-9]'; +const nonzerodigit = '[1-9]'; +const hexdigit = `(?:${digit}|[a-fA-F])`; + +const bininteger = `(?:0[bB](?:_?${bindigit})+)`; +const octinteger = `(?:0(?:_?${octdigit})+)`; +const hexinteger = `(?:0[xX](?:_?${hexdigit})+)`; +const decinteger = `(?:${nonzerodigit}(?:_?${digit})*|0+(?:_?0)*)`; +const integer = `(?:${decinteger}|${bininteger}|${octinteger}|${hexinteger})`; + +const digitpart = `(?:${digit}(?:_?${digit})*)`; +const fraction = `(?:\\.${digitpart})`; +const exponent = `(?:[eE][-+]?${digitpart})`; +const pointfloat = `(?:${digitpart}?${fraction}|${digitpart}\\.)`; +const exponentfloat = `(?:(?:${digitpart}|${pointfloat})${exponent})`; +const floatnumber = `(?:${pointfloat}|${exponentfloat})`; + +const numbers = new RegExp(`(?:${floatnumber}|${integer})`); + +const lexer: l.LexerConfig = { + joinLines: null, + comments: [{ type: 'line-comment', startsWith: '#' }], + symbols: /[_a-zA-Z][_a-zA-Z0-9]*/, + numbers, + operators: ['==', '>=', '>', '=>', ',', ';'], + brackets: [ + { startsWith: '{', endsWith: '}' }, + { startsWith: '(', endsWith: ')' }, + ], + strings: [{ startsWith: "'" }, { startsWith: '"' }], +}; + +const parser: p.ParserConfig = { + useIndentBlocks: false, +}; + +export const cpanfile = lang.createLang({ lexer, parser }); diff --git a/lib/modules/manager/cpanfile/parser.ts b/lib/modules/manager/cpanfile/parser.ts new file mode 100644 index 00000000000000..cf2286eaa79b82 --- /dev/null +++ b/lib/modules/manager/cpanfile/parser.ts @@ -0,0 +1,146 @@ +import { query as q } from 'good-enough-parser'; +import { CpanDatasource } from '../../datasource/cpan'; +import { GithubTagsDatasource } from '../../datasource/github-tags'; +import * as perlVersioning from '../../versioning/perl'; +import type { PackageDependency } from '../types'; +import { cpanfile } from './language'; + +interface Ctx { + deps: PackageDependency[]; + + perlVersion?: string; + + phase?: string; + tempPhase?: string; + + depName?: string; + currentValue?: string; +} + +// requires perl, '5.36.1'; +// requires 'perl' => 5.036001; +const perlVersionMatch = q + .sym('requires') + .alt(q.sym('perl'), q.str('perl')) + .alt(q.op(','), q.op('=>')) + .alt( + q.num((ctx, { value: perlVersion }) => ({ ...ctx, perlVersion })), + q.str((ctx, { value: perlVersion }) => ({ ...ctx, perlVersion })) + ) + .op(';') + .handler((ctx) => { + if (ctx.perlVersion) { + ctx.deps.push({ + depName: 'perl', + packageName: 'Perl/perl5', + currentValue: ctx.perlVersion, + datasource: GithubTagsDatasource.id, + versioning: perlVersioning.id, + extractVersion: '^v(?\\S+)', + }); + } + return ctx; + }); + +const requirementMatch = q.sym(/^(?:requires|recommends|suggests)$/); + +const phasedRequiresMatch = q.sym( + /^(?:configure|build|test|author)_requires$/, + (ctx, { value: phase }) => { + ctx.tempPhase = phase.replace(/_requires/, '').replace(/author/, 'develop'); + return ctx; + } +); + +// requires 'Foo::Bar'; +// +// requires 'Foo::Bar', '1.23'; +// recommends 'Foo::Bar', '1.23'; +// suggests 'Foo::Bar', '1.23'; +// +// configure_requires 'Foo::Bar' => 1.023; +// build_requires 'Foo::Bar' => 1.023; +// test_requires 'Foo::Bar' => 1.023; +// author_requires 'Foo::Bar' => 1.023; +const moduleMatch = q + .alt(requirementMatch, phasedRequiresMatch) + .str((ctx, { value: depName }) => ({ ...ctx, depName })) + .opt( + q.alt(q.op(','), q.op('=>')).alt( + q.num((ctx, { value: currentValue }) => ({ ...ctx, currentValue })), + q.str((ctx, { value }) => { + const currentValue = value.replace(/^(?:\s*(?:==|>=|>))?\s*v?/, ''); + return { ...ctx, currentValue }; + }) + ) + ) + .op(';') + .handler((ctx) => { + const { phase, tempPhase, depName, currentValue } = ctx; + + delete ctx.tempPhase; + delete ctx.depName; + delete ctx.currentValue; + + if (depName) { + const dep: PackageDependency = { + depName, + }; + if (currentValue) { + dep.currentValue = currentValue; + } else { + dep.skipReason = 'no-version'; + } + if (phase) { + dep.depType = phase; + } else if (tempPhase) { + dep.depType = tempPhase; + } + + dep.datasource = CpanDatasource.id; + ctx.deps.push(dep); + } + + return ctx; + }); + +const phaseRegex = /^(?:configure|build|test|runtime|develop)/; + +const phaseMatch = q.alt( + q.sym(phaseRegex, (ctx, { value: phase }) => ({ ...ctx, phase })), + q.str(phaseRegex, (ctx, { value: phase }) => ({ ...ctx, phase })) +); + +// on 'configure' => sub { +// on build => sub { +// on 'test' => sub { +// on runtime => sub { +// on 'develop' => sub { +const onMatch = q + .sym('on') + .join(phaseMatch) + .op('=>') + .sym('sub') + .tree({ + type: 'wrapped-tree', + maxDepth: 1, + search: moduleMatch, + }) + .handler((ctx) => { + delete ctx.phase; + return ctx; + }); + +const query = q.tree({ + type: 'root-tree', + maxDepth: 4, + search: q.alt(perlVersionMatch, moduleMatch, onMatch), +}); + +export function parse( + content: string +): Pick | null { + return cpanfile.query(content, query, { + deps: [], + }); +} diff --git a/lib/modules/manager/cpanfile/readme.md b/lib/modules/manager/cpanfile/readme.md new file mode 100644 index 00000000000000..8653ea9f51b192 --- /dev/null +++ b/lib/modules/manager/cpanfile/readme.md @@ -0,0 +1 @@ +The `cpanfile` manager is used to extract dependencies from `cpanfile`. diff --git a/lib/modules/manager/dockerfile/extract.ts b/lib/modules/manager/dockerfile/extract.ts index 45a6fc56cf4e51..f62f281bf28198 100644 --- a/lib/modules/manager/dockerfile/extract.ts +++ b/lib/modules/manager/dockerfile/extract.ts @@ -182,7 +182,7 @@ export function getDep( ...getDep(`${value}/${groups.depName}`), replaceString: currentFrom, }; - dep.autoReplaceStringTemplate = getAutoReplaceTemplate(dep)!; + dep.autoReplaceStringTemplate = getAutoReplaceTemplate(dep); return dep; } } diff --git a/lib/modules/manager/gradle/extract.spec.ts b/lib/modules/manager/gradle/extract.spec.ts index e5f314711d3bd6..94c9a4f1b18865 100644 --- a/lib/modules/manager/gradle/extract.spec.ts +++ b/lib/modules/manager/gradle/extract.spec.ts @@ -120,6 +120,126 @@ describe('modules/manager/gradle/extract', () => { ]); }); + it('resolves cross-file Kotlin objects', async () => { + const fsMock = { + 'buildSrc/src/main/kotlin/Deps.kt': codeBlock` + object Libraries { + const val jacksonAnnotations = "com.fasterxml.jackson.core:jackson-annotations:\${Versions.jackson}" + const val rxjava: String = "io.reactivex.rxjava2:rxjava:" + Versions.rxjava + const val jCache = "javax.cache:cache-api:1.1.0" + private const val shadowVersion = "7.1.2" + + object Kotlin { + const val version = GradleDeps.Kotlin.version + const val stdlibJdk = "org.jetbrains.kotlin:kotlin-stdlib:$version" + } + + object Android { + object Tools { + private const val version = "4.1.2" + const val buildGradle = "com.android.tools.build:gradle:$version" + } + } + + val modulePlugins = mapOf( + "shadow" to shadowVersion + ) + + object Test { + private const val version = "1.3.0-rc01" + const val core = "androidx.test:core:\${Test.version}" + + object Espresso { + private const val version = "3.3.0-rc01" + const val espressoCore = "androidx.test.espresso:espresso-core:$version" + } + + object Androidx { + const val coreKtx = "androidx.test:core-ktx:$version" + } + } + } + `, + 'buildSrc/src/main/kotlin/GradleDeps.kt': codeBlock` + object GradleDeps { + object Kotlin { + const val version = "1.8.10" + } + } + `, + 'buildSrc/src/main/kotlin/Versions.kt': codeBlock` + object Versions { + const val jackson = "2.9.10" + const val rxjava: String = "1.2.3" + } + `, + }; + mockFs(fsMock); + + const res = await extractAllPackageFiles( + partial(), + Object.keys(fsMock) + ); + + expect(res).toMatchObject([ + { + packageFile: 'buildSrc/src/main/kotlin/Deps.kt', + deps: [ + { + depName: 'javax.cache:cache-api', + currentValue: '1.1.0', + groupName: 'Libraries.jCache', + }, + { + depName: 'com.android.tools.build:gradle', + currentValue: '4.1.2', + groupName: 'Libraries.Android.Tools.version', + }, + { + depName: 'androidx.test:core', + currentValue: '1.3.0-rc01', + groupName: 'Libraries.Test.version', + }, + { + depName: 'androidx.test.espresso:espresso-core', + currentValue: '3.3.0-rc01', + groupName: 'Libraries.Test.Espresso.version', + }, + { + depName: 'androidx.test:core-ktx', + currentValue: '1.3.0-rc01', + groupName: 'Libraries.Test.version', + }, + ], + }, + { + packageFile: 'buildSrc/src/main/kotlin/GradleDeps.kt', + deps: [ + { + depName: 'org.jetbrains.kotlin:kotlin-stdlib', + currentValue: '1.8.10', + groupName: 'GradleDeps.Kotlin.version', + }, + ], + }, + { + packageFile: 'buildSrc/src/main/kotlin/Versions.kt', + deps: [ + { + depName: 'com.fasterxml.jackson.core:jackson-annotations', + currentValue: '2.9.10', + groupName: 'Versions.jackson', + }, + { + depName: 'io.reactivex.rxjava2:rxjava', + currentValue: '1.2.3', + groupName: 'Versions.rxjava', + }, + ], + }, + ]); + }); + it('inherits gradle variables', async () => { const fsMock = { 'gradle.properties': 'foo=1.0.0', diff --git a/lib/modules/manager/gradle/extract.ts b/lib/modules/manager/gradle/extract.ts index e0a76398b747fa..a75d6a9098b430 100644 --- a/lib/modules/manager/gradle/extract.ts +++ b/lib/modules/manager/gradle/extract.ts @@ -9,7 +9,7 @@ import { parseGcv, usesGcv, } from './extract/consistent-versions-plugin'; -import { parseGradle, parseProps } from './parser'; +import { parseGradle, parseKotlinSource, parseProps } from './parser'; import { REGISTRY_URLS } from './parser/common'; import type { GradleManagerData, @@ -19,6 +19,7 @@ import type { import { getVars, isGradleScriptFile, + isKotlinSourceFile, isPropsFile, isTOMLFile, reorderFiles, @@ -94,6 +95,15 @@ async function parsePackageFiles( ) { const deps = parseGcv(packageFile, fileContents); extractedDeps.push(...deps); + } else if (isKotlinSourceFile(packageFile)) { + const vars = getVars(varRegistry, packageFileDir); + const { vars: gradleVars, deps } = parseKotlinSource( + content, + vars, + packageFile + ); + updateVars(varRegistry, '/', gradleVars); + extractedDeps.push(...deps); } else if (isGradleScriptFile(packageFile)) { const vars = getVars(varRegistry, packageFileDir); const { @@ -123,11 +133,14 @@ export async function extractAllPackageFiles( const packageFilesByName: Record = {}; const packageRegistries: PackageRegistry[] = []; const extractedDeps: PackageDependency[] = []; - const gradleFiles = reorderFiles(packageFiles); + const kotlinSourceFiles = packageFiles.filter(isKotlinSourceFile); + const gradleFiles = reorderFiles( + packageFiles.filter((e) => !kotlinSourceFiles.includes(e)) + ); await parsePackageFiles( config, - gradleFiles, + [...kotlinSourceFiles, ...kotlinSourceFiles, ...gradleFiles], extractedDeps, packageFilesByName, packageRegistries @@ -161,9 +174,10 @@ export async function extractAllPackageFiles( dep.registryUrls = getRegistryUrlsForDep(packageRegistries, dep); if (!dep.depType) { - dep.depType = key.startsWith('buildSrc') - ? 'devDependencies' - : 'dependencies'; + dep.depType = + key.startsWith('buildSrc') && !kotlinSourceFiles.length + ? 'devDependencies' + : 'dependencies'; } } diff --git a/lib/modules/manager/gradle/index.ts b/lib/modules/manager/gradle/index.ts index ad83ff7f60ba5d..82419fa6f81868 100644 --- a/lib/modules/manager/gradle/index.ts +++ b/lib/modules/manager/gradle/index.ts @@ -14,6 +14,7 @@ export const defaultConfig = { '\\.gradle(\\.kts)?$', '(^|/)gradle\\.properties$', '(^|/)gradle/.+\\.toml$', + '(^|/)buildSrc/.+\\.kt$', '\\.versions\\.toml$', // The two below is for gradle-consistent-versions plugin `(^|/)versions.props$`, diff --git a/lib/modules/manager/gradle/parser.spec.ts b/lib/modules/manager/gradle/parser.spec.ts index 4cf790ce64404f..fe948df16dd442 100644 --- a/lib/modules/manager/gradle/parser.spec.ts +++ b/lib/modules/manager/gradle/parser.spec.ts @@ -2,7 +2,7 @@ import is from '@sindresorhus/is'; import { codeBlock } from 'common-tags'; import { Fixtures } from '../../../../test/fixtures'; import { fs, logger } from '../../../../test/util'; -import { parseGradle, parseProps } from './parser'; +import { parseGradle, parseKotlinSource, parseProps } from './parser'; import { GRADLE_PLUGINS, REGISTRY_URLS } from './parser/common'; jest.mock('../../../util/fs'); @@ -930,4 +930,107 @@ describe('modules/manager/gradle/parser', () => { expect(deps).toMatchObject([output].filter(is.truthy)); }); }); + + describe('Kotlin object notation', () => { + it('simple objects', () => { + const input = codeBlock` + object Versions { + const val baz = "1.2.3" + } + + object Libraries { + val deps = mapOf("api" to "org.slf4j:slf4j-api:\${Versions.baz}") + val dep: String = "foo:bar:" + Versions.baz + } + `; + + const res = parseKotlinSource(input); + expect(res).toMatchObject({ + vars: { + 'Versions.baz': { + key: 'Versions.baz', + value: '1.2.3', + }, + }, + deps: [ + { + depName: 'org.slf4j:slf4j-api', + groupName: 'Versions.baz', + currentValue: '1.2.3', + }, + { + depName: 'foo:bar', + groupName: 'Versions.baz', + currentValue: '1.2.3', + }, + ], + }); + }); + + it('nested objects', () => { + const input = codeBlock` + object Deps { + const val kotlinVersion = "1.5.31" + + object Kotlin { + val stdlib = "org.jetbrains.kotlin:kotlin-stdlib-jdk7:\${Deps.kotlinVersion}" + } + + object Test { + private const val version = "1.3.0-rc01" + const val core = "androidx.test:core:\${Deps.Test.version}" + + object Espresso { + private const val version = "3.3.0-rc01" + const val espressoCore = "androidx.test.espresso:espresso-core:$version" + } + + object Androidx { + const val coreKtx = "androidx.test:core-ktx:$version" + } + } + } + `; + + const res = parseKotlinSource(input); + expect(res).toMatchObject({ + vars: { + 'Deps.kotlinVersion': { + key: 'Deps.kotlinVersion', + value: '1.5.31', + }, + 'Deps.Test.version': { + key: 'Deps.Test.version', + value: '1.3.0-rc01', + }, + 'Deps.Test.Espresso.version': { + key: 'Deps.Test.Espresso.version', + value: '3.3.0-rc01', + }, + }, + deps: [ + { + depName: 'org.jetbrains.kotlin:kotlin-stdlib-jdk7', + currentValue: '1.5.31', + groupName: 'Deps.kotlinVersion', + }, + { + depName: 'androidx.test:core', + currentValue: '1.3.0-rc01', + groupName: 'Deps.Test.version', + }, + { + depName: 'androidx.test.espresso:espresso-core', + currentValue: '3.3.0-rc01', + groupName: 'Deps.Test.Espresso.version', + }, + { + depName: 'androidx.test:core-ktx', + currentValue: '1.3.0-rc01', + groupName: 'Deps.Test.version', + }, + ], + }); + }); + }); }); diff --git a/lib/modules/manager/gradle/parser.ts b/lib/modules/manager/gradle/parser.ts index 1d4d3914b989eb..a3824ed8a2d0e7 100644 --- a/lib/modules/manager/gradle/parser.ts +++ b/lib/modules/manager/gradle/parser.ts @@ -5,6 +5,7 @@ import { qApplyFrom } from './parser/apply-from'; import { qAssignments } from './parser/assignments'; import { qDependencies, qLongFormDep } from './parser/dependencies'; import { setParseGradleFunc } from './parser/handlers'; +import { qKotlinMultiObjectVarAssignment } from './parser/objects'; import { qPlugins } from './parser/plugins'; import { qRegistryUrls } from './parser/registry-urls'; import { qVersionCatalogs } from './parser/version-catalogs'; @@ -77,6 +78,34 @@ export function parseGradle( return { deps, urls, vars }; } +export function parseKotlinSource( + input: string, + initVars: PackageVariables = {}, + packageFile = '' +): { vars: PackageVariables; deps: PackageDependency[] } { + let vars: PackageVariables = { ...initVars }; + const deps: PackageDependency[] = []; + + const query = q.tree({ + type: 'root-tree', + maxDepth: 1, + search: qKotlinMultiObjectVarAssignment, + }); + + const parsedResult = groovy.query(input, query, { + ...ctx, + packageFile, + globalVars: vars, + }); + + if (parsedResult) { + deps.push(...parsedResult.deps); + vars = { ...vars, ...parsedResult.globalVars }; + } + + return { deps, vars }; +} + const propWord = '[a-zA-Z_][a-zA-Z0-9_]*(?:\\.[a-zA-Z_][a-zA-Z0-9_]*)*'; const propRegex = regEx( `^(?\\s*(?${propWord})\\s*[= :]\\s*['"]?)(?[^\\s'"]+)['"]?\\s*$` diff --git a/lib/modules/manager/gradle/parser/assignments.ts b/lib/modules/manager/gradle/parser/assignments.ts index 91da408fb475c8..424be4895e8c80 100644 --- a/lib/modules/manager/gradle/parser/assignments.ts +++ b/lib/modules/manager/gradle/parser/assignments.ts @@ -138,7 +138,7 @@ const qKotlinMapOfExpr = ( ); // val versions = mapOf("foo1" to "bar1", "foo2" to "bar2", "foo3" to "bar3") -const qKotlinMultiMapOfVarAssignment = qVariableAssignmentIdentifier +export const qKotlinMultiMapOfVarAssignment = qVariableAssignmentIdentifier .op('=') .sym('mapOf') .tree({ diff --git a/lib/modules/manager/gradle/parser/common.spec.ts b/lib/modules/manager/gradle/parser/common.spec.ts index 77a7df15e851c5..6915f7339d4b3a 100644 --- a/lib/modules/manager/gradle/parser/common.spec.ts +++ b/lib/modules/manager/gradle/parser/common.spec.ts @@ -121,11 +121,23 @@ describe('modules/manager/gradle/parser/common', () => { }); it('findVariable', () => { + ctx.tmpNestingDepth = [token, token]; ctx.globalVars = { foo: { key: 'foo', value: 'bar' }, + 'test.foo': { key: 'test.foo', value: 'bar2' }, + 'test.test.foo3': { key: 'test.test.foo3', value: 'bar3' }, }; expect(findVariable('unknown-global-var', ctx)).toBeUndefined(); + expect(findVariable('foo3', ctx)).toStrictEqual( + ctx.globalVars['test.test.foo3'] + ); + expect(findVariable('test.foo', ctx)).toStrictEqual( + ctx.globalVars['test.foo'] + ); + expect(findVariable('foo', ctx)).toStrictEqual(ctx.globalVars['test.foo']); + + ctx.tmpNestingDepth = []; expect(findVariable('foo', ctx)).toStrictEqual(ctx.globalVars['foo']); }); diff --git a/lib/modules/manager/gradle/parser/common.ts b/lib/modules/manager/gradle/parser/common.ts index 6379bb5644893c..6f92589544e793 100644 --- a/lib/modules/manager/gradle/parser/common.ts +++ b/lib/modules/manager/gradle/parser/common.ts @@ -116,6 +116,18 @@ export function findVariable( ctx: Ctx, variables: PackageVariables = ctx.globalVars ): VariableData | undefined { + if (ctx.tmpNestingDepth.length) { + const prefixParts = ctx.tmpNestingDepth.map((token) => token.value); + for (let idx = ctx.tmpNestingDepth.length; idx > 0; idx -= 1) { + const prefix = prefixParts.slice(0, idx).join('.'); + const identifier = `${prefix}.${name}`; + + if (variables[identifier]) { + return variables[identifier]; + } + } + } + return variables[name]; } diff --git a/lib/modules/manager/gradle/parser/objects.ts b/lib/modules/manager/gradle/parser/objects.ts new file mode 100644 index 00000000000000..b1d0f0c862e358 --- /dev/null +++ b/lib/modules/manager/gradle/parser/objects.ts @@ -0,0 +1,54 @@ +import { parser, query as q } from 'good-enough-parser'; +import type { Ctx } from '../types'; +import { qKotlinMultiMapOfVarAssignment } from './assignments'; +import { + cleanupTempVars, + coalesceVariable, + increaseNestingDepth, + prependNestingDepth, + qValueMatcher, + qVariableAssignmentIdentifier, + reduceNestingDepth, + storeInTokenMap, + storeVarToken, +} from './common'; +import { handleAssignment } from './handlers'; + +const qKotlinSingleObjectVarAssignment = q.alt( + // val dep = mapOf("qux" to "foo:bar:\${Versions.baz}") + qKotlinMultiMapOfVarAssignment, + // val dep: String = "foo:bar:" + Versions.baz + qVariableAssignmentIdentifier + .opt(q.op(':').sym('String')) + .op('=') + .handler(prependNestingDepth) + .handler(coalesceVariable) + .handler((ctx) => storeInTokenMap(ctx, 'keyToken')) + .join(qValueMatcher) + .handler((ctx) => storeInTokenMap(ctx, 'valToken')) + .handler(handleAssignment) + .handler(cleanupTempVars) +); + +// object foo { ... } +const qKotlinMultiObjectExpr = ( + search: q.QueryBuilder +): q.QueryBuilder => + q.alt( + q.sym('object').sym(storeVarToken).tree({ + type: 'wrapped-tree', + maxDepth: 1, + startsWith: '{', + endsWith: '}', + preHandler: increaseNestingDepth, + search, + postHandler: reduceNestingDepth, + }), + qKotlinSingleObjectVarAssignment + ); + +export const qKotlinMultiObjectVarAssignment = qKotlinMultiObjectExpr( + qKotlinMultiObjectExpr( + qKotlinMultiObjectExpr(qKotlinSingleObjectVarAssignment) + ) +).handler(cleanupTempVars); diff --git a/lib/modules/manager/gradle/utils.ts b/lib/modules/manager/gradle/utils.ts index bed8720663dc5f..06b8476d8d5572 100644 --- a/lib/modules/manager/gradle/utils.ts +++ b/lib/modules/manager/gradle/utils.ts @@ -113,6 +113,11 @@ export function isPropsFile(path: string): boolean { return filename === 'gradle.properties'; } +export function isKotlinSourceFile(path: string): boolean { + const filename = upath.basename(path).toLowerCase(); + return filename.endsWith('.kt'); +} + export function isTOMLFile(path: string): boolean { const filename = upath.basename(path).toLowerCase(); return filename.endsWith('.toml'); diff --git a/lib/modules/manager/npm/update/locked-dependency/yarn-lock/__fixtures__/3.yarn.lock b/lib/modules/manager/npm/update/locked-dependency/yarn-lock/__fixtures__/3.yarn.lock index 15ed204e76c285..370eb3df7bd6a8 100644 --- a/lib/modules/manager/npm/update/locked-dependency/yarn-lock/__fixtures__/3.yarn.lock +++ b/lib/modules/manager/npm/update/locked-dependency/yarn-lock/__fixtures__/3.yarn.lock @@ -1,11 +1,46 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 +# This file is generated by running "yarn install" inside your project. +# Manual changes might be lost - proceed with caution! +__metadata: + version: 7 + cacheKey: 9 -"@actions/core@1.6.0", "@actions/core@^1.2.0", "@actions/core@^1.2.6": - version "1.6.0" - resolved "https://registry.yarnpkg.com/@actions/core/-/core-1.6.0.tgz#0568e47039bfb6a9170393a73f3b7eb3b22462cb" - integrity sha512-NB1UAZomZlCV/LmJqkLhNTqtKfFXJZAUPcfl/zqG7EfsQdeUJtaWO98SGbuQ3pydJ3fHl2CvI/51OKYlCYYcaw== +"@actions/core@npm:^1.2.6": + version: 1.2.6 + resolution: "@actions/core@npm:1.2.6" + checksum: 034e57fcb5f944d5fb0ef55be1b212dd88e23d1a50aaffda874cb94e8f4bfa633a66f108f26e81a7cce287cd2b349aa88c97d2023135c8879495326db37a7feb + languageName: node + linkType: hard + +"@algolia/autocomplete-core@npm:1.7.1": + version: 1.7.1 + resolution: "@algolia/autocomplete-core@npm:1.7.1" + dependencies: + "@algolia/autocomplete-shared": "npm:1.7.1" + checksum: db772275618c3844b411a66195403f2b118758b52b94fd292fef9569b3e1d90ee1bfdee7473a90e114e8ee58e867fa197f011721ebc704ed3cd253b2edcc78e4 + languageName: node + linkType: hard + +"@algolia/autocomplete-preset-algolia@npm:1.7.1": + version: 1.7.1 + resolution: "@algolia/autocomplete-preset-algolia@npm:1.7.1" dependencies: - "@actions/http-client" "^1.0.11" + "@algolia/autocomplete-shared": "npm:1.7.1" + peerDependencies: + "@algolia/client-search": ^4.9.1 + algoliasearch: ^4.9.1 + checksum: b110379b1bf49a230a35cbf167c858d480f196480474ef954a64e822c46e5e2a39eae2440a2c1c5f6beb96f51f8a5c75ba05586defa611a4cf32b4208ad29ce2 + languageName: node + linkType: hard +"@strictsoftware/typedoc-plugin-monorepo@patch:@strictsoftware/typedoc-plugin-monorepo@^0.2.2#./.patches/@strictsoftware/typedoc-plugin-monorepo.patch::locator=%40yarnpkg%2Fgatsby%40workspace%3Apackages%2Fgatsby": + version: 0.2.2 + resolution: "@strictsoftware/typedoc-plugin-monorepo@patch:@strictsoftware/typedoc-plugin-monorepo@npm%3A0.2.2#./.patches/@strictsoftware/typedoc-plugin-monorepo.patch::version=0.2.2&hash=dc07b1&locator=%40yarnpkg%2Fgatsby%40workspace%3Apackages%2Fgatsby" + dependencies: + highlight.js: "npm:^9.15.6" + marked: "npm:^0.8.0" + peerDependencies: + typedoc: ">=0.8 <1.0" + checksum: 25b9eb5ad9e5028c7cf320ab6c458af535ed2ec3e1bdfd7d71daf1f8cb33ae684823064a889a63695db4686c2830bd118f792282b82d31e579c4a1e495ce473a + languageName: node + linkType: hard diff --git a/lib/modules/manager/npm/update/locked-dependency/yarn-lock/get-locked.spec.ts b/lib/modules/manager/npm/update/locked-dependency/yarn-lock/get-locked.spec.ts index 3d6e8aa598037a..0995f696e188db 100644 --- a/lib/modules/manager/npm/update/locked-dependency/yarn-lock/get-locked.spec.ts +++ b/lib/modules/manager/npm/update/locked-dependency/yarn-lock/get-locked.spec.ts @@ -26,46 +26,19 @@ describe('modules/manager/npm/update/locked-dependency/yarn-lock/get-locked', () }); it('finds scoped', () => { - expect(getLockedDependencies(yarnLock3, '@actions/core', '1.6.0')) + expect(getLockedDependencies(yarnLock3, '@actions/core', '1.2.6')) .toMatchInlineSnapshot(` [ - { - "constraint": "1.6.0", - "depName": "@actions/core", - "depNameConstraint": "@actions/core@1.6.0", - "entry": { - "dependencies": { - "@actions/http-client": "^1.0.11", - }, - "integrity": "sha512-NB1UAZomZlCV/LmJqkLhNTqtKfFXJZAUPcfl/zqG7EfsQdeUJtaWO98SGbuQ3pydJ3fHl2CvI/51OKYlCYYcaw==", - "resolved": "https://registry.yarnpkg.com/@actions/core/-/core-1.6.0.tgz#0568e47039bfb6a9170393a73f3b7eb3b22462cb", - "version": "1.6.0", - }, - }, - { - "constraint": "^1.2.0", - "depName": "@actions/core", - "depNameConstraint": "@actions/core@^1.2.0", - "entry": { - "dependencies": { - "@actions/http-client": "^1.0.11", - }, - "integrity": "sha512-NB1UAZomZlCV/LmJqkLhNTqtKfFXJZAUPcfl/zqG7EfsQdeUJtaWO98SGbuQ3pydJ3fHl2CvI/51OKYlCYYcaw==", - "resolved": "https://registry.yarnpkg.com/@actions/core/-/core-1.6.0.tgz#0568e47039bfb6a9170393a73f3b7eb3b22462cb", - "version": "1.6.0", - }, - }, { "constraint": "^1.2.6", "depName": "@actions/core", - "depNameConstraint": "@actions/core@^1.2.6", + "depNameConstraint": "@actions/core@npm:^1.2.6", "entry": { - "dependencies": { - "@actions/http-client": "^1.0.11", - }, - "integrity": "sha512-NB1UAZomZlCV/LmJqkLhNTqtKfFXJZAUPcfl/zqG7EfsQdeUJtaWO98SGbuQ3pydJ3fHl2CvI/51OKYlCYYcaw==", - "resolved": "https://registry.yarnpkg.com/@actions/core/-/core-1.6.0.tgz#0568e47039bfb6a9170393a73f3b7eb3b22462cb", - "version": "1.6.0", + "checksum": "034e57fcb5f944d5fb0ef55be1b212dd88e23d1a50aaffda874cb94e8f4bfa633a66f108f26e81a7cce287cd2b349aa88c97d2023135c8879495326db37a7feb", + "languageName": "node", + "linkType": "hard", + "resolution": "@actions/core@npm:1.2.6", + "version": "1.2.6", }, }, ] diff --git a/lib/modules/manager/npm/update/locked-dependency/yarn-lock/get-locked.ts b/lib/modules/manager/npm/update/locked-dependency/yarn-lock/get-locked.ts index 84da024089bd32..7f4f5fa73db189 100644 --- a/lib/modules/manager/npm/update/locked-dependency/yarn-lock/get-locked.ts +++ b/lib/modules/manager/npm/update/locked-dependency/yarn-lock/get-locked.ts @@ -1,8 +1,26 @@ import { logger } from '../../../../../../logger'; import type { YarnLock, YarnLockEntrySummary } from './types'; -// Finds matching dependencies withing a package lock file of sub-entry -export function getLockedDependencies( +export function parseEntry(depNameConstraint: string): { + entryName: string; + constraint: string; +} | null { + let entryName: string; + let constraint: string; + const split = depNameConstraint.split('@'); + if (split.length === 2) { + [entryName, constraint] = split; + } else if (split.length === 3) { + entryName = '@' + split[1]; + constraint = split[2]; + } else { + logger.debug({ depNameConstraint }, 'Unexpected depNameConstraint'); + return null; + } + return { entryName, constraint }; +} + +export function getYarn1LockedDependencies( yarnLock: YarnLock, depName: string, currentVersion: string @@ -10,22 +28,12 @@ export function getLockedDependencies( const res: YarnLockEntrySummary[] = []; try { for (const [depNameConstraint, entry] of Object.entries(yarnLock)) { - let entryName: string; - let constraint: string; - const split = depNameConstraint.split('@'); - // istanbul ignore else - if (split.length === 2) { - [entryName, constraint] = split; - } else if (split.length === 3) { - entryName = '@' + split[1]; - constraint = split[2]; - } else { - logger.debug( - { depNameConstraint, entry }, - 'Unexpected depNameConstraint' - ); + const parsed = parseEntry(depNameConstraint); + // istanbul ignore if + if (!parsed) { continue; } + const { entryName, constraint } = parsed; if (entryName === depName && entry?.version === currentVersion) { res.push({ entry, depNameConstraint, depName, constraint }); } @@ -35,3 +43,46 @@ export function getLockedDependencies( } return res; } + +export function getYarn2LockedDependencies( + yarnLock: YarnLock, + depName: string, + currentVersion: string +): YarnLockEntrySummary[] { + const res: YarnLockEntrySummary[] = []; + try { + for (const [fullConstraint, entry] of Object.entries(yarnLock)) { + if (fullConstraint === '__metadata') { + continue; + } + for (const subConstraint of fullConstraint.split(', ')) { + const depNameConstraint = subConstraint; + const parsed = parseEntry(depNameConstraint); + // istanbul ignore if + if (!parsed) { + continue; + } + const { entryName } = parsed; + const constraint = parsed.constraint.replace(/^npm:/, ''); + if (entryName === depName && entry?.version === currentVersion) { + res.push({ entry, depNameConstraint, depName, constraint }); + } + } + } + } catch (err) /* istanbul ignore next */ { + logger.warn({ err }, 'getLockedDependencies() error'); + } + return res; +} + +// Finds matching dependencies withing a package lock file of sub-entry +export function getLockedDependencies( + yarnLock: YarnLock, + depName: string, + currentVersion: string +): YarnLockEntrySummary[] { + if ('__metadata' in yarnLock) { + return getYarn2LockedDependencies(yarnLock, depName, currentVersion); + } + return getYarn1LockedDependencies(yarnLock, depName, currentVersion); +} diff --git a/lib/modules/manager/nuget/extract.spec.ts b/lib/modules/manager/nuget/extract.spec.ts index ba8b9b84e7af84..5156a9fbd406b1 100644 --- a/lib/modules/manager/nuget/extract.spec.ts +++ b/lib/modules/manager/nuget/extract.spec.ts @@ -22,10 +22,10 @@ describe('modules/manager/nuget/extract', () => { GlobalConfig.reset(); }); - it('returns empty for invalid csproj', async () => { - expect(await extractPackageFile('nothing here', 'bogus', config)).toEqual( - { deps: [] } - ); + it('returns null for invalid csproj', async () => { + expect( + await extractPackageFile('nothing here', 'bogus', config) + ).toBeNull(); }); it('extracts package version dependency', async () => { @@ -347,6 +347,12 @@ describe('modules/manager/nuget/extract', () => { ).toBeNull(); }); + it('returns null for no deps', async () => { + expect( + await extractPackageFile('{"version": 1}', packageFile, config) + ).toBeNull(); + }); + it('does not throw', async () => { expect(await extractPackageFile('{{', packageFile, config)).toBeNull(); }); diff --git a/lib/modules/manager/nuget/extract.ts b/lib/modules/manager/nuget/extract.ts index 5fafd4c6598f57..2e329f9f387406 100644 --- a/lib/modules/manager/nuget/extract.ts +++ b/lib/modules/manager/nuget/extract.ts @@ -74,7 +74,7 @@ function extractDepsFromXml(xmlNode: XmlDocument): PackageDependency[] { export async function extractPackageFile( content: string, packageFile: string, - config: ExtractConfig + _config: ExtractConfig ): Promise { logger.trace({ packageFile }, 'nuget.extractPackageFile()'); @@ -99,7 +99,7 @@ export async function extractPackageFile( return null; } - for (const depName of Object.keys(manifest.tools)) { + for (const depName of Object.keys(manifest.tools ?? {})) { const tool = manifest.tools[depName]; const currentValue = tool.version; const dep: PackageDependency = { @@ -115,7 +115,7 @@ export async function extractPackageFile( deps.push(dep); } - return { deps }; + return deps.length ? { deps } : null; } if (packageFile.endsWith('global.json')) { @@ -134,6 +134,11 @@ export async function extractPackageFile( } catch (err) { logger.debug({ err }, `Failed to parse ${packageFile}`); } + + if (!deps.length) { + return null; + } + const res: PackageFileContent = { deps, packageFileVersion }; const lockFileName = getSiblingFileName(packageFile, 'packages.lock.json'); // istanbul ignore if diff --git a/lib/modules/manager/pep621/__fixtures__/pyproject_pdm_sources.toml b/lib/modules/manager/pep621/__fixtures__/pyproject_pdm_sources.toml new file mode 100644 index 00000000000000..a09c836f392278 --- /dev/null +++ b/lib/modules/manager/pep621/__fixtures__/pyproject_pdm_sources.toml @@ -0,0 +1,33 @@ +[project] +name = "pdm" +dynamic = ["version"] +requires-python = ">=3.7" +license = {text = "MIT"} +dependencies = [ + "blinker", + "packaging>=20.9,!=22.0", +] +readme = "README.md" + +[project.optional-dependencies] +pytest = [ + "pytest>12", +] + +[tool.pdm.dev-dependencies] +test = [ + "pytest-rerunfailures>=10.2", +] +tox = [ + "tox-pdm>=0.5", +] + +[[tool.pdm.source]] +url = "https://private-site.org/pypi/simple" +verify_ssl = true +name = "internal" + +[[tool.pdm.source]] +url = "https://private.pypi.org/simple" +verify_ssl = true +name = "pypi" diff --git a/lib/modules/manager/pep621/__fixtures__/pyproject_with_pdm.toml b/lib/modules/manager/pep621/__fixtures__/pyproject_with_pdm.toml new file mode 100644 index 00000000000000..915cf6063ca561 --- /dev/null +++ b/lib/modules/manager/pep621/__fixtures__/pyproject_with_pdm.toml @@ -0,0 +1,37 @@ +[project] +name = "pdm" +dynamic = ["version"] +requires-python = ">=3.7" +license = {text = "MIT"} +dependencies = [ + "blinker", + "packaging>=20.9,!=22.0", + "rich>=12.3.0", + "virtualenv==20.0.0", + "pyproject-hooks", + "unearth>=0.9.0", + "tomlkit>=0.11.1,<1", + "installer<0.8,>=0.7", + "cachecontrol[filecache]>=0.12.11", + "tomli>=1.1.0; python_version < \"3.11\"", + "typing-extensions; python_version < \"3.8\"", + "importlib-metadata>=3.6; python_version < \"3.10\"", +] +readme = "README.md" + +[project.optional-dependencies] +pytest = [ + "pytest>12", + "pytest-mock", +] + +[tool.pdm.dev-dependencies] +test = [ + "pdm[pytest]", + "pytest-rerunfailures>=10.2", +] +tox = [ + "tox", + "tox-pdm>=0.5", + "", # fail to parse +] diff --git a/lib/modules/manager/pep621/artifacts.spec.ts b/lib/modules/manager/pep621/artifacts.spec.ts new file mode 100644 index 00000000000000..f104c7e51f4327 --- /dev/null +++ b/lib/modules/manager/pep621/artifacts.spec.ts @@ -0,0 +1,105 @@ +import { join } from 'upath'; +import { mockExecAll } from '../../../../test/exec-util'; +import { fs, mockedFunction } from '../../../../test/util'; +import { GlobalConfig } from '../../../config/global'; +import type { RepoGlobalConfig } from '../../../config/types'; +import { getPkgReleases as _getPkgReleases } from '../../datasource'; +import type { UpdateArtifactsConfig } from '../types'; +import { updateArtifacts } from './artifacts'; + +jest.mock('../../../util/fs'); +jest.mock('../../datasource'); + +const getPkgReleases = mockedFunction(_getPkgReleases); + +const config: UpdateArtifactsConfig = {}; +const adminConfig: RepoGlobalConfig = { + localDir: join('/tmp/github/some/repo'), + cacheDir: join('/tmp/cache'), + containerbaseDir: join('/tmp/cache/containerbase'), +}; + +describe('modules/manager/pep621/artifacts', () => { + describe('updateArtifacts()', () => { + it('return null if all processors returns are empty', async () => { + const updatedDeps = [ + { + packageName: 'dep1', + }, + ]; + const result = await updateArtifacts({ + packageFileName: 'pyproject.toml', + newPackageFileContent: '', + config, + updatedDeps, + }); + expect(result).toBeNull(); + }); + + it('return processor result', async () => { + const execSnapshots = mockExecAll(); + GlobalConfig.set({ ...adminConfig, binarySource: 'docker' }); + fs.getSiblingFileName.mockReturnValueOnce('pdm.lock'); + fs.readLocalFile.mockResolvedValueOnce('old test content'); + fs.readLocalFile.mockResolvedValueOnce('new test content'); + // pdm + getPkgReleases.mockResolvedValueOnce({ + releases: [{ version: 'v2.6.1' }, { version: 'v2.5.0' }], + }); + + const updatedDeps = [{ packageName: 'dep1' }]; + const result = await updateArtifacts({ + packageFileName: 'pyproject.toml', + newPackageFileContent: '', + config: {}, + updatedDeps, + }); + expect(result).toEqual([ + { + file: { + contents: 'new test content', + path: 'pdm.lock', + type: 'addition', + }, + }, + ]); + expect(execSnapshots).toMatchObject([ + { + cmd: 'docker pull containerbase/sidecar', + options: { + encoding: 'utf-8', + }, + }, + { + cmd: 'docker ps --filter name=renovate_sidecar -aq', + options: { + encoding: 'utf-8', + }, + }, + { + 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 BUILDPACK_CACHE_DIR ' + + '-e CONTAINERBASE_CACHE_DIR ' + + '-w "/tmp/github/some/repo" ' + + 'containerbase/sidecar ' + + 'bash -l -c "' + + 'install-tool pdm v2.5.0 ' + + '&& ' + + 'pdm update dep1' + + '"', + options: { + cwd: '/tmp/github/some/repo', + encoding: 'utf-8', + env: { + BUILDPACK_CACHE_DIR: '/tmp/cache/containerbase', + CONTAINERBASE_CACHE_DIR: '/tmp/cache/containerbase', + }, + }, + }, + ]); + }); + }); +}); diff --git a/lib/modules/manager/pep621/artifacts.ts b/lib/modules/manager/pep621/artifacts.ts new file mode 100644 index 00000000000000..21145c463c14e2 --- /dev/null +++ b/lib/modules/manager/pep621/artifacts.ts @@ -0,0 +1,23 @@ +import is from '@sindresorhus/is'; +import { writeLocalFile } from '../../../util/fs'; +import type { UpdateArtifact, UpdateArtifactsResult } from '../types'; +import { processors } from './processors'; + +export async function updateArtifacts( + updateArtifact: UpdateArtifact +): Promise { + const { packageFileName, newPackageFileContent } = updateArtifact; + + await writeLocalFile(packageFileName, newPackageFileContent); + + // process specific tool sets + const result: UpdateArtifactsResult[] = []; + for (const processor of processors) { + const artifactUpdates = await processor.updateArtifacts(updateArtifact); + if (is.array(artifactUpdates)) { + result.push(...artifactUpdates); + } + } + + return result.length > 0 ? result : null; +} diff --git a/lib/modules/manager/pep621/extract.spec.ts b/lib/modules/manager/pep621/extract.spec.ts new file mode 100644 index 00000000000000..75e1ad6e2745bc --- /dev/null +++ b/lib/modules/manager/pep621/extract.spec.ts @@ -0,0 +1,267 @@ +import { codeBlock } from 'common-tags'; +import { Fixtures } from '../../../../test/fixtures'; +import { extractPackageFile } from './extract'; + +const pdmPyProject = Fixtures.get('pyproject_with_pdm.toml'); +const pdmSourcesPyProject = Fixtures.get('pyproject_pdm_sources.toml'); + +describe('modules/manager/pep621/extract', () => { + describe('extractPackageFile()', () => { + it('should return null for empty content', function () { + const result = extractPackageFile('', 'pyproject.toml'); + expect(result).toBeNull(); + }); + + it('should return null for invalid toml', function () { + const result = extractPackageFile( + codeBlock` + [project] + name = + `, + 'pyproject.toml' + ); + expect(result).toBeNull(); + }); + + it('should return dependencies for valid content', function () { + const result = extractPackageFile(pdmPyProject, 'pyproject.toml'); + + const dependencies = result?.deps.filter( + (dep) => dep.depType === 'project.dependencies' + ); + expect(dependencies).toEqual([ + { + packageName: 'blinker', + depName: 'blinker', + datasource: 'pypi', + depType: 'project.dependencies', + skipReason: 'any-version', + }, + { + packageName: 'packaging', + depName: 'packaging', + datasource: 'pypi', + depType: 'project.dependencies', + currentValue: '>=20.9,!=22.0', + }, + { + packageName: 'rich', + depName: 'rich', + datasource: 'pypi', + depType: 'project.dependencies', + currentValue: '>=12.3.0', + }, + { + packageName: 'virtualenv', + depName: 'virtualenv', + datasource: 'pypi', + depType: 'project.dependencies', + currentValue: '==20.0.0', + }, + { + packageName: 'pyproject-hooks', + depName: 'pyproject-hooks', + datasource: 'pypi', + depType: 'project.dependencies', + skipReason: 'any-version', + }, + { + packageName: 'unearth', + depName: 'unearth', + datasource: 'pypi', + depType: 'project.dependencies', + currentValue: '>=0.9.0', + }, + { + packageName: 'tomlkit', + depName: 'tomlkit', + datasource: 'pypi', + depType: 'project.dependencies', + currentValue: '>=0.11.1,<1', + }, + { + packageName: 'installer', + depName: 'installer', + datasource: 'pypi', + depType: 'project.dependencies', + currentValue: '<0.8,>=0.7', + }, + { + packageName: 'cachecontrol', + depName: 'cachecontrol', + datasource: 'pypi', + depType: 'project.dependencies', + currentValue: '>=0.12.11', + }, + { + packageName: 'tomli', + depName: 'tomli', + datasource: 'pypi', + depType: 'project.dependencies', + currentValue: '>=1.1.0', + }, + { + packageName: 'typing-extensions', + depName: 'typing-extensions', + datasource: 'pypi', + depType: 'project.dependencies', + skipReason: 'any-version', + }, + { + packageName: 'importlib-metadata', + depName: 'importlib-metadata', + datasource: 'pypi', + depType: 'project.dependencies', + currentValue: '>=3.6', + }, + ]); + + const optionalDependencies = result?.deps.filter( + (dep) => dep.depType === 'project.optional-dependencies' + ); + expect(optionalDependencies).toEqual([ + { + packageName: 'pytest', + datasource: 'pypi', + depType: 'project.optional-dependencies', + currentValue: '>12', + depName: 'pytest/pytest', + }, + { + packageName: 'pytest-mock', + datasource: 'pypi', + depType: 'project.optional-dependencies', + skipReason: 'any-version', + depName: 'pytest/pytest-mock', + }, + ]); + + const pdmDevDependencies = result?.deps.filter( + (dep) => dep.depType === 'tool.pdm.dev-dependencies' + ); + expect(pdmDevDependencies).toEqual([ + { + packageName: 'pdm', + datasource: 'pypi', + depType: 'tool.pdm.dev-dependencies', + skipReason: 'any-version', + depName: 'test/pdm', + }, + { + packageName: 'pytest-rerunfailures', + datasource: 'pypi', + depType: 'tool.pdm.dev-dependencies', + currentValue: '>=10.2', + depName: 'test/pytest-rerunfailures', + }, + { + packageName: 'tox', + datasource: 'pypi', + depType: 'tool.pdm.dev-dependencies', + skipReason: 'any-version', + depName: 'tox/tox', + }, + { + packageName: 'tox-pdm', + datasource: 'pypi', + depType: 'tool.pdm.dev-dependencies', + currentValue: '>=0.5', + depName: 'tox/tox-pdm', + }, + ]); + }); + + it('should return dependencies with overwritten pypi registryUrl', function () { + const result = extractPackageFile(pdmSourcesPyProject, 'pyproject.toml'); + + expect(result?.deps).toEqual([ + { + packageName: 'blinker', + depName: 'blinker', + datasource: 'pypi', + depType: 'project.dependencies', + skipReason: 'any-version', + registryUrls: [ + 'https://private-site.org/pypi/simple', + 'https://private.pypi.org/simple', + ], + }, + { + packageName: 'packaging', + depName: 'packaging', + datasource: 'pypi', + depType: 'project.dependencies', + currentValue: '>=20.9,!=22.0', + registryUrls: [ + 'https://private-site.org/pypi/simple', + 'https://private.pypi.org/simple', + ], + }, + { + packageName: 'pytest', + datasource: 'pypi', + depType: 'project.optional-dependencies', + currentValue: '>12', + depName: 'pytest/pytest', + registryUrls: [ + 'https://private-site.org/pypi/simple', + 'https://private.pypi.org/simple', + ], + }, + { + packageName: 'pytest-rerunfailures', + datasource: 'pypi', + depType: 'tool.pdm.dev-dependencies', + currentValue: '>=10.2', + depName: 'test/pytest-rerunfailures', + registryUrls: [ + 'https://private-site.org/pypi/simple', + 'https://private.pypi.org/simple', + ], + }, + { + packageName: 'tox-pdm', + datasource: 'pypi', + depType: 'tool.pdm.dev-dependencies', + currentValue: '>=0.5', + depName: 'tox/tox-pdm', + registryUrls: [ + 'https://private-site.org/pypi/simple', + 'https://private.pypi.org/simple', + ], + }, + ]); + }); + + it('should return dependencies with original pypi registryUrl', function () { + const result = extractPackageFile( + codeBlock` + [project] + dependencies = [ + "packaging>=20.9,!=22.0", + ] + + [[tool.pdm.source]] + url = "https://private-site.org/pypi/simple" + verify_ssl = true + name = "internal" + `, + 'pyproject.toml' + ); + + expect(result?.deps).toEqual([ + { + packageName: 'packaging', + depName: 'packaging', + datasource: 'pypi', + depType: 'project.dependencies', + currentValue: '>=20.9,!=22.0', + registryUrls: [ + 'https://pypi.org/pypi/', + 'https://private-site.org/pypi/simple', + ], + }, + ]); + }); + }); +}); diff --git a/lib/modules/manager/pep621/extract.ts b/lib/modules/manager/pep621/extract.ts new file mode 100644 index 00000000000000..09064595188470 --- /dev/null +++ b/lib/modules/manager/pep621/extract.ts @@ -0,0 +1,51 @@ +import toml from '@iarna/toml'; +import { logger } from '../../../logger'; +import type { + ExtractConfig, + PackageDependency, + PackageFileContent, +} from '../types'; +import { processors } from './processors'; +import { PyProject, PyProjectSchema } from './schema'; +import { parseDependencyGroupRecord, parseDependencyList } from './utils'; + +export function extractPackageFile( + content: string, + fileName: string, + config?: ExtractConfig +): PackageFileContent | null { + logger.trace({ fileName }, 'pep621.extractPackageFile'); + + const deps: PackageDependency[] = []; + + let def: PyProject; + try { + const jsonMap = toml.parse(content); + def = PyProjectSchema.parse(jsonMap); + } catch (err) { + logger.warn( + { fileName, err }, + `Failed to parse and validate pyproject file` + ); + return null; + } + + // pyProject standard definitions + deps.push( + ...parseDependencyList('project.dependencies', def.project?.dependencies) + ); + deps.push( + ...parseDependencyGroupRecord( + 'project.optional-dependencies', + def.project?.['optional-dependencies'] + ) + ); + + // process specific tool sets + let processedDeps = deps; + for (const processor of processors) { + processedDeps = processor.process(def, processedDeps); + } + + return processedDeps.length ? { deps: processedDeps } : null; +} diff --git a/lib/modules/manager/pep621/index.ts b/lib/modules/manager/pep621/index.ts new file mode 100644 index 00000000000000..62a464046df595 --- /dev/null +++ b/lib/modules/manager/pep621/index.ts @@ -0,0 +1,11 @@ +import { PypiDatasource } from '../../datasource/pypi'; +export { extractPackageFile } from './extract'; +export { updateArtifacts } from './artifacts'; + +export const supportedDatasources = [PypiDatasource.id]; + +export const supportsLockFileMaintenance = true; + +export const defaultConfig = { + fileMatch: ['(^|/)pyproject\\.toml$'], +}; diff --git a/lib/modules/manager/pep621/processors/index.ts b/lib/modules/manager/pep621/processors/index.ts new file mode 100644 index 00000000000000..ba80de12ccbe20 --- /dev/null +++ b/lib/modules/manager/pep621/processors/index.ts @@ -0,0 +1,3 @@ +import { PdmProcessor } from './pdm'; + +export const processors = [new PdmProcessor()]; diff --git a/lib/modules/manager/pep621/processors/pdm.spec.ts b/lib/modules/manager/pep621/processors/pdm.spec.ts new file mode 100644 index 00000000000000..d455b0b722b576 --- /dev/null +++ b/lib/modules/manager/pep621/processors/pdm.spec.ts @@ -0,0 +1,172 @@ +import { join } from 'upath'; +import { mockExecAll } from '../../../../../test/exec-util'; +import { fs, mockedFunction } from '../../../../../test/util'; +import { GlobalConfig } from '../../../../config/global'; +import type { RepoGlobalConfig } from '../../../../config/types'; +import { getPkgReleases as _getPkgReleases } from '../../../datasource'; +import type { UpdateArtifactsConfig } from '../../types'; +import { PdmProcessor } from './pdm'; + +jest.mock('../../../../util/fs'); +jest.mock('../../../datasource'); + +const getPkgReleases = mockedFunction(_getPkgReleases); + +const config: UpdateArtifactsConfig = {}; +const adminConfig: RepoGlobalConfig = { + localDir: join('/tmp/github/some/repo'), + cacheDir: join('/tmp/cache'), + containerbaseDir: join('/tmp/cache/containerbase'), +}; + +const processor = new PdmProcessor(); + +describe('modules/manager/pep621/processors/pdm', () => { + describe('updateArtifacts()', () => { + it('return null if there is no lock file', async () => { + fs.getSiblingFileName.mockReturnValueOnce('pdm.lock'); + const updatedDeps = [{ packageName: 'dep1' }]; + const result = await processor.updateArtifacts({ + packageFileName: 'pyproject.toml', + newPackageFileContent: '', + config, + updatedDeps, + }); + expect(result).toBeNull(); + }); + + it('return null if the lock file is unchanged', async () => { + const execSnapshots = mockExecAll(); + GlobalConfig.set({ ...adminConfig, binarySource: 'docker' }); + fs.getSiblingFileName.mockReturnValueOnce('pdm.lock'); + fs.readLocalFile.mockResolvedValueOnce('test content'); + fs.readLocalFile.mockResolvedValueOnce('test content'); + // pdm + getPkgReleases.mockResolvedValueOnce({ + releases: [{ version: 'v2.6.1' }, { version: 'v2.5.0' }], + }); + + const updatedDeps = [{ packageName: 'dep1' }]; + const result = await processor.updateArtifacts({ + packageFileName: 'pyproject.toml', + newPackageFileContent: '', + config: {}, + updatedDeps, + }); + expect(result).toBeNull(); + expect(execSnapshots).toMatchObject([ + { + cmd: 'docker pull 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 BUILDPACK_CACHE_DIR ' + + '-e CONTAINERBASE_CACHE_DIR ' + + '-w "/tmp/github/some/repo" ' + + 'containerbase/sidecar ' + + 'bash -l -c "' + + 'install-tool pdm v2.5.0 ' + + '&& ' + + 'pdm update dep1' + + '"', + }, + ]); + }); + + it('returns artifact error', async () => { + const execSnapshots = mockExecAll(); + GlobalConfig.set({ ...adminConfig, binarySource: 'docker' }); + fs.getSiblingFileName.mockReturnValueOnce('pdm.lock'); + fs.readLocalFile.mockImplementationOnce(() => { + throw new Error('test error'); + }); + + const updatedDeps = [{ packageName: 'dep1' }]; + const result = await processor.updateArtifacts({ + packageFileName: 'pyproject.toml', + newPackageFileContent: '', + config: {}, + updatedDeps, + }); + expect(result).toEqual([ + { artifactError: { lockFile: 'pdm.lock', stderr: 'test error' } }, + ]); + expect(execSnapshots).toEqual([]); + }); + + it('return update dep update', async () => { + const execSnapshots = mockExecAll(); + GlobalConfig.set(adminConfig); + fs.getSiblingFileName.mockReturnValueOnce('pdm.lock'); + fs.readLocalFile.mockResolvedValueOnce('test content'); + fs.readLocalFile.mockResolvedValueOnce('changed test content'); + // pdm + getPkgReleases.mockResolvedValueOnce({ + releases: [{ version: 'v2.6.1' }, { version: 'v2.5.0' }], + }); + + const updatedDeps = [{ packageName: 'dep1' }, { packageName: 'dep2' }]; + const result = await processor.updateArtifacts({ + packageFileName: 'pyproject.toml', + newPackageFileContent: '', + config: {}, + updatedDeps, + }); + expect(result).toEqual([ + { + file: { + contents: 'changed test content', + path: 'pdm.lock', + type: 'addition', + }, + }, + ]); + expect(execSnapshots).toMatchObject([ + { + cmd: 'pdm update dep1 dep2', + }, + ]); + }); + + it('return update on lockfileMaintenance', async () => { + const execSnapshots = mockExecAll(); + GlobalConfig.set(adminConfig); + fs.getSiblingFileName.mockReturnValueOnce('pdm.lock'); + fs.readLocalFile.mockResolvedValueOnce('test content'); + fs.readLocalFile.mockResolvedValueOnce('changed test content'); + // pdm + getPkgReleases.mockResolvedValueOnce({ + releases: [{ version: 'v2.6.1' }, { version: 'v2.5.0' }], + }); + + const result = await processor.updateArtifacts({ + packageFileName: 'pyproject.toml', + newPackageFileContent: '', + config: { + updateType: 'lockFileMaintenance', + }, + updatedDeps: [], + }); + expect(result).toEqual([ + { + file: { + contents: 'changed test content', + path: 'pdm.lock', + type: 'addition', + }, + }, + ]); + expect(execSnapshots).toMatchObject([ + { + cmd: 'pdm update', + }, + ]); + }); + }); +}); diff --git a/lib/modules/manager/pep621/processors/pdm.ts b/lib/modules/manager/pep621/processors/pdm.ts new file mode 100644 index 00000000000000..cf717b6dbfcfd0 --- /dev/null +++ b/lib/modules/manager/pep621/processors/pdm.ts @@ -0,0 +1,121 @@ +import is from '@sindresorhus/is'; +import { TEMPORARY_ERROR } from '../../../../constants/error-messages'; +import { logger } from '../../../../logger'; +import { exec } from '../../../../util/exec'; +import type { ExecOptions, ToolConstraint } from '../../../../util/exec/types'; +import { getSiblingFileName, readLocalFile } from '../../../../util/fs'; +import { PypiDatasource } from '../../../datasource/pypi'; +import type { + PackageDependency, + UpdateArtifact, + UpdateArtifactsResult, +} from '../../types'; +import type { PyProject } from '../schema'; +import { parseDependencyGroupRecord } from '../utils'; +import type { PyProjectProcessor } from './types'; + +export class PdmProcessor implements PyProjectProcessor { + process(project: PyProject, deps: PackageDependency[]): PackageDependency[] { + const pdm = project.tool?.pdm; + if (is.nullOrUndefined(pdm)) { + return deps; + } + + deps.push( + ...parseDependencyGroupRecord( + 'tool.pdm.dev-dependencies', + pdm['dev-dependencies'] + ) + ); + + const pdmSource = pdm.source; + if (is.nullOrUndefined(pdmSource)) { + return deps; + } + + // add pypi default url, if there is no source declared with the name `pypi`. https://daobook.github.io/pdm/pyproject/tool-pdm/#specify-other-sources-for-finding-packages + const containsPyPiUrl = pdmSource.some((value) => value.name === 'pypi'); + const registryUrls: string[] = []; + if (!containsPyPiUrl) { + registryUrls.push(PypiDatasource.defaultURL); + } + for (const source of pdmSource) { + registryUrls.push(source.url); + } + for (const dep of deps) { + dep.registryUrls = registryUrls; + } + + return deps; + } + + async updateArtifacts( + updateArtifact: UpdateArtifact + ): Promise { + const { config, updatedDeps, packageFileName } = updateArtifact; + + const isLockFileMaintenance = config.updateType === 'lockFileMaintenance'; + + // abort if no lockfile is defined + const lockFileName = getSiblingFileName(packageFileName, 'pdm.lock'); + try { + const existingLockFileContent = await readLocalFile(lockFileName, 'utf8'); + if (is.nullOrUndefined(existingLockFileContent)) { + logger.debug('No pdm.lock found'); + return null; + } + + const toolConstraint: ToolConstraint = { + toolName: 'pdm', + constraint: config.constraints?.pdm, + }; + + const execOptions: ExecOptions = { + docker: {}, + toolConstraints: [toolConstraint], + }; + + // on lockFileMaintenance do not specify any packages and update the complete lock file + // else only update specific packages + let packageList = ''; + if (!isLockFileMaintenance) { + packageList = ' '; + packageList += updatedDeps.map((value) => value.packageName).join(' '); + } + const cmd = `pdm update${packageList}`; + await exec(cmd, execOptions); + + // check for changes + const fileChanges: UpdateArtifactsResult[] = []; + const newLockContent = await readLocalFile(lockFileName, 'utf8'); + const isLockFileChanged = existingLockFileContent !== newLockContent; + if (isLockFileChanged) { + fileChanges.push({ + file: { + type: 'addition', + path: lockFileName, + contents: newLockContent, + }, + }); + } else { + logger.debug('pdm.lock is unchanged'); + } + + return fileChanges.length ? fileChanges : null; + } catch (err) { + // istanbul ignore if + if (err.message === TEMPORARY_ERROR) { + throw err; + } + logger.debug({ err }, 'Failed to update PDM lock file'); + return [ + { + artifactError: { + lockFile: lockFileName, + stderr: err.message, + }, + }, + ]; + } + } +} diff --git a/lib/modules/manager/pep621/processors/types.ts b/lib/modules/manager/pep621/processors/types.ts new file mode 100644 index 00000000000000..37798951b7e161 --- /dev/null +++ b/lib/modules/manager/pep621/processors/types.ts @@ -0,0 +1,20 @@ +import type { + PackageDependency, + UpdateArtifact, + UpdateArtifactsResult, +} from '../../types'; +import type { PyProject } from '../schema'; + +export interface PyProjectProcessor { + updateArtifacts( + updateArtifact: UpdateArtifact + ): Promise; + + /** + * Extracts additional dependencies and/or modifies existing ones based on the tool configuration. + * If no relevant section for the processor exists, then it should return the received dependencies unmodified. + * @param project PyProject object + * @param deps List of already extracted/processed dependencies + */ + process(project: PyProject, deps: PackageDependency[]): PackageDependency[]; +} diff --git a/lib/modules/manager/pep621/readme.md b/lib/modules/manager/pep621/readme.md new file mode 100644 index 00000000000000..073e1bf787c172 --- /dev/null +++ b/lib/modules/manager/pep621/readme.md @@ -0,0 +1,11 @@ +This manager supports updating dependencies inside `pyproject.toml` files. + +In addition to standard dependencies, these toolsets are also supported: + +- `pdm` ( including `pdm.lock` files ) + +Available `depType`s: + +- `project.dependencies` +- `project.optional-dependencies` +- `tool.pdm.dev-dependencies` diff --git a/lib/modules/manager/pep621/schema.ts b/lib/modules/manager/pep621/schema.ts new file mode 100644 index 00000000000000..04dcc6609ce98c --- /dev/null +++ b/lib/modules/manager/pep621/schema.ts @@ -0,0 +1,35 @@ +import { z } from 'zod'; + +export type PyProject = z.infer; + +const DependencyListSchema = z.array(z.string()).optional(); +const DependencyRecordSchema = z + .record(z.string(), z.array(z.string())) + .optional(); + +export const PyProjectSchema = z.object({ + project: z + .object({ + dependencies: DependencyListSchema, + 'optional-dependencies': DependencyRecordSchema, + }) + .optional(), + tool: z + .object({ + pdm: z + .object({ + 'dev-dependencies': DependencyRecordSchema, + source: z + .array( + z.object({ + url: z.string(), + name: z.string(), + verify_ssl: z.boolean().optional(), + }) + ) + .optional(), + }) + .optional(), + }) + .optional(), +}); diff --git a/lib/modules/manager/pep621/types.ts b/lib/modules/manager/pep621/types.ts new file mode 100644 index 00000000000000..1e68aa19818a84 --- /dev/null +++ b/lib/modules/manager/pep621/types.ts @@ -0,0 +1,6 @@ +export interface Pep508ParseResult { + packageName: string; + currentValue?: string; + extras?: string[]; + marker?: string; +} diff --git a/lib/modules/manager/pep621/utils.spec.ts b/lib/modules/manager/pep621/utils.spec.ts new file mode 100644 index 00000000000000..6029a7b8ec8a51 --- /dev/null +++ b/lib/modules/manager/pep621/utils.spec.ts @@ -0,0 +1,39 @@ +import is from '@sindresorhus/is'; +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"'} + `( + '(parse $value"', + ({ value, success, packageName, currentValue, extras, marker }) => { + const result = parsePEP508(value); + + const expected = is.truthy(success) + ? clear({ packageName, currentValue, extras, marker }) + : null; + expect(result).toEqual(expected); + } + ); + }); +}); + +function clear(a: any) { + Object.keys(a).forEach((key) => { + if (a[key] === undefined) { + delete a[key]; + } + }); + return a; +} diff --git a/lib/modules/manager/pep621/utils.ts b/lib/modules/manager/pep621/utils.ts new file mode 100644 index 00000000000000..8741c28dd46a21 --- /dev/null +++ b/lib/modules/manager/pep621/utils.ts @@ -0,0 +1,101 @@ +import is from '@sindresorhus/is'; +import { logger } from '../../../logger'; +import { regEx } from '../../../util/regex'; +import { PypiDatasource } from '../../datasource/pypi'; +import type { PackageDependency } from '../types'; +import type { Pep508ParseResult } from './types'; + +const pep508Regex = regEx( + /^(?[A-Z0-9._-]+)\s*(\[(?[A-Z0-9,._-]+)\])?\s*(?[^;]+)?(;\s*(?.*))?/i +); + +export function parsePEP508( + value: string | null | undefined +): Pep508ParseResult | null { + if (is.nullOrUndefined(value)) { + return null; + } + + const regExpExec = pep508Regex.exec(value); + if ( + is.nullOrUndefined(regExpExec) || + is.nullOrUndefined(regExpExec?.groups) + ) { + logger.trace(`Pep508 could not be extracted`); + return null; + } + + const result: Pep508ParseResult = { + packageName: regExpExec.groups.packageName, + }; + if (is.nonEmptyString(regExpExec.groups.currentValue)) { + 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(','); + } + + return result; +} + +export function pep508ToPackageDependency( + depType: string, + value: string +): PackageDependency | null { + const parsed = parsePEP508(value); + if (is.nullOrUndefined(parsed)) { + return null; + } + + const dep: PackageDependency = { + packageName: parsed.packageName, + depName: parsed.packageName, + datasource: PypiDatasource.id, + depType, + }; + + if (is.nullOrUndefined(parsed.currentValue)) { + dep.skipReason = 'any-version'; + } else { + dep.currentValue = parsed.currentValue; + } + return dep; +} + +export function parseDependencyGroupRecord( + depType: string, + records: Record | null | undefined +): PackageDependency[] { + if (is.nullOrUndefined(records)) { + return []; + } + + const deps: PackageDependency[] = []; + for (const [groupName, pep508Strings] of Object.entries(records)) { + for (const dep of parseDependencyList(depType, pep508Strings)) { + deps.push({ ...dep, depName: `${groupName}/${dep.packageName!}` }); + } + } + return deps; +} + +export function parseDependencyList( + depType: string, + list: string[] | null | undefined +): PackageDependency[] { + if (is.nullOrUndefined(list)) { + return []; + } + + const deps: PackageDependency[] = []; + for (const element of list) { + const dep = pep508ToPackageDependency(depType, element); + if (is.truthy(dep)) { + deps.push(dep); + } + } + return deps; +} diff --git a/lib/modules/manager/poetry/__fixtures__/poetry12.lock b/lib/modules/manager/poetry/__fixtures__/poetry12.lock new file mode 100644 index 00000000000000..0bd5addc4f251e --- /dev/null +++ b/lib/modules/manager/poetry/__fixtures__/poetry12.lock @@ -0,0 +1,482 @@ +[[package]] +name = "attrs" +version = "22.2.0" +description = "Classes Without Boilerplate" +category = "dev" +optional = false +python-versions = ">=3.6" + +[metadata] +lock-version = "1.1" +python-versions = ">=3.8,<4.0" +content-hash = "8387ae7c79d1e9c796e33b5c4506682418457e8b0b55908ce811bb876dcb40fd" + +[metadata.files] +attrs = [ + {file = "attrs-22.2.0-py3-none-any.whl", hash = "sha256:29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836"}, + {file = "attrs-22.2.0.tar.gz", hash = "sha256:c9227bfc2f01993c03f68db37d1d15c9690188323c067c641f1a35ca58185f99"}, +] +certifi = [ + {file = "certifi-2022.12.7-py3-none-any.whl", hash = "sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18"}, + {file = "certifi-2022.12.7.tar.gz", hash = "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3"}, +] +cfgv = [ + {file = "cfgv-3.3.1-py2.py3-none-any.whl", hash = "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426"}, + {file = "cfgv-3.3.1.tar.gz", hash = "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"}, +] +chardet = [ + {file = "chardet-5.1.0-py3-none-any.whl", hash = "sha256:362777fb014af596ad31334fde1e8c327dfdb076e1960d1694662d46a6917ab9"}, + {file = "chardet-5.1.0.tar.gz", hash = "sha256:0d62712b956bc154f85fb0a266e2a3c5913c2967e00348701b32411d6def31e5"}, +] +charset-normalizer = [ + {file = "charset-normalizer-3.1.0.tar.gz", hash = "sha256:34e0a2f9c370eb95597aae63bf85eb5e96826d81e3dcf88b8886012906f509b5"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e0ac8959c929593fee38da1c2b64ee9778733cdf03c482c9ff1d508b6b593b2b"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d7fc3fca01da18fbabe4625d64bb612b533533ed10045a2ac3dd194bfa656b60"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:04eefcee095f58eaabe6dc3cc2262f3bcd776d2c67005880894f447b3f2cb9c1"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20064ead0717cf9a73a6d1e779b23d149b53daf971169289ed2ed43a71e8d3b0"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1435ae15108b1cb6fffbcea2af3d468683b7afed0169ad718451f8db5d1aff6f"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c84132a54c750fda57729d1e2599bb598f5fa0344085dbde5003ba429a4798c0"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75f2568b4189dda1c567339b48cba4ac7384accb9c2a7ed655cd86b04055c795"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11d3bcb7be35e7b1bba2c23beedac81ee893ac9871d0ba79effc7fc01167db6c"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:891cf9b48776b5c61c700b55a598621fdb7b1e301a550365571e9624f270c203"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:5f008525e02908b20e04707a4f704cd286d94718f48bb33edddc7d7b584dddc1"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:b06f0d3bf045158d2fb8837c5785fe9ff9b8c93358be64461a1089f5da983137"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:49919f8400b5e49e961f320c735388ee686a62327e773fa5b3ce6721f7e785ce"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:22908891a380d50738e1f978667536f6c6b526a2064156203d418f4856d6e86a"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-win32.whl", hash = "sha256:12d1a39aa6b8c6f6248bb54550efcc1c38ce0d8096a146638fd4738e42284448"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:65ed923f84a6844de5fd29726b888e58c62820e0769b76565480e1fdc3d062f8"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9a3267620866c9d17b959a84dd0bd2d45719b817245e49371ead79ed4f710d19"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6734e606355834f13445b6adc38b53c0fd45f1a56a9ba06c2058f86893ae8017"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f8303414c7b03f794347ad062c0516cee0e15f7a612abd0ce1e25caf6ceb47df"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aaf53a6cebad0eae578f062c7d462155eada9c172bd8c4d250b8c1d8eb7f916a"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3dc5b6a8ecfdc5748a7e429782598e4f17ef378e3e272eeb1340ea57c9109f41"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e1b25e3ad6c909f398df8921780d6a3d120d8c09466720226fc621605b6f92b1"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ca564606d2caafb0abe6d1b5311c2649e8071eb241b2d64e75a0d0065107e62"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b82fab78e0b1329e183a65260581de4375f619167478dddab510c6c6fb04d9b6"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bd7163182133c0c7701b25e604cf1611c0d87712e56e88e7ee5d72deab3e76b5"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:11d117e6c63e8f495412d37e7dc2e2fff09c34b2d09dbe2bee3c6229577818be"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:cf6511efa4801b9b38dc5546d7547d5b5c6ef4b081c60b23e4d941d0eba9cbeb"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:abc1185d79f47c0a7aaf7e2412a0eb2c03b724581139193d2d82b3ad8cbb00ac"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cb7b2ab0188829593b9de646545175547a70d9a6e2b63bf2cd87a0a391599324"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-win32.whl", hash = "sha256:c36bcbc0d5174a80d6cccf43a0ecaca44e81d25be4b7f90f0ed7bcfbb5a00909"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:cca4def576f47a09a943666b8f829606bcb17e2bc2d5911a46c8f8da45f56755"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0c95f12b74681e9ae127728f7e5409cbbef9cd914d5896ef238cc779b8152373"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fca62a8301b605b954ad2e9c3666f9d97f63872aa4efcae5492baca2056b74ab"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac0aa6cd53ab9a31d397f8303f92c42f534693528fafbdb997c82bae6e477ad9"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c3af8e0f07399d3176b179f2e2634c3ce9c1301379a6b8c9c9aeecd481da494f"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a5fc78f9e3f501a1614a98f7c54d3969f3ad9bba8ba3d9b438c3bc5d047dd28"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:628c985afb2c7d27a4800bfb609e03985aaecb42f955049957814e0491d4006d"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:74db0052d985cf37fa111828d0dd230776ac99c740e1a758ad99094be4f1803d"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:1e8fcdd8f672a1c4fc8d0bd3a2b576b152d2a349782d1eb0f6b8e52e9954731d"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:04afa6387e2b282cf78ff3dbce20f0cc071c12dc8f685bd40960cc68644cfea6"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:dd5653e67b149503c68c4018bf07e42eeed6b4e956b24c00ccdf93ac79cdff84"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d2686f91611f9e17f4548dbf050e75b079bbc2a82be565832bc8ea9047b61c8c"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-win32.whl", hash = "sha256:4155b51ae05ed47199dc5b2a4e62abccb274cee6b01da5b895099b61b1982974"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:322102cdf1ab682ecc7d9b1c5eed4ec59657a65e1c146a0da342b78f4112db23"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e633940f28c1e913615fd624fcdd72fdba807bf53ea6925d6a588e84e1151531"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3a06f32c9634a8705f4ca9946d667609f52cf130d5548881401f1eb2c39b1e2c"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7381c66e0561c5757ffe616af869b916c8b4e42b367ab29fedc98481d1e74e14"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3573d376454d956553c356df45bb824262c397c6e26ce43e8203c4c540ee0acb"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e89df2958e5159b811af9ff0f92614dabf4ff617c03a4c1c6ff53bf1c399e0e1"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:78cacd03e79d009d95635e7d6ff12c21eb89b894c354bd2b2ed0b4763373693b"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de5695a6f1d8340b12a5d6d4484290ee74d61e467c39ff03b39e30df62cf83a0"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c60b9c202d00052183c9be85e5eaf18a4ada0a47d188a83c8f5c5b23252f649"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:f645caaf0008bacf349875a974220f1f1da349c5dbe7c4ec93048cdc785a3326"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ea9f9c6034ea2d93d9147818f17c2a0860d41b71c38b9ce4d55f21b6f9165a11"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:80d1543d58bd3d6c271b66abf454d437a438dff01c3e62fdbcd68f2a11310d4b"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:73dc03a6a7e30b7edc5b01b601e53e7fc924b04e1835e8e407c12c037e81adbd"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6f5c2e7bc8a4bf7c426599765b1bd33217ec84023033672c1e9a8b35eaeaaaf8"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-win32.whl", hash = "sha256:12a2b561af122e3d94cdb97fe6fb2bb2b82cef0cdca131646fdb940a1eda04f0"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:3160a0fd9754aab7d47f95a6b63ab355388d890163eb03b2d2b87ab0a30cfa59"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:38e812a197bf8e71a59fe55b757a84c1f946d0ac114acafaafaf21667a7e169e"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6baf0baf0d5d265fa7944feb9f7451cc316bfe30e8df1a61b1bb08577c554f31"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8f25e17ab3039b05f762b0a55ae0b3632b2e073d9c8fc88e89aca31a6198e88f"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3747443b6a904001473370d7810aa19c3a180ccd52a7157aacc264a5ac79265e"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b116502087ce8a6b7a5f1814568ccbd0e9f6cfd99948aa59b0e241dc57cf739f"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d16fd5252f883eb074ca55cb622bc0bee49b979ae4e8639fff6ca3ff44f9f854"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21fa558996782fc226b529fdd2ed7866c2c6ec91cee82735c98a197fae39f706"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6f6c7a8a57e9405cad7485f4c9d3172ae486cfef1344b5ddd8e5239582d7355e"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ac3775e3311661d4adace3697a52ac0bab17edd166087d493b52d4f4f553f9f0"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:10c93628d7497c81686e8e5e557aafa78f230cd9e77dd0c40032ef90c18f2230"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:6f4f4668e1831850ebcc2fd0b1cd11721947b6dc7c00bf1c6bd3c929ae14f2c7"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:0be65ccf618c1e7ac9b849c315cc2e8a8751d9cfdaa43027d4f6624bd587ab7e"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:53d0a3fa5f8af98a1e261de6a3943ca631c526635eb5817a87a59d9a57ebf48f"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-win32.whl", hash = "sha256:a04f86f41a8916fe45ac5024ec477f41f886b3c435da2d4e3d2709b22ab02af1"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:830d2948a5ec37c386d3170c483063798d7879037492540f10a475e3fd6f244b"}, + {file = "charset_normalizer-3.1.0-py3-none-any.whl", hash = "sha256:3d9098b479e78c85080c98e1e35ff40b4a31d8953102bb0fd7d1b6f8a2111a3d"}, +] +click = [ + {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, + {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, +] +colorama = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] +coverage = [ + {file = "coverage-7.2.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c90e73bdecb7b0d1cea65a08cb41e9d672ac6d7995603d6465ed4914b98b9ad7"}, + {file = "coverage-7.2.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e2926b8abedf750c2ecf5035c07515770944acf02e1c46ab08f6348d24c5f94d"}, + {file = "coverage-7.2.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:57b77b9099f172804e695a40ebaa374f79e4fb8b92f3e167f66facbf92e8e7f5"}, + {file = "coverage-7.2.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:efe1c0adad110bf0ad7fb59f833880e489a61e39d699d37249bdf42f80590169"}, + {file = "coverage-7.2.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2199988e0bc8325d941b209f4fd1c6fa007024b1442c5576f1a32ca2e48941e6"}, + {file = "coverage-7.2.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:81f63e0fb74effd5be736cfe07d710307cc0a3ccb8f4741f7f053c057615a137"}, + {file = "coverage-7.2.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:186e0fc9cf497365036d51d4d2ab76113fb74f729bd25da0975daab2e107fd90"}, + {file = "coverage-7.2.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:420f94a35e3e00a2b43ad5740f935358e24478354ce41c99407cddd283be00d2"}, + {file = "coverage-7.2.2-cp310-cp310-win32.whl", hash = "sha256:38004671848b5745bb05d4d621526fca30cee164db42a1f185615f39dc997292"}, + {file = "coverage-7.2.2-cp310-cp310-win_amd64.whl", hash = "sha256:0ce383d5f56d0729d2dd40e53fe3afeb8f2237244b0975e1427bfb2cf0d32bab"}, + {file = "coverage-7.2.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3eb55b7b26389dd4f8ae911ba9bc8c027411163839dea4c8b8be54c4ee9ae10b"}, + {file = "coverage-7.2.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d2b96123a453a2d7f3995ddb9f28d01fd112319a7a4d5ca99796a7ff43f02af5"}, + {file = "coverage-7.2.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:299bc75cb2a41e6741b5e470b8c9fb78d931edbd0cd009c58e5c84de57c06731"}, + {file = "coverage-7.2.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5e1df45c23d4230e3d56d04414f9057eba501f78db60d4eeecfcb940501b08fd"}, + {file = "coverage-7.2.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:006ed5582e9cbc8115d2e22d6d2144a0725db542f654d9d4fda86793832f873d"}, + {file = "coverage-7.2.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d683d230b5774816e7d784d7ed8444f2a40e7a450e5720d58af593cb0b94a212"}, + {file = "coverage-7.2.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:8efb48fa743d1c1a65ee8787b5b552681610f06c40a40b7ef94a5b517d885c54"}, + {file = "coverage-7.2.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4c752d5264053a7cf2fe81c9e14f8a4fb261370a7bb344c2a011836a96fb3f57"}, + {file = "coverage-7.2.2-cp311-cp311-win32.whl", hash = "sha256:55272f33da9a5d7cccd3774aeca7a01e500a614eaea2a77091e9be000ecd401d"}, + {file = "coverage-7.2.2-cp311-cp311-win_amd64.whl", hash = "sha256:92ebc1619650409da324d001b3a36f14f63644c7f0a588e331f3b0f67491f512"}, + {file = "coverage-7.2.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5afdad4cc4cc199fdf3e18088812edcf8f4c5a3c8e6cb69127513ad4cb7471a9"}, + {file = "coverage-7.2.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0484d9dd1e6f481b24070c87561c8d7151bdd8b044c93ac99faafd01f695c78e"}, + {file = "coverage-7.2.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d530191aa9c66ab4f190be8ac8cc7cfd8f4f3217da379606f3dd4e3d83feba69"}, + {file = "coverage-7.2.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ac0f522c3b6109c4b764ffec71bf04ebc0523e926ca7cbe6c5ac88f84faced0"}, + {file = "coverage-7.2.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:ba279aae162b20444881fc3ed4e4f934c1cf8620f3dab3b531480cf602c76b7f"}, + {file = "coverage-7.2.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:53d0fd4c17175aded9c633e319360d41a1f3c6e352ba94edcb0fa5167e2bad67"}, + {file = "coverage-7.2.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c99cb7c26a3039a8a4ee3ca1efdde471e61b4837108847fb7d5be7789ed8fd9"}, + {file = "coverage-7.2.2-cp37-cp37m-win32.whl", hash = "sha256:5cc0783844c84af2522e3a99b9b761a979a3ef10fb87fc4048d1ee174e18a7d8"}, + {file = "coverage-7.2.2-cp37-cp37m-win_amd64.whl", hash = "sha256:817295f06eacdc8623dc4df7d8b49cea65925030d4e1e2a7c7218380c0072c25"}, + {file = "coverage-7.2.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6146910231ece63facfc5984234ad1b06a36cecc9fd0c028e59ac7c9b18c38c6"}, + {file = "coverage-7.2.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:387fb46cb8e53ba7304d80aadca5dca84a2fbf6fe3faf6951d8cf2d46485d1e5"}, + {file = "coverage-7.2.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:046936ab032a2810dcaafd39cc4ef6dd295df1a7cbead08fe996d4765fca9fe4"}, + {file = "coverage-7.2.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e627dee428a176ffb13697a2c4318d3f60b2ccdde3acdc9b3f304206ec130ccd"}, + {file = "coverage-7.2.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4fa54fb483decc45f94011898727802309a109d89446a3c76387d016057d2c84"}, + {file = "coverage-7.2.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:3668291b50b69a0c1ef9f462c7df2c235da3c4073f49543b01e7eb1dee7dd540"}, + {file = "coverage-7.2.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:7c20b731211261dc9739bbe080c579a1835b0c2d9b274e5fcd903c3a7821cf88"}, + {file = "coverage-7.2.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5764e1f7471cb8f64b8cda0554f3d4c4085ae4b417bfeab236799863703e5de2"}, + {file = "coverage-7.2.2-cp38-cp38-win32.whl", hash = "sha256:4f01911c010122f49a3e9bdc730eccc66f9b72bd410a3a9d3cb8448bb50d65d3"}, + {file = "coverage-7.2.2-cp38-cp38-win_amd64.whl", hash = "sha256:c448b5c9e3df5448a362208b8d4b9ed85305528313fca1b479f14f9fe0d873b8"}, + {file = "coverage-7.2.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bfe7085783cda55e53510482fa7b5efc761fad1abe4d653b32710eb548ebdd2d"}, + {file = "coverage-7.2.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9d22e94e6dc86de981b1b684b342bec5e331401599ce652900ec59db52940005"}, + {file = "coverage-7.2.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:507e4720791977934bba016101579b8c500fb21c5fa3cd4cf256477331ddd988"}, + {file = "coverage-7.2.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bc4803779f0e4b06a2361f666e76f5c2e3715e8e379889d02251ec911befd149"}, + {file = "coverage-7.2.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db8c2c5ace167fd25ab5dd732714c51d4633f58bac21fb0ff63b0349f62755a8"}, + {file = "coverage-7.2.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4f68ee32d7c4164f1e2c8797535a6d0a3733355f5861e0f667e37df2d4b07140"}, + {file = "coverage-7.2.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:d52f0a114b6a58305b11a5cdecd42b2e7f1ec77eb20e2b33969d702feafdd016"}, + {file = "coverage-7.2.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:797aad79e7b6182cb49c08cc5d2f7aa7b2128133b0926060d0a8889ac43843be"}, + {file = "coverage-7.2.2-cp39-cp39-win32.whl", hash = "sha256:db45eec1dfccdadb179b0f9ca616872c6f700d23945ecc8f21bb105d74b1c5fc"}, + {file = "coverage-7.2.2-cp39-cp39-win_amd64.whl", hash = "sha256:8dbe2647bf58d2c5a6c5bcc685f23b5f371909a5624e9f5cd51436d6a9f6c6ef"}, + {file = "coverage-7.2.2-pp37.pp38.pp39-none-any.whl", hash = "sha256:872d6ce1f5be73f05bea4df498c140b9e7ee5418bfa2cc8204e7f9b817caa968"}, + {file = "coverage-7.2.2.tar.gz", hash = "sha256:36dd42da34fe94ed98c39887b86db9d06777b1c8f860520e21126a75507024f2"}, +] +deptry = [ + {file = "deptry-0.6.6-py3-none-any.whl", hash = "sha256:38c03085899339a43374ba51c845d6d1e3d3d2d003d8270d85f0c67f19775e36"}, + {file = "deptry-0.6.6.tar.gz", hash = "sha256:b968b459929ede5428d695c801f39d03c058de7fa7f855585ca8620a1ec3ae62"}, +] +distlib = [ + {file = "distlib-0.3.6-py2.py3-none-any.whl", hash = "sha256:f35c4b692542ca110de7ef0bea44d73981caeb34ca0b9b6b2e6d7790dda8f80e"}, + {file = "distlib-0.3.6.tar.gz", hash = "sha256:14bad2d9b04d3a36127ac97f30b12a19268f211063d8f8ee4f47108896e11b46"}, +] +exceptiongroup = [ + {file = "exceptiongroup-1.1.1-py3-none-any.whl", hash = "sha256:232c37c63e4f682982c8b6459f33a8981039e5fb8756b2074364e5055c498c9e"}, + {file = "exceptiongroup-1.1.1.tar.gz", hash = "sha256:d484c3090ba2889ae2928419117447a14daf3c1231d5e30d0aae34f354f01785"}, +] +filelock = [ + {file = "filelock-3.10.0-py3-none-any.whl", hash = "sha256:e90b34656470756edf8b19656785c5fea73afa1953f3e1b0d645cef11cab3182"}, + {file = "filelock-3.10.0.tar.gz", hash = "sha256:3199fd0d3faea8b911be52b663dfccceb84c95949dd13179aa21436d1a79c4ce"}, +] +ghp-import = [ + {file = "ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343"}, + {file = "ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619"}, +] +griffe = [ + {file = "griffe-0.25.5-py3-none-any.whl", hash = "sha256:1fb9edff48e66d4873014a2ebf21aca5f271d0006a4c937826e3cf592ffb3706"}, + {file = "griffe-0.25.5.tar.gz", hash = "sha256:11ea3403ef0560a1cbcf7f302eb5d21cf4c1d8ed3f8a16a75aa9f6f458caf3f1"}, +] +identify = [ + {file = "identify-2.5.21-py2.py3-none-any.whl", hash = "sha256:69edcaffa8e91ae0f77d397af60f148b6b45a8044b2cc6d99cafa5b04793ff00"}, + {file = "identify-2.5.21.tar.gz", hash = "sha256:7671a05ef9cfaf8ff63b15d45a91a1147a03aaccb2976d4e9bd047cbbc508471"}, +] +idna = [ + {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, + {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, +] +importlib-metadata = [ + {file = "importlib_metadata-6.0.0-py3-none-any.whl", hash = "sha256:7efb448ec9a5e313a57655d35aa54cd3e01b7e1fbcf72dce1bf06119420f5bad"}, + {file = "importlib_metadata-6.0.0.tar.gz", hash = "sha256:e354bedeb60efa6affdcc8ae121b73544a7aa74156d047311948f6d711cd378d"}, +] +iniconfig = [ + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, +] +jinja2 = [ + {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"}, + {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"}, +] +markdown = [ + {file = "Markdown-3.3.7-py3-none-any.whl", hash = "sha256:f5da449a6e1c989a4cea2631aa8ee67caa5a2ef855d551c88f9e309f4634c621"}, + {file = "Markdown-3.3.7.tar.gz", hash = "sha256:cbb516f16218e643d8e0a95b309f77eb118cb138d39a4f27851e6a63581db874"}, +] +markupsafe = [ + {file = "MarkupSafe-2.1.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:665a36ae6f8f20a4676b53224e33d456a6f5a72657d9c83c2aa00765072f31f7"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:340bea174e9761308703ae988e982005aedf427de816d1afe98147668cc03036"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22152d00bf4a9c7c83960521fc558f55a1adbc0631fbb00a9471e097b19d72e1"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28057e985dace2f478e042eaa15606c7efccb700797660629da387eb289b9323"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca244fa73f50a800cf8c3ebf7fd93149ec37f5cb9596aa8873ae2c1d23498601"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d9d971ec1e79906046aa3ca266de79eac42f1dbf3612a05dc9368125952bd1a1"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7e007132af78ea9df29495dbf7b5824cb71648d7133cf7848a2a5dd00d36f9ff"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7313ce6a199651c4ed9d7e4cfb4aa56fe923b1adf9af3b420ee14e6d9a73df65"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-win32.whl", hash = "sha256:c4a549890a45f57f1ebf99c067a4ad0cb423a05544accaf2b065246827ed9603"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:835fb5e38fd89328e9c81067fd642b3593c33e1e17e2fdbf77f5676abb14a156"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2ec4f2d48ae59bbb9d1f9d7efb9236ab81429a764dedca114f5fdabbc3788013"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:608e7073dfa9e38a85d38474c082d4281f4ce276ac0010224eaba11e929dd53a"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:65608c35bfb8a76763f37036547f7adfd09270fbdbf96608be2bead319728fcd"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2bfb563d0211ce16b63c7cb9395d2c682a23187f54c3d79bfec33e6705473c6"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:da25303d91526aac3672ee6d49a2f3db2d9502a4a60b55519feb1a4c7714e07d"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9cad97ab29dfc3f0249b483412c85c8ef4766d96cdf9dcf5a1e3caa3f3661cf1"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:085fd3201e7b12809f9e6e9bc1e5c96a368c8523fad5afb02afe3c051ae4afcc"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1bea30e9bf331f3fef67e0a3877b2288593c98a21ccb2cf29b74c581a4eb3af0"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-win32.whl", hash = "sha256:7df70907e00c970c60b9ef2938d894a9381f38e6b9db73c5be35e59d92e06625"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:e55e40ff0cc8cc5c07996915ad367fa47da6b3fc091fdadca7f5403239c5fec3"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a6e40afa7f45939ca356f348c8e23048e02cb109ced1eb8420961b2f40fb373a"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf877ab4ed6e302ec1d04952ca358b381a882fbd9d1b07cccbfd61783561f98a"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63ba06c9941e46fa389d389644e2d8225e0e3e5ebcc4ff1ea8506dce646f8c8a"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f1cd098434e83e656abf198f103a8207a8187c0fc110306691a2e94a78d0abb2"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:55f44b440d491028addb3b88f72207d71eeebfb7b5dbf0643f7c023ae1fba619"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:a6f2fcca746e8d5910e18782f976489939d54a91f9411c32051b4aab2bd7c513"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0b462104ba25f1ac006fdab8b6a01ebbfbce9ed37fd37fd4acd70c67c973e460"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-win32.whl", hash = "sha256:7668b52e102d0ed87cb082380a7e2e1e78737ddecdde129acadb0eccc5423859"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6d6607f98fcf17e534162f0709aaad3ab7a96032723d8ac8750ffe17ae5a0666"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:a806db027852538d2ad7555b203300173dd1b77ba116de92da9afbc3a3be3eed"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a4abaec6ca3ad8660690236d11bfe28dfd707778e2442b45addd2f086d6ef094"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f03a532d7dee1bed20bc4884194a16160a2de9ffc6354b3878ec9682bb623c54"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4cf06cdc1dda95223e9d2d3c58d3b178aa5dacb35ee7e3bbac10e4e1faacb419"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:22731d79ed2eb25059ae3df1dfc9cb1546691cc41f4e3130fe6bfbc3ecbbecfa"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:f8ffb705ffcf5ddd0e80b65ddf7bed7ee4f5a441ea7d3419e861a12eaf41af58"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8db032bf0ce9022a8e41a22598eefc802314e81b879ae093f36ce9ddf39ab1ba"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2298c859cfc5463f1b64bd55cb3e602528db6fa0f3cfd568d3605c50678f8f03"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-win32.whl", hash = "sha256:50c42830a633fa0cf9e7d27664637532791bfc31c731a87b202d2d8ac40c3ea2"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-win_amd64.whl", hash = "sha256:bb06feb762bade6bf3c8b844462274db0c76acc95c52abe8dbed28ae3d44a147"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:99625a92da8229df6d44335e6fcc558a5037dd0a760e11d84be2260e6f37002f"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8bca7e26c1dd751236cfb0c6c72d4ad61d986e9a41bbf76cb445f69488b2a2bd"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40627dcf047dadb22cd25ea7ecfe9cbf3bbbad0482ee5920b582f3809c97654f"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40dfd3fefbef579ee058f139733ac336312663c6706d1163b82b3003fb1925c4"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:090376d812fb6ac5f171e5938e82e7f2d7adc2b629101cec0db8b267815c85e2"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2e7821bffe00aa6bd07a23913b7f4e01328c3d5cc0b40b36c0bd81d362faeb65"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:c0a33bc9f02c2b17c3ea382f91b4db0e6cde90b63b296422a939886a7a80de1c"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b8526c6d437855442cdd3d87eede9c425c4445ea011ca38d937db299382e6fa3"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-win32.whl", hash = "sha256:137678c63c977754abe9086a3ec011e8fd985ab90631145dfb9294ad09c102a7"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-win_amd64.whl", hash = "sha256:0576fe974b40a400449768941d5d0858cc624e3249dfd1e0c33674e5c7ca7aed"}, + {file = "MarkupSafe-2.1.2.tar.gz", hash = "sha256:abcabc8c2b26036d62d4c746381a6f7cf60aafcc653198ad678306986b09450d"}, +] +mergedeep = [ + {file = "mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307"}, + {file = "mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8"}, +] +mkdocs = [ + {file = "mkdocs-1.4.2-py3-none-any.whl", hash = "sha256:c8856a832c1e56702577023cd64cc5f84948280c1c0fcc6af4cd39006ea6aa8c"}, + {file = "mkdocs-1.4.2.tar.gz", hash = "sha256:8947af423a6d0facf41ea1195b8e1e8c85ad94ac95ae307fe11232e0424b11c5"}, +] +mkdocs-autorefs = [ + {file = "mkdocs-autorefs-0.4.1.tar.gz", hash = "sha256:70748a7bd025f9ecd6d6feeba8ba63f8e891a1af55f48e366d6d6e78493aba84"}, + {file = "mkdocs_autorefs-0.4.1-py3-none-any.whl", hash = "sha256:a2248a9501b29dc0cc8ba4c09f4f47ff121945f6ce33d760f145d6f89d313f5b"}, +] +mkdocs-material = [ + {file = "mkdocs_material-8.5.11-py3-none-any.whl", hash = "sha256:c907b4b052240a5778074a30a78f31a1f8ff82d7012356dc26898b97559f082e"}, + {file = "mkdocs_material-8.5.11.tar.gz", hash = "sha256:b0ea0513fd8cab323e8a825d6692ea07fa83e917bb5db042e523afecc7064ab7"}, +] +mkdocs-material-extensions = [ + {file = "mkdocs_material_extensions-1.1.1-py3-none-any.whl", hash = "sha256:e41d9f38e4798b6617ad98ca8f7f1157b1e4385ac1459ca1e4ea219b556df945"}, + {file = "mkdocs_material_extensions-1.1.1.tar.gz", hash = "sha256:9c003da71e2cc2493d910237448c672e00cefc800d3d6ae93d2fc69979e3bd93"}, +] +mkdocstrings = [ + {file = "mkdocstrings-0.19.1-py3-none-any.whl", hash = "sha256:32a38d88f67f65b264184ea71290f9332db750d189dea4200cbbe408d304c261"}, + {file = "mkdocstrings-0.19.1.tar.gz", hash = "sha256:d1037cacb4b522c1e8c164ed5d00d724a82e49dcee0af80db8fb67b384faeef9"}, +] +mkdocstrings-python = [ + {file = "mkdocstrings-python-0.8.3.tar.gz", hash = "sha256:9ae473f6dc599339b09eee17e4d2b05d6ac0ec29860f3fc9b7512d940fc61adf"}, + {file = "mkdocstrings_python-0.8.3-py3-none-any.whl", hash = "sha256:4e6e1cd6f37a785de0946ced6eb846eb2f5d891ac1cc2c7b832943d3529087a7"}, +] +mypy = [ + {file = "mypy-0.981-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4bc460e43b7785f78862dab78674e62ec3cd523485baecfdf81a555ed29ecfa0"}, + {file = "mypy-0.981-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:756fad8b263b3ba39e4e204ee53042671b660c36c9017412b43af210ddee7b08"}, + {file = "mypy-0.981-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a16a0145d6d7d00fbede2da3a3096dcc9ecea091adfa8da48fa6a7b75d35562d"}, + {file = "mypy-0.981-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce65f70b14a21fdac84c294cde75e6dbdabbcff22975335e20827b3b94bdbf49"}, + {file = "mypy-0.981-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6e35d764784b42c3e256848fb8ed1d4292c9fc0098413adb28d84974c095b279"}, + {file = "mypy-0.981-cp310-cp310-win_amd64.whl", hash = "sha256:e53773073c864d5f5cec7f3fc72fbbcef65410cde8cc18d4f7242dea60dac52e"}, + {file = "mypy-0.981-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:6ee196b1d10b8b215e835f438e06965d7a480f6fe016eddbc285f13955cca659"}, + {file = "mypy-0.981-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ad21d4c9d3673726cf986ea1d0c9fb66905258709550ddf7944c8f885f208be"}, + {file = "mypy-0.981-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d1debb09043e1f5ee845fa1e96d180e89115b30e47c5d3ce53bc967bab53f62d"}, + {file = "mypy-0.981-cp37-cp37m-win_amd64.whl", hash = "sha256:9f362470a3480165c4c6151786b5379351b790d56952005be18bdbdd4c7ce0ae"}, + {file = "mypy-0.981-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:c9e0efb95ed6ca1654951bd5ec2f3fa91b295d78bf6527e026529d4aaa1e0c30"}, + {file = "mypy-0.981-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e178eaffc3c5cd211a87965c8c0df6da91ed7d258b5fc72b8e047c3771317ddb"}, + {file = "mypy-0.981-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:06e1eac8d99bd404ed8dd34ca29673c4346e76dd8e612ea507763dccd7e13c7a"}, + {file = "mypy-0.981-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa38f82f53e1e7beb45557ff167c177802ba7b387ad017eab1663d567017c8ee"}, + {file = "mypy-0.981-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:64e1f6af81c003f85f0dfed52db632817dabb51b65c0318ffbf5ff51995bbb08"}, + {file = "mypy-0.981-cp38-cp38-win_amd64.whl", hash = "sha256:e1acf62a8c4f7c092462c738aa2c2489e275ed386320c10b2e9bff31f6f7e8d6"}, + {file = "mypy-0.981-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b6ede64e52257931315826fdbfc6ea878d89a965580d1a65638ef77cb551f56d"}, + {file = "mypy-0.981-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:eb3978b191b9fa0488524bb4ffedf2c573340e8c2b4206fc191d44c7093abfb7"}, + {file = "mypy-0.981-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:77f8fcf7b4b3cc0c74fb33ae54a4cd00bb854d65645c48beccf65fa10b17882c"}, + {file = "mypy-0.981-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f64d2ce043a209a297df322eb4054dfbaa9de9e8738291706eaafda81ab2b362"}, + {file = "mypy-0.981-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2ee3dbc53d4df7e6e3b1c68ac6a971d3a4fb2852bf10a05fda228721dd44fae1"}, + {file = "mypy-0.981-cp39-cp39-win_amd64.whl", hash = "sha256:8e8e49aa9cc23aa4c926dc200ce32959d3501c4905147a66ce032f05cb5ecb92"}, + {file = "mypy-0.981-py3-none-any.whl", hash = "sha256:794f385653e2b749387a42afb1e14c2135e18daeb027e0d97162e4b7031210f8"}, + {file = "mypy-0.981.tar.gz", hash = "sha256:ad77c13037d3402fbeffda07d51e3f228ba078d1c7096a73759c9419ea031bf4"}, +] +mypy-extensions = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] +nodeenv = [ + {file = "nodeenv-1.7.0-py2.py3-none-any.whl", hash = "sha256:27083a7b96a25f2f5e1d8cb4b6317ee8aeda3bdd121394e5ac54e498028a042e"}, + {file = "nodeenv-1.7.0.tar.gz", hash = "sha256:e0e7f7dfb85fc5394c6fe1e8fa98131a2473e04311a45afb6508f7cf1836fa2b"}, +] +packaging = [ + {file = "packaging-23.0-py3-none-any.whl", hash = "sha256:714ac14496c3e68c99c29b00845f7a2b85f3bb6f1078fd9f72fd20f0570002b2"}, + {file = "packaging-23.0.tar.gz", hash = "sha256:b6ad297f8907de0fa2fe1ccbd26fdaf387f5f47c7275fedf8cce89f99446cf97"}, +] +platformdirs = [ + {file = "platformdirs-3.1.1-py3-none-any.whl", hash = "sha256:e5986afb596e4bb5bde29a79ac9061aa955b94fca2399b7aaac4090860920dd8"}, + {file = "platformdirs-3.1.1.tar.gz", hash = "sha256:024996549ee88ec1a9aa99ff7f8fc819bb59e2c3477b410d90a16d32d6e707aa"}, +] +pluggy = [ + {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, + {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, +] +pre-commit = [ + {file = "pre_commit-2.21.0-py2.py3-none-any.whl", hash = "sha256:e2f91727039fc39a92f58a588a25b87f936de6567eed4f0e673e0507edc75bad"}, + {file = "pre_commit-2.21.0.tar.gz", hash = "sha256:31ef31af7e474a8d8995027fefdfcf509b5c913ff31f2015b4ec4beb26a6f658"}, +] +py = [ + {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, + {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, +] +pygments = [ + {file = "Pygments-2.14.0-py3-none-any.whl", hash = "sha256:fa7bd7bd2771287c0de303af8bfdfc731f51bd2c6a47ab69d117138893b82717"}, + {file = "Pygments-2.14.0.tar.gz", hash = "sha256:b3ed06a9e8ac9a9aae5a6f5dbe78a8a58655d17b43b93c078f094ddc476ae297"}, +] +pymdown-extensions = [ + {file = "pymdown_extensions-9.10-py3-none-any.whl", hash = "sha256:31eaa76ce6f96aabfcea98787c2fff2c5c0611b20a53a94213970cfbf05f02b8"}, + {file = "pymdown_extensions-9.10.tar.gz", hash = "sha256:562c38eee4ce3f101ce631b804bfc2177a8a76c7e4dc908871fb6741a90257a7"}, +] +pytest = [ + {file = "pytest-7.2.2-py3-none-any.whl", hash = "sha256:130328f552dcfac0b1cec75c12e3f005619dc5f874f0a06e8ff7263f0ee6225e"}, + {file = "pytest-7.2.2.tar.gz", hash = "sha256:c99ab0c73aceb050f68929bc93af19ab6db0558791c6a0715723abe9d0ade9d4"}, +] +pytest-cov = [ + {file = "pytest-cov-4.0.0.tar.gz", hash = "sha256:996b79efde6433cdbd0088872dbc5fb3ed7fe1578b68cdbba634f14bb8dd0470"}, + {file = "pytest_cov-4.0.0-py3-none-any.whl", hash = "sha256:2feb1b751d66a8bd934e5edfa2e961d11309dc37b73b0eabe73b5945fee20f6b"}, +] +python-dateutil = [ + {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, + {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, +] +pyyaml = [ + {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"}, + {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"}, + {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"}, + {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"}, + {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"}, + {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"}, + {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"}, + {file = "PyYAML-6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358"}, + {file = "PyYAML-6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1"}, + {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d"}, + {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f"}, + {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782"}, + {file = "PyYAML-6.0-cp311-cp311-win32.whl", hash = "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7"}, + {file = "PyYAML-6.0-cp311-cp311-win_amd64.whl", hash = "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf"}, + {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"}, + {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"}, + {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"}, + {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"}, + {file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"}, + {file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"}, + {file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"}, + {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"}, + {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"}, + {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"}, + {file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"}, + {file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"}, + {file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"}, + {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"}, + {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"}, + {file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"}, + {file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"}, + {file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"}, + {file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"}, + {file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"}, + {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"}, + {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"}, + {file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"}, + {file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"}, + {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"}, + {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"}, +] +pyyaml-env-tag = [ + {file = "pyyaml_env_tag-0.1-py3-none-any.whl", hash = "sha256:af31106dec8a4d68c60207c1886031cbf839b68aa7abccdb19868200532c2069"}, + {file = "pyyaml_env_tag-0.1.tar.gz", hash = "sha256:70092675bda14fdec33b31ba77e7543de9ddc88f2e5b99160396572d11525bdb"}, +] +requests = [ + {file = "requests-2.28.2-py3-none-any.whl", hash = "sha256:64299f4909223da747622c030b781c0d7811e359c37124b4bd368fb8c6518baa"}, + {file = "requests-2.28.2.tar.gz", hash = "sha256:98b1b2782e3c6c4904938b84c0eb932721069dfdb9134313beff7c83c2df24bf"}, +] +setuptools = [ + {file = "setuptools-67.6.0-py3-none-any.whl", hash = "sha256:b78aaa36f6b90a074c1fa651168723acbf45d14cb1196b6f02c0fd07f17623b2"}, + {file = "setuptools-67.6.0.tar.gz", hash = "sha256:2ee892cd5f29f3373097f5a814697e397cf3ce313616df0af11231e2ad118077"}, +] +six = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] +tomli = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] +tox = [ + {file = "tox-3.28.0-py2.py3-none-any.whl", hash = "sha256:57b5ab7e8bb3074edc3c0c0b4b192a4f3799d3723b2c5b76f1fa9f2d40316eea"}, + {file = "tox-3.28.0.tar.gz", hash = "sha256:d0d28f3fe6d6d7195c27f8b054c3e99d5451952b54abdae673b71609a581f640"}, +] +typing-extensions = [ + {file = "typing_extensions-4.5.0-py3-none-any.whl", hash = "sha256:fb33085c39dd998ac16d1431ebc293a8b3eedd00fd4a32de0ff79002c19511b4"}, + {file = "typing_extensions-4.5.0.tar.gz", hash = "sha256:5cb5f4a79139d699607b3ef622a1dedafa84e115ab0024e0d9c044a9479ca7cb"}, +] +urllib3 = [ + {file = "urllib3-1.26.15-py2.py3-none-any.whl", hash = "sha256:aa751d169e23c7479ce47a0cb0da579e3ede798f994f5816a74e4f4500dcea42"}, + {file = "urllib3-1.26.15.tar.gz", hash = "sha256:8a388717b9476f934a21484e8c8e61875ab60644d29b9b39e11e4b9dc1c6b305"}, +] +virtualenv = [ + {file = "virtualenv-20.21.0-py3-none-any.whl", hash = "sha256:31712f8f2a17bd06234fa97fdf19609e789dd4e3e4bf108c3da71d710651adbc"}, + {file = "virtualenv-20.21.0.tar.gz", hash = "sha256:f50e3e60f990a0757c9b68333c9fdaa72d7188caa417f96af9e52407831a3b68"}, +] +watchdog = [ + {file = "watchdog-2.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d1f1200d4ec53b88bf04ab636f9133cb703eb19768a39351cee649de21a33697"}, + {file = "watchdog-2.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:564e7739abd4bd348aeafbf71cc006b6c0ccda3160c7053c4a53b67d14091d42"}, + {file = "watchdog-2.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:95ad708a9454050a46f741ba5e2f3468655ea22da1114e4c40b8cbdaca572565"}, + {file = "watchdog-2.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a073c91a6ef0dda488087669586768195c3080c66866144880f03445ca23ef16"}, + {file = "watchdog-2.3.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:aa8b028750b43e80eea9946d01925168eeadb488dfdef1d82be4b1e28067f375"}, + {file = "watchdog-2.3.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:964fd236cd443933268ae49b59706569c8b741073dbfd7ca705492bae9d39aab"}, + {file = "watchdog-2.3.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:91fd146d723392b3e6eb1ac21f122fcce149a194a2ba0a82c5e4d0ee29cd954c"}, + {file = "watchdog-2.3.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:efe3252137392a471a2174d721e1037a0e6a5da7beb72a021e662b7000a9903f"}, + {file = "watchdog-2.3.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:85bf2263290591b7c5fa01140601b64c831be88084de41efbcba6ea289874f44"}, + {file = "watchdog-2.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8f2df370cd8e4e18499dd0bfdef476431bcc396108b97195d9448d90924e3131"}, + {file = "watchdog-2.3.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ea5d86d1bcf4a9d24610aa2f6f25492f441960cf04aed2bd9a97db439b643a7b"}, + {file = "watchdog-2.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:6f5d0f7eac86807275eba40b577c671b306f6f335ba63a5c5a348da151aba0fc"}, + {file = "watchdog-2.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b848c71ef2b15d0ef02f69da8cc120d335cec0ed82a3fa7779e27a5a8527225"}, + {file = "watchdog-2.3.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0d9878be36d2b9271e3abaa6f4f051b363ff54dbbe7e7df1af3c920e4311ee43"}, + {file = "watchdog-2.3.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:4cd61f98cb37143206818cb1786d2438626aa78d682a8f2ecee239055a9771d5"}, + {file = "watchdog-2.3.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3d2dbcf1acd96e7a9c9aefed201c47c8e311075105d94ce5e899f118155709fd"}, + {file = "watchdog-2.3.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:03f342a9432fe08107defbe8e405a2cb922c5d00c4c6c168c68b633c64ce6190"}, + {file = "watchdog-2.3.1-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7a596f9415a378d0339681efc08d2249e48975daae391d58f2e22a3673b977cf"}, + {file = "watchdog-2.3.1-py3-none-manylinux2014_armv7l.whl", hash = "sha256:0e1dd6d449267cc7d6935d7fe27ee0426af6ee16578eed93bacb1be9ff824d2d"}, + {file = "watchdog-2.3.1-py3-none-manylinux2014_i686.whl", hash = "sha256:7a1876f660e32027a1a46f8a0fa5747ad4fcf86cb451860eae61a26e102c8c79"}, + {file = "watchdog-2.3.1-py3-none-manylinux2014_ppc64.whl", hash = "sha256:2caf77ae137935c1466f8cefd4a3aec7017b6969f425d086e6a528241cba7256"}, + {file = "watchdog-2.3.1-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:53f3e95081280898d9e4fc51c5c69017715929e4eea1ab45801d5e903dd518ad"}, + {file = "watchdog-2.3.1-py3-none-manylinux2014_s390x.whl", hash = "sha256:9da7acb9af7e4a272089bd2af0171d23e0d6271385c51d4d9bde91fe918c53ed"}, + {file = "watchdog-2.3.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:8a4d484e846dcd75e96b96d80d80445302621be40e293bfdf34a631cab3b33dc"}, + {file = "watchdog-2.3.1-py3-none-win32.whl", hash = "sha256:a74155398434937ac2780fd257c045954de5b11b5c52fc844e2199ce3eecf4cf"}, + {file = "watchdog-2.3.1-py3-none-win_amd64.whl", hash = "sha256:5defe4f0918a2a1a4afbe4dbb967f743ac3a93d546ea4674567806375b024adb"}, + {file = "watchdog-2.3.1-py3-none-win_ia64.whl", hash = "sha256:4109cccf214b7e3462e8403ab1e5b17b302ecce6c103eb2fc3afa534a7f27b96"}, + {file = "watchdog-2.3.1.tar.gz", hash = "sha256:d9f9ed26ed22a9d331820a8432c3680707ea8b54121ddcc9dc7d9f2ceeb36906"}, +] +zipp = [ + {file = "zipp-3.15.0-py3-none-any.whl", hash = "sha256:48904fc76a60e542af151aded95726c1a5c34ed43ab4134b597665c86d7ad556"}, + {file = "zipp-3.15.0.tar.gz", hash = "sha256:112929ad649da941c23de50f356a2b5570c954b65150642bccdd66bf194d224b"}, +] diff --git a/lib/modules/manager/poetry/__fixtures__/poetry142.lock b/lib/modules/manager/poetry/__fixtures__/poetry142.lock new file mode 100644 index 00000000000000..a0bee059f58a89 --- /dev/null +++ b/lib/modules/manager/poetry/__fixtures__/poetry142.lock @@ -0,0 +1,18 @@ +# This file is automatically @generated by Poetry 1.4.2 and should not be changed by hand. + +[[package]] +name = "attrs" +version = "22.2.0" +description = "Classes Without Boilerplate" +category = "main" +optional = false +python-versions = ">=3.6" +files = [ + {file = "attrs-22.2.0-py3-none-any.whl", hash = "sha256:29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836"}, + {file = "attrs-22.2.0.tar.gz", hash = "sha256:c9227bfc2f01993c03f68db37d1d15c9690188323c067c641f1a35ca58185f99"}, +] + +[metadata] +lock-version = "2.0" +python-versions = "^3.7" +content-hash = "9aaf819933593fe3f84ff37db4ed316090da9b491e66fd5108b2b33f32f683c3" diff --git a/lib/modules/manager/poetry/artifacts.spec.ts b/lib/modules/manager/poetry/artifacts.spec.ts index 733d5ad9870bdc..67cc4098f841dd 100644 --- a/lib/modules/manager/poetry/artifacts.spec.ts +++ b/lib/modules/manager/poetry/artifacts.spec.ts @@ -8,6 +8,7 @@ import * as docker from '../../../util/exec/docker'; import * as _hostRules from '../../../util/host-rules'; import * as _datasource from '../../datasource'; import type { UpdateArtifactsConfig } from '../types'; +import { getPoetryRequirement } from './artifacts'; import { updateArtifacts } from '.'; const pyproject1toml = Fixtures.get('pyproject.1.toml'); @@ -32,419 +33,440 @@ const adminConfig: RepoGlobalConfig = { const config: UpdateArtifactsConfig = {}; describe('modules/manager/poetry/artifacts', () => { - beforeEach(() => { - jest.resetAllMocks(); - env.getChildProcessEnv.mockReturnValue(envMock.basic); - GlobalConfig.set(adminConfig); - docker.resetPrefetchedImages(); - }); + describe('getPoetryRequirement', () => { + const poetry12lock = Fixtures.get('poetry12.lock'); + const poetry142lock = Fixtures.get('poetry142.lock'); - it('returns null if no poetry.lock found', async () => { - const execSnapshots = mockExecAll(); - const updatedDeps = [{ depName: 'dep1' }]; - expect( - await updateArtifacts({ - packageFileName: 'pyproject.toml', - updatedDeps, - newPackageFileContent: '', - config, - }) - ).toBeNull(); - expect(execSnapshots).toEqual([]); - }); + it('detects poetry from first line of poetry.lock', () => { + const pyprojectContent = ''; + expect(getPoetryRequirement(pyprojectContent, poetry142lock)).toBe( + '1.4.2' + ); + }); - it('returns null if updatedDeps is empty', async () => { - const execSnapshots = mockExecAll(); - expect( - await updateArtifacts({ - packageFileName: 'pyproject.toml', - updatedDeps: [], - newPackageFileContent: '', - config, - }) - ).toBeNull(); - expect(execSnapshots).toEqual([]); + it('detects poetry from metadata', () => { + const pyprojectContent = ''; + expect(getPoetryRequirement(pyprojectContent, poetry12lock)).toBe( + '<1.3.0' + ); + }); }); - it('returns null if unchanged', async () => { - const execSnapshots = mockExecAll(); - fs.ensureCacheDir.mockResolvedValueOnce('/tmp/renovate/cache/others/pip'); - fs.readLocalFile.mockResolvedValueOnce('Current poetry.lock'); - fs.readLocalFile.mockResolvedValueOnce('Current poetry.lock'); - const updatedDeps = [{ depName: 'dep1' }]; - expect( - await updateArtifacts({ - packageFileName: 'pyproject.toml', - updatedDeps, - newPackageFileContent: '', - config, - }) - ).toBeNull(); - expect(execSnapshots).toMatchObject([ - { - cmd: 'poetry update --lock --no-interaction dep1', - options: { - cwd: '/tmp/github/some/repo', - env: { PIP_CACHE_DIR: '/tmp/renovate/cache/others/pip' }, - }, - }, - ]); - }); + describe('updateArtifacts', () => { + beforeEach(() => { + jest.resetAllMocks(); + env.getChildProcessEnv.mockReturnValue(envMock.basic); + GlobalConfig.set(adminConfig); + docker.resetPrefetchedImages(); + }); - it('returns updated poetry.lock', async () => { - const execSnapshots = mockExecAll(); - // poetry.lock - fs.getSiblingFileName.mockReturnValueOnce('poetry.lock'); - fs.readLocalFile.mockResolvedValueOnce('[metadata]\n'); - fs.readLocalFile.mockResolvedValueOnce('New poetry.lock'); - const updatedDeps = [{ depName: 'dep1' }]; - expect( - await updateArtifacts({ - packageFileName: 'pyproject.toml', - updatedDeps, - newPackageFileContent: '{}', - config, - }) - ).toEqual([ - { - file: { - type: 'addition', - path: 'poetry.lock', - contents: 'New poetry.lock', + it('returns null if no poetry.lock found', async () => { + const execSnapshots = mockExecAll(); + const updatedDeps = [{ depName: 'dep1' }]; + expect( + await updateArtifacts({ + packageFileName: 'pyproject.toml', + updatedDeps, + newPackageFileContent: '', + config, + }) + ).toBeNull(); + expect(execSnapshots).toEqual([]); + }); + + it('returns null if updatedDeps is empty', async () => { + const execSnapshots = mockExecAll(); + expect( + await updateArtifacts({ + packageFileName: 'pyproject.toml', + updatedDeps: [], + newPackageFileContent: '', + config, + }) + ).toBeNull(); + expect(execSnapshots).toEqual([]); + }); + + it('returns null if unchanged', async () => { + const execSnapshots = mockExecAll(); + fs.ensureCacheDir.mockResolvedValueOnce('/tmp/renovate/cache/others/pip'); + fs.readLocalFile.mockResolvedValueOnce('Current poetry.lock'); + fs.readLocalFile.mockResolvedValueOnce('Current poetry.lock'); + const updatedDeps = [{ depName: 'dep1' }]; + expect( + await updateArtifacts({ + packageFileName: 'pyproject.toml', + updatedDeps, + newPackageFileContent: '', + config, + }) + ).toBeNull(); + expect(execSnapshots).toMatchObject([ + { + cmd: 'poetry update --lock --no-interaction dep1', + options: { + cwd: '/tmp/github/some/repo', + env: { PIP_CACHE_DIR: '/tmp/renovate/cache/others/pip' }, + }, }, - }, - ]); - expect(execSnapshots).toMatchObject([ - { cmd: 'poetry update --lock --no-interaction dep1' }, - ]); - }); + ]); + }); - it('passes private credential 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'); - hostRules.find.mockReturnValueOnce({ - username: 'usernameOne', - password: 'passwordOne', + it('returns updated poetry.lock', async () => { + const execSnapshots = mockExecAll(); + // poetry.lock + fs.getSiblingFileName.mockReturnValueOnce('poetry.lock'); + fs.readLocalFile.mockResolvedValueOnce('[metadata]\n'); + fs.readLocalFile.mockResolvedValueOnce('New poetry.lock'); + const updatedDeps = [{ depName: 'dep1' }]; + expect( + await updateArtifacts({ + packageFileName: 'pyproject.toml', + updatedDeps, + newPackageFileContent: '{}', + config, + }) + ).toEqual([ + { + file: { + type: 'addition', + path: 'poetry.lock', + contents: 'New poetry.lock', + }, + }, + ]); + expect(execSnapshots).toMatchObject([ + { cmd: 'poetry update --lock --no-interaction dep1' }, + ]); }); - hostRules.find.mockReturnValueOnce({ username: 'usernameTwo' }); - hostRules.find.mockReturnValueOnce({}); - hostRules.find.mockReturnValueOnce({ password: 'passwordFour' }); - const updatedDeps = [{ depName: 'dep1' }]; - expect( - await updateArtifacts({ - packageFileName: 'pyproject.toml', - updatedDeps, - newPackageFileContent: pyproject10toml, - config, - }) - ).toEqual([ - { - file: { - type: 'addition', - path: 'pyproject.lock', - contents: 'New poetry.lock', + + it('passes private credential 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'); + hostRules.find.mockReturnValueOnce({ + username: 'usernameOne', + password: 'passwordOne', + }); + hostRules.find.mockReturnValueOnce({ username: 'usernameTwo' }); + hostRules.find.mockReturnValueOnce({}); + hostRules.find.mockReturnValueOnce({ password: 'passwordFour' }); + const updatedDeps = [{ depName: 'dep1' }]; + expect( + await updateArtifacts({ + packageFileName: 'pyproject.toml', + updatedDeps, + newPackageFileContent: pyproject10toml, + config, + }) + ).toEqual([ + { + file: { + type: 'addition', + path: 'pyproject.lock', + contents: 'New poetry.lock', + }, }, - }, - ]); - expect(hostRules.find.mock.calls).toHaveLength(4); - expect(execSnapshots).toMatchObject([ - { cmd: 'poetry update --lock --no-interaction dep1' }, - ]); - }); + ]); + expect(hostRules.find.mock.calls).toHaveLength(4); + expect(execSnapshots).toMatchObject([ + { cmd: 'poetry update --lock --no-interaction dep1' }, + ]); + }); - it('prioritizes pypi-scoped credentials', async () => { - const execSnapshots = mockExecAll(); - // poetry.lock - fs.getSiblingFileName.mockReturnValueOnce('poetry.lock'); - fs.readLocalFile.mockResolvedValueOnce(null); - // pyproject.lock - fs.getSiblingFileName.mockReturnValueOnce('pyproject.lock'); - fs.readLocalFile.mockResolvedValueOnce('[metadata]\n'); - fs.readLocalFile.mockResolvedValueOnce('New poetry.lock'); - hostRules.find.mockImplementation((search) => ({ - password: - search.hostType === 'pypi' ? 'scoped-password' : 'unscoped-password', - })); - const updatedDeps = [{ depName: 'dep1' }]; - expect( - await updateArtifacts({ - packageFileName: 'pyproject.toml', - updatedDeps, - newPackageFileContent: ` + it('prioritizes pypi-scoped credentials', async () => { + const execSnapshots = mockExecAll(); + // poetry.lock + fs.getSiblingFileName.mockReturnValueOnce('poetry.lock'); + fs.readLocalFile.mockResolvedValueOnce(null); + // pyproject.lock + fs.getSiblingFileName.mockReturnValueOnce('pyproject.lock'); + fs.readLocalFile.mockResolvedValueOnce('[metadata]\n'); + fs.readLocalFile.mockResolvedValueOnce('New poetry.lock'); + hostRules.find.mockImplementation((search) => ({ + password: + search.hostType === 'pypi' ? 'scoped-password' : 'unscoped-password', + })); + const updatedDeps = [{ depName: 'dep1' }]; + expect( + await updateArtifacts({ + packageFileName: 'pyproject.toml', + updatedDeps, + newPackageFileContent: ` [[tool.poetry.source]] name = "one" url = "some.url" `, - config, - }) - ).toEqual([ - { - file: { - type: 'addition', - path: 'pyproject.lock', - contents: 'New poetry.lock', + config, + }) + ).toEqual([ + { + file: { + type: 'addition', + path: 'pyproject.lock', + contents: 'New poetry.lock', + }, }, - }, - ]); - expect(execSnapshots).toMatchObject([ - { cmd: 'poetry update --lock --no-interaction dep1' }, - ]); - }); + ]); + expect(execSnapshots).toMatchObject([ + { cmd: 'poetry update --lock --no-interaction dep1' }, + ]); + }); - it('returns updated pyproject.lock', async () => { - const execSnapshots = mockExecAll(); - // poetry.lock - fs.getSiblingFileName.mockReturnValueOnce('poetry.lock'); - fs.readLocalFile.mockResolvedValueOnce(null); - // pyproject.lock - fs.getSiblingFileName.mockReturnValueOnce('pyproject.lock'); - fs.readLocalFile.mockResolvedValueOnce('[metadata]\n'); - fs.readLocalFile.mockResolvedValueOnce('New poetry.lock'); - const updatedDeps = [{ depName: 'dep1' }]; - expect( - await updateArtifacts({ - packageFileName: 'pyproject.toml', - updatedDeps, - newPackageFileContent: '{}', - config, - }) - ).toEqual([ - { - file: { - type: 'addition', - path: 'pyproject.lock', - contents: 'New poetry.lock', + it('returns updated pyproject.lock', async () => { + const execSnapshots = mockExecAll(); + // poetry.lock + fs.getSiblingFileName.mockReturnValueOnce('poetry.lock'); + fs.readLocalFile.mockResolvedValueOnce(null); + // pyproject.lock + fs.getSiblingFileName.mockReturnValueOnce('pyproject.lock'); + fs.readLocalFile.mockResolvedValueOnce('[metadata]\n'); + fs.readLocalFile.mockResolvedValueOnce('New poetry.lock'); + const updatedDeps = [{ depName: 'dep1' }]; + expect( + await updateArtifacts({ + packageFileName: 'pyproject.toml', + updatedDeps, + newPackageFileContent: '{}', + config, + }) + ).toEqual([ + { + file: { + type: 'addition', + path: 'pyproject.lock', + contents: 'New poetry.lock', + }, }, - }, - ]); - expect(execSnapshots).toMatchObject([ - { cmd: 'poetry update --lock --no-interaction dep1' }, - ]); - }); - - it('returns updated poetry.lock using docker', async () => { - GlobalConfig.set({ ...adminConfig, binarySource: 'docker' }); - const execSnapshots = mockExecAll(); - fs.ensureCacheDir.mockResolvedValueOnce('/tmp/renovate/cache/others/pip'); - // poetry.lock - fs.getSiblingFileName.mockReturnValueOnce('poetry.lock'); - fs.readLocalFile.mockResolvedValueOnce('[metadata]\n'); - fs.readLocalFile.mockResolvedValueOnce('New poetry.lock'); - // python - datasource.getPkgReleases.mockResolvedValueOnce({ - releases: [{ version: '2.7.5' }, { version: '3.4.2' }], - }); - // poetry - datasource.getPkgReleases.mockResolvedValueOnce({ - releases: [{ version: '1.2.0' }], + ]); + expect(execSnapshots).toMatchObject([ + { cmd: 'poetry update --lock --no-interaction dep1' }, + ]); }); - const updatedDeps = [{ depName: 'dep1' }]; - expect( - await updateArtifacts({ - packageFileName: 'pyproject.toml', - updatedDeps, - newPackageFileContent: pyproject1toml, - config: { - ...config, - constraints: { - python: '~2.7 || ^3.4', + + it('returns updated poetry.lock using docker', async () => { + GlobalConfig.set({ ...adminConfig, binarySource: 'docker' }); + const execSnapshots = mockExecAll(); + fs.ensureCacheDir.mockResolvedValueOnce('/tmp/renovate/cache/others/pip'); + // poetry.lock + fs.getSiblingFileName.mockReturnValueOnce('poetry.lock'); + fs.readLocalFile.mockResolvedValueOnce('[metadata]\n'); + fs.readLocalFile.mockResolvedValueOnce('New poetry.lock'); + // python + datasource.getPkgReleases.mockResolvedValueOnce({ + releases: [{ version: '2.7.5' }, { version: '3.4.2' }], + }); + // poetry + datasource.getPkgReleases.mockResolvedValueOnce({ + releases: [{ version: '1.2.0' }], + }); + const updatedDeps = [{ depName: 'dep1' }]; + expect( + await updateArtifacts({ + packageFileName: 'pyproject.toml', + updatedDeps, + newPackageFileContent: pyproject1toml, + config: { + ...config, + constraints: { + python: '~2.7 || ^3.4', + }, + }, + }) + ).toEqual([ + { + file: { + type: 'addition', + path: 'poetry.lock', + contents: 'New poetry.lock', }, }, - }) - ).toEqual([ - { - file: { - type: 'addition', - path: 'poetry.lock', - contents: 'New poetry.lock', + ]); + expect(execSnapshots).toMatchObject([ + { cmd: 'docker pull 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 PIP_CACHE_DIR ' + + '-e BUILDPACK_CACHE_DIR ' + + '-e CONTAINERBASE_CACHE_DIR ' + + '-w "/tmp/github/some/repo" ' + + 'containerbase/sidecar ' + + 'bash -l -c "' + + 'install-tool python 3.4.2 ' + + '&& ' + + 'install-tool poetry 1.2.0 ' + + '&& ' + + 'poetry update --lock --no-interaction dep1' + + '"', }, - }, - ]); - expect(execSnapshots).toMatchObject([ - { cmd: 'docker pull 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 PIP_CACHE_DIR ' + - '-e BUILDPACK_CACHE_DIR ' + - '-e CONTAINERBASE_CACHE_DIR ' + - '-w "/tmp/github/some/repo" ' + - 'containerbase/sidecar ' + - 'bash -l -c "' + - 'install-tool python 3.4.2 ' + - '&& ' + - 'install-tool poetry 1.2.0 ' + - '&& ' + - 'poetry update --lock --no-interaction dep1' + - '"', - }, - ]); - }); + ]); + }); - it('returns updated poetry.lock using docker (constraints)', async () => { - GlobalConfig.set({ ...adminConfig, binarySource: 'docker' }); - const execSnapshots = mockExecAll(); + it('returns updated poetry.lock using docker (constraints)', async () => { + GlobalConfig.set({ ...adminConfig, binarySource: 'docker' }); + const execSnapshots = mockExecAll(); - fs.ensureCacheDir.mockResolvedValueOnce('/tmp/renovate/cache/others/pip'); - // poetry.lock - fs.getSiblingFileName.mockReturnValueOnce('poetry.lock'); - fs.readLocalFile.mockResolvedValueOnce( - '[metadata]\npython-versions = "~2.7 || ^3.4"' - ); - fs.readLocalFile.mockResolvedValueOnce('New poetry.lock'); - // python - datasource.getPkgReleases.mockResolvedValueOnce({ - releases: [{ version: '2.7.5' }, { version: '3.3.2' }], - }); - // poetry - datasource.getPkgReleases.mockResolvedValueOnce({ - releases: [{ version: '1.0.0' }, { version: '1.2.0' }], - }); - const updatedDeps = [{ depName: 'dep1' }]; - expect( - await updateArtifacts({ - packageFileName: 'pyproject.toml', - updatedDeps, - newPackageFileContent: pyproject1toml, - config: { - ...config, - constraints: {}, + fs.ensureCacheDir.mockResolvedValueOnce('/tmp/renovate/cache/others/pip'); + // poetry.lock + fs.getSiblingFileName.mockReturnValueOnce('poetry.lock'); + fs.readLocalFile.mockResolvedValueOnce( + '[metadata]\npython-versions = "~2.7 || ^3.4"' + ); + fs.readLocalFile.mockResolvedValueOnce('New poetry.lock'); + // python + datasource.getPkgReleases.mockResolvedValueOnce({ + releases: [{ version: '2.7.5' }, { version: '3.3.2' }], + }); + // poetry + datasource.getPkgReleases.mockResolvedValueOnce({ + releases: [{ version: '1.0.0' }, { version: '1.2.0' }], + }); + const updatedDeps = [{ depName: 'dep1' }]; + expect( + await updateArtifacts({ + packageFileName: 'pyproject.toml', + updatedDeps, + newPackageFileContent: pyproject1toml, + config: { + ...config, + constraints: {}, + }, + }) + ).toEqual([ + { + file: { + type: 'addition', + path: 'poetry.lock', + contents: 'New poetry.lock', + }, }, - }) - ).toEqual([ - { - file: { - type: 'addition', - path: 'poetry.lock', - contents: 'New poetry.lock', + ]); + expect(execSnapshots).toMatchObject([ + { cmd: 'docker pull 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 PIP_CACHE_DIR ' + + '-e BUILDPACK_CACHE_DIR ' + + '-e CONTAINERBASE_CACHE_DIR ' + + '-w "/tmp/github/some/repo" ' + + 'containerbase/sidecar ' + + 'bash -l -c "' + + 'install-tool python 2.7.5 ' + + '&& ' + + 'install-tool poetry 1.2.0 ' + + '&& ' + + 'poetry update --lock --no-interaction dep1' + + '"', }, - }, - ]); - expect(execSnapshots).toMatchObject([ - { cmd: 'docker pull 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 PIP_CACHE_DIR ' + - '-e BUILDPACK_CACHE_DIR ' + - '-e CONTAINERBASE_CACHE_DIR ' + - '-w "/tmp/github/some/repo" ' + - 'containerbase/sidecar ' + - 'bash -l -c "' + - 'install-tool python 2.7.5 ' + - '&& ' + - 'install-tool poetry 1.2.0 ' + - '&& ' + - 'poetry update --lock --no-interaction dep1' + - '"', - }, - ]); - }); - - it('returns updated poetry.lock using install mode', async () => { - GlobalConfig.set({ ...adminConfig, binarySource: 'install' }); - const execSnapshots = mockExecAll(); - // poetry.lock - fs.getSiblingFileName.mockReturnValueOnce('poetry.lock'); - fs.readLocalFile.mockResolvedValueOnce( - '[metadata]\npython-versions = "~2.7 || ^3.4"' - ); - fs.readLocalFile.mockResolvedValueOnce('New poetry.lock'); - // python - datasource.getPkgReleases.mockResolvedValueOnce({ - releases: [{ version: '2.7.5' }, { version: '3.3.2' }], + ]); }); - // poetry - datasource.getPkgReleases.mockResolvedValueOnce({ - releases: [{ version: '1.2.0' }], - }); - const updatedDeps = [{ depName: 'dep1' }]; - expect( - await updateArtifacts({ - packageFileName: 'pyproject.toml', - updatedDeps, - newPackageFileContent: pyproject1toml, - config: { - ...config, - constraints: {}, - }, - }) - ).toEqual([ - { - file: { - type: 'addition', - path: 'poetry.lock', - contents: 'New poetry.lock', + + it('returns updated poetry.lock using install mode', async () => { + GlobalConfig.set({ ...adminConfig, binarySource: 'install' }); + const execSnapshots = mockExecAll(); + // poetry.lock + fs.getSiblingFileName.mockReturnValueOnce('poetry.lock'); + fs.readLocalFile.mockResolvedValueOnce( + '[metadata]\npython-versions = "~2.7 || ^3.4"' + ); + fs.readLocalFile.mockResolvedValueOnce('New poetry.lock'); + // python + datasource.getPkgReleases.mockResolvedValueOnce({ + releases: [{ version: '2.7.5' }, { version: '3.3.2' }], + }); + // poetry + datasource.getPkgReleases.mockResolvedValueOnce({ + releases: [{ version: '1.2.0' }], + }); + const updatedDeps = [{ depName: 'dep1' }]; + expect( + await updateArtifacts({ + packageFileName: 'pyproject.toml', + updatedDeps, + newPackageFileContent: pyproject1toml, + config: { + ...config, + constraints: {}, + }, + }) + ).toEqual([ + { + file: { + type: 'addition', + path: 'poetry.lock', + contents: 'New poetry.lock', + }, }, - }, - ]); + ]); - expect(execSnapshots).toMatchObject([ - { cmd: 'install-tool python 2.7.5' }, - { cmd: 'install-tool poetry 1.2.0' }, - { cmd: 'poetry update --lock --no-interaction dep1' }, - ]); - }); + expect(execSnapshots).toMatchObject([ + { cmd: 'install-tool python 2.7.5' }, + { cmd: 'install-tool poetry 1.2.0' }, + { cmd: 'poetry update --lock --no-interaction dep1' }, + ]); + }); - it('catches errors', async () => { - const execSnapshots = mockExecAll(); - // poetry.lock - fs.getSiblingFileName.mockReturnValueOnce('poetry.lock'); - fs.readLocalFile.mockResolvedValueOnce('Current poetry.lock'); - fs.writeLocalFile.mockImplementationOnce(() => { - throw new Error('not found'); + it('catches errors', async () => { + const execSnapshots = mockExecAll(); + // poetry.lock + fs.getSiblingFileName.mockReturnValueOnce('poetry.lock'); + fs.readLocalFile.mockResolvedValueOnce('Current poetry.lock'); + fs.writeLocalFile.mockImplementationOnce(() => { + throw new Error('not found'); + }); + const updatedDeps = [{ depName: 'dep1' }]; + expect( + await updateArtifacts({ + packageFileName: 'pyproject.toml', + updatedDeps, + newPackageFileContent: '{}', + config, + }) + ).toMatchObject([{ artifactError: { lockFile: 'poetry.lock' } }]); + expect(execSnapshots).toMatchObject([]); }); - const updatedDeps = [{ depName: 'dep1' }]; - expect( - await updateArtifacts({ - packageFileName: 'pyproject.toml', - updatedDeps, - newPackageFileContent: '{}', - config, - }) - ).toMatchObject([{ artifactError: { lockFile: 'poetry.lock' } }]); - expect(execSnapshots).toMatchObject([]); - }); - it('returns updated poetry.lock when doing lockfile maintenance', async () => { - const execSnapshots = mockExecAll(); - // poetry.lock - fs.getSiblingFileName.mockReturnValueOnce('poetry.lock'); - fs.readLocalFile.mockResolvedValueOnce('Old poetry.lock'); - fs.readLocalFile.mockResolvedValueOnce('New poetry.lock'); - expect( - await updateArtifacts({ - packageFileName: 'pyproject.toml', - updatedDeps: [], - newPackageFileContent: '{}', - config: { - ...config, - updateType: 'lockFileMaintenance', - }, - }) - ).toEqual([ - { - file: { - contents: 'New poetry.lock', - path: 'poetry.lock', - type: 'addition', + it('returns updated poetry.lock when doing lockfile maintenance', async () => { + const execSnapshots = mockExecAll(); + // poetry.lock + fs.getSiblingFileName.mockReturnValueOnce('poetry.lock'); + fs.readLocalFile.mockResolvedValueOnce('Old poetry.lock'); + fs.readLocalFile.mockResolvedValueOnce('New poetry.lock'); + expect( + await updateArtifacts({ + packageFileName: 'pyproject.toml', + updatedDeps: [], + newPackageFileContent: '{}', + config: { + ...config, + updateType: 'lockFileMaintenance', + }, + }) + ).toEqual([ + { + file: { + contents: 'New poetry.lock', + path: 'poetry.lock', + type: 'addition', + }, }, - }, - ]); - expect(execSnapshots).toMatchObject([ - { cmd: 'poetry update --lock --no-interaction' }, - ]); + ]); + expect(execSnapshots).toMatchObject([ + { cmd: 'poetry update --lock --no-interaction' }, + ]); + }); }); }); diff --git a/lib/modules/manager/poetry/artifacts.ts b/lib/modules/manager/poetry/artifacts.ts index f0248841a781e9..0bcb3c721830a3 100644 --- a/lib/modules/manager/poetry/artifacts.ts +++ b/lib/modules/manager/poetry/artifacts.ts @@ -17,24 +17,12 @@ import { find } from '../../../util/host-rules'; import { regEx } from '../../../util/regex'; import { PypiDatasource } from '../../datasource/pypi'; import { dependencyPattern } from '../pip_requirements/extract'; -import type { - UpdateArtifact, - UpdateArtifactsConfig, - UpdateArtifactsResult, -} from '../types'; +import type { UpdateArtifact, UpdateArtifactsResult } from '../types'; import type { PoetryFile, PoetryLock, PoetrySource } from './types'; export function getPythonConstraint( - existingLockFileContent: string, - config: UpdateArtifactsConfig + existingLockFileContent: string ): string | undefined | null { - const { constraints = {} } = config; - const { python } = constraints; - - if (python) { - logger.debug('Using python constraint from config'); - return python; - } try { const data = parse(existingLockFileContent) as PoetryLock; if (is.string(data?.metadata?.['python-versions'])) { @@ -48,7 +36,35 @@ export function getPythonConstraint( const pkgValRegex = regEx(`^${dependencyPattern}$`); -export function getPoetryRequirement(pyProjectContent: string): string | null { +const poetryConstraint: Record = { + '1.0': '<1.1.0', + '1.1': '<1.3.0', + '2.0': '>=1.3.0', +}; + +export function getPoetryRequirement( + pyProjectContent: string, + existingLockFileContent: string +): undefined | string | null { + // Read Poetry version from first line of poetry.lock + const firstLine = existingLockFileContent.split('\n')[0]; + const poetryVersionMatch = firstLine.match(/by Poetry ([\d\\.]+)/); + if (poetryVersionMatch?.[1]) { + logger.debug('Using poetry version from poetry.lock header'); + return poetryVersionMatch[1]; + } + try { + const data = parse(existingLockFileContent) as PoetryLock; + const lockVersion = data?.metadata?.['lock-version']; + if (is.string(lockVersion)) { + if (poetryConstraint[lockVersion]) { + logger.debug('Using poetry version from poetry.lock metadata'); + return poetryConstraint[lockVersion]; + } + } + } catch (err) { + // Do nothing + } try { const pyproject: PoetryFile = parse(pyProjectContent); // https://python-poetry.org/docs/pyproject/#poetry-and-pep-517 @@ -173,12 +189,12 @@ export async function updateArtifacts({ .join(' ')}` ); } - const pythonConstraint = getPythonConstraint( - existingLockFileContent, - config - ); + const pythonConstraint = + config?.constraints?.python ?? + getPythonConstraint(existingLockFileContent); const poetryConstraint = - config.constraints?.poetry ?? getPoetryRequirement(newPackageFileContent); + config.constraints?.poetry ?? + getPoetryRequirement(newPackageFileContent, existingLockFileContent); const extraEnv = { ...getSourceCredentialVars(newPackageFileContent, packageFileName), PIP_CACHE_DIR: await ensureCacheDir('pip'), diff --git a/lib/modules/manager/poetry/types.ts b/lib/modules/manager/poetry/types.ts index 6fa510ad515f9c..0c2eaa792548a4 100644 --- a/lib/modules/manager/poetry/types.ts +++ b/lib/modules/manager/poetry/types.ts @@ -40,6 +40,7 @@ export interface PoetryLockSection { export interface PoetryLock { metadata?: { + 'lock-version'?: string; 'python-versions'?: string; }; package?: PoetryLockSection[]; diff --git a/lib/modules/manager/regex/utils.spec.ts b/lib/modules/manager/regex/utils.spec.ts new file mode 100644 index 00000000000000..8e40e3a5ff69db --- /dev/null +++ b/lib/modules/manager/regex/utils.spec.ts @@ -0,0 +1,14 @@ +import { regEx } from '../../../util/regex'; +import * as utils from './utils'; + +describe('modules/manager/regex/utils', () => { + it('does not crash for lazy regex', () => { + const lazyMatch = regEx('(?.*?)', 'g'); + expect( + utils.regexMatchAll( + lazyMatch, + '1f699d2bfc99bbbe4c1ed5bb8fc21e6911d69c6e\n' + ) + ).toBeArray(); + }); +}); diff --git a/lib/modules/manager/regex/utils.ts b/lib/modules/manager/regex/utils.ts index 8f9a2743fcd219..ca5470b9f0d37f 100644 --- a/lib/modules/manager/regex/utils.ts +++ b/lib/modules/manager/regex/utils.ts @@ -85,12 +85,18 @@ export function regexMatchAll( ): RegExpMatchArray[] { const matches: RegExpMatchArray[] = []; let matchResult: RegExpMatchArray | null; + let iterations = 0; + const maxIterations = 10000; do { matchResult = regex.exec(content); if (matchResult) { matches.push(matchResult); } - } while (matchResult); + iterations += 1; + } while (matchResult && iterations < maxIterations); + if (iterations === maxIterations) { + logger.warn('Max iterations reached for matchStrings'); + } return matches; } diff --git a/lib/modules/manager/terraform/__fixtures__/docker.tf b/lib/modules/manager/terraform/__fixtures__/docker.tf index de04d0cd91d607..4490a11bff41ea 100644 --- a/lib/modules/manager/terraform/__fixtures__/docker.tf +++ b/lib/modules/manager/terraform/__fixtures__/docker.tf @@ -12,6 +12,10 @@ resource "docker_image" "ignore_variable" { pull_triggers = ["${data.docker_registry_image.ubuntu.sha256_digest}"] } +resource "docker_image" "proxy" { + name = "hub.proxy.test/bitnami/nginx:1.24.0" +} + # docker_container resources # https://registry.terraform.io/providers/kreuzwerker/docker/latest/docs/resources/container diff --git a/lib/modules/manager/terraform/__fixtures__/helm.tf b/lib/modules/manager/terraform/__fixtures__/helm.tf index 6cae1674acbcaf..bef91bd3c646a3 100644 --- a/lib/modules/manager/terraform/__fixtures__/helm.tf +++ b/lib/modules/manager/terraform/__fixtures__/helm.tf @@ -53,3 +53,11 @@ resource "helm_release" "karpenter_oci_repo" { chart = "karpenter" version = "v0.22.1" } + +## chart in OCI registry +resource "helm_release" "proxy_oci_repo" { + name = "kube-prometheus" + repository = "oci://hub.proxy.test/bitnamicharts" + chart = "kube-prometheus" + version = "8.9.1" +} diff --git a/lib/modules/manager/terraform/base.ts b/lib/modules/manager/terraform/base.ts index 274052535b94aa..4947f14f8ddb8d 100644 --- a/lib/modules/manager/terraform/base.ts +++ b/lib/modules/manager/terraform/base.ts @@ -1,7 +1,7 @@ import is from '@sindresorhus/is'; import { regEx } from '../../../util/regex'; import { TerraformProviderDatasource } from '../../datasource/terraform-provider'; -import type { PackageDependency } from '../types'; +import type { ExtractConfig, PackageDependency } from '../types'; import type { TerraformDefinitionFile } from './hcl/types'; import type { ProviderLock } from './lockfile/types'; import { getLockedVersion, massageProviderLookupName } from './util'; @@ -20,7 +20,8 @@ export abstract class DependencyExtractor { */ abstract extract( hclRoot: TerraformDefinitionFile, - locks: ProviderLock[] + locks: ProviderLock[], + config: ExtractConfig ): PackageDependency[]; } diff --git a/lib/modules/manager/terraform/extract.spec.ts b/lib/modules/manager/terraform/extract.spec.ts index cbdea0323c7c01..c4e8246a9adc16 100644 --- a/lib/modules/manager/terraform/extract.spec.ts +++ b/lib/modules/manager/terraform/extract.spec.ts @@ -401,18 +401,19 @@ describe('modules/manager/terraform/extract', () => { }); it('extracts docker resources', async () => { - const res = await extractPackageFile(docker, 'docker.tf', {}); - expect(res?.deps).toHaveLength(6); + const res = await extractPackageFile(docker, 'docker.tf', { + registryAliases: { 'hub.proxy.test': 'index.docker.io' }, + }); + expect(res?.deps).toHaveLength(7); expect(res?.deps.filter((dep) => dep.skipReason)).toHaveLength(3); - expect(res?.deps).toIncludeAllPartialMembers([ + expect(res?.deps).toMatchObject([ { autoReplaceStringTemplate: '{{depName}}{{#if newValue}}:{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}', - currentValue: '1.7.8', datasource: 'docker', - depName: 'nginx', depType: 'docker_image', - replaceString: 'nginx:1.7.8', + replaceString: '${data.docker_registry_image.ubuntu.name}', + skipReason: 'contains-variable', }, { depType: 'docker_image', @@ -421,10 +422,20 @@ describe('modules/manager/terraform/extract', () => { { autoReplaceStringTemplate: '{{depName}}{{#if newValue}}:{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}', + currentValue: '1.7.8', datasource: 'docker', + depName: 'nginx', depType: 'docker_image', - replaceString: '${data.docker_registry_image.ubuntu.name}', - skipReason: 'contains-variable', + replaceString: 'nginx:1.7.8', + }, + { + autoReplaceStringTemplate: + 'hub.proxy.test/bitnami/nginx:{{#if newValue}}{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}', + currentValue: '1.24.0', + datasource: 'docker', + depName: 'index.docker.io/bitnami/nginx', + depType: 'docker_image', + replaceString: 'hub.proxy.test/bitnami/nginx:1.24.0', }, { autoReplaceStringTemplate: @@ -574,29 +585,12 @@ describe('modules/manager/terraform/extract', () => { }); it('extract helm releases', async () => { - const res = await extractPackageFile(helm, 'helm.tf', {}); - expect(res?.deps).toHaveLength(8); + const res = await extractPackageFile(helm, 'helm.tf', { + registryAliases: { 'hub.proxy.test': 'index.docker.io' }, + }); + expect(res?.deps).toHaveLength(9); expect(res?.deps.filter((dep) => dep.skipReason)).toHaveLength(2); - expect(res?.deps).toIncludeAllPartialMembers([ - { - currentValue: '1.0.1', - datasource: 'helm', - depName: 'redis', - depType: 'helm_release', - registryUrls: ['https://charts.helm.sh/stable'], - }, - { - datasource: 'helm', - depName: 'redis', - depType: 'helm_release', - registryUrls: ['https://charts.helm.sh/stable'], - }, - { - datasource: 'helm', - depName: './charts/example', - depType: 'helm_release', - skipReason: 'local-chart', - }, + expect(res?.deps).toMatchObject([ { currentValue: '4.0.1', datasource: 'helm', @@ -630,6 +624,32 @@ describe('modules/manager/terraform/extract', () => { depType: 'helm_release', packageName: 'public.ecr.aws/karpenter/karpenter', }, + { + datasource: 'helm', + depName: './charts/example', + depType: 'helm_release', + skipReason: 'local-chart', + }, + { + currentValue: '8.9.1', + datasource: 'docker', + depName: 'kube-prometheus', + depType: 'helm_release', + packageName: 'index.docker.io/bitnamicharts/kube-prometheus', + }, + { + currentValue: '1.0.1', + datasource: 'helm', + depName: 'redis', + depType: 'helm_release', + registryUrls: ['https://charts.helm.sh/stable'], + }, + { + datasource: 'helm', + depName: 'redis', + depType: 'helm_release', + registryUrls: ['https://charts.helm.sh/stable'], + }, ]); }); diff --git a/lib/modules/manager/terraform/extract.ts b/lib/modules/manager/terraform/extract.ts index e15cc17af3d58b..ef6ac343891362 100644 --- a/lib/modules/manager/terraform/extract.ts +++ b/lib/modules/manager/terraform/extract.ts @@ -46,7 +46,7 @@ export async function extractPackageFile( const locks = await extractLocksForPackageFile(fileName); for (const extractor of passedExtractors) { - const deps = extractor.extract(hclMap, locks); + const deps = extractor.extract(hclMap, locks, config); dependencies.push(...deps); } diff --git a/lib/modules/manager/terraform/extractors/resources/generic-docker-image-ref.spec.ts b/lib/modules/manager/terraform/extractors/resources/generic-docker-image-ref.spec.ts index dc8e78c5e1f8a8..6d48a30c6a27d2 100644 --- a/lib/modules/manager/terraform/extractors/resources/generic-docker-image-ref.spec.ts +++ b/lib/modules/manager/terraform/extractors/resources/generic-docker-image-ref.spec.ts @@ -4,7 +4,7 @@ describe('modules/manager/terraform/extractors/resources/generic-docker-image-re const extractor = new GenericDockerImageRefExtractor(); it('return empty array if no resource is found', () => { - const res = extractor.extract({}); + const res = extractor.extract({}, [], {}); expect(res).toBeArrayOfSize(0); }); }); diff --git a/lib/modules/manager/terraform/extractors/resources/generic-docker-image-ref.ts b/lib/modules/manager/terraform/extractors/resources/generic-docker-image-ref.ts index eb3f4c97d92628..7e89f12fd8200e 100644 --- a/lib/modules/manager/terraform/extractors/resources/generic-docker-image-ref.ts +++ b/lib/modules/manager/terraform/extractors/resources/generic-docker-image-ref.ts @@ -1,8 +1,9 @@ import is from '@sindresorhus/is'; import { getDep } from '../../../dockerfile/extract'; -import type { PackageDependency } from '../../../types'; +import type { ExtractConfig, PackageDependency } from '../../../types'; import { DependencyExtractor } from '../../base'; import type { TerraformDefinitionFile } from '../../hcl/types'; +import type { ProviderLock } from '../../lockfile/types'; import { generic_image_resource } from './utils'; export class GenericDockerImageRefExtractor extends DependencyExtractor { @@ -10,7 +11,11 @@ export class GenericDockerImageRefExtractor extends DependencyExtractor { return generic_image_resource.map((value) => `"${value.type}"`); } - extract(hclMap: TerraformDefinitionFile): PackageDependency[] { + extract( + hclMap: TerraformDefinitionFile, + _locks: ProviderLock[], + config: ExtractConfig + ): PackageDependency[] { const resourceTypMap = hclMap.resource; if (is.nullOrUndefined(resourceTypMap)) { return []; @@ -28,7 +33,9 @@ export class GenericDockerImageRefExtractor extends DependencyExtractor { // loop over instances of a resource type for (const instance of Object.values(resourceInstancesMap).flat()) { - dependencies.push(...this.walkPath({ depType: type }, instance, path)); + dependencies.push( + ...this.walkPath({ depType: type }, instance, path, config) + ); } } return dependencies; @@ -45,7 +52,8 @@ export class GenericDockerImageRefExtractor extends DependencyExtractor { private walkPath( abstractDep: PackageDependency, parentElement: unknown, - leftPath: string[] + leftPath: string[], + config: ExtractConfig ): PackageDependency[] { const dependencies: PackageDependency[] = []; // if there are no path elements left, we have reached the end of the path @@ -59,7 +67,7 @@ export class GenericDockerImageRefExtractor extends DependencyExtractor { }, ]; } - const test = getDep(parentElement); + const test = getDep(parentElement, true, config.registryAliases); const dep: PackageDependency = { ...abstractDep, ...test, @@ -87,11 +95,11 @@ export class GenericDockerImageRefExtractor extends DependencyExtractor { if (is.array(element)) { for (const arrayElement of element) { dependencies.push( - ...this.walkPath(abstractDep, arrayElement, leftPath.slice(1)) + ...this.walkPath(abstractDep, arrayElement, leftPath.slice(1), config) ); } return dependencies; } - return this.walkPath(abstractDep, element, leftPath.slice(1)); + return this.walkPath(abstractDep, element, leftPath.slice(1), config); } } diff --git a/lib/modules/manager/terraform/extractors/resources/helm-release.spec.ts b/lib/modules/manager/terraform/extractors/resources/helm-release.spec.ts index 84f2451c8030bb..7c89c540df6adb 100644 --- a/lib/modules/manager/terraform/extractors/resources/helm-release.spec.ts +++ b/lib/modules/manager/terraform/extractors/resources/helm-release.spec.ts @@ -4,7 +4,7 @@ describe('modules/manager/terraform/extractors/resources/helm-release', () => { const extractor = new HelmReleaseExtractor(); it('return empty array if no resource is found', () => { - const res = extractor.extract({}); + const res = extractor.extract({}, [], {}); expect(res).toBeArrayOfSize(0); }); }); diff --git a/lib/modules/manager/terraform/extractors/resources/helm-release.ts b/lib/modules/manager/terraform/extractors/resources/helm-release.ts index c0c54a3b20ce8f..4e2ec94052ff35 100644 --- a/lib/modules/manager/terraform/extractors/resources/helm-release.ts +++ b/lib/modules/manager/terraform/extractors/resources/helm-release.ts @@ -1,12 +1,13 @@ import is from '@sindresorhus/is'; import { logger } from '../../../../../logger'; import { joinUrlParts } from '../../../../../util/url'; -import { DockerDatasource } from '../../../../datasource/docker'; import { HelmDatasource } from '../../../../datasource/helm'; +import { getDep } from '../../../dockerfile/extract'; import { isOCIRegistry } from '../../../helmv3/utils'; -import type { PackageDependency } from '../../../types'; +import type { ExtractConfig, PackageDependency } from '../../../types'; import { DependencyExtractor } from '../../base'; import type { TerraformDefinitionFile } from '../../hcl/types'; +import type { ProviderLock } from '../../lockfile/types'; import { checkIfStringIsPath } from '../../util'; export class HelmReleaseExtractor extends DependencyExtractor { @@ -14,7 +15,11 @@ export class HelmReleaseExtractor extends DependencyExtractor { return [`"helm_release"`]; } - override extract(hclMap: TerraformDefinitionFile): PackageDependency[] { + override extract( + hclMap: TerraformDefinitionFile, + _locks: ProviderLock[], + config: ExtractConfig + ): PackageDependency[] { const dependencies = []; const helmReleases = hclMap?.resource?.helm_release; @@ -46,19 +51,20 @@ export class HelmReleaseExtractor extends DependencyExtractor { } else if (isOCIRegistry(helmRelease.chart)) { // For oci charts, we remove the oci:// and use the docker datasource dep.depName = helmRelease.chart.replace('oci://', ''); - dep.datasource = DockerDatasource.id; + this.processOCI(dep.depName, config, dep); } else if (checkIfStringIsPath(helmRelease.chart)) { dep.skipReason = 'local-chart'; } else if (is.nonEmptyString(helmRelease.repository)) { if (isOCIRegistry(helmRelease.repository)) { - { - // For oci repos, we remove the oci://, join the chart name and use the docker datasource - dep.packageName = joinUrlParts( + // For oci charts, we remove the oci:// and use the docker datasource + this.processOCI( + joinUrlParts( helmRelease.repository.replace('oci://', ''), helmRelease.chart - ); - dep.datasource = DockerDatasource.id; - } + ), + config, + dep + ); } else { dep.registryUrls = [helmRelease.repository]; } @@ -67,4 +73,18 @@ export class HelmReleaseExtractor extends DependencyExtractor { return dependencies; } + + private processOCI( + depName: string, + config: ExtractConfig, + dep: PackageDependency + ): void { + const { depName: packageName, datasource } = getDep( + depName, + false, + config.registryAliases + ); + dep.packageName = packageName; + dep.datasource = datasource; + } } diff --git a/lib/modules/manager/terragrunt/artifacts.spec.ts b/lib/modules/manager/terragrunt/artifacts.spec.ts new file mode 100644 index 00000000000000..d69cc1ba354d5b --- /dev/null +++ b/lib/modules/manager/terragrunt/artifacts.spec.ts @@ -0,0 +1,71 @@ +import { join } from 'upath'; +import { GlobalConfig } from '../../../config/global'; +import type { UpdateType } from '../../../config/types'; +import * as terraformLockfile from '../terraform/lockfile'; +import type { UpdateArtifactsConfig } from '../types'; +import { updateArtifacts } from './artifacts'; + +jest.mock('../terraform/lockfile'); + +const config = { + constraints: {}, +}; + +const adminConfig = { + // `join` fixes Windows CI + localDir: join('/tmp/github/some/repo'), + cacheDir: join('/tmp/renovate/cache'), + containerbaseDir: join('/tmp/renovate/cache/containerbase'), +}; + +describe('modules/manager/terragrunt/artifacts', () => { + const updateTypes: UpdateType[] = [ + 'digest', + 'pin', + 'rollback', + 'patch', + 'minor', + 'major', + 'replacement', + 'pinDigest', + 'lockfileUpdate', + 'bump', + ]; + + beforeEach(() => { + GlobalConfig.set(adminConfig); + }); + + it('calls terraform updateArtifacts if the update type is lockfileMaintenance', async () => { + const localConfig: UpdateArtifactsConfig = { + updateType: 'lockFileMaintenance', + ...config, + }; + + await updateArtifacts({ + packageFileName: '', + updatedDeps: [], + newPackageFileContent: '', + config: localConfig, + }); + expect(terraformLockfile.updateArtifacts).toHaveBeenCalledOnce(); + }); + + it.each(updateTypes)( + 'does not call terraform updateArtifacts if the update type is %s', + async (updateType) => { + const localConfig: UpdateArtifactsConfig = { + updateType, + ...config, + }; + + await updateArtifacts({ + packageFileName: '', + updatedDeps: [], + newPackageFileContent: '', + config: localConfig, + }); + expect(terraformLockfile.updateArtifacts).not.toHaveBeenCalled(); + } + ); +}); diff --git a/lib/modules/manager/terragrunt/artifacts.ts b/lib/modules/manager/terragrunt/artifacts.ts new file mode 100644 index 00000000000000..865ee1195dba61 --- /dev/null +++ b/lib/modules/manager/terragrunt/artifacts.ts @@ -0,0 +1,18 @@ +import { logger } from '../../../logger'; +import { updateArtifacts as updateTerraformArtifacts } from '../terraform/lockfile/index'; +import type { UpdateArtifact, UpdateArtifactsResult } from '../types'; + +export async function updateArtifacts( + artifact: UpdateArtifact +): Promise { + if (artifact.config.updateType !== 'lockFileMaintenance') { + logger.debug( + `UpdateType ${ + artifact.config.updateType as string + } is not supported for terragrunt` + ); + return null; + } + + return await updateTerraformArtifacts(artifact); +} diff --git a/lib/modules/manager/terragrunt/index.ts b/lib/modules/manager/terragrunt/index.ts index 78eb46b346c2d8..39d6faf56e7fc3 100644 --- a/lib/modules/manager/terragrunt/index.ts +++ b/lib/modules/manager/terragrunt/index.ts @@ -2,6 +2,7 @@ import { GitTagsDatasource } from '../../datasource/git-tags'; import { GithubTagsDatasource } from '../../datasource/github-tags'; import { TerraformModuleDatasource } from '../../datasource/terraform-module'; +export { updateArtifacts } from './artifacts'; export { extractPackageFile } from './extract'; export const supportedDatasources = [ @@ -10,6 +11,7 @@ export const supportedDatasources = [ TerraformModuleDatasource.id, ]; +export const supportsLockFileMaintenance = true; export const defaultConfig = { commitMessageTopic: 'Terragrunt dependency {{depName}}', fileMatch: ['(^|/)terragrunt\\.hcl$'], diff --git a/lib/modules/manager/terragrunt/readme.md b/lib/modules/manager/terragrunt/readme.md index 0e36ffe1550f17..e2484bcfaee478 100644 --- a/lib/modules/manager/terragrunt/readme.md +++ b/lib/modules/manager/terragrunt/readme.md @@ -18,3 +18,8 @@ terraform { source = "github.com/hashicorp/example?ref=v1.0.0" } ``` + +### Terraform lockfiles + +The Terragrunt manager supports [lock file maintenance](https://docs.renovatebot.com/configuration-options/#lockfilemaintenance) for `.terraform.lock.hcl` artifacts. +These artifacts will be updated if and only if the update type is `lockFileMaintenance`. diff --git a/lib/modules/manager/types.ts b/lib/modules/manager/types.ts index 6e26451238eff8..dfb040005aaee0 100644 --- a/lib/modules/manager/types.ts +++ b/lib/modules/manager/types.ts @@ -174,6 +174,7 @@ export interface Upgrade> extends PackageDependency { isLockFileMaintenance?: boolean; isRemediation?: boolean; isVulnerabilityAlert?: boolean; + vulnerabilitySeverity?: string; registryUrls?: string[] | null; currentVersion?: string; replaceString?: string; diff --git a/lib/modules/platform/api.ts b/lib/modules/platform/api.ts index bb67f2c39432a4..973f6b75d39db6 100644 --- a/lib/modules/platform/api.ts +++ b/lib/modules/platform/api.ts @@ -6,6 +6,7 @@ import * as codecommit from './codecommit'; import * as gitea from './gitea'; import * as github from './github'; import * as gitlab from './gitlab'; +import * as local from './local'; import type { Platform } from './types'; const api = new Map(); @@ -18,3 +19,4 @@ api.set(codecommit.id, codecommit); api.set(gitea.id, gitea); api.set(github.id, github); api.set(gitlab.id, gitlab); +api.set(local.id, local); diff --git a/lib/modules/platform/azure/__snapshots__/index.spec.ts.snap b/lib/modules/platform/azure/__snapshots__/index.spec.ts.snap index 21858fbbb4b3cc..3be9ce9411245c 100644 --- a/lib/modules/platform/azure/__snapshots__/index.spec.ts.snap +++ b/lib/modules/platform/azure/__snapshots__/index.spec.ts.snap @@ -274,7 +274,7 @@ exports[`modules/platform/azure/index initRepo should initialise the config for } `; -exports[`modules/platform/azure/index updatePr(prNo, title, body) should close the PR 1`] = ` +exports[`modules/platform/azure/index updatePr(prNo, title, body, platformOptions) should close the PR 1`] = ` [ [ { @@ -288,7 +288,9 @@ exports[`modules/platform/azure/index updatePr(prNo, title, body) should close t ] `; -exports[`modules/platform/azure/index updatePr(prNo, title, body) should reopen the PR 1`] = ` +exports[`modules/platform/azure/index updatePr(prNo, title, body, platformOptions) should re-approve the PR 1`] = `undefined`; + +exports[`modules/platform/azure/index updatePr(prNo, title, body, platformOptions) should reopen the PR 1`] = ` [ [ { @@ -308,7 +310,7 @@ exports[`modules/platform/azure/index updatePr(prNo, title, body) should reopen ] `; -exports[`modules/platform/azure/index updatePr(prNo, title, body) should update the PR 1`] = ` +exports[`modules/platform/azure/index updatePr(prNo, title, body, platformOptions) should update the PR 1`] = ` [ [ { @@ -321,7 +323,7 @@ exports[`modules/platform/azure/index updatePr(prNo, title, body) should update ] `; -exports[`modules/platform/azure/index updatePr(prNo, title, body) should update the PR without description 1`] = ` +exports[`modules/platform/azure/index updatePr(prNo, title, body, platformOptions) should update the PR without description 1`] = ` [ [ { diff --git a/lib/modules/platform/azure/index.spec.ts b/lib/modules/platform/azure/index.spec.ts index da8a998a7b702e..29493cd2421217 100644 --- a/lib/modules/platform/azure/index.spec.ts +++ b/lib/modules/platform/azure/index.spec.ts @@ -812,7 +812,7 @@ describe('modules/platform/azure/index', () => { }); }); - describe('updatePr(prNo, title, body)', () => { + describe('updatePr(prNo, title, body, platformOptions)', () => { it('should update the PR', async () => { await initRepo({ repository: 'some/repo' }); const updatePullRequest = jest.fn(); @@ -881,6 +881,43 @@ describe('modules/platform/azure/index', () => { }); expect(updatePullRequest.mock.calls).toMatchSnapshot(); }); + + it('should re-approve the PR', async () => { + await initRepo({ repository: 'some/repo' }); + const prResult = { + pullRequestId: 456, + createdBy: { + id: 123, + url: 'user-url', + }, + }; + const prUpdateResult = { + reviewerUrl: prResult.createdBy.url, + vote: AzurePrVote.Approved, + isFlagged: false, + isRequired: false, + }; + const updateFn = jest.fn(() => prUpdateResult); + azureApi.gitApi.mockImplementationOnce( + () => + ({ + updatePullRequest: jest.fn(() => prResult), + createPullRequestReviewer: updateFn, + getPullRequestById: jest.fn(() => ({ + pullRequestId: prResult.pullRequestId, + createdBy: prResult.createdBy, + })), + } as any) + ); + const pr = await azure.updatePr({ + number: prResult.pullRequestId, + prTitle: 'The Title', + prBody: 'Hello world', + platformOptions: { autoApprove: true }, + }); + expect(updateFn).toHaveBeenCalled(); + expect(pr).toMatchSnapshot(); + }); }); describe('ensureComment', () => { diff --git a/lib/modules/platform/azure/index.ts b/lib/modules/platform/azure/index.ts index b1eb1430369d14..def6948ea10b12 100644 --- a/lib/modules/platform/azure/index.ts +++ b/lib/modules/platform/azure/index.ts @@ -307,7 +307,9 @@ export async function findPr({ ); if (prTitle) { - prsFiltered = prsFiltered.filter((item) => item.title === prTitle); + prsFiltered = prsFiltered.filter( + (item) => item.title.toUpperCase() === prTitle.toUpperCase() + ); } switch (state) { @@ -506,6 +508,7 @@ export async function updatePr({ prTitle: title, prBody: body, state, + platformOptions, }: UpdatePrConfig): Promise { logger.debug(`updatePr(${prNo}, ${title}, body)`); @@ -527,6 +530,21 @@ export async function updatePr({ } else if (state === 'closed') { objToUpdate.status = PullRequestStatus.Abandoned; } + if (platformOptions?.autoApprove) { + const pr = await azureApiGit.getPullRequestById(prNo, config.project); + await azureApiGit.createPullRequestReviewer( + { + reviewerUrl: pr.createdBy!.url, + vote: AzurePrVote.Approved, + isFlagged: false, + isRequired: false, + }, + config.repoId, + // TODO #7154 + pr.pullRequestId!, + pr.createdBy!.id! + ); + } await azureApiGit.updatePullRequest(objToUpdate, config.repoId, prNo); } @@ -759,6 +777,10 @@ export function massageMarkdown(input: string): string { 'you tick the rebase/retry checkbox', 'rename PR to start with "rebase!"' ) + .replace( + 'checking the rebase/retry box above', + 'renaming the PR to start with "rebase!"' + ) .replace(regEx(`\n---\n\n.*?.*?\n`), '') .replace(regEx(//g), ''); } diff --git a/lib/modules/platform/bitbucket-server/index.ts b/lib/modules/platform/bitbucket-server/index.ts index b8258e58043656..9da5a7fff7a2eb 100644 --- a/lib/modules/platform/bitbucket-server/index.ts +++ b/lib/modules/platform/bitbucket-server/index.ts @@ -289,7 +289,7 @@ const isRelevantPr = (branchName: string, prTitle: string | null | undefined, state: string) => (p: Pr): boolean => p.sourceBranch === branchName && - (!prTitle || p.title === prTitle) && + (!prTitle || p.title.toUpperCase() === prTitle.toUpperCase()) && matchesState(p.state, state); // TODO: coverage (#9624) @@ -974,6 +974,10 @@ export function massageMarkdown(input: string): string { 'you tick the rebase/retry checkbox', 'rename PR to start with "rebase!"' ) + .replace( + 'checking the rebase/retry box above', + 'renaming the PR to start with "rebase!"' + ) .replace(regEx(/<\/?summary>/g), '**') .replace(regEx(/<\/?details>/g), '') .replace(regEx(`\n---\n\n.*?.*?(\n|$)`), '') diff --git a/lib/modules/platform/bitbucket/index.ts b/lib/modules/platform/bitbucket/index.ts index b76e66576851c6..b12eb09a114dae 100644 --- a/lib/modules/platform/bitbucket/index.ts +++ b/lib/modules/platform/bitbucket/index.ts @@ -293,7 +293,7 @@ export async function findPr({ const pr = prList.find( (p) => p.sourceBranch === branchName && - (!prTitle || p.title === prTitle) && + (!prTitle || p.title.toUpperCase() === prTitle.toUpperCase()) && matchesState(p.state, state) ); if (pr) { @@ -519,6 +519,10 @@ export function massageMarkdown(input: string): string { 'you tick the rebase/retry checkbox', 'by renaming this PR to start with "rebase!"' ) + .replace( + 'checking the rebase/retry box above', + 'renaming the PR to start with "rebase!"' + ) .replace(regEx(/<\/?summary>/g), '**') .replace(regEx(/<\/?(details|blockquote)>/g), '') .replace(regEx(`\n---\n\n.*?.*?\n`), '') @@ -798,7 +802,10 @@ export async function createPr({ if (platformOptions?.bbUseDefaultReviewers) { const reviewersResponse = ( await bitbucketHttp.getJson>( - `/2.0/repositories/${config.repository}/effective-default-reviewers` + `/2.0/repositories/${config.repository}/effective-default-reviewers`, + { + paginate: true, + } ) ).body; reviewers = reviewersResponse.values.map((reviewer: EffectiveReviewer) => ({ diff --git a/lib/modules/platform/codecommit/index.ts b/lib/modules/platform/codecommit/index.ts index e689415cb39457..6ce173083c4901 100644 --- a/lib/modules/platform/codecommit/index.ts +++ b/lib/modules/platform/codecommit/index.ts @@ -208,7 +208,9 @@ export async function findPr({ ); if (prTitle) { - prsFiltered = prsFiltered.filter((item) => item.title === prTitle); + prsFiltered = prsFiltered.filter( + (item) => item.title.toUpperCase() === prTitle.toUpperCase() + ); } switch (state) { @@ -307,6 +309,10 @@ export function massageMarkdown(input: string): string { 'you tick the rebase/retry checkbox', 'rename PR to start with "rebase!"' ) + .replace( + 'checking the rebase/retry box above', + 'renaming the PR to start with "rebase!"' + ) .replace(regEx(/<\/?summary>/g), '**') .replace(regEx(/<\/?details>/g), '') .replace(regEx(`\n---\n\n.*?.*?\n`), '') diff --git a/lib/modules/platform/github/index.spec.ts b/lib/modules/platform/github/index.spec.ts index 51b25a6d951557..0789f597bcb205 100644 --- a/lib/modules/platform/github/index.spec.ts +++ b/lib/modules/platform/github/index.spec.ts @@ -174,9 +174,15 @@ describe('modules/platform/github/index', () => { .reply(200, [ { full_name: 'a/b', + archived: false, }, { full_name: 'c/d', + archived: false, + }, + { + full_name: 'e/f', + archived: true, }, null, ]); @@ -227,9 +233,15 @@ describe('modules/platform/github/index', () => { repositories: [ { full_name: 'a/b', + archived: false, }, { full_name: 'c/d', + archived: false, + }, + { + full_name: 'e/f', + archived: true, }, null, ], diff --git a/lib/modules/platform/github/index.ts b/lib/modules/platform/github/index.ts index 8f5bdab301d5ab..a82a532eb04a29 100644 --- a/lib/modules/platform/github/index.ts +++ b/lib/modules/platform/github/index.ts @@ -191,20 +191,24 @@ export async function getRepos(): Promise { try { if (platformConfig.isGHApp) { const res = await githubApi.getJson<{ - repositories: { full_name: string }[]; + repositories: GhRestRepo[]; }>(`installation/repositories?per_page=100`, { paginationField: 'repositories', paginate: 'all', }); return res.body.repositories .filter(is.nonEmptyObject) + .filter((repo) => !repo.archived) .map((repo) => repo.full_name); } else { - const res = await githubApi.getJson<{ full_name: string }[]>( + const res = await githubApi.getJson( `user/repos?per_page=100`, { paginate: 'all' } ); - return res.body.filter(is.nonEmptyObject).map((repo) => repo.full_name); + return res.body + .filter(is.nonEmptyObject) + .filter((repo) => !repo.archived) + .map((repo) => repo.full_name); } } catch (err) /* istanbul ignore next */ { logger.error({ err }, `GitHub getRepos error`); @@ -712,7 +716,7 @@ export async function findPr({ return false; } - if (prTitle && prTitle !== p.title) { + if (prTitle && prTitle.toUpperCase() !== p.title.toUpperCase()) { return false; } diff --git a/lib/modules/platform/github/types.ts b/lib/modules/platform/github/types.ts index fd06dcf31b2d82..ef01406661370b 100644 --- a/lib/modules/platform/github/types.ts +++ b/lib/modules/platform/github/types.ts @@ -26,6 +26,7 @@ export interface GhRestRepo { owner: { login: string; }; + archived: boolean; } export interface GhRestPr { diff --git a/lib/modules/platform/gitlab/index.md b/lib/modules/platform/gitlab/index.md index a4b6c25f42710f..31ab87bd630469 100644 --- a/lib/modules/platform/gitlab/index.md +++ b/lib/modules/platform/gitlab/index.md @@ -29,7 +29,7 @@ Remember to set `platform=gitlab` somewhere in your Renovate config file. If you're using a private [GitLab container registry](https://docs.gitlab.com/ee/user/packages/container_registry/), you must: -- Set the `RENOVATE_HOST_RULES` CI variable to `[{"matchHost": "${CI_REGISTRY}","username": "${GITLAB_USER_NAME}","password": "${RENOVATE_TOKEN}"}]`. +- Set the `RENOVATE_HOST_RULES` CI variable to `[{"matchHost": "${CI_REGISTRY}","username": "${GITLAB_USER_NAME}","password": "${RENOVATE_TOKEN}", "hostType": "docker"}]`. - Make sure the user that owns the `RENOVATE_TOKEN` PAT is a member of the corresponding GitLab projects/groups with the right permissions. - Make sure the `RENOVATE_TOKEN` PAT has the `read_registry` scope. diff --git a/lib/modules/platform/gitlab/index.spec.ts b/lib/modules/platform/gitlab/index.spec.ts index de8b8b466c2ce0..500e7ccb6b8603 100644 --- a/lib/modules/platform/gitlab/index.spec.ts +++ b/lib/modules/platform/gitlab/index.spec.ts @@ -1713,6 +1713,63 @@ describe('modules/platform/gitlab/index', () => { `); }); + it('will modify a rule of type any_approvers, if such a rule exists', async () => { + await initPlatform('13.3.6-ee'); + httpMock + .scope(gitlabApiHost) + .post('/api/v4/projects/undefined/merge_requests') + .reply(200, { + id: 1, + iid: 12345, + title: 'some title', + }) + .get('/api/v4/projects/undefined/merge_requests/12345') + .reply(200) + .get('/api/v4/projects/undefined/merge_requests/12345') + .reply(200, { + merge_status: 'can_be_merged', + pipeline: { + id: 29626725, + sha: '2be7ddb704c7b6b83732fdd5b9f09d5a397b5f8f', + ref: 'patch-28', + status: 'success', + }, + }) + .put('/api/v4/projects/undefined/merge_requests/12345/merge') + .reply(200) + .get('/api/v4/projects/undefined/merge_requests/12345/approval_rules') + .reply(200, [ + { + name: 'AnyApproverRule', + rule_type: 'any_approver', + id: 50005, + }, + ]) + .put( + '/api/v4/projects/undefined/merge_requests/12345/approval_rules/50005' + ) + .reply(200); + expect( + await gitlab.createPr({ + sourceBranch: 'some-branch', + targetBranch: 'master', + prTitle: 'some-title', + prBody: 'the-body', + labels: [], + platformOptions: { + usePlatformAutomerge: true, + gitLabIgnoreApprovals: true, + }, + }) + ).toStrictEqual({ + id: 1, + iid: 12345, + number: 12345, + sourceBranch: 'some-branch', + title: 'some title', + }); + }); + it('does not try to create already existing approval rule', async () => { await initPlatform('13.3.6-ee'); httpMock diff --git a/lib/modules/platform/gitlab/index.ts b/lib/modules/platform/gitlab/index.ts index 24b69b9865ed25..4f1cdf8527a0c9 100644 --- a/lib/modules/platform/gitlab/index.ts +++ b/lib/modules/platform/gitlab/index.ts @@ -530,7 +530,25 @@ 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<{ name: string }[]>(url); + const { body: rules } = await gitlabApi.getJson< + { + name: string; + rule_type: string; + id: number; + }[] + >(url); + + const existingAnyApproverRule = rules?.find( + ({ rule_type }) => rule_type === 'any_approver' + ); + + if (existingAnyApproverRule) { + await gitlabApi.putJson(`${url}/${existingAnyApproverRule.id}`, { + body: { ...existingAnyApproverRule, approvals_required: 0 }, + }); + return; + } + const ruleName = 'renovateIgnoreApprovals'; const zeroApproversRule = rules?.find(({ name }) => name === ruleName); if (!zeroApproversRule) { @@ -752,7 +770,7 @@ export async function findPr({ prList.find( (p: { sourceBranch: string; title: string; state: string }) => p.sourceBranch === branchName && - (!prTitle || p.title === prTitle) && + (!prTitle || p.title.toUpperCase() === prTitle.toUpperCase()) && matchesState(p.state, state) ) ?? null ); diff --git a/lib/modules/platform/local/index.md b/lib/modules/platform/local/index.md new file mode 100644 index 00000000000000..15ede0932e21cb --- /dev/null +++ b/lib/modules/platform/local/index.md @@ -0,0 +1,22 @@ +# Local + +With the "local" platform you can perform dry runs of Renovate against the local file system. +This can be handy when testing a new Renovate configuration for example. + +## Usage + +Run the `renovate --platform=local` command in the directory you want Renovate to run in. +In this mode, Renovate defaults to `dryRun=lookup`. + +Avoid giving "repositories" arguments, as this command can only run in a _single_ directory, and it can only run in the _current working_ directory. + +You may run the command above on "plain" directories, or "Git directories". +You don't need to provide any config, as the command will run with or without "repo config". + +The command doesn't do any "compare" - or before and after analysis - if you want to test a new config then you must manually compare. + +## Limitations + +- `local>` presets can't be resolved. Normally these would point to the local platform such as GitHub, but in the case of running locally, it does not exist +- `baseBranches` are ignored +- Branch creation is not supported diff --git a/lib/modules/platform/local/index.spec.ts b/lib/modules/platform/local/index.spec.ts new file mode 100644 index 00000000000000..c226d334d79cbe --- /dev/null +++ b/lib/modules/platform/local/index.spec.ts @@ -0,0 +1,128 @@ +import * as platform from './index'; + +describe('modules/platform/local/index', () => { + describe('initPlatform', () => { + it('returns input', async () => { + expect(await platform.initPlatform({})).toMatchInlineSnapshot(` + { + "dryRun": "lookup", + "endpoint": "local", + "persistRepoData": true, + "requireConfig": "optional", + } + `); + }); + }); + + describe('getRepos', () => { + it('returns empty array', async () => { + expect(await platform.getRepos()).toEqual([]); + }); + }); + + describe('initRepo', () => { + it('returns object', async () => { + expect(await platform.initRepo()).toMatchInlineSnapshot(` + { + "defaultBranch": "", + "isFork": false, + "repoFingerprint": "", + } + `); + }); + }); + + describe('dummy functions', () => { + it('getRepoForceRebase', async () => { + expect(await platform.getRepoForceRebase()).toBe(false); + }); + + it('findIssue', async () => { + expect(await platform.findIssue()).toBeNull(); + }); + + it('getIssueList', async () => { + expect(await platform.getIssueList()).toEqual([]); + }); + + it('getRawFile', async () => { + expect(await platform.getRawFile()).toBeNull(); + }); + + it('getJsonFile', async () => { + expect(await platform.getJsonFile()).toBeNull(); + }); + + it('getPrList', async () => { + expect(await platform.getPrList()).toEqual([]); + }); + + it('ensureIssueClosing', async () => { + expect(await platform.ensureIssueClosing()).toBeUndefined(); + }); + + it('ensureIssue', async () => { + expect(await platform.ensureIssue()).toBeNull(); + }); + + it('massageMarkdown', () => { + expect(platform.massageMarkdown('foo')).toBe('foo'); + }); + + it('updatePr', async () => { + expect(await platform.updatePr()).toBeUndefined(); + }); + + it('mergePr', async () => { + expect(await platform.mergePr()).toBe(false); + }); + + it('addReviewers', async () => { + expect(await platform.addReviewers()).toBeUndefined(); + }); + + it('addAssignees', async () => { + expect(await platform.addAssignees()).toBeUndefined(); + }); + + it('createPr', async () => { + expect(await platform.createPr()).toBeNull(); + }); + + it('deleteLabel', async () => { + expect(await platform.deleteLabel()).toBeUndefined(); + }); + + it('setBranchStatus', async () => { + expect(await platform.setBranchStatus()).toBeUndefined(); + }); + + it('getBranchStatus', async () => { + expect(await platform.getBranchStatus()).toBe('red'); + }); + + it('getBranchStatusCheck', async () => { + expect(await platform.getBranchStatusCheck()).toBeNull(); + }); + + it('ensureCommentRemoval', async () => { + expect(await platform.ensureCommentRemoval()).toBeUndefined(); + }); + + it('ensureComment', async () => { + expect(await platform.ensureComment()).toBeFalse(); + }); + + it('getPr', async () => { + expect(await platform.getPr()).toBeNull(); + }); + + it('findPr', async () => { + expect(await platform.findPr()).toBeNull(); + }); + + it('getBranchPr', async () => { + expect(await platform.getBranchPr()).toBeNull(); + }); + }); +}); diff --git a/lib/modules/platform/local/index.ts b/lib/modules/platform/local/index.ts new file mode 100644 index 00000000000000..1c88d787371daf --- /dev/null +++ b/lib/modules/platform/local/index.ts @@ -0,0 +1,123 @@ +import type { BranchStatus } from '../../../types'; +import type { + Issue, + PlatformParams, + PlatformResult, + Pr, + RepoResult, +} from '../types'; + +export const id = 'local'; + +export function initPlatform(params: PlatformParams): Promise { + return Promise.resolve({ + dryRun: 'lookup', + endpoint: 'local', + persistRepoData: true, + requireConfig: 'optional', + }); +} + +export function getRepos(): Promise { + return Promise.resolve([]); +} + +export function initRepo(): Promise { + return Promise.resolve({ + defaultBranch: '', + isFork: false, + repoFingerprint: '', + }); +} + +export function getRepoForceRebase(): Promise { + return Promise.resolve(false); +} + +export function findIssue(): Promise { + return Promise.resolve(null); +} + +export function getIssueList(): Promise { + return Promise.resolve([]); +} + +export function getRawFile(): Promise { + return Promise.resolve(null); +} + +export function getJsonFile(): Promise | null> { + return Promise.resolve(null); +} + +export function getPrList(): Promise { + return Promise.resolve([]); +} + +export function ensureIssueClosing(): Promise { + return Promise.resolve(); +} + +export function ensureIssue(): Promise { + return Promise.resolve(null); +} + +export function massageMarkdown(input: string): string { + return input; +} + +export function updatePr(): Promise { + return Promise.resolve(); +} + +export function mergePr(): Promise { + return Promise.resolve(false); +} + +export function addReviewers(): Promise { + return Promise.resolve(); +} + +export function addAssignees(): Promise { + return Promise.resolve(); +} + +export function createPr(): Promise { + return Promise.resolve(null); +} + +export function deleteLabel(): Promise { + return Promise.resolve(); +} + +export function setBranchStatus(): Promise { + return Promise.resolve(); +} + +export function getBranchStatus(): Promise { + return Promise.resolve('red'); +} + +export function getBranchStatusCheck(): Promise { + return Promise.resolve(null); +} + +export function ensureCommentRemoval(): Promise { + return Promise.resolve(); +} + +export function ensureComment(): Promise { + return Promise.resolve(false); +} + +export function getPr(): Promise { + return Promise.resolve(null); +} + +export function findPr(): Promise { + return Promise.resolve(null); +} + +export function getBranchPr(): Promise { + return Promise.resolve(null); +} diff --git a/lib/modules/platform/local/scm.spec.ts b/lib/modules/platform/local/scm.spec.ts new file mode 100644 index 00000000000000..6549475ad55d93 --- /dev/null +++ b/lib/modules/platform/local/scm.spec.ts @@ -0,0 +1,68 @@ +import { execSync as _execSync } from 'node:child_process'; +import { mockedFunction } from '../../../../test/util'; +import { LocalFs } from './scm'; + +jest.mock('node:child_process'); +const execSync = mockedFunction(_execSync); + +describe('modules/platform/local/scm', () => { + let localFs: LocalFs; + + beforeEach(() => { + localFs = new LocalFs(); + }); + + describe('dummy functions', () => { + it('behindBaseBranch', async () => { + expect(await localFs.isBranchBehindBase('', '')).toBe(false); + }); + + it('isBranchModified', async () => { + expect(await localFs.isBranchModified('')).toBe(false); + }); + + it('isBranchConflicted', async () => { + expect(await localFs.isBranchConflicted('', '')).toBe(false); + }); + + it('branchExists', async () => { + expect(await localFs.branchExists('')).toBe(true); + }); + + it('getBranchCommit', async () => { + expect(await localFs.getBranchCommit('')).toBeNull(); + }); + + it('deleteBranch', async () => { + expect(await localFs.deleteBranch('')).toBeUndefined(); + }); + + it('commitAndPush', async () => { + expect(await localFs.commitAndPush({} as any)).toBeNull(); + }); + + it('checkoutBranch', async () => { + expect(await localFs.checkoutBranch('')).toBe(''); + }); + }); + + describe('getFileList', () => { + it('should return file list using git', async () => { + execSync.mockReturnValueOnce('file1\nfile2'); + expect(await localFs.getFileList()).toHaveLength(2); + }); + + it('should return file list using glob', async () => { + execSync.mockImplementationOnce(() => { + throw new Error(); + }); + jest.mock('glob', () => ({ + glob: jest + .fn() + .mockImplementation(() => Promise.resolve(['file1', 'file2'])), + })); + + expect(await localFs.getFileList()).toHaveLength(2); + }); + }); +}); diff --git a/lib/modules/platform/local/scm.ts b/lib/modules/platform/local/scm.ts new file mode 100644 index 00000000000000..5b01391572c110 --- /dev/null +++ b/lib/modules/platform/local/scm.ts @@ -0,0 +1,51 @@ +import { execSync } from 'node:child_process'; +import { glob } from 'glob'; +import { logger } from '../../../logger'; +import type { CommitFilesConfig, CommitSha } from '../../../util/git/types'; +import type { PlatformScm } from '../types'; + +let fileList: string[] | undefined; +export class LocalFs implements PlatformScm { + isBranchBehindBase(branchName: string, baseBranch: string): Promise { + return Promise.resolve(false); + } + isBranchModified(branchName: string): Promise { + return Promise.resolve(false); + } + isBranchConflicted(baseBranch: string, branch: string): Promise { + return Promise.resolve(false); + } + branchExists(branchName: string): Promise { + return Promise.resolve(true); + } + getBranchCommit(branchName: string): Promise { + return Promise.resolve(null); + } + deleteBranch(branchName: string): Promise { + return Promise.resolve(); + } + commitAndPush(commitConfig: CommitFilesConfig): Promise { + return Promise.resolve(null); + } + + async getFileList(): Promise { + try { + // fetch file list using git + const stdout = execSync('git ls-files', { encoding: 'utf-8' }); + logger.debug('Got file list using git'); + fileList = stdout.split('\n'); + } catch (err) { + logger.debug('Could not get file list using git, using glob instead'); + fileList ??= await glob('**', { + dot: true, + nodir: true, + }); + } + + return fileList; + } + + checkoutBranch(branchName: string): Promise { + return Promise.resolve(''); + } +} diff --git a/lib/modules/platform/scm.ts b/lib/modules/platform/scm.ts index 9a26a35594401d..8f80217ec36da5 100644 --- a/lib/modules/platform/scm.ts +++ b/lib/modules/platform/scm.ts @@ -3,6 +3,7 @@ import type { PlatformId } from '../../constants'; import { PLATFORM_NOT_FOUND } from '../../constants/error-messages'; import { DefaultGitScm } from './default-scm'; import { GithubScm } from './github/scm'; +import { LocalFs } from './local/scm'; import type { PlatformScm } from './types'; export const platformScmImpls = new Map>(); @@ -13,6 +14,7 @@ platformScmImpls.set('bitbucket-server', DefaultGitScm); platformScmImpls.set('gitea', DefaultGitScm); platformScmImpls.set('github', GithubScm); platformScmImpls.set('gitlab', DefaultGitScm); +platformScmImpls.set('local', LocalFs); let _scm: PlatformScm | undefined; diff --git a/lib/modules/versioning/maven/compare.spec.ts b/lib/modules/versioning/maven/compare.spec.ts index 64d545ad87a976..5de6a0185de6ba 100644 --- a/lib/modules/versioning/maven/compare.spec.ts +++ b/lib/modules/versioning/maven/compare.spec.ts @@ -92,6 +92,8 @@ describe('modules/versioning/maven/compare', () => { ${'Hoxton.RELEASE'} | ${'hoxton'} ${'Hoxton.SR1'} | ${'hoxton.sr-1'} ${'1_5ea'} | ${'1.0_5ea'} + ${'1.foo'} | ${'1-foo'} + ${'1.x'} | ${'1-x'} `('$x == $y', ({ x, y }) => { expect(compare(x, y)).toBe(0); expect(compare(y, x)).toBe(0); @@ -164,7 +166,6 @@ describe('modules/versioning/maven/compare', () => { ${'1'} | ${'1-sp'} ${'1-foo2'} | ${'1-foo10'} ${'1-m1'} | ${'1-milestone-2'} - ${'1.foo'} | ${'1-foo'} ${'1-foo'} | ${'1-1'} ${'1-alpha.1'} | ${'1-beta.1'} ${'1-1'} | ${'1.1'} @@ -195,6 +196,30 @@ describe('modules/versioning/maven/compare', () => { }); }); + // @see https://issues.apache.org/jira/browse/MNG-7644 + describe('MNG-7644', () => { + it.each` + qualifier + ${'abc'} + ${'alpha'} + ${'a'} + ${'beta'} + ${'b'} + ${'def'} + ${'milestone'} + ${'m'} + ${'RC'} + `('$qualifier', ({ qualifier }: { qualifier: string }) => { + // 1.0.0.X1 < 1.0.0-X2 for any string x + expect(compare(`1.0.0.${qualifier}1`, `1.0.0-${qualifier}2`)).toBe(-1); + + // 2.0.X == 2-X == 2.0.0.X for any string x + expect(compare(`2-${qualifier}`, `2.0.${qualifier}`)).toBe(0); // previously ordered, now equals + expect(compare(`2-${qualifier}`, `2.0.0.${qualifier}`)).toBe(0); // previously ordered, now equals + expect(compare(`2.0.${qualifier}`, `2.0.0.${qualifier}`)).toBe(0); // previously ordered, now equals + }); + }); + describe('Non-standard behavior', () => { describe('equality', () => { it.each` diff --git a/lib/modules/versioning/maven/compare.ts b/lib/modules/versioning/maven/compare.ts index f186d0fbfac286..f894c8e35c365d 100644 --- a/lib/modules/versioning/maven/compare.ts +++ b/lib/modules/versioning/maven/compare.ts @@ -123,7 +123,7 @@ function tokenize(versionStr: string, preserveMinorZeroes = false): Token[] { let result: Token[] = []; let leadingZero = true; iterateTokens(versionStr.toLowerCase().replace(regEx(/^v/i), ''), (token) => { - if (token.prefix === PREFIX_HYPHEN) { + if (token.prefix === PREFIX_HYPHEN || token.type === TYPE_QUALIFIER) { buf = []; } buf.push(token); @@ -154,10 +154,7 @@ function nullFor(token: Token): Token { } function commonOrder(token: Token): number { - if (token.prefix === PREFIX_DOT && token.type === TYPE_QUALIFIER) { - return 0; - } - if (token.prefix === PREFIX_HYPHEN && token.type === TYPE_QUALIFIER) { + if (token.type === TYPE_QUALIFIER) { return 1; } if (token.prefix === PREFIX_HYPHEN && token.type === TYPE_NUMBER) { diff --git a/lib/modules/versioning/maven/index.spec.ts b/lib/modules/versioning/maven/index.spec.ts index e0e012bbe3ba57..c0b23ac2eceb2d 100644 --- a/lib/modules/versioning/maven/index.spec.ts +++ b/lib/modules/versioning/maven/index.spec.ts @@ -112,12 +112,13 @@ describe('modules/versioning/maven/index', () => { ${'1'} | ${'(,1),(1,)'} | ${false} ${'1'} | ${'(0,1),(1,2)'} | ${false} ${'1.0.0.RC9.2'} | ${'(,1.0.0.RC9.2),(1.0.0.RC9.2,)'} | ${false} - ${'1.0.0-RC14'} | ${'(,1.0.0.RC9.2),(1.0.0.RC9.2,)'} | ${true} + ${'1.0.0.RC14'} | ${'(,1.0.0.RC9.2),(1.0.0.RC9.2,)'} | ${true} ${'0'} | ${''} | ${false} ${'1'} | ${'1'} | ${true} ${'1'} | ${'(1'} | ${false} ${'2.4.2'} | ${'2.4.2'} | ${true} ${'2.4.2'} | ${'= 2.4.2'} | ${false} + ${'1.2.3'} | ${'[1,2],[3,4]'} | ${true} `( 'matches("$version", "$range") === $expected', ({ version, range, expected }) => { diff --git a/lib/util/array.spec.ts b/lib/util/array.spec.ts new file mode 100644 index 00000000000000..57356be7de65df --- /dev/null +++ b/lib/util/array.spec.ts @@ -0,0 +1,12 @@ +import { isNotNullOrUndefined } from './array'; + +describe('util/array', () => { + it.each` + a | exp + ${null} | ${false} + ${undefined} | ${false} + ${{ name: 'foo' }} | ${true} + `('.isNotNullOrUndefined', ({ a, exp }) => { + expect(isNotNullOrUndefined(a)).toEqual(exp); + }); +}); diff --git a/lib/util/array.ts b/lib/util/array.ts index 6862260bc20bc5..0175fabf26f8e4 100644 --- a/lib/util/array.ts +++ b/lib/util/array.ts @@ -10,3 +10,12 @@ export function coerceArray(input: T[] | null | undefined): T[] { export function sortNumeric(a: number, b: number): number { return a - b; } + +// Useful for filtering an array so that it includes values that are not null or +// undefined. This predicate acts as a type guard so that the resulting type for +// `values.filter(isNotNullOrUndefined)` is `T[]`. +export function isNotNullOrUndefined( + value: T | undefined | null +): value is T { + return !is.nullOrUndefined(value); +} diff --git a/lib/util/cache/repository/types.ts b/lib/util/cache/repository/types.ts index 6f5cbfe32601da..3af4fa03d44c32 100644 --- a/lib/util/cache/repository/types.ts +++ b/lib/util/cache/repository/types.ts @@ -1,9 +1,11 @@ import type { RepositoryCacheConfig, RepositoryCacheType, + UpdateType, } from '../../../config/types'; import type { PackageFile } from '../../../modules/manager/types'; import type { RepoInitConfig } from '../../../workers/repository/init/types'; +import type { PrBlockedBy } from '../../../workers/types'; export interface BaseBranchCache { sha: string; // branch commit sha @@ -17,6 +19,8 @@ export interface BranchUpgradeCache { currentValue?: string; datasource?: string; depName?: string; + depType?: string; + displayPending?: unknown; fixedVersion?: string; currentVersion?: string; packageName?: string; @@ -24,12 +28,16 @@ export interface BranchUpgradeCache { newValue?: string; newVersion?: string; sourceUrl?: string; + packageFile?: string; + remediationNotPossible?: unknown; + updateType?: UpdateType; } export interface OnboardingBranchCache { - onboardingBranch: string; defaultBranchSha: string; onboardingBranchSha: string; + isConflicted: boolean; + isModified: boolean; } export interface PrCache { @@ -44,15 +52,15 @@ export interface BranchCache { /** * Whether this branch has automerge enabled */ - automerge: boolean; + automerge?: boolean; /** * Name of base branch */ - baseBranch: string; + baseBranch?: string; /** * The base branch's most recent commit SHA */ - baseBranchSha: string | null; + baseBranchSha?: string | null; /** * Hash of the manager fingerprints and the filtered update branch config */ @@ -84,7 +92,7 @@ export interface BranchCache { /** * The branch's most recent commit SHA */ - sha: string | null; + sha?: string | null; /** * Details on the dependency upgrades that have been applied in this branch */ @@ -93,6 +101,13 @@ export interface BranchCache { * Object that has PR info */ prCache?: PrCache | null; + + /** + * Dependency dashboard information + */ + prBlockedBy?: PrBlockedBy; + prTitle?: string; + result?: string; } export interface RepoCacheData { diff --git a/lib/util/exec/containerbase.ts b/lib/util/exec/containerbase.ts index bcb21adab9dee1..d9efe6285ac82b 100644 --- a/lib/util/exec/containerbase.ts +++ b/lib/util/exec/containerbase.ts @@ -130,6 +130,11 @@ const allToolConfig: Record = { hash: true, versioning: npmVersioningId, }, + pdm: { + datasource: 'github-releases', + packageName: 'pdm-project/pdm', + versioning: semverVersioningId, + }, php: { datasource: 'github-releases', packageName: 'containerbase/php-prebuild', diff --git a/lib/util/fs/index.spec.ts b/lib/util/fs/index.spec.ts index f200818843e2d7..361f4eff62dda9 100644 --- a/lib/util/fs/index.spec.ts +++ b/lib/util/fs/index.spec.ts @@ -134,6 +134,11 @@ describe('util/fs/index', () => { }); describe('deleteLocalFile', () => { + it('throws if platform is local', async () => { + GlobalConfig.set({ platform: 'local' }); + await expect(deleteLocalFile('foo/bar/file.txt')).rejects.toThrow(); + }); + it('deletes file', async () => { const filePath = `${localDir}/foo/bar/file.txt`; await fs.outputFile(filePath, 'foobar'); diff --git a/lib/util/fs/index.ts b/lib/util/fs/index.ts index 5493a6397f8493..2a9b2793975755 100644 --- a/lib/util/fs/index.ts +++ b/lib/util/fs/index.ts @@ -65,6 +65,10 @@ export async function writeLocalFile( } export async function deleteLocalFile(fileName: string): Promise { + // This a failsafe and hopefully will never be triggered + if (GlobalConfig.get('platform') === 'local') { + throw new Error('Cannot delete file when platform=local'); + } const localDir = GlobalConfig.get('localDir'); if (localDir) { const localFileName = ensureLocalPath(fileName); diff --git a/lib/util/git/index.spec.ts b/lib/util/git/index.spec.ts index 1551fdca230c63..297e3691d0232d 100644 --- a/lib/util/git/index.spec.ts +++ b/lib/util/git/index.spec.ts @@ -344,6 +344,12 @@ describe('util/git/index', () => { expect(merged.all).toContain('renovate/future_branch'); }); + it('does not push if localOnly=true', async () => { + const pushSpy = jest.spyOn(SimpleGit.prototype, 'push'); + await git.mergeBranch('renovate/future_branch', true); + expect(pushSpy).toHaveBeenCalledTimes(0); + }); + it('should throw if branch merge throws', async () => { await expect(git.mergeBranch('not_found')).rejects.toThrow(); }); diff --git a/lib/util/git/index.ts b/lib/util/git/index.ts index 806bda394b9889..107c67decd1241 100644 --- a/lib/util/git/index.ts +++ b/lib/util/git/index.ts @@ -377,8 +377,16 @@ export function isCloned(): boolean { export async function syncGit(): Promise { if (gitInitialized) { + // istanbul ignore if + if (process.env.RENOVATE_X_CLEAR_HOOKS) { + await git.raw(['config', 'core.hooksPath', '/dev/null']); + } return; } + // istanbul ignore if: failsafe + if (GlobalConfig.get('platform') === 'local') { + throw new Error('Cannot sync git when platform=local'); + } gitInitialized = true; const localDir = GlobalConfig.get('localDir')!; logger.debug(`Initializing git repository into ${localDir}`); @@ -766,7 +774,10 @@ export async function deleteBranch(branchName: string): Promise { delete config.branchCommits[branchName]; } -export async function mergeBranch(branchName: string): Promise { +export async function mergeBranch( + branchName: string, + localOnly = false +): Promise { let status: StatusResult | undefined; try { await syncGit(); @@ -782,8 +793,13 @@ export async function mergeBranch(branchName: string): Promise { ]) ); status = await git.status(); - await gitRetry(() => git.merge(['--ff-only', branchName])); - await gitRetry(() => git.push('origin', config.currentBranch)); + if (localOnly) { + // merge commit, don't push to origin + await gitRetry(() => git.merge([branchName])); + } else { + await gitRetry(() => git.merge(['--ff-only', branchName])); + await gitRetry(() => git.push('origin', config.currentBranch)); + } incLimitedValue('Commits'); } catch (err) { logger.debug( diff --git a/lib/util/host-rules.spec.ts b/lib/util/host-rules.spec.ts index 6513bf9e50ac4c..d8c7dbd78ddf4a 100644 --- a/lib/util/host-rules.spec.ts +++ b/lib/util/host-rules.spec.ts @@ -235,6 +235,26 @@ describe('util/host-rules', () => { expect(find({ url: 'httpsdomain.com' }).token).toBeUndefined(); }); + it('matches on matchHost with port', () => { + add({ + matchHost: 'https://domain.com:9118', + token: 'def', + }); + expect(find({ url: 'https://domain.com:9118' }).token).toBe('def'); + expect(find({ url: 'https://domain.com' }).token).toBeUndefined(); + expect(find({ url: 'httpsdomain.com' }).token).toBeUndefined(); + }); + + it('host with port is interpreted as empty', () => { + add({ + matchHost: 'domain.com:9118', + token: 'def', + }); + expect(find({ url: 'https://domain.com:9118' }).token).toBe('def'); + expect(find({ url: 'https://domain.com' }).token).toBe('def'); + expect(find({ url: 'httpsdomain.com' }).token).toBe('def'); + }); + it('matches on hostType and endpoint', () => { add({ hostType: NugetDatasource.id, diff --git a/lib/util/http/bitbucket.spec.ts b/lib/util/http/bitbucket.spec.ts index ac7bb06e010322..7f74909d1c8175 100644 --- a/lib/util/http/bitbucket.spec.ts +++ b/lib/util/http/bitbucket.spec.ts @@ -55,4 +55,34 @@ describe('util/http/bitbucket', () => { statusCode: 200, }); }); + + it('paginates', async () => { + httpMock + .scope(baseUrl) + .get('/some-url') + .reply(200, { + values: ['a'], + page: '1', + next: `${baseUrl}/some-url?page=2`, + }) + .get('/some-url?page=2') + .reply(200, { + values: ['b', 'c'], + page: '2', + next: `${baseUrl}/some-url?page=3`, + }) + .get('/some-url?page=3') + .reply(200, { + values: ['d'], + page: '3', + }); + const res = await api.getJson('some-url', { paginate: true }); + expect(res.body).toEqual({ + page: '1', + pagelen: 4, + size: 4, + values: ['a', 'b', 'c', 'd'], + next: undefined, + }); + }); }); diff --git a/lib/util/http/bitbucket.ts b/lib/util/http/bitbucket.ts index 628ef154cba1fe..15bea99b04860a 100644 --- a/lib/util/http/bitbucket.ts +++ b/lib/util/http/bitbucket.ts @@ -1,4 +1,7 @@ -import type { HttpOptions, HttpResponse, InternalHttpOptions } from './types'; +import is from '@sindresorhus/is'; +import type { PagedResult } from '../../modules/platform/bitbucket/types'; +import { parseUrl, resolveBaseUrl } from '../url'; +import type { HttpOptions, HttpResponse } from './types'; import { Http } from '.'; let baseUrl = 'https://api.bitbucket.org/'; @@ -7,16 +10,79 @@ export const setBaseUrl = (url: string): void => { baseUrl = url; }; -export class BitbucketHttp extends Http { - constructor(type = 'bitbucket', options?: HttpOptions) { +export interface BitbucketHttpOptions extends HttpOptions { + paginate?: boolean; +} + +export class BitbucketHttp extends Http { + constructor(type = 'bitbucket', options?: BitbucketHttpOptions) { super(type, options); } - protected override request( - url: string | URL, - options?: InternalHttpOptions + protected override async request( + path: string, + options?: BitbucketHttpOptions ): Promise> { const opts = { baseUrl, ...options }; - return super.request(url, opts); + + const result = await super.request(path, opts); + + if (opts.paginate && isPagedResult(result.body)) { + const resultBody = result.body as PagedResult; + + let nextPage = getPageFromURL(resultBody.next); + + while (is.nonEmptyString(nextPage)) { + const nextPath = getNextPagePath(path, nextPage); + + // istanbul ignore if + if (is.nullOrUndefined(nextPath)) { + break; + } + + const nextResult = await super.request>( + nextPath, + options + ); + + resultBody.values.push(...nextResult.body.values); + + nextPage = getPageFromURL(nextResult.body?.next); + } + + // Override other page-related attributes + resultBody.pagelen = resultBody.values.length; + resultBody.size = resultBody.values.length; + resultBody.next = undefined; + } + + return result; } } + +function getPageFromURL(url: string | undefined): string | null { + const resolvedURL = parseUrl(url); + + if (is.nullOrUndefined(resolvedURL)) { + return null; + } + + return resolvedURL.searchParams.get('page'); +} + +function getNextPagePath(path: string, nextPage: string): string | null { + const resolvedURL = parseUrl(resolveBaseUrl(baseUrl, path)); + + // istanbul ignore if + if (is.nullOrUndefined(resolvedURL)) { + return null; + } + + resolvedURL.searchParams.set('page', nextPage); + + return resolvedURL.toString(); +} + +function isPagedResult(obj: any): obj is PagedResult { + return is.nonEmptyObject(obj) && Array.isArray(obj.values); +} diff --git a/lib/util/http/index.ts b/lib/util/http/index.ts index 21e13646f43044..e5dd4ac87e98b1 100644 --- a/lib/util/http/index.ts +++ b/lib/util/http/index.ts @@ -221,21 +221,14 @@ export class Http { return this.request(url, { ...options, method: 'head' }); } - protected requestBuffer( - url: string | URL, - httpOptions?: InternalHttpOptions - ): Promise | null> { - return this.request(url, { - ...httpOptions, - responseType: 'buffer', - }); - } - getBuffer( url: string, options: HttpOptions = {} - ): Promise | null> { - return this.requestBuffer(url, options); + ): Promise> { + return this.request(url, { + ...options, + responseType: 'buffer', + }); } private async requestJson( diff --git a/lib/util/string.ts b/lib/util/string.ts index 4030956cdd923c..7a4d7d87608fb4 100644 --- a/lib/util/string.ts +++ b/lib/util/string.ts @@ -56,3 +56,14 @@ export function looseEquals( export function isDockerDigest(input: string): boolean { return /^sha256:[a-f0-9]{64}$/i.test(input); } + +export function titleCase(input: string): string { + const words = input.toLowerCase().split(' '); + + for (let i = 0; i < words.length; i++) { + const word = words[i]; + words[i] = word.charAt(0).toUpperCase() + word.slice(1).toLowerCase(); + } + + return words.join(' '); +} diff --git a/lib/util/template/index.ts b/lib/util/template/index.ts index f3e4a8809c7e6f..5c3e1261e29a73 100644 --- a/lib/util/template/index.ts +++ b/lib/util/template/index.ts @@ -100,6 +100,7 @@ export const allowedFields = { isRange: 'true if the new value is a range', isSingleVersion: 'true if the upgrade is to a single version rather than a range', + isVulnerabilityAlert: 'true if the upgrade is a vulnerability alert', logJSON: 'ChangeLogResult object for the upgrade', manager: 'The (package) manager which detected the dependency', newDigest: 'The new digest value', @@ -143,6 +144,8 @@ export const allowedFields = { version: 'The version number of the changelog', versioning: 'The versioning scheme in use', versions: 'An array of ChangeLogRelease objects in the upgrade', + vulnerabilitySeverity: + 'The severity for a vulnerability alert upgrade (LOW, MEDIUM, MODERATE, HIGH, CRITICAL, UNKNOWN)', }; const prBodyFields = [ diff --git a/lib/util/vulnerability/utils.spec.ts b/lib/util/vulnerability/utils.spec.ts new file mode 100644 index 00000000000000..4ba086a5394d85 --- /dev/null +++ b/lib/util/vulnerability/utils.spec.ts @@ -0,0 +1,157 @@ +import { getHighestVulnerabilitySeverity } from './utils'; + +describe('util/vulnerability/utils', () => { + it('parent CRITICAL vulnerability severity rating is maintained', () => { + const parentConfig = { + vulnerabilitySeverity: 'CRITICAL', + }; + + const childConfig = { + vulnerabilitySeverity: 'MODERATE', + }; + + const severity = getHighestVulnerabilitySeverity(parentConfig, childConfig); + + expect(severity).toBe('CRITICAL'); + }); + + it('child CRITICAL vulnerability severity rating is maintained', () => { + const parentConfig = { + vulnerabilitySeverity: 'MODERATE', + }; + + const childConfig = { + vulnerabilitySeverity: 'CRITICAL', + }; + + const severity = getHighestVulnerabilitySeverity(parentConfig, childConfig); + + expect(severity).toBe('CRITICAL'); + }); + + it('parent HIGH vulnerability severity rating is maintained', () => { + const parentConfig = { + vulnerabilitySeverity: 'HIGH', + }; + + const childConfig = { + vulnerabilitySeverity: 'MODERATE', + }; + + const severity = getHighestVulnerabilitySeverity(parentConfig, childConfig); + + expect(severity).toBe('HIGH'); + }); + + it('child HIGH vulnerability severity rating is maintained', () => { + const parentConfig = { + vulnerabilitySeverity: 'MODERATE', + }; + + const childConfig = { + vulnerabilitySeverity: 'HIGH', + }; + + const severity = getHighestVulnerabilitySeverity(parentConfig, childConfig); + + expect(severity).toBe('HIGH'); + }); + + it('parent MODERATE vulnerability severity rating is maintained', () => { + const parentConfig = { + vulnerabilitySeverity: 'MODERATE', + }; + + const childConfig = { + vulnerabilitySeverity: 'LOW', + }; + + const severity = getHighestVulnerabilitySeverity(parentConfig, childConfig); + + expect(severity).toBe('MODERATE'); + }); + + it('child MODERATE vulnerability severity rating is maintained', () => { + const parentConfig = { + vulnerabilitySeverity: 'LOW', + }; + + const childConfig = { + vulnerabilitySeverity: 'MODERATE', + }; + + const severity = getHighestVulnerabilitySeverity(parentConfig, childConfig); + + expect(severity).toBe('MODERATE'); + }); + + it('child MEDIUM vulnerability severity rating is maintained', () => { + const parentConfig = { + vulnerabilitySeverity: 'LOW', + }; + + const childConfig = { + vulnerabilitySeverity: 'MEDIUM', + }; + + const severity = getHighestVulnerabilitySeverity(parentConfig, childConfig); + + expect(severity).toBe('MEDIUM'); + }); + + it('parent LOW vulnerability severity rating is maintained', () => { + const parentConfig = { + vulnerabilitySeverity: 'LOW', + }; + + const childConfig = { + vulnerabilitySeverity: undefined, + }; + + const severity = getHighestVulnerabilitySeverity(parentConfig, childConfig); + + expect(severity).toBe('LOW'); + }); + + it('child LOW vulnerability severity rating is maintained', () => { + const parentConfig = { + vulnerabilitySeverity: undefined, + }; + + const childConfig = { + vulnerabilitySeverity: 'LOW', + }; + + const severity = getHighestVulnerabilitySeverity(parentConfig, childConfig); + + expect(severity).toBe('LOW'); + }); + + it('child UNKNOWN vulnerability severity rating is maintained', () => { + const parentConfig = { + vulnerabilitySeverity: 'CRITICAL', + }; + + const childConfig = { + vulnerabilitySeverity: 'UNKNOWN', + }; + + const severity = getHighestVulnerabilitySeverity(parentConfig, childConfig); + + expect(severity).toBe('UNKNOWN'); + }); + + it('handled undefined parent and child vulnerability severity', () => { + const parentConfig = { + vulnerabilitySeverity: undefined, + }; + + const childConfig = { + vulnerabilitySeverity: undefined, + }; + + const severity = getHighestVulnerabilitySeverity(parentConfig, childConfig); + + expect(severity).toBeUndefined(); + }); +}); diff --git a/lib/util/vulnerability/utils.ts b/lib/util/vulnerability/utils.ts new file mode 100644 index 00000000000000..bc451a7db53658 --- /dev/null +++ b/lib/util/vulnerability/utils.ts @@ -0,0 +1,28 @@ +const severityOrder: Record = { + LOW: 1, + MEDIUM: 2, + MODERATE: 2, + HIGH: 3, + CRITICAL: 4, + UNKNOWN: 5, +}; + +export function getHighestVulnerabilitySeverity< + T extends Record, + TChild extends Record | undefined +>(parent: T, child: TChild): string { + const parentVulSeverity = parent.vulnerabilitySeverity?.toUpperCase(); + const childVulSeverity = child?.vulnerabilitySeverity?.toUpperCase(); + + if (childVulSeverity === undefined) { + return parentVulSeverity; + } + + if (parentVulSeverity === undefined) { + return childVulSeverity; + } + + return severityOrder[parentVulSeverity] >= severityOrder[childVulSeverity] + ? parentVulSeverity + : childVulSeverity; +} diff --git a/lib/workers/global/autodiscover.spec.ts b/lib/workers/global/autodiscover.spec.ts index e401268d6fd148..ae75305ad695a9 100644 --- a/lib/workers/global/autodiscover.spec.ts +++ b/lib/workers/global/autodiscover.spec.ts @@ -25,6 +25,19 @@ describe('workers/global/autodiscover', () => { }); }); + it('throws if local and repositories defined', async () => { + config.platform = 'local'; + config.repositories = ['a']; + await expect(autodiscoverRepositories(config)).rejects.toThrow(); + }); + + it('returns local', async () => { + config.platform = 'local'; + expect((await autodiscoverRepositories(config)).repositories).toEqual([ + 'local', + ]); + }); + it('returns if not autodiscovering', async () => { expect(await autodiscoverRepositories(config)).toEqual(config); }); diff --git a/lib/workers/global/autodiscover.ts b/lib/workers/global/autodiscover.ts index 332961b82e1506..943f739d67f247 100644 --- a/lib/workers/global/autodiscover.ts +++ b/lib/workers/global/autodiscover.ts @@ -13,6 +13,19 @@ function repoName(value: string | { repository: string }): string { export async function autodiscoverRepositories( config: AllConfig ): Promise { + if (config.platform === 'local') { + if (config.repositories?.length) { + logger.debug( + { repositories: config.repositories }, + 'Found repositories when in local mode' + ); + throw new Error( + 'Invalid configuration: repositories list not supported when platform=local' + ); + } + config.repositories = ['local']; + return config; + } if (!config.autodiscover) { if (!config.repositories?.length) { logger.warn( diff --git a/lib/workers/global/index.spec.ts b/lib/workers/global/index.spec.ts index 8c371725b1569a..0bc6aec1add7c0 100644 --- a/lib/workers/global/index.spec.ts +++ b/lib/workers/global/index.spec.ts @@ -95,6 +95,15 @@ describe('workers/global/index', () => { expect(repositoryWorker.renovateRepository).not.toHaveBeenCalled(); }); + it('handles local', async () => { + parseConfigs.mockResolvedValueOnce({ + platform: 'local', + }); + await expect(globalWorker.start()).resolves.toBe(0); + expect(parseConfigs).toHaveBeenCalledTimes(1); + expect(repositoryWorker.renovateRepository).toHaveBeenCalledTimes(1); + }); + it('processes repositories', async () => { parseConfigs.mockResolvedValueOnce({ gitAuthor: 'a@b.com', diff --git a/lib/workers/global/index.ts b/lib/workers/global/index.ts index 52e7beb5ea9a67..80869a7426c87e 100644 --- a/lib/workers/global/index.ts +++ b/lib/workers/global/index.ts @@ -37,10 +37,13 @@ export async function getRepositoryConfig( ); // TODO: types (#7154) const platform = GlobalConfig.get('platform')!; - repoConfig.localDir = upath.join( - repoConfig.baseDir, - `./repos/${platform}/${repoConfig.repository}` - ); + repoConfig.localDir = + platform === 'local' + ? process.cwd() + : upath.join( + repoConfig.baseDir, + `./repos/${platform}/${repoConfig.repository}` + ); await fs.ensureDir(repoConfig.localDir); delete repoConfig.baseDir; return configParser.filterConfig(repoConfig, 'repository'); diff --git a/lib/workers/repository/cache.ts b/lib/workers/repository/cache.ts index e80979449435d9..684c6220524297 100644 --- a/lib/workers/repository/cache.ts +++ b/lib/workers/repository/cache.ts @@ -22,23 +22,37 @@ function generateBranchUpgradeCache( const { datasource, depName, + depType, + displayPending, packageName, fixedVersion, currentVersion, newVersion, + currentValue, + newValue, currentDigest, newDigest, + packageFile, sourceUrl, + remediationNotPossible, + updateType, } = upgrade; const result: BranchUpgradeCache = { datasource, depName, + depType, + displayPending, fixedVersion, currentVersion, + currentValue, + newValue, newVersion, currentDigest, newDigest, + packageFile, sourceUrl, + remediationNotPossible, + updateType, }; if (packageName) { result.packageName = packageName; @@ -49,7 +63,7 @@ function generateBranchUpgradeCache( async function generateBranchCache( branch: BranchConfig ): Promise { - const { baseBranch, branchName } = branch; + const { baseBranch, branchName, prBlockedBy, prTitle, result } = branch; try { const branchSha = await scm.getBranchCommit(branchName); const baseBranchSha = await scm.getBranchCommit(baseBranch); @@ -79,12 +93,14 @@ async function generateBranchCache( baseBranchSha ) ?? undefined; } + const automerge = !!branch.automerge; const upgrades: BranchUpgradeCache[] = branch.upgrades ? branch.upgrades.map(generateBranchUpgradeCache) : []; const branchFingerprint = branch.branchFingerprint; const prCache = getPrCache(branchName); + return { automerge, baseBranchSha, @@ -94,9 +110,12 @@ async function generateBranchCache( isBehindBase, isConflicted, isModified, + prBlockedBy, pristine, prCache, prNo, + prTitle, + result, sha: branchSha, upgrades, }; diff --git a/lib/workers/repository/dependency-dashboard.spec.ts b/lib/workers/repository/dependency-dashboard.spec.ts index a2d9b97782cf83..809669c610824b 100644 --- a/lib/workers/repository/dependency-dashboard.spec.ts +++ b/lib/workers/repository/dependency-dashboard.spec.ts @@ -1,4 +1,5 @@ import { ERROR, WARN } from 'bunyan'; +import { codeBlock } from 'common-tags'; import { mock } from 'jest-mock-extended'; import { Fixtures } from '../../../test/fixtures'; import { @@ -21,8 +22,21 @@ import { import { regEx } from '../../util/regex'; import type { BranchConfig, BranchUpgradeConfig } from '../types'; import * as dependencyDashboard from './dependency-dashboard'; +import { getDashboardMarkdownVulnerabilities } from './dependency-dashboard'; import { PackageFiles } from './package-files'; +const createVulnerabilitiesMock = jest.fn(); +jest.mock('./process/vulnerabilities', () => { + return { + __esModule: true, + Vulnerabilities: class { + static create() { + return createVulnerabilitiesMock(); + } + }, + }; +}); + type PrUpgrade = BranchUpgradeConfig; const massageMdSpy = platform.massageMarkdown; @@ -1019,4 +1033,175 @@ describe('workers/repository/dependency-dashboard', () => { }); }); }); + + describe('getDashboardMarkdownVulnerabilities()', () => { + const packageFiles = Fixtures.getJson>( + './package-files.json' + ); + + it('return empty string if summary is empty', async () => { + const result = await getDashboardMarkdownVulnerabilities( + config, + packageFiles + ); + expect(result).toBeEmpty(); + }); + + it('return empty string if summary is set to none', async () => { + const result = await getDashboardMarkdownVulnerabilities( + { + ...config, + dependencyDashboardOSVVulnerabilitySummary: 'none', + }, + packageFiles + ); + expect(result).toBeEmpty(); + }); + + it('return no data section if summary is set to all and no vulnerabilities', async () => { + const fetchVulnerabilitiesMock = jest.fn(); + createVulnerabilitiesMock.mockResolvedValueOnce({ + fetchVulnerabilities: fetchVulnerabilitiesMock, + }); + + fetchVulnerabilitiesMock.mockResolvedValueOnce([]); + const result = await getDashboardMarkdownVulnerabilities( + { + ...config, + dependencyDashboardOSVVulnerabilitySummary: 'all', + }, + {} + ); + expect(result).toBe( + `## Vulnerabilities\n\nRenovate has not found any CVEs on [osv.dev](https://osv.dev).\n\n` + ); + }); + + it('return all vulnerabilities if set to all and disabled osvVulnerabilities', async () => { + const fetchVulnerabilitiesMock = jest.fn(); + createVulnerabilitiesMock.mockResolvedValueOnce({ + fetchVulnerabilities: fetchVulnerabilitiesMock, + }); + + fetchVulnerabilitiesMock.mockResolvedValueOnce([ + { + packageName: 'express', + depVersion: '4.17.3', + fixedVersion: '4.18.1', + packageFileConfig: { + manager: 'npm', + }, + vulnerability: { + id: 'GHSA-29mw-wpgm-hmr9', + }, + }, + { + packageName: 'cookie-parser', + depVersion: '1.4.6', + packageFileConfig: { + manager: 'npm', + }, + vulnerability: { + id: 'GHSA-35jh-r3h4-6jhm', + }, + }, + ]); + const result = await getDashboardMarkdownVulnerabilities( + { + ...config, + dependencyDashboardOSVVulnerabilitySummary: 'all', + osvVulnerabilityAlerts: true, + }, + packageFiles + ); + expect(result.trimEnd()).toBe(codeBlock`## Vulnerabilities + +\`1\`/\`2\` CVEs have Renovate fixes. +
npm +
+ +
undefined +
+ +
express +
+ +- [GHSA-29mw-wpgm-hmr9](https://osv.dev/vulnerability/GHSA-29mw-wpgm-hmr9) (fixed in 4.18.1) +
+
+ +
cookie-parser +
+ +- [GHSA-35jh-r3h4-6jhm](https://osv.dev/vulnerability/GHSA-35jh-r3h4-6jhm) +
+
+ +
+
+ +
+
`); + }); + + it('return unresolved vulnerabilities if set to "unresolved"', async () => { + const fetchVulnerabilitiesMock = jest.fn(); + createVulnerabilitiesMock.mockResolvedValueOnce({ + fetchVulnerabilities: fetchVulnerabilitiesMock, + }); + + fetchVulnerabilitiesMock.mockResolvedValueOnce([ + { + packageName: 'express', + depVersion: '4.17.3', + fixedVersion: '4.18.1', + packageFileConfig: { + manager: 'npm', + }, + vulnerability: { + id: 'GHSA-29mw-wpgm-hmr9', + }, + }, + { + packageName: 'cookie-parser', + depVersion: '1.4.6', + packageFileConfig: { + manager: 'npm', + }, + vulnerability: { + id: 'GHSA-35jh-r3h4-6jhm', + }, + }, + ]); + const result = await getDashboardMarkdownVulnerabilities( + { + ...config, + dependencyDashboardOSVVulnerabilitySummary: 'unresolved', + }, + packageFiles + ); + expect(result.trimEnd()).toBe(codeBlock`## Vulnerabilities + +\`1\`/\`2\` CVEs have possible Renovate fixes. +See [\`osvVulnerabilityAlerts\`](https://docs.renovatebot.com/configuration-options/#osvvulnerabilityalerts) to allow Renovate to supply fixes. +
npm +
+ +
undefined +
+ +
cookie-parser +
+ +- [GHSA-35jh-r3h4-6jhm](https://osv.dev/vulnerability/GHSA-35jh-r3h4-6jhm) +
+
+ +
+
+ +
+
`); + }); + }); }); diff --git a/lib/workers/repository/dependency-dashboard.ts b/lib/workers/repository/dependency-dashboard.ts index 6054f0e58e9573..dfd9119169454c 100644 --- a/lib/workers/repository/dependency-dashboard.ts +++ b/lib/workers/repository/dependency-dashboard.ts @@ -11,6 +11,8 @@ import * as template from '../../util/template'; import type { BranchConfig, SelectAllConfig } from '../types'; import { getDepWarningsDashboard } from './errors-warnings'; import { PackageFiles } from './package-files'; +import type { Vulnerability } from './process/types'; +import { Vulnerabilities } from './process/vulnerabilities'; interface DependencyDashboard { dependencyDashboardChecks: Record; @@ -166,6 +168,7 @@ function appendRepoProblems(config: RenovateConfig, issueBody: string): string { ) ); if (repoProblems.size) { + logger.debug({ repoProblems }, 'repository problems'); newIssueBody += '## Repository problems\n\n'; newIssueBody += 'These problems occurred while renovating this repository.\n\n'; @@ -411,6 +414,9 @@ export async function ensureDependencyDashboard( 'This repository currently has no open or pending branches.\n\n'; } + // add CVE section + issueBody += await getDashboardMarkdownVulnerabilities(config, packageFiles); + // fit the detected dependencies section const footer = getFooter(config); issueBody += PackageFiles.getDashboardMarkdown( @@ -468,3 +474,103 @@ function getFooter(config: RenovateConfig): string { return footer; } + +export async function getDashboardMarkdownVulnerabilities( + config: RenovateConfig, + packageFiles: Record +): Promise { + let result = ''; + + if ( + is.nullOrUndefined(config.dependencyDashboardOSVVulnerabilitySummary) || + config.dependencyDashboardOSVVulnerabilitySummary === 'none' + ) { + return result; + } + + result += '## Vulnerabilities\n\n'; + + const vulnerabilityFetcher = await Vulnerabilities.create(); + const vulnerabilities = await vulnerabilityFetcher.fetchVulnerabilities( + config, + packageFiles + ); + + if (vulnerabilities.length === 0) { + result += + 'Renovate has not found any CVEs on [osv.dev](https://osv.dev).\n\n'; + return result; + } + + const unresolvedVulnerabilities = vulnerabilities.filter((value) => + is.nullOrUndefined(value.fixedVersion) + ); + const resolvedVulnerabilitiesLength = + vulnerabilities.length - unresolvedVulnerabilities.length; + + result += `\`${resolvedVulnerabilitiesLength}\`/\`${vulnerabilities.length}\``; + if (is.truthy(config.osvVulnerabilityAlerts)) { + result += ' CVEs have Renovate fixes.\n'; + } else { + result += + ' CVEs have possible Renovate fixes.\nSee [`osvVulnerabilityAlerts`](https://docs.renovatebot.com/configuration-options/#osvvulnerabilityalerts) to allow Renovate to supply fixes.\n'; + } + + let renderedVulnerabilities: Vulnerability[]; + switch (config.dependencyDashboardOSVVulnerabilitySummary) { + // filter vulnerabilities to display based on configuration + case 'unresolved': + renderedVulnerabilities = unresolvedVulnerabilities; + break; + default: + renderedVulnerabilities = vulnerabilities; + } + + const managerRecords: Record< + string, + Record> + > = {}; + for (const vulnerability of renderedVulnerabilities) { + const { manager, packageFile } = vulnerability.packageFileConfig; + if (is.nullOrUndefined(managerRecords[manager!])) { + managerRecords[manager!] = {}; + } + if (is.nullOrUndefined(managerRecords[manager!][packageFile])) { + managerRecords[manager!][packageFile] = {}; + } + if ( + is.nullOrUndefined( + managerRecords[manager!][packageFile][vulnerability.packageName] + ) + ) { + managerRecords[manager!][packageFile][vulnerability.packageName] = []; + } + managerRecords[manager!][packageFile][vulnerability.packageName].push( + vulnerability + ); + } + + for (const [manager, packageFileRecords] of Object.entries(managerRecords)) { + result += `
${manager}\n
\n\n`; + for (const [packageFile, packageNameRecords] of Object.entries( + packageFileRecords + )) { + result += `
${packageFile}\n
\n\n`; + for (const [packageName, cves] of Object.entries(packageNameRecords)) { + result += `
${packageName}\n
\n\n`; + for (const vul of cves) { + const id = vul.vulnerability.id; + const suffix = is.nonEmptyString(vul.fixedVersion) + ? ` (fixed in ${vul.fixedVersion})` + : ''; + result += `- [${id}](https://osv.dev/vulnerability/${id})${suffix}\n`; + } + result += `
\n
\n\n`; + } + result += `
\n
\n\n`; + } + result += `
\n
\n\n`; + } + + return result; +} diff --git a/lib/workers/repository/error-config.spec.ts b/lib/workers/repository/error-config.spec.ts index 5076984e35673d..109bc7aa7d374f 100644 --- a/lib/workers/repository/error-config.spec.ts +++ b/lib/workers/repository/error-config.spec.ts @@ -1,7 +1,13 @@ import { mock } from 'jest-mock-extended'; -import { RenovateConfig, getConfig, platform } from '../../../test/util'; +import { + RenovateConfig, + getConfig, + partial, + platform, +} from '../../../test/util'; import { GlobalConfig } from '../../config/global'; import { CONFIG_VALIDATION } from '../../constants/error-messages'; +import { logger } from '../../logger'; import type { Pr } from '../../modules/platform'; import { raiseConfigWarningIssue } from './error-config'; @@ -24,9 +30,16 @@ describe('workers/repository/error-config', () => { const error = new Error(CONFIG_VALIDATION); error.validationSource = 'package.json'; error.validationMessage = 'some-message'; + error.validationError = 'some-error'; platform.ensureIssue.mockResolvedValueOnce('created'); + const res = await raiseConfigWarningIssue(config, error); + expect(res).toBeUndefined(); + expect(logger.warn).toHaveBeenCalledWith( + { configError: error, res: 'created' }, + 'Configuration Warning' + ); }); it('creates issues (dryRun)', async () => { @@ -35,50 +48,74 @@ describe('workers/repository/error-config', () => { error.validationMessage = 'some-message'; platform.ensureIssue.mockResolvedValueOnce('created'); GlobalConfig.set({ dryRun: 'full' }); + const res = await raiseConfigWarningIssue(config, error); + expect(res).toBeUndefined(); + expect(logger.info).toHaveBeenCalledWith( + { configError: error }, + 'DRY-RUN: Would ensure configuration error issue' + ); }); it('handles onboarding', async () => { const error = new Error(CONFIG_VALIDATION); error.validationSource = 'package.json'; error.validationMessage = 'some-message'; - platform.getBranchPr.mockResolvedValue({ - ...mock(), + const pr = partial({ + title: 'onboarding', number: 1, state: 'open', }); + platform.getBranchPr.mockResolvedValue(pr); + const res = await raiseConfigWarningIssue(config, error); + expect(res).toBeUndefined(); + expect(platform.updatePr).toHaveBeenCalledWith( + expect.objectContaining({ prTitle: pr.title, number: pr.number }) + ); }); it('handles onboarding (dryRun)', async () => { const error = new Error(CONFIG_VALIDATION); error.validationSource = 'package.json'; error.validationMessage = 'some-message'; - platform.getBranchPr.mockResolvedValue({ - ...mock(), + const pr = partial({ number: 1, state: 'open', }); + platform.getBranchPr.mockResolvedValue(pr); GlobalConfig.set({ dryRun: 'full' }); + const res = await raiseConfigWarningIssue(config, error); + expect(res).toBeUndefined(); + expect(logger.info).toHaveBeenCalledWith( + `DRY-RUN: Would update PR #${pr.number}` + ); }); it('disable issue creation on config failure', async () => { + const notificationName = 'configErrorIssue'; const error = new Error(CONFIG_VALIDATION); error.validationSource = 'package.json'; error.validationMessage = 'some-message'; // config.suppressNotifications = ['deprecationWarningIssues'] - config.suppressNotifications = ['configErrorIssue']; + config.suppressNotifications = [notificationName]; platform.getBranchPr.mockResolvedValueOnce({ ...mock(), number: 1, state: '!open', }); + const res = await raiseConfigWarningIssue(config, error); + expect(res).toBeUndefined(); + expect(logger.info).toHaveBeenCalledWith( + { notificationName }, + 'Configuration failure, issues will be suppressed' + ); }); }); }); diff --git a/lib/workers/repository/error-config.ts b/lib/workers/repository/error-config.ts index 0fba9c00eefbbf..54a6d659e00f5c 100644 --- a/lib/workers/repository/error-config.ts +++ b/lib/workers/repository/error-config.ts @@ -2,61 +2,92 @@ import { GlobalConfig } from '../../config/global'; import type { RenovateConfig } from '../../config/types'; import { logger } from '../../logger'; -import { platform } from '../../modules/platform'; +import { Pr, platform } from '../../modules/platform'; import { regEx } from '../../util/regex'; -export async function raiseConfigWarningIssue( +export function raiseConfigWarningIssue( config: RenovateConfig, error: Error ): Promise { logger.debug('raiseConfigWarningIssue()'); - let body = `There is an error with this repository's Renovate configuration that needs to be fixed. As a precaution, Renovate will stop PRs until it is resolved.\n\n`; + const title = `Action Required: Fix Renovate Configuration`; + const body = `There is an error with this repository's Renovate configuration that needs to be fixed. As a precaution, Renovate will stop PRs until it is resolved.\n\n`; + const notificationName = 'configErrorIssue'; + return raiseWarningIssue(config, notificationName, title, body, error); +} + +async function raiseWarningIssue( + config: RenovateConfig, + notificationName: string, + title: string, + initialBody: string, + error: Error +): Promise { + let body = initialBody; if (error.validationSource) { body += `Location: \`${error.validationSource}\`\n`; } - body += `Error type: ${error.validationError!}\n`; + if (error.validationError) { + body += `Error type: ${error.validationError}\n`; + } if (error.validationMessage) { body += `Message: \`${error.validationMessage.replace( regEx(/`/g), "'" )}\`\n`; } + const pr = await platform.getBranchPr(config.onboardingBranch!); if (pr?.state === 'open') { - logger.debug('Updating onboarding PR with config error notice'); - body = `## Action Required: Fix Renovate Configuration\n\n${body}`; - body += `\n\nOnce you have resolved this problem (in this onboarding branch), Renovate will return to providing you with a preview of your repository's configuration.`; - if (GlobalConfig.get('dryRun')) { - logger.info(`DRY-RUN: Would update PR #${pr.number}`); - } else { - try { - await platform.updatePr({ - number: pr.number, - prTitle: config.onboardingPrTitle!, - prBody: body, - }); - } catch (err) /* istanbul ignore next */ { - logger.warn({ err }, 'Error updating onboarding PR'); - } - } - } else if (GlobalConfig.get('dryRun')) { - logger.info('DRY-RUN: Would ensure config error issue'); - } else if (config.suppressNotifications?.includes('configErrorIssue')) { + await handleOnboardingPr(pr, body); + return; + } + + if (GlobalConfig.get('dryRun')) { logger.info( - 'configErrorIssue - configuration failure, issues will be suppressed' + { configError: error }, + 'DRY-RUN: Would ensure configuration error issue' ); - } else { - const once = false; - const shouldReopen = config.configWarningReuseIssue; - const res = await platform.ensureIssue({ - title: `Action Required: Fix Renovate Configuration`, - body, - once, - shouldReOpen: shouldReopen, - confidential: config.confidential, + return; + } + + if (config.suppressNotifications?.includes(notificationName)) { + logger.info( + { notificationName }, + 'Configuration failure, issues will be suppressed' + ); + return; + } + + const res = await platform.ensureIssue({ + title, + body, + once: false, + shouldReOpen: config.configWarningReuseIssue, + confidential: config.confidential, + }); + if (res === 'created') { + logger.warn({ configError: error, res }, 'Configuration Warning'); + } +} + +async function handleOnboardingPr(pr: Pr, issueMessage: string): Promise { + logger.debug('Updating onboarding PR with config error notice'); + if (GlobalConfig.get('dryRun')) { + logger.info(`DRY-RUN: Would update PR #${pr.number}`); + return; + } + + let prBody = `## Action Required: Fix Renovate Configuration\n\n${issueMessage}`; + prBody += `\n\nOnce you have resolved this problem (in this onboarding branch), Renovate will return to providing you with a preview of your repository's configuration.`; + + try { + await platform.updatePr({ + number: pr.number, + prTitle: pr.title, + prBody, }); - if (res === 'created') { - logger.warn({ configError: error, res }, 'Config Warning'); - } + } catch (err) /* istanbul ignore next */ { + logger.warn({ err }, 'Error updating onboarding PR'); } } diff --git a/lib/workers/repository/finalize/repository-statistics.spec.ts b/lib/workers/repository/finalize/repository-statistics.spec.ts index 3f2c323550e1be..68f7ff022e6f5c 100644 --- a/lib/workers/repository/finalize/repository-statistics.spec.ts +++ b/lib/workers/repository/finalize/repository-statistics.spec.ts @@ -11,6 +11,7 @@ import * as cache from '../../../util/cache/repository'; import type { BaseBranchCache, BranchCache, + BranchUpgradeCache, RepoCacheData, } from '../../../util/cache/repository/types'; import { @@ -103,6 +104,7 @@ describe('workers/repository/finalize/repository-statistics', () => { isModified: false, automerge: false, pristine: false, + upgrades: [], }); const expectedMeta = { automerge: branchCache.automerge, @@ -152,5 +154,37 @@ describe('workers/repository/finalize/repository-statistics', () => { `Branch summary` ); }); + + it('logs extended branch info if branchSummaryExtended', () => { + const defaultBranch = 'main'; + const config: RenovateConfig = { + defaultBranch, + branchSummaryExtended: true, + }; + const branchCache = partial({ + result: 'done', + upgrades: partial([ + { + datasource: 'npm', + depName: 'minimist', + currentValue: '1.2.3', + sourceUrl: 'someUrl', + depType: 'dependencies', + }, + ]), + }); + + const branches: BranchCache[] = [{ ...branchCache, branchName: 'b1' }]; + const cache = partial({ + scan: {}, + branches, + }); + getCacheSpy.mockReturnValueOnce(cache); + isCacheModifiedSpy.mockReturnValueOnce(false); + + runBranchSummary(config); + + expect(logger.debug).toHaveBeenCalledTimes(2); + }); }); }); diff --git a/lib/workers/repository/finalize/repository-statistics.ts b/lib/workers/repository/finalize/repository-statistics.ts index 1d3e487d6fd5be..e2b5224a5be35c 100644 --- a/lib/workers/repository/finalize/repository-statistics.ts +++ b/lib/workers/repository/finalize/repository-statistics.ts @@ -2,7 +2,10 @@ import type { RenovateConfig } from '../../../config/types'; import { logger } from '../../../logger'; import type { Pr } from '../../../modules/platform'; import { getCache, isCacheModified } from '../../../util/cache/repository'; -import type { BranchCache } from '../../../util/cache/repository/types'; +import type { + BranchCache, + BranchUpgradeCache, +} from '../../../util/cache/repository/types'; import type { BaseBranchMetadata, BranchMetadata, @@ -60,7 +63,61 @@ function branchCacheToMetadata({ }; } -export function runBranchSummary({ defaultBranch }: RenovateConfig): void { +function filterDependencyDashboardData( + branches: BranchCache[] +): Partial[] { + const branchesFiltered: Partial[] = []; + for (const branch of branches) { + const upgradesFiltered: Partial[] = []; + const { branchName, prNo, prTitle, result, upgrades, prBlockedBy } = branch; + + for (const upgrade of upgrades ?? []) { + const { + datasource, + depName, + displayPending, + fixedVersion, + currentVersion, + currentValue, + newValue, + newVersion, + packageFile, + updateType, + packageName, + } = upgrade; + + const filteredUpgrade: Partial = { + datasource, + depName, + displayPending, + fixedVersion, + currentVersion, + currentValue, + newValue, + newVersion, + packageFile, + updateType, + packageName, + }; + upgradesFiltered.push(filteredUpgrade); + } + + const filteredBranch: Partial = { + branchName, + prNo, + prTitle, + result, + prBlockedBy, + upgrades: upgradesFiltered, + }; + branchesFiltered.push(filteredBranch); + } + + return branchesFiltered; +} + +export function runBranchSummary(config: RenovateConfig): void { + const defaultBranch = config.defaultBranch; const { scan, branches } = getCache(); const baseMetadata: BaseBranchMetadata[] = []; @@ -88,4 +145,9 @@ export function runBranchSummary({ defaultBranch }: RenovateConfig): void { }; logger.debug(res, 'Branch summary'); + + if (branches?.length) { + const branchesInformation = filterDependencyDashboardData(branches); + logger.debug({ branchesInformation }, 'branches info extended'); + } } diff --git a/lib/workers/repository/onboarding/branch/check.spec.ts b/lib/workers/repository/onboarding/branch/check.spec.ts index 74684f8f809352..7fd1d200bee611 100644 --- a/lib/workers/repository/onboarding/branch/check.spec.ts +++ b/lib/workers/repository/onboarding/branch/check.spec.ts @@ -27,9 +27,10 @@ describe('workers/repository/onboarding/branch/check', () => { it('skips normal onboarding check if onboardingCache is valid', async () => { cache.getCache.mockReturnValueOnce({ onboardingBranchCache: { - onboardingBranch: 'configure/renovate', defaultBranchSha: 'default-sha', onboardingBranchSha: 'onboarding-sha', + isConflicted: false, + isModified: false, }, }); git.getBranchCommit @@ -45,9 +46,10 @@ describe('workers/repository/onboarding/branch/check', () => { it('continues with normal logic if onboardingCache is invalid', async () => { cache.getCache.mockReturnValueOnce({ onboardingBranchCache: { - onboardingBranch: 'configure/renovate', defaultBranchSha: 'default-sha', onboardingBranchSha: 'onboarding-sha', + isConflicted: false, + isModified: false, }, }); scm.getFileList.mockResolvedValue([]); diff --git a/lib/workers/repository/onboarding/branch/check.ts b/lib/workers/repository/onboarding/branch/check.ts index bf3abf09f1fe03..0f7fca6870bd7a 100644 --- a/lib/workers/repository/onboarding/branch/check.ts +++ b/lib/workers/repository/onboarding/branch/check.ts @@ -52,8 +52,13 @@ function closedPrExists(config: RenovateConfig): Promise { export async function isOnboarded(config: RenovateConfig): Promise { logger.debug('isOnboarded()'); const title = `Action required: Add a Renovate config`; + // Repo is onboarded if global config is bypassing onboarding and does not require a // configuration file. + // The repo is considered "not onboarded" if: + // - An onboarding cache is present, and + // - The current default branch SHA matches the default SHA found in the cache + // Also if there is a closed pr skip using cache as it is outdated if (config.requireConfig === 'optional' && config.onboarding === false) { // Return early and avoid checking for config files return true; @@ -63,19 +68,17 @@ export async function isOnboarded(config: RenovateConfig): Promise { return true; } - const pr = await closedPrExists(config); + const closedOnboardingPr = await closedPrExists(config); const cache = getCache(); const onboardingBranchCache = cache?.onboardingBranchCache; // if onboarding cache is present and base branch has not been updated branch is not onboarded // if closed pr exists then presence of onboarding cache doesn't matter as we need to skip onboarding if ( config.onboarding && - !pr && + !closedOnboardingPr && onboardingBranchCache && onboardingBranchCache.defaultBranchSha === - getBranchCommit(config.defaultBranch!) && - onboardingBranchCache.onboardingBranchSha === - getBranchCommit(config.onboardingBranch!) + getBranchCommit(config.defaultBranch!) ) { logger.debug('Onboarding cache is valid. Repo is not onboarded'); return false; @@ -123,7 +126,7 @@ export async function isOnboarded(config: RenovateConfig): Promise { throw new Error(REPOSITORY_NO_CONFIG); } - if (!pr) { + if (!closedOnboardingPr) { logger.debug('Found no closed onboarding PR'); return false; } @@ -136,9 +139,9 @@ export async function isOnboarded(config: RenovateConfig): Promise { if (!config.suppressNotifications!.includes('onboardingClose')) { // ensure PR comment await ensureComment({ - number: pr.number, + number: closedOnboardingPr.number, topic: `Renovate is disabled`, - content: `Renovate is disabled due to lack of config. If you wish to reenable it, you can either (a) commit a config file to your base branch, or (b) rename this closed PR to trigger a replacement onboarding PR.`, + content: `Renovate is disabled due to lack of config. If you wish to re-enable it, you can either (a) commit a config file to your base branch, or (b) rename this closed PR to trigger a replacement onboarding PR.`, }); } throw new Error(REPOSITORY_CLOSED_ONBOARDING); diff --git a/lib/workers/repository/onboarding/branch/index.spec.ts b/lib/workers/repository/onboarding/branch/index.spec.ts index d9821294b5880b..ca37252be7d2fe 100644 --- a/lib/workers/repository/onboarding/branch/index.spec.ts +++ b/lib/workers/repository/onboarding/branch/index.spec.ts @@ -3,6 +3,7 @@ import { RenovateConfig, fs, getConfig, + git, mocked, platform, scm, @@ -17,17 +18,15 @@ import { logger } from '../../../../logger'; import type { Pr } from '../../../../modules/platform'; import * as memCache from '../../../../util/cache/memory'; import * as _cache from '../../../../util/cache/repository'; +import type { RepoCacheData } from '../../../../util/cache/repository/types'; import type { FileAddition } from '../../../../util/git/types'; import { OnboardingState } from '../common'; import * as _config from './config'; import * as _onboardingCache from './onboarding-branch-cache'; -import * as _rebase from './rebase'; import { checkOnboardingBranch } from '.'; -const rebase: any = _rebase; const configModule: any = _config; -jest.mock('../../../repository/onboarding/branch/rebase'); jest.mock('../../../../util/cache/repository'); jest.mock('../../../../util/fs'); jest.mock('../../../../util/git'); @@ -40,13 +39,6 @@ const onboardingCache = mocked(_onboardingCache); describe('workers/repository/onboarding/branch/index', () => { describe('checkOnboardingBranch', () => { let config: RenovateConfig; - const dummyCache = { - onboardingBranchCache: { - onboardingBranch: 'configure/renovate', - defaultBranchSha: 'default-sha', - onboardingBranchSha: 'onboarding-sha', - }, - }; beforeEach(() => { memCache.init(); @@ -177,7 +169,6 @@ describe('workers/repository/onboarding/branch/index', () => { }); it('detects repo is onboarded via file', async () => { - cache.getCache.mockReturnValue(dummyCache); scm.getFileList.mockResolvedValueOnce(['renovate.json']); const res = await checkOnboardingBranch(config); expect(res.repoIsOnboarded).toBeTrue(); @@ -261,20 +252,90 @@ describe('workers/repository/onboarding/branch/index', () => { await expect(checkOnboardingBranch(config)).rejects.toThrow(); }); - it('updates onboarding branch', async () => { - cache.getCache.mockReturnValue(dummyCache); + it('processes onboarding branch', async () => { scm.getFileList.mockResolvedValue(['package.json']); platform.findPr.mockResolvedValue(null); platform.getBranchPr.mockResolvedValueOnce(mock()); - rebase.rebaseOnboardingBranch.mockResolvedValueOnce('123test'); const res = await checkOnboardingBranch(config); expect(res.repoIsOnboarded).toBeFalse(); expect(res.branchList).toEqual(['renovate/configure']); - expect(scm.checkoutBranch).toHaveBeenCalledTimes(1); - expect(onboardingCache.setOnboardingCache).toHaveBeenCalledTimes(1); // update onboarding cache + expect(git.mergeBranch).toHaveBeenCalledOnce(); expect(scm.commitAndPush).toHaveBeenCalledTimes(0); }); + it('processes modified onboarding branch and invalidates extract cache', async () => { + const dummyCache = { + scan: { + master: { + sha: 'base_sha', + configHash: 'hash', + packageFiles: {}, + extractionFingerprints: {}, + }, + }, + } satisfies RepoCacheData; + cache.getCache.mockReturnValue(dummyCache); + platform.findPr.mockResolvedValue(null); + platform.getBranchPr.mockResolvedValueOnce(mock()); + git.getBranchCommit + .mockReturnValueOnce('default-sha') + .mockReturnValueOnce('new-onboarding-sha'); + onboardingCache.isOnboardingBranchModified.mockResolvedValueOnce(true); + onboardingCache.hasOnboardingBranchChanged.mockReturnValueOnce(true); + onboardingCache.isOnboardingBranchConflicted.mockResolvedValueOnce(false); + config.baseBranch = 'master'; + await checkOnboardingBranch(config); + expect(git.mergeBranch).toHaveBeenCalledOnce(); + expect(onboardingCache.setOnboardingCache).toHaveBeenCalledWith( + 'default-sha', + 'new-onboarding-sha', + false, + true + ); + expect(dummyCache).toMatchObject({ + scan: {}, + }); + }); + + it('skips processing conflicted onboarding branch', async () => { + scm.getFileList.mockResolvedValue(['package.json']); + platform.findPr.mockResolvedValue(null); + platform.getBranchPr.mockResolvedValueOnce(mock()); + platform.getBranchPr.mockResolvedValueOnce(mock()); + git.getBranchCommit + .mockReturnValueOnce('default-sha') + .mockReturnValueOnce('onboarding-sha'); + onboardingCache.isOnboardingBranchModified.mockResolvedValueOnce(true); + onboardingCache.hasOnboardingBranchChanged.mockReturnValueOnce(true); + onboardingCache.isOnboardingBranchConflicted.mockResolvedValueOnce(true); + await checkOnboardingBranch(config); + expect(git.mergeBranch).not.toHaveBeenCalled(); + expect(onboardingCache.setOnboardingCache).toHaveBeenCalledWith( + 'default-sha', + 'onboarding-sha', + true, + true + ); + }); + + it('sets onboarding cache for existing onboarding branch', async () => { + scm.getFileList.mockResolvedValue(['package.json']); + platform.findPr.mockResolvedValue(null); + platform.getBranchPr.mockResolvedValueOnce(mock()); + git.getBranchCommit + .mockReturnValueOnce('default-sha') + .mockReturnValueOnce('onboarding-sha'); + onboardingCache.isOnboardingBranchModified.mockResolvedValueOnce(false); + await checkOnboardingBranch(config); + expect(git.mergeBranch).toHaveBeenCalled(); + expect(onboardingCache.setOnboardingCache).toHaveBeenCalledWith( + 'default-sha', + 'onboarding-sha', + false, + false + ); + }); + describe('tests onboarding rebase/retry checkbox handling', () => { beforeEach(() => { GlobalConfig.set({ platform: 'github' }); @@ -282,7 +343,6 @@ describe('workers/repository/onboarding/branch/index', () => { OnboardingState.prUpdateRequested = false; scm.getFileList.mockResolvedValueOnce(['package.json']); platform.findPr.mockResolvedValueOnce(null); - rebase.rebaseOnboardingBranch.mockResolvedValueOnce(null); }); it('detects unsupported platfom', async () => { @@ -296,7 +356,7 @@ describe('workers/repository/onboarding/branch/index', () => { `Platform '${pl}' does not support extended markdown` ); expect(OnboardingState.prUpdateRequested).toBeTrue(); - expect(scm.checkoutBranch).toHaveBeenCalledTimes(1); + expect(git.mergeBranch).toHaveBeenCalledOnce(); expect(scm.commitAndPush).toHaveBeenCalledTimes(0); }); @@ -310,7 +370,7 @@ describe('workers/repository/onboarding/branch/index', () => { `No rebase checkbox was found in the onboarding PR` ); expect(OnboardingState.prUpdateRequested).toBeTrue(); - expect(scm.checkoutBranch).toHaveBeenCalledTimes(1); + expect(git.mergeBranch).toHaveBeenCalledOnce(); expect(scm.commitAndPush).toHaveBeenCalledTimes(0); }); @@ -324,8 +384,7 @@ describe('workers/repository/onboarding/branch/index', () => { `Manual onboarding PR update requested` ); expect(OnboardingState.prUpdateRequested).toBeTrue(); - ``; - expect(scm.checkoutBranch).toHaveBeenCalledTimes(1); + expect(git.mergeBranch).toHaveBeenCalledOnce(); expect(scm.commitAndPush).toHaveBeenCalledTimes(0); }); @@ -336,7 +395,7 @@ describe('workers/repository/onboarding/branch/index', () => { await checkOnboardingBranch(config); expect(OnboardingState.prUpdateRequested).toBeFalse(); - expect(scm.checkoutBranch).toHaveBeenCalledTimes(1); + expect(git.mergeBranch).toHaveBeenCalledOnce(); expect(scm.commitAndPush).toHaveBeenCalledTimes(0); }); }); diff --git a/lib/workers/repository/onboarding/branch/index.ts b/lib/workers/repository/onboarding/branch/index.ts index e131f8069a4a66..a4853d1fec8eca 100644 --- a/lib/workers/repository/onboarding/branch/index.ts +++ b/lib/workers/repository/onboarding/branch/index.ts @@ -7,9 +7,13 @@ import { REPOSITORY_NO_PACKAGE_FILES, } from '../../../../constants/error-messages'; import { logger } from '../../../../logger'; -import { Pr, platform } from '../../../../modules/platform'; -import { scm } from '../../../../modules/platform/scm'; -import { getBranchCommit, setGitAuthor } from '../../../../util/git'; +import type { Pr } from '../../../../modules/platform'; +import { getCache } from '../../../../util/cache/repository'; +import { + getBranchCommit, + mergeBranch, + setGitAuthor, +} from '../../../../util/git'; import { extractAllDependencies } from '../../extract'; import { mergeRenovateConfig } from '../../init/merge'; import { OnboardingState } from '../common'; @@ -18,9 +22,11 @@ import { getOnboardingConfig } from './config'; import { createOnboardingBranch } from './create'; import { deleteOnboardingCache, + hasOnboardingBranchChanged, + isOnboardingBranchConflicted, + isOnboardingBranchModified, setOnboardingCache, } from './onboarding-branch-cache'; -import { rebaseOnboardingBranch } from './rebase'; export async function checkOnboardingBranch( config: RenovateConfig @@ -28,6 +34,8 @@ export async function checkOnboardingBranch( logger.debug('checkOnboarding()'); logger.trace({ config }); let onboardingBranch = config.onboardingBranch; + let isConflicted = false; + let isModified = false; const repoIsOnboarded = await isOnboarded(config); if (repoIsOnboarded) { logger.debug('Repo is onboarded'); @@ -48,25 +56,17 @@ export async function checkOnboardingBranch( handleOnboardingManualRebase(onboardingPr); } logger.debug('Onboarding PR already exists'); - const { rawConfigHash } = onboardingPr.bodyStruct ?? {}; - const commit = await rebaseOnboardingBranch(config, rawConfigHash); - if (commit) { - logger.info( - { branch: config.onboardingBranch, commit, onboarding: true }, - 'Branch updated' - ); - // update onboarding cache - setOnboardingCache( - config.onboardingBranch!, - getBranchCommit(config.defaultBranch!)!, - commit + isModified = await isOnboardingBranchModified(config.onboardingBranch!); + if (isModified) { + if (hasOnboardingBranchChanged(config.onboardingBranch!)) { + invalidateExtractCache(config.baseBranch!); + } + isConflicted = await isOnboardingBranchConflicted( + config.baseBranch!, + config.onboardingBranch! ); } - // istanbul ignore if - if (platform.refreshPr) { - await platform.refreshPr(onboardingPr.number); - } } else { logger.debug('Onboarding PR does not exist'); const onboardingConfig = await getOnboardingConfig(config); @@ -93,20 +93,22 @@ export async function checkOnboardingBranch( { branch: onboardingBranch, commit, onboarding: true }, 'Branch created' ); - - // set onboarding branch cache - setOnboardingCache( - config.onboardingBranch!, - getBranchCommit(config.defaultBranch!)!, - commit - ); } } if (!GlobalConfig.get('dryRun')) { - logger.debug('Checkout onboarding branch.'); // TODO #7154 - await scm.checkoutBranch(onboardingBranch!); + if (!isConflicted) { + logger.debug('Merge onboarding branch in default branch'); + await mergeBranch(onboardingBranch!, true); + } } + setOnboardingCache( + getBranchCommit(config.defaultBranch!)!, + getBranchCommit(onboardingBranch!)!, + isConflicted, + isModified + ); + // TODO #7154 const branchList = [onboardingBranch!]; return { ...config, repoIsOnboarded, onboardingBranch, branchList }; @@ -126,3 +128,12 @@ function handleOnboardingManualRebase(onboardingPr: Pr): void { OnboardingState.prUpdateRequested = true; } } + +function invalidateExtractCache(baseBranch: string): void { + const cache = getCache(); + cache.scan ||= {}; + + if (cache.scan?.[baseBranch]) { + delete cache.scan[baseBranch]; + } +} diff --git a/lib/workers/repository/onboarding/branch/onboarding-branch-cache.spec.ts b/lib/workers/repository/onboarding/branch/onboarding-branch-cache.spec.ts index 10307e5a3ec374..40cb3017741454 100644 --- a/lib/workers/repository/onboarding/branch/onboarding-branch-cache.spec.ts +++ b/lib/workers/repository/onboarding/branch/onboarding-branch-cache.spec.ts @@ -1,61 +1,235 @@ -import { mocked } from '../../../../../test/util'; +import { git, mocked, scm } from '../../../../../test/util'; import * as _cache from '../../../../util/cache/repository'; import type { RepoCacheData } from '../../../../util/cache/repository/types'; import { deleteOnboardingCache, + hasOnboardingBranchChanged, + isOnboardingBranchConflicted, + isOnboardingBranchModified, setOnboardingCache, } from './onboarding-branch-cache'; jest.mock('../../../../util/cache/repository'); +jest.mock('../../../../util/git'); const cache = mocked(_cache); describe('workers/repository/onboarding/branch/onboarding-branch-cache', () => { - it('sets new cache', () => { - const dummyCache = {} satisfies RepoCacheData; - cache.getCache.mockReturnValueOnce(dummyCache); - setOnboardingCache('configure/renovate', 'default-sha', 'onboarding-sha'); - expect(dummyCache).toEqual({ - onboardingBranchCache: { - onboardingBranch: 'configure/renovate', - defaultBranchSha: 'default-sha', - onboardingBranchSha: 'onboarding-sha', - }, + describe('setOnboardingCache', () => { + it('does not create new cache', () => { + const dummyCache = {} satisfies RepoCacheData; + cache.getCache.mockReturnValue(dummyCache); + setOnboardingCache('default-sha', null as never, false, false); + expect(dummyCache).toEqual({}); + }); + + it('sets new cache', () => { + const dummyCache = {} satisfies RepoCacheData; + cache.getCache.mockReturnValue(dummyCache); + setOnboardingCache('default-sha', 'onboarding-sha', false, false); + expect(dummyCache).toEqual({ + onboardingBranchCache: { + defaultBranchSha: 'default-sha', + onboardingBranchSha: 'onboarding-sha', + isConflicted: false, + isModified: false, + }, + }); + }); + + it('updates old cache', () => { + const dummyCache = { + onboardingBranchCache: { + defaultBranchSha: 'default-sha', + onboardingBranchSha: 'onboarding-sha', + isConflicted: false, + isModified: false, + }, + } satisfies RepoCacheData; + cache.getCache.mockReturnValue(dummyCache); + setOnboardingCache('default-sha-1', 'onboarding-sha-1', false, true); + expect(dummyCache).toEqual({ + onboardingBranchCache: { + defaultBranchSha: 'default-sha-1', + onboardingBranchSha: 'onboarding-sha-1', + isConflicted: false, + isModified: true, + }, + }); + }); + }); + + describe('deleteOnboardingCache', () => { + it('deletes cache', () => { + const dummyCache = { + onboardingBranchCache: { + defaultBranchSha: 'default-sha', + onboardingBranchSha: 'onboarding-sha', + isConflicted: false, + isModified: false, + }, + } satisfies RepoCacheData; + cache.getCache.mockReturnValue(dummyCache); + deleteOnboardingCache(); + expect(dummyCache.onboardingBranchCache).toBeUndefined(); }); }); - it('updates old cache', () => { - const dummyCache = { - onboardingBranchCache: { - onboardingBranch: 'configure/renovate', - defaultBranchSha: 'default-sha', - onboardingBranchSha: 'onboarding-sha', - }, - } satisfies RepoCacheData; - cache.getCache.mockReturnValueOnce(dummyCache); - setOnboardingCache( - 'configure/renovate', - 'default-sha-1', - 'onboarding-sha-1' - ); - expect(dummyCache).toEqual({ - onboardingBranchCache: { - onboardingBranch: 'configure/renovate', - defaultBranchSha: 'default-sha-1', - onboardingBranchSha: 'onboarding-sha-1', - }, + describe('hasOnboardingBranchChanged()', () => { + it('return true if cache is absent', () => { + cache.getCache.mockReturnValueOnce({}); + git.getBranchCommit.mockReturnValueOnce('onboarding-sha'); + expect(hasOnboardingBranchChanged('configure/renovate')).toBeTrue(); + }); + + it('returns true', () => { + const dummyCache = { + onboardingBranchCache: { + defaultBranchSha: 'default-sha', + onboardingBranchSha: 'old-onboarding-sha', + isConflicted: false, + isModified: false, + }, + } satisfies RepoCacheData; + cache.getCache.mockReturnValueOnce(dummyCache); + git.getBranchCommit.mockReturnValueOnce('new-onboarding-sha'); + expect(hasOnboardingBranchChanged('configure/renovate')).toBeTrue(); + }); + + it('returns false', () => { + const dummyCache = { + onboardingBranchCache: { + defaultBranchSha: 'default-sha', + onboardingBranchSha: 'onboarding-sha', + isConflicted: false, + isModified: false, + }, + } satisfies RepoCacheData; + cache.getCache.mockReturnValueOnce(dummyCache); + git.getBranchCommit.mockReturnValueOnce('onboarding-sha'); + expect(hasOnboardingBranchChanged('configure/renovate')).toBeFalse(); + }); + + it('returns false when branch is modified but has not changed since last run', () => { + const dummyCache = { + onboardingBranchCache: { + defaultBranchSha: 'default-sha', + onboardingBranchSha: 'onboarding-sha', + isConflicted: false, + isModified: true, + }, + } satisfies RepoCacheData; + cache.getCache.mockReturnValueOnce(dummyCache); + git.getBranchCommit.mockReturnValueOnce('onboarding-sha'); + expect(hasOnboardingBranchChanged('configure/renovate')).toBeFalse(); }); }); - it('deletes cache', () => { - const dummyCache = { - onboardingBranchCache: { - onboardingBranch: 'configure/renovate', - defaultBranchSha: 'default-sha', - onboardingBranchSha: 'onboarding-sha', - }, - } satisfies RepoCacheData; - cache.getCache.mockReturnValueOnce(dummyCache); - deleteOnboardingCache(); - expect(dummyCache.onboardingBranchCache).toBeUndefined(); + describe('isOnboardingBranchModified()', () => { + it('falls back to git if cache is absent', async () => { + cache.getCache.mockReturnValueOnce({}); + git.getBranchCommit.mockReturnValueOnce('onboarding-sha'); + scm.isBranchModified.mockResolvedValueOnce(false); + expect( + await isOnboardingBranchModified('configure/renovate') + ).toBeFalse(); + }); + + it('falls back to git if onboarding branch is updated', async () => { + const dummyCache = { + onboardingBranchCache: { + defaultBranchSha: 'default-sha', + onboardingBranchSha: 'old-onboarding-sha', + isConflicted: false, + isModified: false, + }, + } satisfies RepoCacheData; + cache.getCache.mockReturnValueOnce(dummyCache); + git.getBranchCommit.mockReturnValueOnce('new-onboarding-sha'); + scm.isBranchModified.mockResolvedValueOnce(true); + expect(await isOnboardingBranchModified('configure/renovate')).toBeTrue(); + }); + + it('returns cached value', async () => { + const dummyCache = { + onboardingBranchCache: { + defaultBranchSha: 'default-sha', + onboardingBranchSha: 'onboarding-sha', + isConflicted: true, + isModified: true, + }, + } satisfies RepoCacheData; + cache.getCache.mockReturnValueOnce(dummyCache); + git.getBranchCommit.mockReturnValueOnce('onboarding-sha'); + expect(await isOnboardingBranchModified('configure/renovate')).toBeTrue(); + }); + }); + + describe('isOnboardingBranchConflicted()', () => { + it('falls back to git if cache is absent', async () => { + cache.getCache.mockReturnValueOnce({}); + git.getBranchCommit + .mockReturnValueOnce('onboarding-sha') + .mockReturnValueOnce('default-sha'); + scm.isBranchConflicted.mockResolvedValueOnce(false); + expect( + await isOnboardingBranchConflicted('master', 'configure/renovate') + ).toBeFalse(); + }); + + it('falls back to git if default branch is updated', async () => { + const dummyCache = { + onboardingBranchCache: { + defaultBranchSha: 'old-default-sha', + onboardingBranchSha: 'onboarding-sha', + isConflicted: false, + isModified: false, + }, + } satisfies RepoCacheData; + cache.getCache.mockReturnValueOnce(dummyCache); + git.getBranchCommit + .mockReturnValueOnce('onboarding-sha') + .mockReturnValueOnce('new-default-sha'); + scm.isBranchConflicted.mockResolvedValueOnce(false); + expect( + await isOnboardingBranchConflicted('master', 'configure/renovate') + ).toBeFalse(); + }); + + it('falls back to git if onboarding branch is modified', async () => { + const dummyCache = { + onboardingBranchCache: { + defaultBranchSha: 'default-sha', + onboardingBranchSha: 'old-onboarding-sha', + isConflicted: false, + isModified: false, + }, + } satisfies RepoCacheData; + cache.getCache.mockReturnValueOnce(dummyCache); + git.getBranchCommit + .mockReturnValueOnce('new-onboarding-sha') + .mockReturnValueOnce('default-sha'); + scm.isBranchConflicted.mockResolvedValueOnce(false); + expect( + await isOnboardingBranchConflicted('master', 'configure/renovate') + ).toBeFalse(); + }); + + it('returns cached value', async () => { + const dummyCache = { + onboardingBranchCache: { + defaultBranchSha: 'default-sha', + onboardingBranchSha: 'onboarding-sha', + isConflicted: true, + isModified: true, + }, + } satisfies RepoCacheData; + cache.getCache.mockReturnValueOnce(dummyCache); + git.getBranchCommit + .mockReturnValueOnce('onboarding-sha') + .mockReturnValueOnce('default-sha'); + expect( + await isOnboardingBranchConflicted('master', 'configure/renovate') + ).toBeTrue(); + }); }); }); diff --git a/lib/workers/repository/onboarding/branch/onboarding-branch-cache.ts b/lib/workers/repository/onboarding/branch/onboarding-branch-cache.ts index a6ecfcb29677b2..9f7ebd1b47cf1b 100644 --- a/lib/workers/repository/onboarding/branch/onboarding-branch-cache.ts +++ b/lib/workers/repository/onboarding/branch/onboarding-branch-cache.ts @@ -1,21 +1,37 @@ +import is from '@sindresorhus/is'; import { logger } from '../../../../logger'; +import { scm } from '../../../../modules/platform/scm'; import { getCache } from '../../../../util/cache/repository'; +import { getBranchCommit } from '../../../../util/git'; export function setOnboardingCache( - onboardingBranch: string, defaultBranchSha: string, - onboardingBranchSha: string + onboardingBranchSha: string, + isConflicted: boolean, + isModified: boolean ): void { + // do not update cache if commit is null/undefined + if ( + !( + is.nonEmptyString(defaultBranchSha) && + is.nonEmptyString(onboardingBranchSha) + ) + ) { + logger.debug('Onboarding cache not updated'); + return; + } + const cache = getCache(); const onboardingCache = { - onboardingBranch, defaultBranchSha, onboardingBranchSha, + isConflicted, + isModified, }; if (cache.onboardingBranchCache) { - logger.debug('Update Onboarding Cache'); + logger.debug({ onboardingCache }, 'Update Onboarding Cache'); } else { - logger.debug('Create Onboarding Cache'); + logger.debug({ onboardingCache }, 'Create Onboarding Cache'); } cache.onboardingBranchCache = onboardingCache; } @@ -28,3 +44,65 @@ export function deleteOnboardingCache(): void { delete cache.onboardingBranchCache; } } + +// checks if onboarding branch has been modified since last run +// return true if cache isn't present +export function hasOnboardingBranchChanged(onboardingBranch: string): boolean { + const cache = getCache(); + const onboardingSha = getBranchCommit(onboardingBranch); + + if (cache.onboardingBranchCache) { + return onboardingSha !== cache.onboardingBranchCache.onboardingBranchSha; + } + return true; +} + +// checks if onboarding branch has been modified by user +// once set to true it stays true as we do not rebase onboarding branches anymore (this feature will be added in future though) +export async function isOnboardingBranchModified( + onboardingBranch: string +): Promise { + const cache = getCache(); + const onboardingCache = cache.onboardingBranchCache; + const onboardingSha = getBranchCommit(onboardingBranch); + let isModified = false; + + if ( + onboardingCache && + onboardingSha === onboardingCache.onboardingBranchSha && + !is.undefined(onboardingCache.isModified) + ) { + return onboardingCache.isModified; + } else { + isModified = await scm.isBranchModified(onboardingBranch); + } + + return isModified; +} + +export async function isOnboardingBranchConflicted( + defaultBranch: string, + onboardingBranch: string +): Promise { + const cache = getCache(); + const onboardingCache = cache.onboardingBranchCache; + const onboardingSha = getBranchCommit(onboardingBranch); + const defaultBranchSha = getBranchCommit(defaultBranch); + let isConflicted = false; + + if ( + onboardingCache && + defaultBranchSha === onboardingCache.defaultBranchSha && + onboardingSha === onboardingCache.onboardingBranchSha && + !is.undefined(onboardingCache.isConflicted) + ) { + return onboardingCache.isConflicted; + } else { + isConflicted = await scm.isBranchConflicted( + defaultBranch, + onboardingBranch + ); + } + + return isConflicted; +} diff --git a/lib/workers/repository/onboarding/branch/rebase.spec.ts b/lib/workers/repository/onboarding/branch/rebase.spec.ts deleted file mode 100644 index 1bb98d5e05c17d..00000000000000 --- a/lib/workers/repository/onboarding/branch/rebase.spec.ts +++ /dev/null @@ -1,180 +0,0 @@ -import { RenovateConfig, getConfig, git, scm } from '../../../../../test/util'; -import { GlobalConfig } from '../../../../config/global'; -import * as memCache from '../../../../util/cache/memory'; -import { toSha256 } from '../../../../util/hasha'; -import { OnboardingState } from '../common'; -import { rebaseOnboardingBranch } from './rebase'; - -jest.mock('../../../../util/git'); - -describe('workers/repository/onboarding/branch/rebase', () => { - beforeAll(() => { - GlobalConfig.set({ - localDir: '', - }); - }); - - describe('rebaseOnboardingBranch()', () => { - let config: RenovateConfig; - const hash = ''; - - beforeEach(() => { - memCache.init(); - jest.resetAllMocks(); - OnboardingState.prUpdateRequested = false; - config = { - ...getConfig(), - repository: 'some/repo', - }; - }); - - it('does not rebase modified branch', async () => { - scm.isBranchModified.mockResolvedValueOnce(true); - await rebaseOnboardingBranch(config, hash); - expect(scm.commitAndPush).toHaveBeenCalledTimes(0); - }); - - it.each` - checkboxEnabled - ${true} - ${false} - `( - 'does nothing if branch is up to date ' + - '(config.onboardingRebaseCheckbox="$checkboxEnabled")', - async ({ checkboxEnabled }) => { - config.onboardingRebaseCheckbox = checkboxEnabled; - const contents = - JSON.stringify(getConfig().onboardingConfig, null, 2) + '\n'; - git.getFile - .mockResolvedValueOnce(contents) // package.json - .mockResolvedValueOnce(contents); // renovate.json - await rebaseOnboardingBranch(config, toSha256(contents)); - expect(scm.commitAndPush).toHaveBeenCalledTimes(0); - expect(OnboardingState.prUpdateRequested).toBeFalse(); - } - ); - - it.each` - checkboxEnabled | expected - ${true} | ${true} - ${false} | ${false} - `( - 'rebases onboarding branch ' + - '(config.onboardingRebaseCheckbox="$checkboxEnabled")', - async ({ checkboxEnabled, expected }) => { - config.onboardingRebaseCheckbox = checkboxEnabled; - scm.isBranchBehindBase.mockResolvedValueOnce(true); - await rebaseOnboardingBranch(config, hash); - expect(scm.commitAndPush).toHaveBeenCalledTimes(1); - expect(OnboardingState.prUpdateRequested).toBe(expected); - } - ); - - it.each` - checkboxEnabled | expected - ${true} | ${true} - ${false} | ${false} - `( - 'uses the onboardingConfigFileName if set ' + - '(config.onboardingRebaseCheckbox="$checkboxEnabled")', - async ({ checkboxEnabled, expected }) => { - scm.isBranchBehindBase.mockResolvedValueOnce(true); - await rebaseOnboardingBranch({ - ...config, - onboardingConfigFileName: '.github/renovate.json', - onboardingRebaseCheckbox: checkboxEnabled, - }); - expect(scm.commitAndPush).toHaveBeenCalledTimes(1); - expect(scm.commitAndPush.mock.calls[0][0].message).toContain( - '.github/renovate.json' - ); - expect(scm.commitAndPush.mock.calls[0][0].files[0].path).toBe( - '.github/renovate.json' - ); - expect(OnboardingState.prUpdateRequested).toBe(expected); - } - ); - - it.each` - checkboxEnabled | expected - ${true} | ${true} - ${false} | ${false} - `( - 'falls back to "renovate.json" if onboardingConfigFileName is not set ' + - '(config.onboardingRebaseCheckbox="$checkboxEnabled")', - async ({ checkboxEnabled, expected }) => { - scm.isBranchBehindBase.mockResolvedValueOnce(true); - await rebaseOnboardingBranch({ - ...config, - onboardingConfigFileName: undefined, - onboardingRebaseCheckbox: checkboxEnabled, - }); - expect(scm.commitAndPush).toHaveBeenCalledTimes(1); - expect(scm.commitAndPush.mock.calls[0][0].message).toContain( - 'renovate.json' - ); - expect(scm.commitAndPush.mock.calls[0][0].files[0].path).toBe( - 'renovate.json' - ); - expect(OnboardingState.prUpdateRequested).toBe(expected); - } - ); - - describe('handle onboarding config hashes', () => { - const contents = - JSON.stringify(getConfig().onboardingConfig, null, 2) + '\n'; - - beforeEach(() => { - scm.isBranchModified.mockResolvedValueOnce(true); - git.getFile.mockResolvedValueOnce(contents); - }); - - it.each` - checkboxEnabled | expected - ${true} | ${true} - ${false} | ${false} - `( - 'handles a missing previous config hash ' + - '(config.onboardingRebaseCheckbox="$checkboxEnabled")', - async ({ checkboxEnabled, expected }) => { - config.onboardingRebaseCheckbox = checkboxEnabled; - await rebaseOnboardingBranch(config, undefined); - - expect(OnboardingState.prUpdateRequested).toBe(expected); - } - ); - - it.each` - checkboxEnabled - ${true} - ${false} - `( - 'does nothing if config hashes match' + - '(config.onboardingRebaseCheckbox="$checkboxEnabled")', - async ({ checkboxEnabled, expected }) => { - git.getFile.mockResolvedValueOnce(contents); // package.json - config.onboardingRebaseCheckbox = checkboxEnabled; - await rebaseOnboardingBranch(config, toSha256(contents)); - expect(scm.commitAndPush).toHaveBeenCalledTimes(0); - expect(OnboardingState.prUpdateRequested).toBeFalse(); - } - ); - - it.each` - checkboxEnabled | expected - ${true} | ${true} - ${false} | ${false} - `( - 'requests update if config hashes mismatch' + - '(config.onboardingRebaseCheckbox="$checkboxEnabled")', - async ({ checkboxEnabled, expected }) => { - git.getFile.mockResolvedValueOnce(contents); // package.json - config.onboardingRebaseCheckbox = checkboxEnabled; - await rebaseOnboardingBranch(config, hash); - expect(scm.commitAndPush).toHaveBeenCalledTimes(0); - expect(OnboardingState.prUpdateRequested).toBe(expected); - } - ); - }); - }); -}); diff --git a/lib/workers/repository/onboarding/branch/rebase.ts b/lib/workers/repository/onboarding/branch/rebase.ts deleted file mode 100644 index 4cb1d27345db4d..00000000000000 --- a/lib/workers/repository/onboarding/branch/rebase.ts +++ /dev/null @@ -1,89 +0,0 @@ -import is from '@sindresorhus/is'; -import { GlobalConfig } from '../../../../config/global'; -import type { RenovateConfig } from '../../../../config/types'; -import { logger } from '../../../../logger'; -import { scm } from '../../../../modules/platform/scm'; -import { getFile } from '../../../../util/git'; -import { toSha256 } from '../../../../util/hasha'; -import { OnboardingState, defaultConfigFile } from '../common'; -import { OnboardingCommitMessageFactory } from './commit-message'; -import { getOnboardingConfigContents } from './config'; - -export async function rebaseOnboardingBranch( - config: RenovateConfig, - previousConfigHash?: string -): Promise { - logger.debug('Checking if onboarding branch needs rebasing'); - const configFile = defaultConfigFile(config); - const existingContents = - (await getFile(configFile, config.onboardingBranch)) ?? ''; - const currentConfigHash = toSha256(existingContents); - const contents = await getOnboardingConfigContents(config, configFile); - - if (config.onboardingRebaseCheckbox) { - handleOnboardingManualRebase(previousConfigHash, currentConfigHash); - } - - // TODO #7154 - if (await scm.isBranchModified(config.onboardingBranch!)) { - logger.debug('Onboarding branch has been edited and cannot be rebased'); - return null; - } - - // TODO: fix types (#7154) - if ( - contents === existingContents && - !(await scm.isBranchBehindBase( - config.onboardingBranch!, - config.defaultBranch! - )) - ) { - logger.debug('Onboarding branch is up to date'); - return null; - } - - logger.debug('Rebasing onboarding branch'); - if (config.onboardingRebaseCheckbox) { - OnboardingState.prUpdateRequested = true; - } - // istanbul ignore next - const commitMessageFactory = new OnboardingCommitMessageFactory( - config, - configFile - ); - const commitMessage = commitMessageFactory.create(); - - // istanbul ignore if - if (GlobalConfig.get('dryRun')) { - logger.info('DRY-RUN: Would rebase files in onboarding branch'); - return null; - } - - // TODO #7154 - return scm.commitAndPush({ - baseBranch: config.baseBranch, - branchName: config.onboardingBranch!, - files: [ - { - type: 'addition', - path: configFile, - contents, - }, - ], - message: commitMessage.toString(), - platformCommit: !!config.platformCommit, - }); -} - -function handleOnboardingManualRebase( - previousConfigHash: string | undefined, - currentConfigHash: string -): void { - if (is.nullOrUndefined(previousConfigHash)) { - logger.debug('Missing previousConfigHash bodyStruct prop in onboarding PR'); - OnboardingState.prUpdateRequested = true; - } else if (previousConfigHash !== currentConfigHash) { - logger.debug('Onboarding config has been modified by the user'); - OnboardingState.prUpdateRequested = true; - } -} diff --git a/lib/workers/repository/onboarding/pr/index.spec.ts b/lib/workers/repository/onboarding/pr/index.spec.ts index 500a62d1e71ea0..0bc3ad94282deb 100644 --- a/lib/workers/repository/onboarding/pr/index.spec.ts +++ b/lib/workers/repository/onboarding/pr/index.spec.ts @@ -155,6 +155,7 @@ describe('workers/repository/onboarding/pr/index', () => { config.baseBranch = 'some-branch'; config.repository = 'test'; config.onboardingRebaseCheckbox = onboardingRebaseCheckbox; + config.onboardingConfigFileName = undefined; // checks the case when fileName isn't available OnboardingState.prUpdateRequested = true; // case 'false' is tested in "breaks early when onboarding" await ensureOnboardingPr( { @@ -201,7 +202,7 @@ describe('workers/repository/onboarding/pr/index', () => { } ); - it('updates PR when conflicted', async () => { + it('ensures comment, when PR is conflicted', async () => { config.baseBranch = 'some-branch'; platform.getBranchPr.mockResolvedValueOnce( partial({ @@ -210,10 +211,10 @@ describe('workers/repository/onboarding/pr/index', () => { }) ); scm.isBranchConflicted.mockResolvedValueOnce(true); - scm.isBranchModified.mockResolvedValueOnce(true); await ensureOnboardingPr(config, {}, branches); + expect(platform.ensureComment).toHaveBeenCalledTimes(1); expect(platform.createPr).toHaveBeenCalledTimes(0); - expect(platform.updatePr).toHaveBeenCalledTimes(1); + expect(platform.updatePr).toHaveBeenCalledTimes(0); }); it('updates PR when modified', async () => { @@ -224,7 +225,6 @@ describe('workers/repository/onboarding/pr/index', () => { bodyStruct, }) ); - scm.isBranchModified.mockResolvedValueOnce(true); await ensureOnboardingPr(config, {}, branches); expect(platform.createPr).toHaveBeenCalledTimes(0); expect(platform.updatePr).toHaveBeenCalledTimes(1); @@ -242,34 +242,31 @@ describe('workers/repository/onboarding/pr/index', () => { expect(platform.createPr).toHaveBeenCalledTimes(1); }); - it('dryrun of updates PR when modified', async () => { + it('dryrun of creates PR', async () => { GlobalConfig.set({ dryRun: 'full' }); - config.baseBranch = 'some-branch'; - platform.getBranchPr.mockResolvedValueOnce( - partial({ - title: 'Configure Renovate', - bodyStruct, - }) - ); - scm.isBranchConflicted.mockResolvedValueOnce(true); - scm.isBranchModified.mockResolvedValueOnce(true); - await ensureOnboardingPr(config, {}, branches); + await ensureOnboardingPr(config, packageFiles, branches); expect(logger.info).toHaveBeenCalledWith( 'DRY-RUN: Would check branch renovate/configure' ); expect(logger.info).toHaveBeenLastCalledWith( - 'DRY-RUN: Would update onboarding PR' + 'DRY-RUN: Would create onboarding PR' ); }); - it('dryrun of creates PR', async () => { + it('dryrun of updates PR', async () => { GlobalConfig.set({ dryRun: 'full' }); + platform.getBranchPr.mockResolvedValueOnce( + partial({ + title: 'Configure Renovate', + bodyStruct, + }) + ); await ensureOnboardingPr(config, packageFiles, branches); expect(logger.info).toHaveBeenCalledWith( 'DRY-RUN: Would check branch renovate/configure' ); expect(logger.info).toHaveBeenLastCalledWith( - 'DRY-RUN: Would create onboarding PR' + 'DRY-RUN: Would update onboarding PR' ); }); diff --git a/lib/workers/repository/onboarding/pr/index.ts b/lib/workers/repository/onboarding/pr/index.ts index 923dec654e8c2d..2bf76f3ee5526b 100644 --- a/lib/workers/repository/onboarding/pr/index.ts +++ b/lib/workers/repository/onboarding/pr/index.ts @@ -4,6 +4,7 @@ import type { RenovateConfig } from '../../../../config/types'; import { logger } from '../../../../logger'; import type { PackageFile } from '../../../../modules/manager/types'; import { platform } from '../../../../modules/platform'; +import { ensureComment } from '../../../../modules/platform/comment'; import { hashBody } from '../../../../modules/platform/pr-body'; import { scm } from '../../../../modules/platform/scm'; import { emojify } from '../../../../util/emoji'; @@ -19,6 +20,7 @@ import { import { getPlatformPrOptions } from '../../update/pr'; import { prepareLabels } from '../../update/pr/labels'; import { addParticipants } from '../../update/pr/participants'; +import { isOnboardingBranchConflicted } from '../branch/onboarding-branch-cache'; import { OnboardingState, defaultConfigFile } from '../common'; import { getBaseBranchDesc } from './base-branch'; import { getConfigDesc } from './config-description'; @@ -39,6 +41,24 @@ export async function ensureOnboardingPr( logger.trace({ config }); // TODO #7154 const existingPr = await platform.getBranchPr(config.onboardingBranch!); + if (existingPr) { + // skip pr-update if branch is conflicted + if ( + await isOnboardingBranchConflicted( + config.defaultBranch!, + config.onboardingBranch! + ) + ) { + await ensureComment({ + number: existingPr.number, + topic: 'Branch Conflicted', + content: emojify( + `:warning: This PR has a merge conflict which Renovate is unable to automatically resolve, so updates to this PR description are now paused. Please resolve the merge conflict manually.\n\n` + ), + }); + return; + } + } const { rebaseCheckBox, renovateConfigHashComment } = await getRebaseCheckboxComponents(config); logger.debug('Filling in onboarding PR template'); @@ -96,23 +116,6 @@ If you need any further assistance then you can also [request help here](${ if (GlobalConfig.get('dryRun')) { // TODO: types (#7154) logger.info(`DRY-RUN: Would check branch ${config.onboardingBranch!}`); - } else if (await scm.isBranchModified(config.onboardingBranch!)) { - configDesc = emojify( - `### Configuration\n\n:abcd: Renovate has detected a custom config for this PR. Feel free to ask for [help](${ - config.productLinks!.help - }) if you have any doubts and would like it reviewed.\n\n` - ); - const isConflicted = await scm.isBranchConflicted( - config.baseBranch!, - config.onboardingBranch! - ); - if (isConflicted) { - configDesc += emojify( - `:warning: This PR has a merge conflict. However, Renovate is unable to automatically fix that due to edits in this branch. Please resolve the merge conflict manually.\n\n` - ); - } else { - configDesc += `Important: Now that this branch is edited, Renovate can't rebase it from the base branch any more. If you make changes to the base branch that could impact this onboarding PR, please merge them manually.\n\n`; - } } else { configDesc = getConfigDesc(config, packageFiles!); } diff --git a/lib/workers/repository/process/index.ts b/lib/workers/repository/process/index.ts index 0593f539bc42bb..cced4e1702d921 100644 --- a/lib/workers/repository/process/index.ts +++ b/lib/workers/repository/process/index.ts @@ -108,7 +108,7 @@ export async function extractDependencies( branchList: [], packageFiles: null!, }; - if (config.baseBranches?.length) { + if (GlobalConfig.get('platform') !== 'local' && config.baseBranches?.length) { config.baseBranches = unfoldBaseBranches(config.baseBranches); logger.debug({ baseBranches: config.baseBranches }, 'baseBranches'); const extracted: Record> = {}; diff --git a/lib/workers/repository/process/types.ts b/lib/workers/repository/process/types.ts index fd739b99a7d1c3..c0de869e16ab17 100644 --- a/lib/workers/repository/process/types.ts +++ b/lib/workers/repository/process/types.ts @@ -17,3 +17,9 @@ export interface DependencyVulnerabilities { versioningApi: VersioningApi; vulnerabilities: Vulnerability[]; } + +export interface SeverityDetails { + cvssVector: string; + score: string; + severityLevel: string; +} diff --git a/lib/workers/repository/process/vulnerabilities.spec.ts b/lib/workers/repository/process/vulnerabilities.spec.ts index acfb0424435dba..eb63590dea7a21 100644 --- a/lib/workers/repository/process/vulnerabilities.spec.ts +++ b/lib/workers/repository/process/vulnerabilities.spec.ts @@ -944,7 +944,7 @@ describe('workers/repository/process/vulnerabilities', () => { No details. #### Severity - Unknown severity. + Unknown #### References No references. diff --git a/lib/workers/repository/process/vulnerabilities.ts b/lib/workers/repository/process/vulnerabilities.ts index b3745a7692d463..9ff98a803dfb6a 100644 --- a/lib/workers/repository/process/vulnerabilities.ts +++ b/lib/workers/repository/process/vulnerabilities.ts @@ -18,7 +18,12 @@ import { import { sanitizeMarkdown } from '../../../util/markdown'; import * as p from '../../../util/promises'; import { regEx } from '../../../util/regex'; -import type { DependencyVulnerabilities, Vulnerability } from './types'; +import { titleCase } from '../../../util/string'; +import type { + DependencyVulnerabilities, + SeverityDetails, + Vulnerability, +} from './types'; export class Vulnerabilities { private osvOffline: OsvOffline | undefined; @@ -454,12 +459,19 @@ export class Vulnerabilities { logger.debug( `Setting allowed version ${fixedVersion} to fix vulnerability ${vulnerability.id} in ${packageName} ${depVersion}` ); + + const severityDetails = this.extractSeverityDetails( + vulnerability, + affected + ); + return { matchDatasources: [datasource], matchPackageNames: [packageName], matchCurrentVersion: depVersion, allowedVersions: fixedVersion, isVulnerabilityAlert: true, + vulnerabilitySeverity: severityDetails.severityLevel, prBodyNotes: this.generatePrBodyNotes(vulnerability, affected), force: { ...packageFileConfig.vulnerabilityAlerts, @@ -470,9 +482,7 @@ export class Vulnerabilities { private evaluateCvssVector(vector: string): [string, string] { try { const parsedCvss: CvssScore = parseCvssVector(vector); - const severityLevel = - parsedCvss.cvss3OverallSeverityText.charAt(0).toUpperCase() + - parsedCvss.cvss3OverallSeverityText.slice(1); + const severityLevel = parsedCvss.cvss3OverallSeverityText; return [parsedCvss.baseScore.toFixed(1), severityLevel]; } catch (err) { @@ -513,26 +523,16 @@ export class Vulnerabilities { content += `#### Details\n${details ?? 'No details.'}\n`; content += '#### Severity\n'; - const cvssVector = - vulnerability.severity?.find((e) => e.type === 'CVSS_V3')?.score ?? - vulnerability.severity?.[0]?.score ?? - (affected.database_specific?.cvss as string); // RUSTSEC - if (cvssVector) { - const [baseScore, severity] = this.evaluateCvssVector(cvssVector); - const score = baseScore ? `${baseScore} / 10 (${severity})` : 'Unknown'; - content += `- CVSS Score: ${score}\n`; - content += `- Vector String: \`${cvssVector}\`\n`; - } else if ( - vulnerability.id.startsWith('GHSA-') && - vulnerability.database_specific?.severity - ) { - const severity = vulnerability.database_specific.severity as string; - content += - severity.charAt(0).toUpperCase() + - severity.slice(1).toLowerCase() + - '\n'; + const severityDetails = this.extractSeverityDetails( + vulnerability, + affected + ); + + if (severityDetails.cvssVector) { + content += `- CVSS Score: ${severityDetails.score}\n`; + content += `- Vector String: \`${severityDetails.cvssVector}\`\n`; } else { - content += 'Unknown severity.\n'; + content += `${titleCase(severityDetails.severityLevel)}\n`; } content += `\n#### References\n${ @@ -558,4 +558,37 @@ export class Vulnerabilities { return [sanitizeMarkdown(content)]; } + + private extractSeverityDetails( + vulnerability: Osv.Vulnerability, + affected: Osv.Affected + ): SeverityDetails { + let severityLevel = 'UNKNOWN'; + let score = 'Unknown'; + + const cvssVector = + vulnerability.severity?.find((e) => e.type === 'CVSS_V3')?.score ?? + vulnerability.severity?.[0]?.score ?? + (affected.database_specific?.cvss as string); // RUSTSEC + + if (cvssVector) { + const [baseScore, severity] = this.evaluateCvssVector(cvssVector); + severityLevel = severity.toUpperCase(); + score = baseScore + ? `${baseScore} / 10 (${titleCase(severityLevel)})` + : 'Unknown'; + } else if ( + vulnerability.id.startsWith('GHSA-') && + vulnerability.database_specific?.severity + ) { + const severity = vulnerability.database_specific.severity as string; + severityLevel = severity.toUpperCase(); + } + + return { + cvssVector, + score, + severityLevel, + }; + } } diff --git a/lib/workers/repository/update/branch/index.spec.ts b/lib/workers/repository/update/branch/index.spec.ts index aaec7534c8499c..5a4ad531e64e75 100644 --- a/lib/workers/repository/update/branch/index.spec.ts +++ b/lib/workers/repository/update/branch/index.spec.ts @@ -289,6 +289,21 @@ describe('workers/repository/update/branch/index', () => { expect(scm.deleteBranch).toHaveBeenCalledTimes(1); }); + it('allows branch but disables automerge if merged PR found', async () => { + schedule.isScheduledNow.mockReturnValueOnce(false); + scm.branchExists.mockResolvedValue(true); + config.automerge = true; + config.updateType = 'digest'; + checkExisting.prAlreadyExisted.mockResolvedValueOnce( + partial({ + number: 13, + state: 'merged', + }) + ); + await branchWorker.processBranch(config); + expect(reuse.shouldReuseExistingBranch).toHaveBeenCalledTimes(0); + }); + it('skips branch if closed minor PR found', async () => { schedule.isScheduledNow.mockReturnValueOnce(false); scm.branchExists.mockResolvedValue(true); diff --git a/lib/workers/repository/update/branch/index.ts b/lib/workers/repository/update/branch/index.ts index 7b61df3f669645..562a08f61539f7 100644 --- a/lib/workers/repository/update/branch/index.ts +++ b/lib/workers/repository/update/branch/index.ts @@ -113,8 +113,19 @@ export async function processBranch( const artifactErrorTopic = emojify(':warning: Artifact update problem'); try { // Check if branch already existed - const existingPr = branchPr ? undefined : await prAlreadyExisted(config); - if (existingPr && !dependencyDashboardCheck) { + const existingPr = + !branchPr || config.automerge + ? await prAlreadyExisted(config) + : undefined; + if (existingPr?.state === 'merged') { + logger.debug(`Matching PR #${existingPr.number} was merged previously`); + if (config.automerge) { + logger.debug('Disabling automerge because PR was merged previously'); + config.automerge = false; + config.automergedPreviously = true; + } + } + if (!branchPr && existingPr && !dependencyDashboardCheck) { logger.debug( { prTitle: config.prTitle }, 'Closed PR already exists. Skipping branch.' diff --git a/lib/workers/repository/update/pr/body/config-description.spec.ts b/lib/workers/repository/update/pr/body/config-description.spec.ts index 9465753fd48e10..435c37258c3940 100644 --- a/lib/workers/repository/update/pr/body/config-description.spec.ts +++ b/lib/workers/repository/update/pr/body/config-description.spec.ts @@ -87,5 +87,15 @@ describe('workers/repository/update/pr/body/config-description', () => { const res = getPrConfigDescription({ ...config, automerge: true }); expect(res).toContain(`**Automerge**: Enabled.`); }); + + it('renders blocked automerge', () => { + const res = getPrConfigDescription({ + ...config, + automergedPreviously: true, + }); + expect(res).toContain( + `**Automerge**: Disabled because a matching PR was automerged previously.` + ); + }); }); }); diff --git a/lib/workers/repository/update/pr/body/config-description.ts b/lib/workers/repository/update/pr/body/config-description.ts index f3d0757c1a1f31..11d1aeed0186f8 100644 --- a/lib/workers/repository/update/pr/body/config-description.ts +++ b/lib/workers/repository/update/pr/body/config-description.ts @@ -15,6 +15,8 @@ export function getPrConfigDescription(config: BranchConfig): string { prBody += emojify(':vertical_traffic_light: **Automerge**: '); if (config.automerge) { prBody += 'Enabled.'; + } else if (config.automergedPreviously) { + prBody += 'Disabled because a matching PR was automerged previously.'; } else { prBody += 'Disabled by config. Please merge this manually once you are satisfied.'; diff --git a/lib/workers/repository/update/pr/changelog/github.spec.ts b/lib/workers/repository/update/pr/changelog/github.spec.ts index 8571c684606ae6..ee6fe19cee6109 100644 --- a/lib/workers/repository/update/pr/changelog/github.spec.ts +++ b/lib/workers/repository/update/pr/changelog/github.spec.ts @@ -366,6 +366,10 @@ describe('workers/repository/update/pr/changelog/github', () => { { version: '1.0.1' }, { version: 'correctPrefix/target@1.0.1' }, { version: 'wrongPrefix/target-1.0.1' }, + { version: 'v1.0.2' }, + { version: '1.0.2' }, + { version: 'correctPrefix/target-1.0.2' }, + { version: 'wrongPrefix/target@1.0.2' }, ]) ); @@ -376,9 +380,10 @@ describe('workers/repository/update/pr/changelog/github', () => { endpoint: 'https://api.github.com/', versioning: 'npm', currentVersion: '1.0.0', - newVersion: '1.0.1', + newVersion: '1.0.2', sourceUrl: 'https://github.com/chalk/chalk', releases: [ + { version: '1.0.2', gitRef: '789012' }, { version: '1.0.1', gitRef: '123456' }, { version: '0.1.1', gitRef: 'npm_1.0.0' }, ], @@ -398,6 +403,18 @@ describe('workers/repository/update/pr/changelog/github', () => { packageName: 'correctPrefix/target', }, versions: [ + { + version: '1.0.2', + date: undefined, + changes: [], + compare: { + url: 'https://github.com/chalk/chalk/compare/correctPrefix/target@1.0.1...correctPrefix/target-1.0.2', + }, + releaseNotes: { + url: 'https://github.com/chalk/chalk/compare/correctPrefix/target@1.0.1...correctPrefix/target-1.0.2', + notesSourceUrl: '', + }, + }, { version: '1.0.1', date: undefined, diff --git a/lib/workers/repository/update/pr/changelog/source-github.ts b/lib/workers/repository/update/pr/changelog/source-github.ts index 19ed0f561d3388..9b7bc2922b6668 100644 --- a/lib/workers/repository/update/pr/changelog/source-github.ts +++ b/lib/workers/repository/update/pr/changelog/source-github.ts @@ -195,7 +195,7 @@ function findTagOfRelease( tags: string[] ): string | undefined { const regex = regEx(`(?:${packageName}|release)[@-]`, undefined, false); - const excactReleaseRegex = regEx(`${packageName}[@-_]v?${depNewVersion}`); + const excactReleaseRegex = regEx(`${packageName}[@\\-_]v?${depNewVersion}`); const exactTagsList = tags.filter((tag) => { return excactReleaseRegex.test(tag); }); diff --git a/lib/workers/repository/update/pr/pr-fingerprint.ts b/lib/workers/repository/update/pr/pr-fingerprint.ts index ccc55276a2b539..5e71b179454af9 100644 --- a/lib/workers/repository/update/pr/pr-fingerprint.ts +++ b/lib/workers/repository/update/pr/pr-fingerprint.ts @@ -45,6 +45,9 @@ export function generatePrFingerprintConfig( const filteredUpgrades = config.upgrades.map((upgrade) => { return { depName: upgrade.depName, + displayFrom: upgrade.displayFrom, + displayTo: upgrade.displayTo, + displayPending: upgrade.displayPending, gitRef: upgrade.gitRef, hasReleaseNotes: upgrade.hasReleaseNotes, prBodyDefinitions: upgrade.prBodyDefinitions, diff --git a/lib/workers/repository/updates/generate.ts b/lib/workers/repository/updates/generate.ts index 3dd6b922615837..e02cf5012b7c20 100644 --- a/lib/workers/repository/updates/generate.ts +++ b/lib/workers/repository/updates/generate.ts @@ -226,7 +226,7 @@ export function generateBranchConfig( regEx(/to vv(\d)/), 'to v$1' ); - if (upgrade.toLowerCase) { + if (upgrade.toLowerCase && upgrade.commitMessageLowerCase !== 'never') { // We only need to lowercase the first line const splitMessage = upgrade.commitMessage.split(newlineRegex); splitMessage[0] = splitMessage[0].toLowerCase(); @@ -249,7 +249,7 @@ export function generateBranchConfig( ); throw new Error(CONFIG_SECRETS_EXPOSED); } - if (upgrade.toLowerCase) { + if (upgrade.toLowerCase && upgrade.commitMessageLowerCase !== 'never') { upgrade.prTitle = upgrade.prTitle.toLowerCase(); } } else { diff --git a/lib/workers/types.ts b/lib/workers/types.ts index 3a14f60295b1ae..27ac01583ae953 100644 --- a/lib/workers/types.ts +++ b/lib/workers/types.ts @@ -111,6 +111,7 @@ export interface BranchConfig PlatformPrOptions { automergeComment?: string; automergeType?: string; + automergedPreviously?: boolean; baseBranch: string; errors?: ValidationMessage[]; hasTypes?: boolean; @@ -131,10 +132,10 @@ export interface BranchConfig export interface BranchMetadata { branchName: string; - branchSha: string | null; + branchSha?: string | null; baseBranch?: string; baseBranchSha?: string | null; - automerge: boolean; + automerge?: boolean; isModified?: boolean; isPristine?: boolean; } diff --git a/package.json b/package.json index 3a6de6cd1a198e..729e1bfcfd3518 100644 --- a/package.json +++ b/package.json @@ -135,12 +135,12 @@ "node": "^18.12.0 || >=20.0.0" }, "dependencies": { - "@aws-sdk/client-codecommit": "3.312.0", - "@aws-sdk/client-ec2": "3.312.0", - "@aws-sdk/client-ecr": "3.312.0", - "@aws-sdk/client-iam": "3.312.0", - "@aws-sdk/client-rds": "3.314.0", - "@aws-sdk/client-s3": "3.312.0", + "@aws-sdk/client-codecommit": "3.332.0", + "@aws-sdk/client-ec2": "3.332.0", + "@aws-sdk/client-ecr": "3.332.0", + "@aws-sdk/client-iam": "3.332.0", + "@aws-sdk/client-rds": "3.332.0", + "@aws-sdk/client-s3": "3.332.0", "@breejs/later": "4.1.0", "@cdktf/hcl2json": "0.16.1", "@cheap-glitch/mi-cron": "1.0.1", @@ -156,7 +156,7 @@ "@opentelemetry/sdk-trace-node": "1.12.0", "@opentelemetry/semantic-conventions": "1.12.0", "@qnighy/marshal": "0.1.3", - "@renovatebot/osv-offline": "1.2.4", + "@renovatebot/osv-offline": "1.2.8", "@renovatebot/pep440": "2.1.15", "@renovatebot/ruby-semver": "3.0.1", "@sindresorhus/is": "4.6.0", @@ -194,8 +194,9 @@ "git-url-parse": "13.1.0", "github-url-from-git": "1.5.0", "global-agent": "3.0.0", - "good-enough-parser": "1.1.22", + "good-enough-parser": "1.1.23", "got": "11.8.6", + "glob": "10.2.5", "graph-data-structure": "3.3.0", "handlebars": "4.7.7", "hasha": "5.2.2", @@ -225,7 +226,7 @@ "remark": "13.0.0", "remark-github": "10.1.0", "safe-stable-stringify": "2.4.3", - "semver": "7.5.0", + "semver": "7.5.1", "semver-stable": "3.0.0", "semver-utils": "1.1.4", "shlex": "2.1.2", @@ -278,12 +279,12 @@ "@types/marshal": "0.5.1", "@types/moo": "0.5.5", "@types/nock": "10.0.3", - "@types/node": "18.16.3", + "@types/node": "18.16.8", "@types/parse-link-header": "2.0.1", - "@types/semver": "7.3.13", + "@types/semver": "7.5.0", "@types/semver-stable": "3.0.0", "@types/semver-utils": "1.1.1", - "@types/tar": "6.1.4", + "@types/tar": "6.1.5", "@types/traverse": "0.6.32", "@types/url-join": "4.0.1", "@types/validate-npm-package-name": "4.0.0", @@ -307,14 +308,12 @@ "eslint-plugin-promise": "6.1.1", "eslint-plugin-typescript-enum": "2.1.0", "expect-more-jest": "5.5.0", - "glob": "10.2.2", "graphql": "16.6.0", "husky": "8.0.3", "jest": "29.5.0", "jest-extended": "3.2.4", "jest-junit": "16.0.0", "jest-mock-extended": "3.0.4", - "lint-staged": "13.2.2", "markdownlint-cli2": "0.7.1", "memfs": "3.5.1", "mock-fs": "5.2.0", @@ -324,11 +323,11 @@ "rimraf": "5.0.0", "semantic-release": "21.0.2", "strip-ansi": "6.0.1", - "tar": "6.1.13", + "tar": "6.1.14", "tmp-promise": "3.0.3", "ts-jest": "29.1.0", "ts-node": "10.9.1", - "type-fest": "3.9.0", + "type-fest": "3.10.0", "typescript": "5.0.4", "unified": "9.2.2" }, diff --git a/tools/docs/schema.ts b/tools/docs/schema.ts index abc3c6cbb133db..ed40fbe3c25dcd 100644 --- a/tools/docs/schema.ts +++ b/tools/docs/schema.ts @@ -49,7 +49,12 @@ function createSingleConfig(option: RenovateOptions): Record { if (hasKey('format', option) && option.format) { temp.format = option.format; } - if (option.allowedValues) { + if (option.name === 'versioning') { + temp.oneOf = [ + { enum: option.allowedValues }, + { type: 'string', pattern: '^regex:' }, + ]; + } else if (option.allowedValues) { temp.enum = option.allowedValues; } } @@ -83,7 +88,13 @@ function addChildrenArrayInParents(): void { allOf: [ { type: 'object', - properties: {}, + properties: { + description: { + type: 'string', + description: + 'A custom description for this configuration object', + }, + }, }, ], }; diff --git a/yarn.lock b/yarn.lock index 3320dcf3262f78..11194d887fb50d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -109,12 +109,12 @@ "@aws-sdk/util-utf8-browser" "^3.0.0" tslib "^1.11.1" -"@aws-sdk/abort-controller@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/abort-controller/-/abort-controller-3.310.0.tgz#0da2d29b823daa03b7c1f0b43de1f030583b4f51" - integrity sha512-v1zrRQxDLA1MdPim159Vx/CPHqsB4uybSxRi1CnfHO5ZjHryx3a5htW2gdGAykVCul40+yJXvfpufMrELVxH+g== +"@aws-sdk/abort-controller@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/abort-controller/-/abort-controller-3.329.0.tgz#f311f79cad1040b84b853c5e9386ea2e069e571a" + integrity sha512-hzrjPNQcJoSPe0oS20V5i98oiEZSM3mKNiR6P3xHTHTPI/F23lyjGZ+/CSkCmJbSWfGZ5sHZZcU6AWuS7xBdTw== dependencies: - "@aws-sdk/types" "3.310.0" + "@aws-sdk/types" "3.329.0" tslib "^2.5.0" "@aws-sdk/chunked-blob-reader@3.310.0": @@ -124,582 +124,582 @@ dependencies: tslib "^2.5.0" -"@aws-sdk/client-codecommit@3.312.0": - version "3.312.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/client-codecommit/-/client-codecommit-3.312.0.tgz#e29c3d504b2d65aaccb4a4e8d12e736115ad5893" - integrity sha512-DZ8Ci6REIqBKJLeDN1qk+MgRs0KBPnNvfT0Ktw+3dyykbpo20X8xabcUDpV7l1C1qwTYFAg2vC0xbdbx9O2LOg== +"@aws-sdk/client-codecommit@3.332.0": + version "3.332.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-codecommit/-/client-codecommit-3.332.0.tgz#dc1783c75ba22d96e171ca4e47ce77408bb8a27c" + integrity sha512-sNJTxXQabZXoDCWEEjCThLui6Cos4CXiJvkzMcprnttg1EeocOI233fPIBJrD/RXRjZLIJMdW6Hxy6E2O9yCOQ== dependencies: "@aws-crypto/sha256-browser" "3.0.0" "@aws-crypto/sha256-js" "3.0.0" - "@aws-sdk/client-sts" "3.312.0" - "@aws-sdk/config-resolver" "3.310.0" - "@aws-sdk/credential-provider-node" "3.310.0" - "@aws-sdk/fetch-http-handler" "3.310.0" - "@aws-sdk/hash-node" "3.310.0" - "@aws-sdk/invalid-dependency" "3.310.0" - "@aws-sdk/middleware-content-length" "3.310.0" - "@aws-sdk/middleware-endpoint" "3.310.0" - "@aws-sdk/middleware-host-header" "3.310.0" - "@aws-sdk/middleware-logger" "3.310.0" - "@aws-sdk/middleware-recursion-detection" "3.310.0" - "@aws-sdk/middleware-retry" "3.310.0" - "@aws-sdk/middleware-serde" "3.310.0" - "@aws-sdk/middleware-signing" "3.310.0" - "@aws-sdk/middleware-stack" "3.310.0" - "@aws-sdk/middleware-user-agent" "3.310.0" - "@aws-sdk/node-config-provider" "3.310.0" - "@aws-sdk/node-http-handler" "3.310.0" - "@aws-sdk/protocol-http" "3.310.0" - "@aws-sdk/smithy-client" "3.310.0" - "@aws-sdk/types" "3.310.0" - "@aws-sdk/url-parser" "3.310.0" + "@aws-sdk/client-sts" "3.332.0" + "@aws-sdk/config-resolver" "3.329.0" + "@aws-sdk/credential-provider-node" "3.332.0" + "@aws-sdk/fetch-http-handler" "3.329.0" + "@aws-sdk/hash-node" "3.329.0" + "@aws-sdk/invalid-dependency" "3.329.0" + "@aws-sdk/middleware-content-length" "3.329.0" + "@aws-sdk/middleware-endpoint" "3.329.0" + "@aws-sdk/middleware-host-header" "3.329.0" + "@aws-sdk/middleware-logger" "3.329.0" + "@aws-sdk/middleware-recursion-detection" "3.329.0" + "@aws-sdk/middleware-retry" "3.329.0" + "@aws-sdk/middleware-serde" "3.329.0" + "@aws-sdk/middleware-signing" "3.329.0" + "@aws-sdk/middleware-stack" "3.329.0" + "@aws-sdk/middleware-user-agent" "3.332.0" + "@aws-sdk/node-config-provider" "3.329.0" + "@aws-sdk/node-http-handler" "3.329.0" + "@aws-sdk/protocol-http" "3.329.0" + "@aws-sdk/smithy-client" "3.329.0" + "@aws-sdk/types" "3.329.0" + "@aws-sdk/url-parser" "3.329.0" "@aws-sdk/util-base64" "3.310.0" "@aws-sdk/util-body-length-browser" "3.310.0" "@aws-sdk/util-body-length-node" "3.310.0" - "@aws-sdk/util-defaults-mode-browser" "3.310.0" - "@aws-sdk/util-defaults-mode-node" "3.310.0" - "@aws-sdk/util-endpoints" "3.310.0" - "@aws-sdk/util-retry" "3.310.0" - "@aws-sdk/util-user-agent-browser" "3.310.0" - "@aws-sdk/util-user-agent-node" "3.310.0" + "@aws-sdk/util-defaults-mode-browser" "3.329.0" + "@aws-sdk/util-defaults-mode-node" "3.329.0" + "@aws-sdk/util-endpoints" "3.332.0" + "@aws-sdk/util-retry" "3.329.0" + "@aws-sdk/util-user-agent-browser" "3.329.0" + "@aws-sdk/util-user-agent-node" "3.329.0" "@aws-sdk/util-utf8" "3.310.0" tslib "^2.5.0" uuid "^8.3.2" -"@aws-sdk/client-ec2@3.312.0": - version "3.312.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/client-ec2/-/client-ec2-3.312.0.tgz#df61677afcade8069221e13f4e94dd8f85aec246" - integrity sha512-WybuBygd5v9MfZ1gNnzRkS5ArnoG4wclkHhC1gUb4ylNqptzN9gezUgTR1l9Nfr9V6487r/O0yao2VcdUApAZg== +"@aws-sdk/client-ec2@3.332.0": + version "3.332.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-ec2/-/client-ec2-3.332.0.tgz#886894ed2d31457b3cb463109378f0d184d6ff8a" + integrity sha512-CKKzcxrFN3/yAw6rTG4/WUUxewTw8Yo08SN7T97uXVjqomoCn7ikqRtjESDFD7bsoELCJCDzH/ofJVkm2wnQjQ== dependencies: "@aws-crypto/sha256-browser" "3.0.0" "@aws-crypto/sha256-js" "3.0.0" - "@aws-sdk/client-sts" "3.312.0" - "@aws-sdk/config-resolver" "3.310.0" - "@aws-sdk/credential-provider-node" "3.310.0" - "@aws-sdk/fetch-http-handler" "3.310.0" - "@aws-sdk/hash-node" "3.310.0" - "@aws-sdk/invalid-dependency" "3.310.0" - "@aws-sdk/middleware-content-length" "3.310.0" - "@aws-sdk/middleware-endpoint" "3.310.0" - "@aws-sdk/middleware-host-header" "3.310.0" - "@aws-sdk/middleware-logger" "3.310.0" - "@aws-sdk/middleware-recursion-detection" "3.310.0" - "@aws-sdk/middleware-retry" "3.310.0" - "@aws-sdk/middleware-sdk-ec2" "3.311.0" - "@aws-sdk/middleware-serde" "3.310.0" - "@aws-sdk/middleware-signing" "3.310.0" - "@aws-sdk/middleware-stack" "3.310.0" - "@aws-sdk/middleware-user-agent" "3.310.0" - "@aws-sdk/node-config-provider" "3.310.0" - "@aws-sdk/node-http-handler" "3.310.0" - "@aws-sdk/protocol-http" "3.310.0" - "@aws-sdk/smithy-client" "3.310.0" - "@aws-sdk/types" "3.310.0" - "@aws-sdk/url-parser" "3.310.0" + "@aws-sdk/client-sts" "3.332.0" + "@aws-sdk/config-resolver" "3.329.0" + "@aws-sdk/credential-provider-node" "3.332.0" + "@aws-sdk/fetch-http-handler" "3.329.0" + "@aws-sdk/hash-node" "3.329.0" + "@aws-sdk/invalid-dependency" "3.329.0" + "@aws-sdk/middleware-content-length" "3.329.0" + "@aws-sdk/middleware-endpoint" "3.329.0" + "@aws-sdk/middleware-host-header" "3.329.0" + "@aws-sdk/middleware-logger" "3.329.0" + "@aws-sdk/middleware-recursion-detection" "3.329.0" + "@aws-sdk/middleware-retry" "3.329.0" + "@aws-sdk/middleware-sdk-ec2" "3.329.0" + "@aws-sdk/middleware-serde" "3.329.0" + "@aws-sdk/middleware-signing" "3.329.0" + "@aws-sdk/middleware-stack" "3.329.0" + "@aws-sdk/middleware-user-agent" "3.332.0" + "@aws-sdk/node-config-provider" "3.329.0" + "@aws-sdk/node-http-handler" "3.329.0" + "@aws-sdk/protocol-http" "3.329.0" + "@aws-sdk/smithy-client" "3.329.0" + "@aws-sdk/types" "3.329.0" + "@aws-sdk/url-parser" "3.329.0" "@aws-sdk/util-base64" "3.310.0" "@aws-sdk/util-body-length-browser" "3.310.0" "@aws-sdk/util-body-length-node" "3.310.0" - "@aws-sdk/util-defaults-mode-browser" "3.310.0" - "@aws-sdk/util-defaults-mode-node" "3.310.0" - "@aws-sdk/util-endpoints" "3.310.0" - "@aws-sdk/util-retry" "3.310.0" - "@aws-sdk/util-user-agent-browser" "3.310.0" - "@aws-sdk/util-user-agent-node" "3.310.0" + "@aws-sdk/util-defaults-mode-browser" "3.329.0" + "@aws-sdk/util-defaults-mode-node" "3.329.0" + "@aws-sdk/util-endpoints" "3.332.0" + "@aws-sdk/util-retry" "3.329.0" + "@aws-sdk/util-user-agent-browser" "3.329.0" + "@aws-sdk/util-user-agent-node" "3.329.0" "@aws-sdk/util-utf8" "3.310.0" - "@aws-sdk/util-waiter" "3.310.0" + "@aws-sdk/util-waiter" "3.329.0" fast-xml-parser "4.1.2" tslib "^2.5.0" uuid "^8.3.2" -"@aws-sdk/client-ecr@3.312.0": - version "3.312.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/client-ecr/-/client-ecr-3.312.0.tgz#8425c3305e8e2353f9ec39468bed88e21b44bb15" - integrity sha512-MeVhOOm73m9WPXT+6RIQqrHermOtf6S3QmpdZRHOBj5IVZ+004e+Hxe1sbJZY2TG/r90vDtcU9LwTwQQhbyLKQ== +"@aws-sdk/client-ecr@3.332.0": + version "3.332.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-ecr/-/client-ecr-3.332.0.tgz#a19c3bd6e6f768bb2502671251145f02dd150f7d" + integrity sha512-HnOXI8k3SgnbWfK2iExcW3jUEwJBL687IFvYXmHz9nGcbDhrxluVWStC1X8YkB/ftaRCNFw7U/g5pcZiyOESAw== dependencies: "@aws-crypto/sha256-browser" "3.0.0" "@aws-crypto/sha256-js" "3.0.0" - "@aws-sdk/client-sts" "3.312.0" - "@aws-sdk/config-resolver" "3.310.0" - "@aws-sdk/credential-provider-node" "3.310.0" - "@aws-sdk/fetch-http-handler" "3.310.0" - "@aws-sdk/hash-node" "3.310.0" - "@aws-sdk/invalid-dependency" "3.310.0" - "@aws-sdk/middleware-content-length" "3.310.0" - "@aws-sdk/middleware-endpoint" "3.310.0" - "@aws-sdk/middleware-host-header" "3.310.0" - "@aws-sdk/middleware-logger" "3.310.0" - "@aws-sdk/middleware-recursion-detection" "3.310.0" - "@aws-sdk/middleware-retry" "3.310.0" - "@aws-sdk/middleware-serde" "3.310.0" - "@aws-sdk/middleware-signing" "3.310.0" - "@aws-sdk/middleware-stack" "3.310.0" - "@aws-sdk/middleware-user-agent" "3.310.0" - "@aws-sdk/node-config-provider" "3.310.0" - "@aws-sdk/node-http-handler" "3.310.0" - "@aws-sdk/protocol-http" "3.310.0" - "@aws-sdk/smithy-client" "3.310.0" - "@aws-sdk/types" "3.310.0" - "@aws-sdk/url-parser" "3.310.0" + "@aws-sdk/client-sts" "3.332.0" + "@aws-sdk/config-resolver" "3.329.0" + "@aws-sdk/credential-provider-node" "3.332.0" + "@aws-sdk/fetch-http-handler" "3.329.0" + "@aws-sdk/hash-node" "3.329.0" + "@aws-sdk/invalid-dependency" "3.329.0" + "@aws-sdk/middleware-content-length" "3.329.0" + "@aws-sdk/middleware-endpoint" "3.329.0" + "@aws-sdk/middleware-host-header" "3.329.0" + "@aws-sdk/middleware-logger" "3.329.0" + "@aws-sdk/middleware-recursion-detection" "3.329.0" + "@aws-sdk/middleware-retry" "3.329.0" + "@aws-sdk/middleware-serde" "3.329.0" + "@aws-sdk/middleware-signing" "3.329.0" + "@aws-sdk/middleware-stack" "3.329.0" + "@aws-sdk/middleware-user-agent" "3.332.0" + "@aws-sdk/node-config-provider" "3.329.0" + "@aws-sdk/node-http-handler" "3.329.0" + "@aws-sdk/protocol-http" "3.329.0" + "@aws-sdk/smithy-client" "3.329.0" + "@aws-sdk/types" "3.329.0" + "@aws-sdk/url-parser" "3.329.0" "@aws-sdk/util-base64" "3.310.0" "@aws-sdk/util-body-length-browser" "3.310.0" "@aws-sdk/util-body-length-node" "3.310.0" - "@aws-sdk/util-defaults-mode-browser" "3.310.0" - "@aws-sdk/util-defaults-mode-node" "3.310.0" - "@aws-sdk/util-endpoints" "3.310.0" - "@aws-sdk/util-retry" "3.310.0" - "@aws-sdk/util-user-agent-browser" "3.310.0" - "@aws-sdk/util-user-agent-node" "3.310.0" + "@aws-sdk/util-defaults-mode-browser" "3.329.0" + "@aws-sdk/util-defaults-mode-node" "3.329.0" + "@aws-sdk/util-endpoints" "3.332.0" + "@aws-sdk/util-retry" "3.329.0" + "@aws-sdk/util-user-agent-browser" "3.329.0" + "@aws-sdk/util-user-agent-node" "3.329.0" "@aws-sdk/util-utf8" "3.310.0" - "@aws-sdk/util-waiter" "3.310.0" + "@aws-sdk/util-waiter" "3.329.0" tslib "^2.5.0" -"@aws-sdk/client-iam@3.312.0": - version "3.312.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/client-iam/-/client-iam-3.312.0.tgz#dd66540cd5ecbdf65bb4853c2511159d0bc4a1a7" - integrity sha512-x2jF7teKZ/DbrRreVdLTddJOKDDJ81TVKGklJyB4YJgARAlrwfxxC7jAp9sF+T/HlnZ2HmLkdn1Tan4rVTetEA== +"@aws-sdk/client-iam@3.332.0": + version "3.332.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-iam/-/client-iam-3.332.0.tgz#fb311fdf00947d44ca073662db24f4153ae81038" + integrity sha512-V8vbA0o2+uHIyXnaSCFkZCPX13Gbqom4AdPjn7izf8cCTTW6CInjckZGQczqohEXxOx46RGxKlmulftplQ80Og== dependencies: "@aws-crypto/sha256-browser" "3.0.0" "@aws-crypto/sha256-js" "3.0.0" - "@aws-sdk/client-sts" "3.312.0" - "@aws-sdk/config-resolver" "3.310.0" - "@aws-sdk/credential-provider-node" "3.310.0" - "@aws-sdk/fetch-http-handler" "3.310.0" - "@aws-sdk/hash-node" "3.310.0" - "@aws-sdk/invalid-dependency" "3.310.0" - "@aws-sdk/middleware-content-length" "3.310.0" - "@aws-sdk/middleware-endpoint" "3.310.0" - "@aws-sdk/middleware-host-header" "3.310.0" - "@aws-sdk/middleware-logger" "3.310.0" - "@aws-sdk/middleware-recursion-detection" "3.310.0" - "@aws-sdk/middleware-retry" "3.310.0" - "@aws-sdk/middleware-serde" "3.310.0" - "@aws-sdk/middleware-signing" "3.310.0" - "@aws-sdk/middleware-stack" "3.310.0" - "@aws-sdk/middleware-user-agent" "3.310.0" - "@aws-sdk/node-config-provider" "3.310.0" - "@aws-sdk/node-http-handler" "3.310.0" - "@aws-sdk/protocol-http" "3.310.0" - "@aws-sdk/smithy-client" "3.310.0" - "@aws-sdk/types" "3.310.0" - "@aws-sdk/url-parser" "3.310.0" + "@aws-sdk/client-sts" "3.332.0" + "@aws-sdk/config-resolver" "3.329.0" + "@aws-sdk/credential-provider-node" "3.332.0" + "@aws-sdk/fetch-http-handler" "3.329.0" + "@aws-sdk/hash-node" "3.329.0" + "@aws-sdk/invalid-dependency" "3.329.0" + "@aws-sdk/middleware-content-length" "3.329.0" + "@aws-sdk/middleware-endpoint" "3.329.0" + "@aws-sdk/middleware-host-header" "3.329.0" + "@aws-sdk/middleware-logger" "3.329.0" + "@aws-sdk/middleware-recursion-detection" "3.329.0" + "@aws-sdk/middleware-retry" "3.329.0" + "@aws-sdk/middleware-serde" "3.329.0" + "@aws-sdk/middleware-signing" "3.329.0" + "@aws-sdk/middleware-stack" "3.329.0" + "@aws-sdk/middleware-user-agent" "3.332.0" + "@aws-sdk/node-config-provider" "3.329.0" + "@aws-sdk/node-http-handler" "3.329.0" + "@aws-sdk/protocol-http" "3.329.0" + "@aws-sdk/smithy-client" "3.329.0" + "@aws-sdk/types" "3.329.0" + "@aws-sdk/url-parser" "3.329.0" "@aws-sdk/util-base64" "3.310.0" "@aws-sdk/util-body-length-browser" "3.310.0" "@aws-sdk/util-body-length-node" "3.310.0" - "@aws-sdk/util-defaults-mode-browser" "3.310.0" - "@aws-sdk/util-defaults-mode-node" "3.310.0" - "@aws-sdk/util-endpoints" "3.310.0" - "@aws-sdk/util-retry" "3.310.0" - "@aws-sdk/util-user-agent-browser" "3.310.0" - "@aws-sdk/util-user-agent-node" "3.310.0" + "@aws-sdk/util-defaults-mode-browser" "3.329.0" + "@aws-sdk/util-defaults-mode-node" "3.329.0" + "@aws-sdk/util-endpoints" "3.332.0" + "@aws-sdk/util-retry" "3.329.0" + "@aws-sdk/util-user-agent-browser" "3.329.0" + "@aws-sdk/util-user-agent-node" "3.329.0" "@aws-sdk/util-utf8" "3.310.0" - "@aws-sdk/util-waiter" "3.310.0" + "@aws-sdk/util-waiter" "3.329.0" fast-xml-parser "4.1.2" tslib "^2.5.0" -"@aws-sdk/client-rds@3.314.0": - version "3.314.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/client-rds/-/client-rds-3.314.0.tgz#8e9cc272a2acfbbc3c976dec1db13f84c4b2fc44" - integrity sha512-+jvimITTzmDkMNwAh2vV4+r22GZWF1TCdCiQqB1+djApmfifUFSEGyDrNRpHOKYeBhDR6mHPVC+qW5hs8XWr6A== +"@aws-sdk/client-rds@3.332.0": + version "3.332.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-rds/-/client-rds-3.332.0.tgz#beb502f6c62f139065981daed90ba4c5a08be6b8" + integrity sha512-idI0Bt5HyUo3Wqcero3VDxRZb0HyZG2Tc8xJHvb29KSFwHezBWQDLi9jbuSMId6HPlA3/IGyQ1ixLEHtJDgICQ== dependencies: "@aws-crypto/sha256-browser" "3.0.0" "@aws-crypto/sha256-js" "3.0.0" - "@aws-sdk/client-sts" "3.312.0" - "@aws-sdk/config-resolver" "3.310.0" - "@aws-sdk/credential-provider-node" "3.310.0" - "@aws-sdk/fetch-http-handler" "3.310.0" - "@aws-sdk/hash-node" "3.310.0" - "@aws-sdk/invalid-dependency" "3.310.0" - "@aws-sdk/middleware-content-length" "3.310.0" - "@aws-sdk/middleware-endpoint" "3.310.0" - "@aws-sdk/middleware-host-header" "3.310.0" - "@aws-sdk/middleware-logger" "3.310.0" - "@aws-sdk/middleware-recursion-detection" "3.310.0" - "@aws-sdk/middleware-retry" "3.310.0" - "@aws-sdk/middleware-sdk-rds" "3.310.0" - "@aws-sdk/middleware-serde" "3.310.0" - "@aws-sdk/middleware-signing" "3.310.0" - "@aws-sdk/middleware-stack" "3.310.0" - "@aws-sdk/middleware-user-agent" "3.310.0" - "@aws-sdk/node-config-provider" "3.310.0" - "@aws-sdk/node-http-handler" "3.310.0" - "@aws-sdk/protocol-http" "3.310.0" - "@aws-sdk/smithy-client" "3.310.0" - "@aws-sdk/types" "3.310.0" - "@aws-sdk/url-parser" "3.310.0" + "@aws-sdk/client-sts" "3.332.0" + "@aws-sdk/config-resolver" "3.329.0" + "@aws-sdk/credential-provider-node" "3.332.0" + "@aws-sdk/fetch-http-handler" "3.329.0" + "@aws-sdk/hash-node" "3.329.0" + "@aws-sdk/invalid-dependency" "3.329.0" + "@aws-sdk/middleware-content-length" "3.329.0" + "@aws-sdk/middleware-endpoint" "3.329.0" + "@aws-sdk/middleware-host-header" "3.329.0" + "@aws-sdk/middleware-logger" "3.329.0" + "@aws-sdk/middleware-recursion-detection" "3.329.0" + "@aws-sdk/middleware-retry" "3.329.0" + "@aws-sdk/middleware-sdk-rds" "3.329.0" + "@aws-sdk/middleware-serde" "3.329.0" + "@aws-sdk/middleware-signing" "3.329.0" + "@aws-sdk/middleware-stack" "3.329.0" + "@aws-sdk/middleware-user-agent" "3.332.0" + "@aws-sdk/node-config-provider" "3.329.0" + "@aws-sdk/node-http-handler" "3.329.0" + "@aws-sdk/protocol-http" "3.329.0" + "@aws-sdk/smithy-client" "3.329.0" + "@aws-sdk/types" "3.329.0" + "@aws-sdk/url-parser" "3.329.0" "@aws-sdk/util-base64" "3.310.0" "@aws-sdk/util-body-length-browser" "3.310.0" "@aws-sdk/util-body-length-node" "3.310.0" - "@aws-sdk/util-defaults-mode-browser" "3.310.0" - "@aws-sdk/util-defaults-mode-node" "3.310.0" - "@aws-sdk/util-endpoints" "3.310.0" - "@aws-sdk/util-retry" "3.310.0" - "@aws-sdk/util-user-agent-browser" "3.310.0" - "@aws-sdk/util-user-agent-node" "3.310.0" + "@aws-sdk/util-defaults-mode-browser" "3.329.0" + "@aws-sdk/util-defaults-mode-node" "3.329.0" + "@aws-sdk/util-endpoints" "3.332.0" + "@aws-sdk/util-retry" "3.329.0" + "@aws-sdk/util-user-agent-browser" "3.329.0" + "@aws-sdk/util-user-agent-node" "3.329.0" "@aws-sdk/util-utf8" "3.310.0" - "@aws-sdk/util-waiter" "3.310.0" + "@aws-sdk/util-waiter" "3.329.0" fast-xml-parser "4.1.2" tslib "^2.5.0" -"@aws-sdk/client-s3@3.312.0": - version "3.312.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/client-s3/-/client-s3-3.312.0.tgz#d5f286f38db04612dad46407d0115e7a5755e8a1" - integrity sha512-aqlll2g7eKwV0j+IAK4Ly7c0CRVSI712VTdItAWpLSQPw1VVUP9IKaIsBTiigoOBCJq+fb2+ufFrSTUAPdEzPQ== +"@aws-sdk/client-s3@3.332.0": + version "3.332.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-s3/-/client-s3-3.332.0.tgz#99488145424265e87e55cbc740f3bed8751116ed" + integrity sha512-4AkbBPGjFkIvN15l9uDHcry3kwMknpl0b7mqFaNQqQJR2OyFJnr7US/KyeTjwijJAuU+f7lKz8QMTtBcghJm3w== dependencies: "@aws-crypto/sha1-browser" "3.0.0" "@aws-crypto/sha256-browser" "3.0.0" "@aws-crypto/sha256-js" "3.0.0" - "@aws-sdk/client-sts" "3.312.0" - "@aws-sdk/config-resolver" "3.310.0" - "@aws-sdk/credential-provider-node" "3.310.0" - "@aws-sdk/eventstream-serde-browser" "3.310.0" - "@aws-sdk/eventstream-serde-config-resolver" "3.310.0" - "@aws-sdk/eventstream-serde-node" "3.310.0" - "@aws-sdk/fetch-http-handler" "3.310.0" - "@aws-sdk/hash-blob-browser" "3.310.0" - "@aws-sdk/hash-node" "3.310.0" - "@aws-sdk/hash-stream-node" "3.310.0" - "@aws-sdk/invalid-dependency" "3.310.0" - "@aws-sdk/md5-js" "3.310.0" - "@aws-sdk/middleware-bucket-endpoint" "3.310.0" - "@aws-sdk/middleware-content-length" "3.310.0" - "@aws-sdk/middleware-endpoint" "3.310.0" - "@aws-sdk/middleware-expect-continue" "3.310.0" - "@aws-sdk/middleware-flexible-checksums" "3.310.0" - "@aws-sdk/middleware-host-header" "3.310.0" - "@aws-sdk/middleware-location-constraint" "3.310.0" - "@aws-sdk/middleware-logger" "3.310.0" - "@aws-sdk/middleware-recursion-detection" "3.310.0" - "@aws-sdk/middleware-retry" "3.310.0" - "@aws-sdk/middleware-sdk-s3" "3.310.0" - "@aws-sdk/middleware-serde" "3.310.0" - "@aws-sdk/middleware-signing" "3.310.0" - "@aws-sdk/middleware-ssec" "3.310.0" - "@aws-sdk/middleware-stack" "3.310.0" - "@aws-sdk/middleware-user-agent" "3.310.0" - "@aws-sdk/node-config-provider" "3.310.0" - "@aws-sdk/node-http-handler" "3.310.0" - "@aws-sdk/protocol-http" "3.310.0" - "@aws-sdk/signature-v4-multi-region" "3.310.0" - "@aws-sdk/smithy-client" "3.310.0" - "@aws-sdk/types" "3.310.0" - "@aws-sdk/url-parser" "3.310.0" + "@aws-sdk/client-sts" "3.332.0" + "@aws-sdk/config-resolver" "3.329.0" + "@aws-sdk/credential-provider-node" "3.332.0" + "@aws-sdk/eventstream-serde-browser" "3.329.0" + "@aws-sdk/eventstream-serde-config-resolver" "3.329.0" + "@aws-sdk/eventstream-serde-node" "3.329.0" + "@aws-sdk/fetch-http-handler" "3.329.0" + "@aws-sdk/hash-blob-browser" "3.329.0" + "@aws-sdk/hash-node" "3.329.0" + "@aws-sdk/hash-stream-node" "3.329.0" + "@aws-sdk/invalid-dependency" "3.329.0" + "@aws-sdk/md5-js" "3.329.0" + "@aws-sdk/middleware-bucket-endpoint" "3.329.0" + "@aws-sdk/middleware-content-length" "3.329.0" + "@aws-sdk/middleware-endpoint" "3.329.0" + "@aws-sdk/middleware-expect-continue" "3.329.0" + "@aws-sdk/middleware-flexible-checksums" "3.331.0" + "@aws-sdk/middleware-host-header" "3.329.0" + "@aws-sdk/middleware-location-constraint" "3.329.0" + "@aws-sdk/middleware-logger" "3.329.0" + "@aws-sdk/middleware-recursion-detection" "3.329.0" + "@aws-sdk/middleware-retry" "3.329.0" + "@aws-sdk/middleware-sdk-s3" "3.329.0" + "@aws-sdk/middleware-serde" "3.329.0" + "@aws-sdk/middleware-signing" "3.329.0" + "@aws-sdk/middleware-ssec" "3.329.0" + "@aws-sdk/middleware-stack" "3.329.0" + "@aws-sdk/middleware-user-agent" "3.332.0" + "@aws-sdk/node-config-provider" "3.329.0" + "@aws-sdk/node-http-handler" "3.329.0" + "@aws-sdk/protocol-http" "3.329.0" + "@aws-sdk/signature-v4-multi-region" "3.329.0" + "@aws-sdk/smithy-client" "3.329.0" + "@aws-sdk/types" "3.329.0" + "@aws-sdk/url-parser" "3.329.0" "@aws-sdk/util-base64" "3.310.0" "@aws-sdk/util-body-length-browser" "3.310.0" "@aws-sdk/util-body-length-node" "3.310.0" - "@aws-sdk/util-defaults-mode-browser" "3.310.0" - "@aws-sdk/util-defaults-mode-node" "3.310.0" - "@aws-sdk/util-endpoints" "3.310.0" - "@aws-sdk/util-retry" "3.310.0" - "@aws-sdk/util-stream-browser" "3.310.0" - "@aws-sdk/util-stream-node" "3.310.0" - "@aws-sdk/util-user-agent-browser" "3.310.0" - "@aws-sdk/util-user-agent-node" "3.310.0" + "@aws-sdk/util-defaults-mode-browser" "3.329.0" + "@aws-sdk/util-defaults-mode-node" "3.329.0" + "@aws-sdk/util-endpoints" "3.332.0" + "@aws-sdk/util-retry" "3.329.0" + "@aws-sdk/util-stream-browser" "3.329.0" + "@aws-sdk/util-stream-node" "3.331.0" + "@aws-sdk/util-user-agent-browser" "3.329.0" + "@aws-sdk/util-user-agent-node" "3.329.0" "@aws-sdk/util-utf8" "3.310.0" - "@aws-sdk/util-waiter" "3.310.0" + "@aws-sdk/util-waiter" "3.329.0" "@aws-sdk/xml-builder" "3.310.0" fast-xml-parser "4.1.2" tslib "^2.5.0" -"@aws-sdk/client-sso-oidc@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.310.0.tgz#f71eeb9cc73c13661728cf88d8513b0209b6d265" - integrity sha512-3GKaRSfMD3OiYWGa+qg5KvJw0nLV0Vu7zRiulLuKDvgmWw3SNJKn3frWlmq/bKFUKahLsV8zozbeJItxtKAD6g== +"@aws-sdk/client-sso-oidc@3.332.0": + version "3.332.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.332.0.tgz#8875ce4834d5d0decefadec828e32cbc0465fc30" + integrity sha512-tz8k8Yqm4TScIfit0Tum2zWAq1md+gZKr747CSixd4Zwcp7Vwh75cRoL7Rz1ZHSEn1Yo983MWREevVez3SubLw== dependencies: "@aws-crypto/sha256-browser" "3.0.0" "@aws-crypto/sha256-js" "3.0.0" - "@aws-sdk/config-resolver" "3.310.0" - "@aws-sdk/fetch-http-handler" "3.310.0" - "@aws-sdk/hash-node" "3.310.0" - "@aws-sdk/invalid-dependency" "3.310.0" - "@aws-sdk/middleware-content-length" "3.310.0" - "@aws-sdk/middleware-endpoint" "3.310.0" - "@aws-sdk/middleware-host-header" "3.310.0" - "@aws-sdk/middleware-logger" "3.310.0" - "@aws-sdk/middleware-recursion-detection" "3.310.0" - "@aws-sdk/middleware-retry" "3.310.0" - "@aws-sdk/middleware-serde" "3.310.0" - "@aws-sdk/middleware-stack" "3.310.0" - "@aws-sdk/middleware-user-agent" "3.310.0" - "@aws-sdk/node-config-provider" "3.310.0" - "@aws-sdk/node-http-handler" "3.310.0" - "@aws-sdk/protocol-http" "3.310.0" - "@aws-sdk/smithy-client" "3.310.0" - "@aws-sdk/types" "3.310.0" - "@aws-sdk/url-parser" "3.310.0" + "@aws-sdk/config-resolver" "3.329.0" + "@aws-sdk/fetch-http-handler" "3.329.0" + "@aws-sdk/hash-node" "3.329.0" + "@aws-sdk/invalid-dependency" "3.329.0" + "@aws-sdk/middleware-content-length" "3.329.0" + "@aws-sdk/middleware-endpoint" "3.329.0" + "@aws-sdk/middleware-host-header" "3.329.0" + "@aws-sdk/middleware-logger" "3.329.0" + "@aws-sdk/middleware-recursion-detection" "3.329.0" + "@aws-sdk/middleware-retry" "3.329.0" + "@aws-sdk/middleware-serde" "3.329.0" + "@aws-sdk/middleware-stack" "3.329.0" + "@aws-sdk/middleware-user-agent" "3.332.0" + "@aws-sdk/node-config-provider" "3.329.0" + "@aws-sdk/node-http-handler" "3.329.0" + "@aws-sdk/protocol-http" "3.329.0" + "@aws-sdk/smithy-client" "3.329.0" + "@aws-sdk/types" "3.329.0" + "@aws-sdk/url-parser" "3.329.0" "@aws-sdk/util-base64" "3.310.0" "@aws-sdk/util-body-length-browser" "3.310.0" "@aws-sdk/util-body-length-node" "3.310.0" - "@aws-sdk/util-defaults-mode-browser" "3.310.0" - "@aws-sdk/util-defaults-mode-node" "3.310.0" - "@aws-sdk/util-endpoints" "3.310.0" - "@aws-sdk/util-retry" "3.310.0" - "@aws-sdk/util-user-agent-browser" "3.310.0" - "@aws-sdk/util-user-agent-node" "3.310.0" + "@aws-sdk/util-defaults-mode-browser" "3.329.0" + "@aws-sdk/util-defaults-mode-node" "3.329.0" + "@aws-sdk/util-endpoints" "3.332.0" + "@aws-sdk/util-retry" "3.329.0" + "@aws-sdk/util-user-agent-browser" "3.329.0" + "@aws-sdk/util-user-agent-node" "3.329.0" "@aws-sdk/util-utf8" "3.310.0" tslib "^2.5.0" -"@aws-sdk/client-sso@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/client-sso/-/client-sso-3.310.0.tgz#1ead31442c34ed660479ea9317faab4f1fa47130" - integrity sha512-netFap3Mp9I7bzAjsswHPA5WEbQtNMmXvW9/IVb7tmf85/esXCWindtyI43e/Xerut9ZVyEACPBFn30CLLE2xQ== +"@aws-sdk/client-sso@3.332.0": + version "3.332.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-sso/-/client-sso-3.332.0.tgz#e22fa9ded125cce75ca2cd63d3f3f9a6b8dfaa77" + integrity sha512-4q1Nko8M6YVANdEiLYvdv1qb00j4xN4ppE/6d4xpGp7DxHYlm0GA762h0/TR2dun+2I+SMnwj4Fv6BxOmzBaEw== dependencies: "@aws-crypto/sha256-browser" "3.0.0" "@aws-crypto/sha256-js" "3.0.0" - "@aws-sdk/config-resolver" "3.310.0" - "@aws-sdk/fetch-http-handler" "3.310.0" - "@aws-sdk/hash-node" "3.310.0" - "@aws-sdk/invalid-dependency" "3.310.0" - "@aws-sdk/middleware-content-length" "3.310.0" - "@aws-sdk/middleware-endpoint" "3.310.0" - "@aws-sdk/middleware-host-header" "3.310.0" - "@aws-sdk/middleware-logger" "3.310.0" - "@aws-sdk/middleware-recursion-detection" "3.310.0" - "@aws-sdk/middleware-retry" "3.310.0" - "@aws-sdk/middleware-serde" "3.310.0" - "@aws-sdk/middleware-stack" "3.310.0" - "@aws-sdk/middleware-user-agent" "3.310.0" - "@aws-sdk/node-config-provider" "3.310.0" - "@aws-sdk/node-http-handler" "3.310.0" - "@aws-sdk/protocol-http" "3.310.0" - "@aws-sdk/smithy-client" "3.310.0" - "@aws-sdk/types" "3.310.0" - "@aws-sdk/url-parser" "3.310.0" + "@aws-sdk/config-resolver" "3.329.0" + "@aws-sdk/fetch-http-handler" "3.329.0" + "@aws-sdk/hash-node" "3.329.0" + "@aws-sdk/invalid-dependency" "3.329.0" + "@aws-sdk/middleware-content-length" "3.329.0" + "@aws-sdk/middleware-endpoint" "3.329.0" + "@aws-sdk/middleware-host-header" "3.329.0" + "@aws-sdk/middleware-logger" "3.329.0" + "@aws-sdk/middleware-recursion-detection" "3.329.0" + "@aws-sdk/middleware-retry" "3.329.0" + "@aws-sdk/middleware-serde" "3.329.0" + "@aws-sdk/middleware-stack" "3.329.0" + "@aws-sdk/middleware-user-agent" "3.332.0" + "@aws-sdk/node-config-provider" "3.329.0" + "@aws-sdk/node-http-handler" "3.329.0" + "@aws-sdk/protocol-http" "3.329.0" + "@aws-sdk/smithy-client" "3.329.0" + "@aws-sdk/types" "3.329.0" + "@aws-sdk/url-parser" "3.329.0" "@aws-sdk/util-base64" "3.310.0" "@aws-sdk/util-body-length-browser" "3.310.0" "@aws-sdk/util-body-length-node" "3.310.0" - "@aws-sdk/util-defaults-mode-browser" "3.310.0" - "@aws-sdk/util-defaults-mode-node" "3.310.0" - "@aws-sdk/util-endpoints" "3.310.0" - "@aws-sdk/util-retry" "3.310.0" - "@aws-sdk/util-user-agent-browser" "3.310.0" - "@aws-sdk/util-user-agent-node" "3.310.0" + "@aws-sdk/util-defaults-mode-browser" "3.329.0" + "@aws-sdk/util-defaults-mode-node" "3.329.0" + "@aws-sdk/util-endpoints" "3.332.0" + "@aws-sdk/util-retry" "3.329.0" + "@aws-sdk/util-user-agent-browser" "3.329.0" + "@aws-sdk/util-user-agent-node" "3.329.0" "@aws-sdk/util-utf8" "3.310.0" tslib "^2.5.0" -"@aws-sdk/client-sts@3.312.0": - version "3.312.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/client-sts/-/client-sts-3.312.0.tgz#7b49a04bab2d12a8ca566ef579fd887b71986498" - integrity sha512-t0U7vRvWaMjrzBUo6tPrHe6HE97Blqx+b4GOjFbcbLtzxLlcRfhnWJik0Lp8hJtVqzNoN5mL4OeYgK7CRpL/Sw== +"@aws-sdk/client-sts@3.332.0": + version "3.332.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-sts/-/client-sts-3.332.0.tgz#15bb163319d3da69f152f80fb4583eabe73e0e30" + integrity sha512-uVobnXIzMcEhwBDyk6iOt36N/TRNI8hwq7MQugjYGj7Inma9g4vnR09hXJ24HxyKCoVUoIgMbEguQ43+/+uvDQ== dependencies: "@aws-crypto/sha256-browser" "3.0.0" "@aws-crypto/sha256-js" "3.0.0" - "@aws-sdk/config-resolver" "3.310.0" - "@aws-sdk/credential-provider-node" "3.310.0" - "@aws-sdk/fetch-http-handler" "3.310.0" - "@aws-sdk/hash-node" "3.310.0" - "@aws-sdk/invalid-dependency" "3.310.0" - "@aws-sdk/middleware-content-length" "3.310.0" - "@aws-sdk/middleware-endpoint" "3.310.0" - "@aws-sdk/middleware-host-header" "3.310.0" - "@aws-sdk/middleware-logger" "3.310.0" - "@aws-sdk/middleware-recursion-detection" "3.310.0" - "@aws-sdk/middleware-retry" "3.310.0" - "@aws-sdk/middleware-sdk-sts" "3.310.0" - "@aws-sdk/middleware-serde" "3.310.0" - "@aws-sdk/middleware-signing" "3.310.0" - "@aws-sdk/middleware-stack" "3.310.0" - "@aws-sdk/middleware-user-agent" "3.310.0" - "@aws-sdk/node-config-provider" "3.310.0" - "@aws-sdk/node-http-handler" "3.310.0" - "@aws-sdk/protocol-http" "3.310.0" - "@aws-sdk/smithy-client" "3.310.0" - "@aws-sdk/types" "3.310.0" - "@aws-sdk/url-parser" "3.310.0" + "@aws-sdk/config-resolver" "3.329.0" + "@aws-sdk/credential-provider-node" "3.332.0" + "@aws-sdk/fetch-http-handler" "3.329.0" + "@aws-sdk/hash-node" "3.329.0" + "@aws-sdk/invalid-dependency" "3.329.0" + "@aws-sdk/middleware-content-length" "3.329.0" + "@aws-sdk/middleware-endpoint" "3.329.0" + "@aws-sdk/middleware-host-header" "3.329.0" + "@aws-sdk/middleware-logger" "3.329.0" + "@aws-sdk/middleware-recursion-detection" "3.329.0" + "@aws-sdk/middleware-retry" "3.329.0" + "@aws-sdk/middleware-sdk-sts" "3.329.0" + "@aws-sdk/middleware-serde" "3.329.0" + "@aws-sdk/middleware-signing" "3.329.0" + "@aws-sdk/middleware-stack" "3.329.0" + "@aws-sdk/middleware-user-agent" "3.332.0" + "@aws-sdk/node-config-provider" "3.329.0" + "@aws-sdk/node-http-handler" "3.329.0" + "@aws-sdk/protocol-http" "3.329.0" + "@aws-sdk/smithy-client" "3.329.0" + "@aws-sdk/types" "3.329.0" + "@aws-sdk/url-parser" "3.329.0" "@aws-sdk/util-base64" "3.310.0" "@aws-sdk/util-body-length-browser" "3.310.0" "@aws-sdk/util-body-length-node" "3.310.0" - "@aws-sdk/util-defaults-mode-browser" "3.310.0" - "@aws-sdk/util-defaults-mode-node" "3.310.0" - "@aws-sdk/util-endpoints" "3.310.0" - "@aws-sdk/util-retry" "3.310.0" - "@aws-sdk/util-user-agent-browser" "3.310.0" - "@aws-sdk/util-user-agent-node" "3.310.0" + "@aws-sdk/util-defaults-mode-browser" "3.329.0" + "@aws-sdk/util-defaults-mode-node" "3.329.0" + "@aws-sdk/util-endpoints" "3.332.0" + "@aws-sdk/util-retry" "3.329.0" + "@aws-sdk/util-user-agent-browser" "3.329.0" + "@aws-sdk/util-user-agent-node" "3.329.0" "@aws-sdk/util-utf8" "3.310.0" fast-xml-parser "4.1.2" tslib "^2.5.0" -"@aws-sdk/config-resolver@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/config-resolver/-/config-resolver-3.310.0.tgz#c02dce96546d5cd25551bc89907b27224e16ca7f" - integrity sha512-8vsT+/50lOqfDxka9m/rRt6oxv1WuGZoP8oPMk0Dt+TxXMbAzf4+rejBgiB96wshI1k3gLokYRjSQZn+dDtT8g== +"@aws-sdk/config-resolver@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/config-resolver/-/config-resolver-3.329.0.tgz#f4283c9c8e61752cecad8cfaebb4db52ac1bbf60" + integrity sha512-Oj6eiT3q+Jn685yvUrfRi8PhB3fb81hasJqdrsEivA8IP8qAgnVUTJzXsh8O2UX8UM2MF6A1gTgToSgneJuw2Q== dependencies: - "@aws-sdk/types" "3.310.0" + "@aws-sdk/types" "3.329.0" "@aws-sdk/util-config-provider" "3.310.0" - "@aws-sdk/util-middleware" "3.310.0" + "@aws-sdk/util-middleware" "3.329.0" tslib "^2.5.0" -"@aws-sdk/credential-provider-env@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-env/-/credential-provider-env-3.310.0.tgz#c52694fb276341db6ce4e816cf9ca90fa5830dad" - integrity sha512-vvIPQpI16fj95xwS7M3D48F7QhZJBnnCgB5lR+b7So+vsG9ibm1mZRVGzVpdxCvgyOhHFbvrby9aalNJmmIP1A== +"@aws-sdk/credential-provider-env@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-env/-/credential-provider-env-3.329.0.tgz#54bb313de01324e302b5927733083a4c93ed9962" + integrity sha512-B4orC9hMt9hG82vAR0TAnQqjk6cFDbO2S14RdzUj2n2NPlGWW4Blkv3NTo86K0lq011VRhtqaLcuTwn5EJD5Sg== dependencies: - "@aws-sdk/property-provider" "3.310.0" - "@aws-sdk/types" "3.310.0" + "@aws-sdk/property-provider" "3.329.0" + "@aws-sdk/types" "3.329.0" tslib "^2.5.0" -"@aws-sdk/credential-provider-imds@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-imds/-/credential-provider-imds-3.310.0.tgz#d8fb1223fee7e289a81e28177fe55dedf4d2745e" - integrity sha512-baxK7Zp6dai5AGW01FIW27xS2KAaPUmKLIXv5SvFYsUgXXvNW55im4uG3b+2gA0F7V+hXvVBH08OEqmwW6we5w== +"@aws-sdk/credential-provider-imds@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-imds/-/credential-provider-imds-3.329.0.tgz#566b21c37f5e89730ef3b4229f0824b4c455f669" + integrity sha512-ggPlnd7QROPTid0CwT01TYYGvstRRTpzTGsQ/B31wkh30IrRXE81W3S4xrOYuqQD3u0RnflSxnvhs+EayJEYjg== dependencies: - "@aws-sdk/node-config-provider" "3.310.0" - "@aws-sdk/property-provider" "3.310.0" - "@aws-sdk/types" "3.310.0" - "@aws-sdk/url-parser" "3.310.0" + "@aws-sdk/node-config-provider" "3.329.0" + "@aws-sdk/property-provider" "3.329.0" + "@aws-sdk/types" "3.329.0" + "@aws-sdk/url-parser" "3.329.0" tslib "^2.5.0" -"@aws-sdk/credential-provider-ini@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.310.0.tgz#c317c803b78d6b322a440de15069b35b88c737e5" - integrity sha512-gtRz7I+4BBpwZ3tc6UIt5lQuiAFnkpOibxHh95x1M6HDxBjm+uqD6RPZYVH+dULZPYXOtOTsHV0IGjrcV0sSRg== - dependencies: - "@aws-sdk/credential-provider-env" "3.310.0" - "@aws-sdk/credential-provider-imds" "3.310.0" - "@aws-sdk/credential-provider-process" "3.310.0" - "@aws-sdk/credential-provider-sso" "3.310.0" - "@aws-sdk/credential-provider-web-identity" "3.310.0" - "@aws-sdk/property-provider" "3.310.0" - "@aws-sdk/shared-ini-file-loader" "3.310.0" - "@aws-sdk/types" "3.310.0" +"@aws-sdk/credential-provider-ini@3.332.0": + version "3.332.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.332.0.tgz#03c77480a94d07784c789eeca44ca67c0900ba4a" + integrity sha512-DTW6d6rcqizPVyvcIrwvxecQ7e5GONtVc5Wyf0RTfqf41sDOVZYmn6G+zEFSpBLW0975uZbJS0lyLWtJe2VujQ== + dependencies: + "@aws-sdk/credential-provider-env" "3.329.0" + "@aws-sdk/credential-provider-imds" "3.329.0" + "@aws-sdk/credential-provider-process" "3.329.0" + "@aws-sdk/credential-provider-sso" "3.332.0" + "@aws-sdk/credential-provider-web-identity" "3.329.0" + "@aws-sdk/property-provider" "3.329.0" + "@aws-sdk/shared-ini-file-loader" "3.329.0" + "@aws-sdk/types" "3.329.0" tslib "^2.5.0" -"@aws-sdk/credential-provider-node@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-node/-/credential-provider-node-3.310.0.tgz#e4f69cf95e839c626c41e23b1d8b3cd24c667d8e" - integrity sha512-FrOztUcOq2Sp32xGtJvxfvdlmuAeoxIu/AElHzV1bkx6Pzo9DkQBhXrSQ+JFSpI++weOD4ZGFhAvgbgUOT4VAg== - dependencies: - "@aws-sdk/credential-provider-env" "3.310.0" - "@aws-sdk/credential-provider-imds" "3.310.0" - "@aws-sdk/credential-provider-ini" "3.310.0" - "@aws-sdk/credential-provider-process" "3.310.0" - "@aws-sdk/credential-provider-sso" "3.310.0" - "@aws-sdk/credential-provider-web-identity" "3.310.0" - "@aws-sdk/property-provider" "3.310.0" - "@aws-sdk/shared-ini-file-loader" "3.310.0" - "@aws-sdk/types" "3.310.0" +"@aws-sdk/credential-provider-node@3.332.0": + version "3.332.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-node/-/credential-provider-node-3.332.0.tgz#bfd4fa8855dd3cf80f1e0d8d160966441e44c4a7" + integrity sha512-KkBayS9k4WyJTvC86ngeRM+RmWxNCS1BHvudkR6PLXfnsNPDzxySDVY0UgxVhbNYDYsO561fXZt9ccpKyVWjgg== + dependencies: + "@aws-sdk/credential-provider-env" "3.329.0" + "@aws-sdk/credential-provider-imds" "3.329.0" + "@aws-sdk/credential-provider-ini" "3.332.0" + "@aws-sdk/credential-provider-process" "3.329.0" + "@aws-sdk/credential-provider-sso" "3.332.0" + "@aws-sdk/credential-provider-web-identity" "3.329.0" + "@aws-sdk/property-provider" "3.329.0" + "@aws-sdk/shared-ini-file-loader" "3.329.0" + "@aws-sdk/types" "3.329.0" tslib "^2.5.0" -"@aws-sdk/credential-provider-process@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-process/-/credential-provider-process-3.310.0.tgz#0b2ee77f0c48262442d2768044d72332a4ad8884" - integrity sha512-h73sg6GPMUWC+3zMCbA1nZ2O03nNJt7G96JdmnantiXBwHpRKWW8nBTLzx5uhXn6hTuTaoQRP/P+oxQJKYdMmA== +"@aws-sdk/credential-provider-process@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-process/-/credential-provider-process-3.329.0.tgz#5c07b2f4c67cb97190c69d4af5890c9db3f8a31d" + integrity sha512-5oO220qoFc2pMdZDQa6XN/mVhp669I3+LqMbbscGtX/UgLJPSOb7YzPld9Wjv12L5rf+sD3G1PF3LZXO0vKLFA== dependencies: - "@aws-sdk/property-provider" "3.310.0" - "@aws-sdk/shared-ini-file-loader" "3.310.0" - "@aws-sdk/types" "3.310.0" + "@aws-sdk/property-provider" "3.329.0" + "@aws-sdk/shared-ini-file-loader" "3.329.0" + "@aws-sdk/types" "3.329.0" tslib "^2.5.0" -"@aws-sdk/credential-provider-sso@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.310.0.tgz#86ab095ede5024a4e16aabaf3b2fa92d61656b8d" - integrity sha512-nXkpT8mrM/wRqSiz/a4p9U2UrOKyfZXhbPHIHyQj8K+uLjsYS+WPuH287J4A5Q57A6uarTrj5RjHmVeZVLaHmg== - dependencies: - "@aws-sdk/client-sso" "3.310.0" - "@aws-sdk/property-provider" "3.310.0" - "@aws-sdk/shared-ini-file-loader" "3.310.0" - "@aws-sdk/token-providers" "3.310.0" - "@aws-sdk/types" "3.310.0" +"@aws-sdk/credential-provider-sso@3.332.0": + version "3.332.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.332.0.tgz#ed12b58d30b6ee359462c7e78672734af22fe713" + integrity sha512-SaKXl48af3n6LRitcaEqbeg1YDXwQ0A5QziC1xQyYPraEIj3IZ/GyTjx04Lo2jxNYHuEOE8u4aTw1+IK1GDKbg== + dependencies: + "@aws-sdk/client-sso" "3.332.0" + "@aws-sdk/property-provider" "3.329.0" + "@aws-sdk/shared-ini-file-loader" "3.329.0" + "@aws-sdk/token-providers" "3.332.0" + "@aws-sdk/types" "3.329.0" tslib "^2.5.0" -"@aws-sdk/credential-provider-web-identity@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.310.0.tgz#c9fa09b0068027e58d31178e3fa06bf4e9ae9d36" - integrity sha512-H4SzuZXILNhK6/IR1uVvsUDZvzc051hem7GLyYghBCu8mU+tq28YhKE8MfSroi6eL2e5Vujloij1OM2EQQkPkw== +"@aws-sdk/credential-provider-web-identity@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.329.0.tgz#5610293c03bc4c323dfcae522c545c20e2d8dd86" + integrity sha512-lcEibZD7AlutCacpQ6DyNUqElZJDq+ylaIo5a8MH9jGh7Pg2WpDg0Sy+B6FbGCkVn4eIjdHxeX54JM245nhESg== dependencies: - "@aws-sdk/property-provider" "3.310.0" - "@aws-sdk/types" "3.310.0" + "@aws-sdk/property-provider" "3.329.0" + "@aws-sdk/types" "3.329.0" tslib "^2.5.0" -"@aws-sdk/eventstream-codec@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/eventstream-codec/-/eventstream-codec-3.310.0.tgz#a5def3633f7ccdc3d477fd0b05e2eb31c5598ed9" - integrity sha512-clIeSgWbZbxwtsxZ/yoedNM0/kJFSIjjHPikuDGhxhqc+vP6TN3oYyVMFrYwFaTFhk2+S5wZcWYMw8Op1pWo+A== +"@aws-sdk/eventstream-codec@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/eventstream-codec/-/eventstream-codec-3.329.0.tgz#6bdfd69ad54352309535f53352017e932b9f643b" + integrity sha512-1r+6MNfye0za35FNLxMR5V9zpKY1lyzwySyu7o7aj8lnStBaCcjOEe7iHboP/z3DH73KJbxR++O2N+UC/XHFrg== dependencies: "@aws-crypto/crc32" "3.0.0" - "@aws-sdk/types" "3.310.0" + "@aws-sdk/types" "3.329.0" "@aws-sdk/util-hex-encoding" "3.310.0" tslib "^2.5.0" -"@aws-sdk/eventstream-serde-browser@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/eventstream-serde-browser/-/eventstream-serde-browser-3.310.0.tgz#02aef0262b5f740a1c8ffbdeb8459542f90c14dd" - integrity sha512-3S6ziuQVALgEyz0TANGtYDVeG8ArK4Y05mcgrs8qUTmsvlDIXX37cR/DvmVbNB76M4IrsZeSAIajL9644CywkA== +"@aws-sdk/eventstream-serde-browser@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/eventstream-serde-browser/-/eventstream-serde-browser-3.329.0.tgz#3ba7866a691905e2af8a89c1f562f91fb3779ef9" + integrity sha512-oWFSn4o6sxlbFF0AIuDJYf7N0fkiOyWvYgRW3VTX9FSbd66f/KnDspdxIasaDPDUzJl5YRMwUvQbPWw8y9ZQfQ== dependencies: - "@aws-sdk/eventstream-serde-universal" "3.310.0" - "@aws-sdk/types" "3.310.0" + "@aws-sdk/eventstream-serde-universal" "3.329.0" + "@aws-sdk/types" "3.329.0" tslib "^2.5.0" -"@aws-sdk/eventstream-serde-config-resolver@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-3.310.0.tgz#e4e2358f36b9eb6d37da0a0f0d3fc32da91ad6b4" - integrity sha512-8s1Qdn9STj+sV75nUp9yt0W6fHS4BZ2jTm4Z/1Pcbvh2Gqs0WjH5n2StS+pDW5Y9J/HSGBl0ogmUr5lC5bXFHg== +"@aws-sdk/eventstream-serde-config-resolver@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-3.329.0.tgz#8498747fa40c8cf159181da043fd9b0ae949deb7" + integrity sha512-iQguqvTtxWXAIniaWmmAO0Qy8080fqnS309p9jbYzz7KaT90sNSCX+CxGFHPy5F0QY36uklDdHn1d1fwWTZciA== dependencies: - "@aws-sdk/types" "3.310.0" + "@aws-sdk/types" "3.329.0" tslib "^2.5.0" -"@aws-sdk/eventstream-serde-node@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/eventstream-serde-node/-/eventstream-serde-node-3.310.0.tgz#6e0fbc400bac677c77b946fd2a5cb00b57503c0e" - integrity sha512-kSnRomCgW43K9TmQYuwN9+AoYPnhyOKroanUMyZEzJk7rpCPMj4OzaUpXfDYOvznFNYn7NLaH6nHLJAr0VPlJA== +"@aws-sdk/eventstream-serde-node@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/eventstream-serde-node/-/eventstream-serde-node-3.329.0.tgz#8faf03049bde8772cf75c3831a78df160bbb6ad3" + integrity sha512-+DFia0wdZiHpdOKjBcl1baZjtzPKf4U4MvOpsUpC6CeW1kSy0hoikKzJstNvRb1qxrTSamElT4gKkMHxxVhPBQ== dependencies: - "@aws-sdk/eventstream-serde-universal" "3.310.0" - "@aws-sdk/types" "3.310.0" + "@aws-sdk/eventstream-serde-universal" "3.329.0" + "@aws-sdk/types" "3.329.0" tslib "^2.5.0" -"@aws-sdk/eventstream-serde-universal@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/eventstream-serde-universal/-/eventstream-serde-universal-3.310.0.tgz#d0f95eaafb8fd09d9a21aec8f23b7f3cee2bb19a" - integrity sha512-Qyjt5k/waV5cDukpgT824ISZAz5U0pwzLz5ztR409u85AGNkF/9n7MS+LSyBUBSb0WJ5pUeSD47WBk+nLq9Nhw== +"@aws-sdk/eventstream-serde-universal@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/eventstream-serde-universal/-/eventstream-serde-universal-3.329.0.tgz#c4e4bd786c8e111db8636e76f343c1c08a076c07" + integrity sha512-n9UzW6HKAhVD5wuz3FMC1ew3VI/vUvRSPXGUpKReMiR2z+YyjmuW8UM4nn7q6i7A/I4QHBt1TC/ax/J2yupgPg== dependencies: - "@aws-sdk/eventstream-codec" "3.310.0" - "@aws-sdk/types" "3.310.0" + "@aws-sdk/eventstream-codec" "3.329.0" + "@aws-sdk/types" "3.329.0" tslib "^2.5.0" -"@aws-sdk/fetch-http-handler@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/fetch-http-handler/-/fetch-http-handler-3.310.0.tgz#f31006b7b3103683d72e177cd27d80354f7a37c4" - integrity sha512-Bi9vIwzdkw1zMcvi/zGzlWS9KfIEnAq4NNhsnCxbQ4OoIRU9wvU+WGZdBBhxg0ZxZmpp1j1aZhU53lLjA07MHw== +"@aws-sdk/fetch-http-handler@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/fetch-http-handler/-/fetch-http-handler-3.329.0.tgz#5aee0c9a32ad8ff4fa96c6869bba68c345818532" + integrity sha512-9jfIeJhYCcTX4ScXOueRTB3S/tVce0bRsKxKDP0PnTxnGYOwKXoM9lAPmiYItzYmQ/+QzjTI8xfkA9Usz2SK/Q== dependencies: - "@aws-sdk/protocol-http" "3.310.0" - "@aws-sdk/querystring-builder" "3.310.0" - "@aws-sdk/types" "3.310.0" + "@aws-sdk/protocol-http" "3.329.0" + "@aws-sdk/querystring-builder" "3.329.0" + "@aws-sdk/types" "3.329.0" "@aws-sdk/util-base64" "3.310.0" tslib "^2.5.0" -"@aws-sdk/hash-blob-browser@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/hash-blob-browser/-/hash-blob-browser-3.310.0.tgz#762a56ae655e3bcd0ba46bbc39e8b370b1067629" - integrity sha512-OoR8p0cbypToysLT0v3o2oyjy6+DKrY7GNCAzHOHJK9xmqXCt+DsjKoPeiY7o1sWX2aN6Plmvubj/zWxMKEn/A== +"@aws-sdk/hash-blob-browser@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/hash-blob-browser/-/hash-blob-browser-3.329.0.tgz#a90a73998dd017b80952743a3901d5036e142506" + integrity sha512-F5HwXYYSpJtUJqmCRKbz/xwDdOyxKpu69TlfsliECLvAQiQGMh2GO1wGm7grolgTROVVqLYRKk2TSJl/WBg1pw== dependencies: "@aws-sdk/chunked-blob-reader" "3.310.0" - "@aws-sdk/types" "3.310.0" + "@aws-sdk/types" "3.329.0" tslib "^2.5.0" -"@aws-sdk/hash-node@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/hash-node/-/hash-node-3.310.0.tgz#4c1c89b9a2da3bb9783de84f0b762cc055b90d67" - integrity sha512-NvE2fhRc8GRwCXBfDehxVAWCmVwVMILliAKVPAEr4yz2CkYs0tqU51S48x23dtna07H4qHtgpeNqVTthcIQOEQ== +"@aws-sdk/hash-node@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/hash-node/-/hash-node-3.329.0.tgz#91ef8b1b55e1a438c367f63747673bf146a00499" + integrity sha512-6RmnWXNWpi7yAs0oRDQlkMn2wfXOStr/8kTCgiAiqrk1KopGSBkC2veKiKRSfv02FTd1yV/ISqYNIRqW1VLyxg== dependencies: - "@aws-sdk/types" "3.310.0" + "@aws-sdk/types" "3.329.0" "@aws-sdk/util-buffer-from" "3.310.0" "@aws-sdk/util-utf8" "3.310.0" tslib "^2.5.0" -"@aws-sdk/hash-stream-node@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/hash-stream-node/-/hash-stream-node-3.310.0.tgz#3845d813a7de476c56fac492a50ffa8af265f120" - integrity sha512-ZoXdybNgvMz1Hl6k/e32xVL3jmG5p2IEk5mTtLfFEuskTJ74Z+VMYKkkF1whyy7KQfH83H+TQGnsGtlRCchQKw== +"@aws-sdk/hash-stream-node@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/hash-stream-node/-/hash-stream-node-3.329.0.tgz#137b2bc825a7435514b30a89299b68f33c6e7e9b" + integrity sha512-blSZcb/hJyw3c1bH2Hc1aRoRgruNhRK/qc2svq5kXQFW+qBI5O4fwJayKSdo62/Wh2ejR/N06teYQ9haQLVJEA== dependencies: - "@aws-sdk/types" "3.310.0" + "@aws-sdk/types" "3.329.0" "@aws-sdk/util-utf8" "3.310.0" tslib "^2.5.0" -"@aws-sdk/invalid-dependency@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/invalid-dependency/-/invalid-dependency-3.310.0.tgz#b96da9b9f63b12d1c390f9a06eeb28840fcb5b3c" - integrity sha512-1s5RG5rSPXoa/aZ/Kqr5U/7lqpx+Ry81GprQ2bxWqJvWQIJ0IRUwo5pk8XFxbKVr/2a+4lZT/c3OGoBOM1yRRA== +"@aws-sdk/invalid-dependency@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/invalid-dependency/-/invalid-dependency-3.329.0.tgz#83dc33de710f80eba5e084a82aab656c1d240352" + integrity sha512-UXynGusDxN/HxLma5ByJ7u+XnuMd47NbHOjJgYsaAjb1CVZT7hEPXOB+mcZ+Ku7To5SCOKu2QbRn7m4bGespBg== dependencies: - "@aws-sdk/types" "3.310.0" + "@aws-sdk/types" "3.329.0" tslib "^2.5.0" "@aws-sdk/is-array-buffer@3.310.0": @@ -709,328 +709,335 @@ dependencies: tslib "^2.5.0" -"@aws-sdk/md5-js@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/md5-js/-/md5-js-3.310.0.tgz#14e3d570d92808e68ccc0db8d7492ebdb93f15b5" - integrity sha512-x5sRBUrEfLWAS1EhwbbDQ7cXq6uvBxh3qR2XAsnGvFFceTeAadk7cVogWxlk3PC+OCeeym7c3/6Bv2HQ2f1YyQ== +"@aws-sdk/md5-js@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/md5-js/-/md5-js-3.329.0.tgz#25a6b417ecba04ed4e6b299ad5db0e5ab59c9603" + integrity sha512-newSeHd+CO2hNmXhQOrUk5Y1hH7BsJ5J4IldcqHKY93UwWqvQNiepRowSa2bV5EuS1qx3kfXhD66PFNRprrIlQ== dependencies: - "@aws-sdk/types" "3.310.0" + "@aws-sdk/types" "3.329.0" "@aws-sdk/util-utf8" "3.310.0" tslib "^2.5.0" -"@aws-sdk/middleware-bucket-endpoint@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.310.0.tgz#5dd9b028498a0492c3e773c0aca10d6ded929fc6" - integrity sha512-uJJfHI7v4AgbJZRLtyI8ap2QRWkBokGc3iyUoQ+dVNT3/CE2ZCu694A6W+H0dRqg79dIE+f9CRNdtLGa/Ehhvg== +"@aws-sdk/middleware-bucket-endpoint@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.329.0.tgz#cae414055e1ff7e2f724f7da2feabb93ffffc3a7" + integrity sha512-h3/JdK+FmJ/nxLcd8QciJYLy0B4QRsYqqxSffXJ7DYlDjEhUgvVpfGdVgAYHrTtOP8rHSG/K7l7iY7QqTaZpuw== dependencies: - "@aws-sdk/protocol-http" "3.310.0" - "@aws-sdk/types" "3.310.0" + "@aws-sdk/protocol-http" "3.329.0" + "@aws-sdk/types" "3.329.0" "@aws-sdk/util-arn-parser" "3.310.0" "@aws-sdk/util-config-provider" "3.310.0" tslib "^2.5.0" -"@aws-sdk/middleware-content-length@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-content-length/-/middleware-content-length-3.310.0.tgz#cc9b6c25c10736cec41d0219c94b57cfdb4582a3" - integrity sha512-P8tQZxgDt6CAh1wd/W6WPzjc+uWPJwQkm+F7rAwRlM+k9q17HrhnksGDKcpuuLyIhPQYdmOMIkpKVgXGa4avhQ== +"@aws-sdk/middleware-content-length@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-content-length/-/middleware-content-length-3.329.0.tgz#cadd0c3ba7fe3d0b21812523bb7d7f7526c9c700" + integrity sha512-7kCd+CvY/4KbyXB0uyL7jCwPjMi2yERMALFdEH9dsUciwmxIQT6eSc4aF6wImC4UrbafaqmXvvHErABKMVBTKA== dependencies: - "@aws-sdk/protocol-http" "3.310.0" - "@aws-sdk/types" "3.310.0" + "@aws-sdk/protocol-http" "3.329.0" + "@aws-sdk/types" "3.329.0" tslib "^2.5.0" -"@aws-sdk/middleware-endpoint@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-endpoint/-/middleware-endpoint-3.310.0.tgz#d4bf8ac3cd4800af789d6bcb469b7e8cfa10badb" - integrity sha512-Z+N2vOL8K354/lstkClxLLsr6hCpVRh+0tCMXrVj66/NtKysCEZ/0b9LmqOwD9pWHNiI2mJqXwY0gxNlKAroUg== +"@aws-sdk/middleware-endpoint@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-endpoint/-/middleware-endpoint-3.329.0.tgz#50c5f71afa3b6d3062d3b542279009454898314e" + integrity sha512-hdJRoNdCM0BT4W+rrtee+kfFRgGPGXQDgtbIQlf/FuuuYz2sdef7/SYWr0mxuncnVBW5WkYSPP8h6q07whSKbg== dependencies: - "@aws-sdk/middleware-serde" "3.310.0" - "@aws-sdk/types" "3.310.0" - "@aws-sdk/url-parser" "3.310.0" - "@aws-sdk/util-middleware" "3.310.0" + "@aws-sdk/middleware-serde" "3.329.0" + "@aws-sdk/types" "3.329.0" + "@aws-sdk/url-parser" "3.329.0" + "@aws-sdk/util-middleware" "3.329.0" tslib "^2.5.0" -"@aws-sdk/middleware-expect-continue@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.310.0.tgz#0b5421d5fddb2c0ebf8e5c9c6122d01b159dad45" - integrity sha512-l3d1z2gt+gINJDnPSyu84IxfzjzPfCQrqC1sunw2cZGo/sXtEiq698Q3SiTcO2PGP4LBQAy2RHb5wVBJP708CQ== +"@aws-sdk/middleware-expect-continue@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.329.0.tgz#2a69584020b9c93926b83735fbd9741de117a586" + integrity sha512-E/Jp2KijdR/BwF4s899xcSN4/bbHqYznwmBRL5PiHI+HImA6aZ11qTP8kPt5U5p0l2j5iTmW3FpMnByQKJP5Dw== dependencies: - "@aws-sdk/protocol-http" "3.310.0" - "@aws-sdk/types" "3.310.0" + "@aws-sdk/protocol-http" "3.329.0" + "@aws-sdk/types" "3.329.0" tslib "^2.5.0" -"@aws-sdk/middleware-flexible-checksums@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.310.0.tgz#1bebffe42c4109e255716507b63dc964f84b16a5" - integrity sha512-5ndnLgzgGVpWkmHBAiYkagHqiSuow8q62J4J6E2PzaQ77+fm8W3nfdy7hK5trHokEyouCZdxT/XK/IRhgj/4PA== +"@aws-sdk/middleware-flexible-checksums@3.331.0": + version "3.331.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.331.0.tgz#41878726e7b2da175bfb5b5eb688123c7fb7cce3" + integrity sha512-rdRa4yvyqSQ/HDCh4p1Glv8Y/uRNuIwmOG4nDuL6/GYK1BQdpUpbgrhsszPormku10SnbAdsaWGmVhy3qlUSCQ== dependencies: "@aws-crypto/crc32" "3.0.0" "@aws-crypto/crc32c" "3.0.0" "@aws-sdk/is-array-buffer" "3.310.0" - "@aws-sdk/protocol-http" "3.310.0" - "@aws-sdk/types" "3.310.0" + "@aws-sdk/protocol-http" "3.329.0" + "@aws-sdk/types" "3.329.0" "@aws-sdk/util-utf8" "3.310.0" tslib "^2.5.0" -"@aws-sdk/middleware-host-header@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-host-header/-/middleware-host-header-3.310.0.tgz#bdd4fbffb58b331bda517df8340aa8b44ce55550" - integrity sha512-QWSA+46/hXorXyWa61ic2K7qZzwHTiwfk2e9mRRjeIRepUgI3qxFjsYqrWtrOGBjmFmq0pYIY8Bb/DCJuQqcoA== +"@aws-sdk/middleware-host-header@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-host-header/-/middleware-host-header-3.329.0.tgz#22b1a6d91f3f281ef802f21f2ab0b426526d6066" + integrity sha512-JrHeUdTIpTCfXDo9JpbAbZTS1x4mt63CCytJRq0mpWp+FlP9hjckBcNxWdR/wSKEzP9pDRnTri638BOwWH7O8w== dependencies: - "@aws-sdk/protocol-http" "3.310.0" - "@aws-sdk/types" "3.310.0" + "@aws-sdk/protocol-http" "3.329.0" + "@aws-sdk/types" "3.329.0" tslib "^2.5.0" -"@aws-sdk/middleware-location-constraint@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.310.0.tgz#6a24fa717bff47932d22071861c55421766ecca7" - integrity sha512-LFm0JTQWwTPWL/tZU2wsQTl8J5PpDEkXjEhaXVKamtyH0xhysRqd+0n92n65dc8oztAuQkb9xUbErGn5b6gsew== +"@aws-sdk/middleware-location-constraint@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.329.0.tgz#8f6e21c2eee990579e3ac06bdbb8b89f2cde49a4" + integrity sha512-iUTkyXyhchqoEPkdMZSkHhRQmXe0El1+r9oOw8y9JN6IY0T1bnaqUlerGXzb/tQUeENk9OXYuvDHExegHjEWug== dependencies: - "@aws-sdk/types" "3.310.0" + "@aws-sdk/types" "3.329.0" tslib "^2.5.0" -"@aws-sdk/middleware-logger@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-logger/-/middleware-logger-3.310.0.tgz#8cc6381f49ef867cae1364b8517f939629e4dd9d" - integrity sha512-Lurm8XofrASBRnAVtiSNuDSRsRqPNg27RIFLLsLp/pqog9nFJ0vz0kgdb9S5Z+zw83Mm+UlqOe6D8NTUNp4fVg== +"@aws-sdk/middleware-logger@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-logger/-/middleware-logger-3.329.0.tgz#fa8adc07928da24e713e384d4a32c8d0e36f96ee" + integrity sha512-lKeeTXsYC1NiwmxrXsZepcwNXPoQxTNNbeD1qaCELPGK2cJlrGoeAP2YRWzpwO2kNZWrDLaGAPT/EUEhqw+d1w== dependencies: - "@aws-sdk/types" "3.310.0" + "@aws-sdk/types" "3.329.0" tslib "^2.5.0" -"@aws-sdk/middleware-recursion-detection@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.310.0.tgz#020c986ed8da751bd613fd84c8c8a805c89e0952" - integrity sha512-SuB75/xk/gyue24gkriTwO2jFd7YcUGZDClQYuRejgbXSa3CO0lWyawQtfLcSSEBp9izrEVXuFH24K1eAft5nQ== +"@aws-sdk/middleware-recursion-detection@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.329.0.tgz#afa676f26f9a050cd3d57a2efa2b0247a6e1d614" + integrity sha512-0/TYOJwrj1Z8s+Y7thibD23hggBq/K/01NwPk32CwWG/G+1vWozs5DefknEl++w0vuV+39pkY4KHI8m/+wOCpg== dependencies: - "@aws-sdk/protocol-http" "3.310.0" - "@aws-sdk/types" "3.310.0" + "@aws-sdk/protocol-http" "3.329.0" + "@aws-sdk/types" "3.329.0" tslib "^2.5.0" -"@aws-sdk/middleware-retry@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-retry/-/middleware-retry-3.310.0.tgz#12e95e962875d44af4acbdebe02db337a1ad5c35" - integrity sha512-oTPsRy2W4s+dfxbJPW7Km+hHtv/OMsNsVfThAq8DDYKC13qlr1aAyOqGLD+dpBy2aKe7ss517Sy2HcHtHqm7/g== - dependencies: - "@aws-sdk/protocol-http" "3.310.0" - "@aws-sdk/service-error-classification" "3.310.0" - "@aws-sdk/types" "3.310.0" - "@aws-sdk/util-middleware" "3.310.0" - "@aws-sdk/util-retry" "3.310.0" +"@aws-sdk/middleware-retry@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-retry/-/middleware-retry-3.329.0.tgz#326fb0b7442d665689d311fba43eb49a510d2939" + integrity sha512-cB3D7GlhHUcHGOlygOYxD9cPhwsTYEAMcohK38An8+RHNp6VQEWezzLFCmHVKUSeCQ+wkjZfPA40jOG0rbjSgQ== + dependencies: + "@aws-sdk/protocol-http" "3.329.0" + "@aws-sdk/service-error-classification" "3.329.0" + "@aws-sdk/types" "3.329.0" + "@aws-sdk/util-middleware" "3.329.0" + "@aws-sdk/util-retry" "3.329.0" tslib "^2.5.0" uuid "^8.3.2" -"@aws-sdk/middleware-sdk-ec2@3.311.0": - version "3.311.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-sdk-ec2/-/middleware-sdk-ec2-3.311.0.tgz#313f7e4874be5a0dd07e65c7d2fb9df4807ae230" - integrity sha512-q4VjgBxJCBYpJAV7MDFP8JIvvhMcc2k1mm8RmFkl0YQj0iBQIa6i4+sQ+yoJ/jfwiCrPwSzN7TMrGFcq7fmPDw== - dependencies: - "@aws-sdk/middleware-endpoint" "3.310.0" - "@aws-sdk/protocol-http" "3.310.0" - "@aws-sdk/signature-v4" "3.310.0" - "@aws-sdk/smithy-client" "3.310.0" - "@aws-sdk/types" "3.310.0" - "@aws-sdk/util-format-url" "3.310.0" +"@aws-sdk/middleware-sdk-ec2@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-sdk-ec2/-/middleware-sdk-ec2-3.329.0.tgz#c219d61909d70bb023040e9f77058ef6b34f2e9e" + integrity sha512-V0AAfaNIFz1cLVayLGp+9KjoaIjnAgLd4y6yZKy6M5g6pCpxPKB9hfFjepgpX35xfFnaChS7UqBEUd/PbegcUA== + dependencies: + "@aws-sdk/middleware-endpoint" "3.329.0" + "@aws-sdk/protocol-http" "3.329.0" + "@aws-sdk/signature-v4" "3.329.0" + "@aws-sdk/smithy-client" "3.329.0" + "@aws-sdk/types" "3.329.0" + "@aws-sdk/util-format-url" "3.329.0" tslib "^2.5.0" -"@aws-sdk/middleware-sdk-rds@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-sdk-rds/-/middleware-sdk-rds-3.310.0.tgz#2ecf880063ade9bae8abcfd4fefb386ab29ceb50" - integrity sha512-V1nUsjggGLjy+Hx/z/7tb6bnfzZ1Kx4ikOdYVlTidnSCWZdh+kFE5Em16f5Q3erwG5Sil4Uxk0vpj+MSFP5MKA== - dependencies: - "@aws-sdk/middleware-endpoint" "3.310.0" - "@aws-sdk/protocol-http" "3.310.0" - "@aws-sdk/signature-v4" "3.310.0" - "@aws-sdk/types" "3.310.0" - "@aws-sdk/util-format-url" "3.310.0" +"@aws-sdk/middleware-sdk-rds@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-sdk-rds/-/middleware-sdk-rds-3.329.0.tgz#b7fc6afce0f9899b296d8a6fb9ce9752db21fa78" + integrity sha512-SwID8UbVAKWX/UKL4PGOqRezMG6i8DtARi2252iDRTWE66i+WSjv5XRlxgE++GxfFuwtzO6QM+YdyCPaJGmpgw== + dependencies: + "@aws-sdk/middleware-endpoint" "3.329.0" + "@aws-sdk/protocol-http" "3.329.0" + "@aws-sdk/signature-v4" "3.329.0" + "@aws-sdk/types" "3.329.0" + "@aws-sdk/util-format-url" "3.329.0" tslib "^2.5.0" -"@aws-sdk/middleware-sdk-s3@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.310.0.tgz#9f060e961ccc462ea5ca8c24cb0845d655b00d24" - integrity sha512-QK9x9g2ksg0hOjjYgqddeFcn5ctUEGdxJVu4OumPXceulefMcSO2jyH2qTybYSA93nqNQFdFmg5wQfvIRUWFCQ== +"@aws-sdk/middleware-sdk-s3@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.329.0.tgz#e5b99d7a9074a069c5f75afdce0b91c8b9855112" + integrity sha512-Uo8dLXLDpOb3BnLVl0mkTPiVXlNzNGOXOVtpihvYhF2Z+hGFJW1Ro3aUDbVEsFHu753r2Lss4dLiq1fzREeBKA== dependencies: - "@aws-sdk/protocol-http" "3.310.0" - "@aws-sdk/types" "3.310.0" + "@aws-sdk/protocol-http" "3.329.0" + "@aws-sdk/types" "3.329.0" "@aws-sdk/util-arn-parser" "3.310.0" tslib "^2.5.0" -"@aws-sdk/middleware-sdk-sts@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-sdk-sts/-/middleware-sdk-sts-3.310.0.tgz#2001b421f317404ca98d4a1cfea408b7a64c35f5" - integrity sha512-+5PFwlYNLvLLIfw0ASAoWV/iIF8Zv6R6QGtyP0CclhRSvNjgbQDVnV0g95MC5qvh+GB/Yjlkt8qAjLSPjHfsrQ== +"@aws-sdk/middleware-sdk-sts@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-sdk-sts/-/middleware-sdk-sts-3.329.0.tgz#50056cca7688e708e3db6bd66203878bc373ff7d" + integrity sha512-bqtZuhkH8pANb2Gb4FEM1p27o+BoDBmVhEWm8sWH+APsyOor3jc6eUG2GxkfoO6D5tGNIuyCC/GuvW9XDIe4Kg== dependencies: - "@aws-sdk/middleware-signing" "3.310.0" - "@aws-sdk/types" "3.310.0" + "@aws-sdk/middleware-signing" "3.329.0" + "@aws-sdk/types" "3.329.0" tslib "^2.5.0" -"@aws-sdk/middleware-serde@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-serde/-/middleware-serde-3.310.0.tgz#e334031b66a1a155375ec901478b26570fbe1783" - integrity sha512-RNeeTVWSLTaentUeCgQKZhAl+C6hxtwD78cQWS10UymWpQFwbaxztzKUu4UQS5xA2j6PxwPRRUjqa4jcFjfLsg== +"@aws-sdk/middleware-serde@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-serde/-/middleware-serde-3.329.0.tgz#f822d7419953ba5d31104262724034340908dd28" + integrity sha512-tvM9NdPuRPCozPjTGNOeYZeLlyx3BcEyajrkRorCRf1YzG/mXdB6I1stote7i4q1doFtYTz0sYL8bqW3LUPn9A== dependencies: - "@aws-sdk/types" "3.310.0" + "@aws-sdk/types" "3.329.0" tslib "^2.5.0" -"@aws-sdk/middleware-signing@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-signing/-/middleware-signing-3.310.0.tgz#bd62d5623c80f6318b0d738c44780875500c911a" - integrity sha512-f9mKq+XMdW207Af3hKjdTnpNhdtwqWuvFs/ZyXoOkp/g1MY1O6L23Jy6i52m29LxbT4AuNRG1oKODfXM0vYVjQ== - dependencies: - "@aws-sdk/property-provider" "3.310.0" - "@aws-sdk/protocol-http" "3.310.0" - "@aws-sdk/signature-v4" "3.310.0" - "@aws-sdk/types" "3.310.0" - "@aws-sdk/util-middleware" "3.310.0" +"@aws-sdk/middleware-signing@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-signing/-/middleware-signing-3.329.0.tgz#25011abb0911c1a23840d8d228676758f5b55926" + integrity sha512-bL1nI+EUcF5B1ipwDXxiKL+Uw02Mbt/TNX54PbzunBGZIyO6DZG/H+M3U296bYbvPlwlZhp26O830g6K7VEWsA== + dependencies: + "@aws-sdk/property-provider" "3.329.0" + "@aws-sdk/protocol-http" "3.329.0" + "@aws-sdk/signature-v4" "3.329.0" + "@aws-sdk/types" "3.329.0" + "@aws-sdk/util-middleware" "3.329.0" tslib "^2.5.0" -"@aws-sdk/middleware-ssec@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-ssec/-/middleware-ssec-3.310.0.tgz#6a1da92cbc1734604295149c0d8cfed47f6e0fd3" - integrity sha512-CnEwNKVpd5bXnrCKPaePF8mWTA9ET21OMBb54y9b0fd8K02zoOcdBz4DWfh1SjFD4HkgCdja4egd8l2ivyvqmw== +"@aws-sdk/middleware-ssec@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-ssec/-/middleware-ssec-3.329.0.tgz#c5bef2aca924c694e0ce03e8d1676b6d1885c0d4" + integrity sha512-XtDA/P2Sf79scu4a7tG77QC3VLtAGq/pit73x+qwctnI4gBgZlQ+FpE15d89ulntd7rIaD4v6tVU0bAg/L3PIQ== dependencies: - "@aws-sdk/types" "3.310.0" + "@aws-sdk/types" "3.329.0" tslib "^2.5.0" -"@aws-sdk/middleware-stack@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-stack/-/middleware-stack-3.310.0.tgz#06c83963998fbdc83e99b67a7a138529312a6224" - integrity sha512-010O1PD+UAcZVKRvqEusE1KJqN96wwrf6QsqbRM0ywsKQ21NDweaHvEDlds2VHpgmofxkRLRu/IDrlPkKRQrRg== +"@aws-sdk/middleware-stack@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-stack/-/middleware-stack-3.329.0.tgz#745150a190cc025d0bd7a52c0db5580c05dbbb54" + integrity sha512-2huFLhJ45td2nuiIOjpc9JKJbFNn5CYmw9U8YDITTcydpteRN62CzCpeqroDvF89VOLWxh0ZFtuLCGUr7liSWQ== dependencies: tslib "^2.5.0" -"@aws-sdk/middleware-user-agent@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.310.0.tgz#2aa3982cbc5e9c137024cec47914e86610ab0a09" - integrity sha512-x3IOwSwSbwKidlxRk3CNVHVUb06SRuaELxggCaR++QVI8NU6qD/l4VHXKVRvbTHiC/cYxXE/GaBDgQVpDR7V/g== +"@aws-sdk/middleware-user-agent@3.332.0": + version "3.332.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.332.0.tgz#6f2de9579b09dd7feeab27ef8a18c236694ad903" + integrity sha512-rSL1xP4QmcMOsunN1p5ZDR9GT3vvoSCnYa4iPvMSjP8Jx7l4ff/aVctwfZkMs/up12+68Jqwj4TvtaCvCFXdUA== dependencies: - "@aws-sdk/protocol-http" "3.310.0" - "@aws-sdk/types" "3.310.0" - "@aws-sdk/util-endpoints" "3.310.0" + "@aws-sdk/protocol-http" "3.329.0" + "@aws-sdk/types" "3.329.0" + "@aws-sdk/util-endpoints" "3.332.0" tslib "^2.5.0" -"@aws-sdk/node-config-provider@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/node-config-provider/-/node-config-provider-3.310.0.tgz#ba8fb41af2db0316291ba9002267627553ec65ac" - integrity sha512-T/Pp6htc6hq/Cq+MLNDSyiwWCMVF6GqbBbXKVlO5L8rdHx4sq9xPdoPveZhGWrxvkanjA6eCwUp6E0riBOSVng== +"@aws-sdk/node-config-provider@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/node-config-provider/-/node-config-provider-3.329.0.tgz#32666077565924354a2216a5343ee768d3107eea" + integrity sha512-hg9rGNlkzh8aeR/sQbijrkFx2BIO53j4Z6qDxPNWwSGpl05jri1VHxHx2HZMwgbY6Zy/DSguETN/BL8vdFqyLg== dependencies: - "@aws-sdk/property-provider" "3.310.0" - "@aws-sdk/shared-ini-file-loader" "3.310.0" - "@aws-sdk/types" "3.310.0" + "@aws-sdk/property-provider" "3.329.0" + "@aws-sdk/shared-ini-file-loader" "3.329.0" + "@aws-sdk/types" "3.329.0" tslib "^2.5.0" -"@aws-sdk/node-http-handler@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/node-http-handler/-/node-http-handler-3.310.0.tgz#bd8e72c1c7cf4b48c2a21851f638ad5e63001787" - integrity sha512-irv9mbcM9xC2xYjArQF5SYmHBMu4ciMWtGsoHII1nRuFOl9FoT4ffTvEPuLlfC6pznzvKt9zvnm6xXj7gDChKg== +"@aws-sdk/node-http-handler@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/node-http-handler/-/node-http-handler-3.329.0.tgz#6dc721e6a9df7baebefd145295ef1a8bf1000a51" + integrity sha512-OrjaHjU2ZTPfoHa5DruRvTIbeHH/cc0wvh4ml+FwDpWaPaBpOhLiluhZ3anqX1l5QjrXNiQnL8FxSM5OV/zVCA== dependencies: - "@aws-sdk/abort-controller" "3.310.0" - "@aws-sdk/protocol-http" "3.310.0" - "@aws-sdk/querystring-builder" "3.310.0" - "@aws-sdk/types" "3.310.0" + "@aws-sdk/abort-controller" "3.329.0" + "@aws-sdk/protocol-http" "3.329.0" + "@aws-sdk/querystring-builder" "3.329.0" + "@aws-sdk/types" "3.329.0" tslib "^2.5.0" -"@aws-sdk/property-provider@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/property-provider/-/property-provider-3.310.0.tgz#5fae8a4c11bda052afa9747d47b031f1c4f0f246" - integrity sha512-3lxDb0akV6BBzmFe4nLPaoliQbAifyWJhuvuDOu7e8NzouvpQXs0275w9LePhhcgjKAEVXUIse05ZW2DLbxo/g== +"@aws-sdk/property-provider@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/property-provider/-/property-provider-3.329.0.tgz#069dda84e132c9d4eca1a4ae37c62f7a650a0046" + integrity sha512-1cHLTV6yyMGaMSWWDW/p4vTkJ1cc5BOEO+A0eHuAcoSOk+LDe9IKhUG3/ZOvvYKQYcqIj5jjGSni/noXNCl/qw== dependencies: - "@aws-sdk/types" "3.310.0" + "@aws-sdk/types" "3.329.0" tslib "^2.5.0" -"@aws-sdk/protocol-http@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/protocol-http/-/protocol-http-3.310.0.tgz#855c3314cba7ff3024a9a9701ca3c641691d997e" - integrity sha512-fgZ1aw/irQtnrsR58pS8ThKOWo57Py3xX6giRvwSgZDEcxHfVzuQjy9yPuV++v04fdmdtgpbGf8WfvAAJ11yXQ== +"@aws-sdk/protocol-http@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/protocol-http/-/protocol-http-3.329.0.tgz#a8a7e01477831961f5f040fe607c3552f9ccb013" + integrity sha512-0rLEHY6QTHTUUcVxzGbPUSmCKlXWplxT/fcYRh0bcc5MBK4naKfcQft1O6Ajp8uqs/9YPZ7XCVCn90pDeJfeaw== dependencies: - "@aws-sdk/types" "3.310.0" + "@aws-sdk/types" "3.329.0" tslib "^2.5.0" -"@aws-sdk/querystring-builder@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/querystring-builder/-/querystring-builder-3.310.0.tgz#5307ea52c3a4a1ae6818bbb6987cc6fce68b043f" - integrity sha512-ZHH8GV/80+pWGo7DzsvwvXR5xVxUHXUvPJPFAkhr6nCf78igdoF8gR10ScFoEKbtEapoNTaZlKHPXxpD8aPG7A== +"@aws-sdk/querystring-builder@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/querystring-builder/-/querystring-builder-3.329.0.tgz#c6e6dd03dcd4378d1fbee576ce2a81dd94ac46a6" + integrity sha512-UWgMKkS5trliaDJG4nPv3onu8Y0aBuwRo7RdIgggguOiU8pU6pq1I113nH2FBNWy+Me1bwf+bcviJh0pCo6bEg== dependencies: - "@aws-sdk/types" "3.310.0" + "@aws-sdk/types" "3.329.0" "@aws-sdk/util-uri-escape" "3.310.0" tslib "^2.5.0" -"@aws-sdk/querystring-parser@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/querystring-parser/-/querystring-parser-3.310.0.tgz#438183927e0b06e7c2ee004a1681b8d37c22e104" - integrity sha512-YkIznoP6lsiIUHinx++/lbb3tlMURGGqMpo0Pnn32zYzGrJXA6eC3D0as2EcMjo55onTfuLcIiX4qzXes2MYOA== +"@aws-sdk/querystring-parser@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/querystring-parser/-/querystring-parser-3.329.0.tgz#dbbf2fd23ff0dfa2e4663fa414de1d5e60814896" + integrity sha512-9mkK+FB7snJ2G7H3CqtprDwYIRhzm6jEezffCwUWrC+lbqHBbErbhE9IeU/MKxILmf0RbC2riXEY1MHGspjRrQ== dependencies: - "@aws-sdk/types" "3.310.0" + "@aws-sdk/types" "3.329.0" tslib "^2.5.0" -"@aws-sdk/service-error-classification@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/service-error-classification/-/service-error-classification-3.310.0.tgz#352c1db426dcf54a44393bc9a0607dde796b2abb" - integrity sha512-PuyC7k3qfIKeH2LCnDwbttMOKq3qAx4buvg0yfnJtQOz6t1AR8gsnAq0CjKXXyfkXwNKWTqCpE6lVNUIkXgsMw== +"@aws-sdk/service-error-classification@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/service-error-classification/-/service-error-classification-3.329.0.tgz#32db59091ff28f14e526cee738bc14e32a6850f6" + integrity sha512-TSNr0flOcCLe71aPp7MjblKNGsmxpTU4xR5772MDX9Cz9GUTNZCPFtvrcqd+wzEPP/AC7XwNXe8KjoXooZImUQ== -"@aws-sdk/shared-ini-file-loader@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/shared-ini-file-loader/-/shared-ini-file-loader-3.310.0.tgz#07e9c8e8e8bb0de7ed19b8cea908c920a493c9c9" - integrity sha512-N0q9pG0xSjQwc690YQND5bofm+4nfUviQ/Ppgan2kU6aU0WUq8KwgHJBto/YEEI+VlrME30jZJnxtOvcZJc2XA== +"@aws-sdk/shared-ini-file-loader@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/shared-ini-file-loader/-/shared-ini-file-loader-3.329.0.tgz#190eb922860d49b4259b20ca6df4d20769544802" + integrity sha512-e0hyd75fbjMd4aCoRwpP2/HR+0oScwogErVArIkq3F42c/hyNCQP3sph4JImuXIjuo6HNnpKpf20CEPPhNna8A== dependencies: - "@aws-sdk/types" "3.310.0" + "@aws-sdk/types" "3.329.0" tslib "^2.5.0" -"@aws-sdk/signature-v4-multi-region@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.310.0.tgz#36eb96aa9170994ed1c5551952d2ec2d5e40c4c7" - integrity sha512-q8W+RIomTS/q85Ntgks/CoDElwqkC9+4OCicee5YznNHjQ4gtNWhUkYIyIRWRmXa/qx/AUreW9DM8FAecCOdng== +"@aws-sdk/signature-v4-multi-region@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.329.0.tgz#6ccf1255358a49c1393e6f7c8cd43800827eb37e" + integrity sha512-SiK1ez8Ns61ulDm0MJsTOSGNJNOMNoPgfA9i+Uu/VMCBkotZASuxrcSWW8seQnLEynWLerjUF9CYpCQuCqKn9w== dependencies: - "@aws-sdk/protocol-http" "3.310.0" - "@aws-sdk/signature-v4" "3.310.0" - "@aws-sdk/types" "3.310.0" + "@aws-sdk/protocol-http" "3.329.0" + "@aws-sdk/signature-v4" "3.329.0" + "@aws-sdk/types" "3.329.0" tslib "^2.5.0" -"@aws-sdk/signature-v4@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/signature-v4/-/signature-v4-3.310.0.tgz#ad26426d3f72fa18e6808a36f827beb72d12bf2d" - integrity sha512-1M60P1ZBNAjCFv9sYW29OF6okktaeibWyW3lMXqzoHF70lHBZh+838iUchznXUA5FLabfn4jBFWMRxlAXJUY2Q== +"@aws-sdk/signature-v4@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/signature-v4/-/signature-v4-3.329.0.tgz#8d40683189678f49504169c923e8342247b1da70" + integrity sha512-9EnLoyOD5nFtCRAp+QRllDgQASCfY7jLHVhwht7jzwE80wE65Z9Ym5Z/mwTd4IyTz/xXfCvcE2VwClsBt0Ybdw== dependencies: "@aws-sdk/is-array-buffer" "3.310.0" - "@aws-sdk/types" "3.310.0" + "@aws-sdk/types" "3.329.0" "@aws-sdk/util-hex-encoding" "3.310.0" - "@aws-sdk/util-middleware" "3.310.0" + "@aws-sdk/util-middleware" "3.329.0" "@aws-sdk/util-uri-escape" "3.310.0" "@aws-sdk/util-utf8" "3.310.0" tslib "^2.5.0" -"@aws-sdk/smithy-client@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/smithy-client/-/smithy-client-3.310.0.tgz#04fca042ffc120c35eeea1335fa055d39f1bd7bd" - integrity sha512-UHMFvhoB2RLzsTb0mQe1ofvBUg/+/JEu1uptavxf/hEpEKZnRAaHH5FNkTG+mbFd/olay/QFjqNcMD6t8LcsNQ== +"@aws-sdk/smithy-client@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/smithy-client/-/smithy-client-3.329.0.tgz#54705963939855c87ae6e6c88196d23e819d728e" + integrity sha512-7E0fGpBKxwFqHHAOqNbgNsHSEmCZLuvmU9yvG9DXKVzrS4P48O/PfOro123WpcFZs3STyOVgH8wjUPftHAVKmg== dependencies: - "@aws-sdk/middleware-stack" "3.310.0" - "@aws-sdk/types" "3.310.0" + "@aws-sdk/middleware-stack" "3.329.0" + "@aws-sdk/types" "3.329.0" tslib "^2.5.0" -"@aws-sdk/token-providers@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/token-providers/-/token-providers-3.310.0.tgz#2d0b0d3ef729f6cdc6a0cc859e80bb9efea2d8fa" - integrity sha512-G1JvB+2v8k900VJFkKVQXgLGF50ShOEIPxfK1gSQLkSU85vPwGIAANs1KvnlW08FsNbWp3+sKca4kfYKsooXMw== +"@aws-sdk/token-providers@3.332.0": + version "3.332.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/token-providers/-/token-providers-3.332.0.tgz#d014556ad93c0e43bb20237a3c5e85e9eed612a2" + integrity sha512-fccbg6OSl0l658pxl2p1MoU9gEePo5B361+JNaN0zfRMu7c5HBXCpdl4djlFxAHjltrX9f1+BKqfGHYgI3h8SQ== dependencies: - "@aws-sdk/client-sso-oidc" "3.310.0" - "@aws-sdk/property-provider" "3.310.0" - "@aws-sdk/shared-ini-file-loader" "3.310.0" - "@aws-sdk/types" "3.310.0" + "@aws-sdk/client-sso-oidc" "3.332.0" + "@aws-sdk/property-provider" "3.329.0" + "@aws-sdk/shared-ini-file-loader" "3.329.0" + "@aws-sdk/types" "3.329.0" tslib "^2.5.0" -"@aws-sdk/types@3.310.0", "@aws-sdk/types@^3.222.0": +"@aws-sdk/types@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/types/-/types-3.329.0.tgz#bc20659abfcd666954196c3a24ad47785db80dd3" + integrity sha512-wFBW4yciDfzQBSFmWNaEvHShnSGLMxSu9Lls6EUf6xDMavxSB36bsrVRX6CyAo/W0NeIIyEOW1LclGPgJV1okg== + dependencies: + tslib "^2.5.0" + +"@aws-sdk/types@^3.222.0": version "3.310.0" resolved "https://registry.yarnpkg.com/@aws-sdk/types/-/types-3.310.0.tgz#b83a0580feb38b58417abb8b4ed3eae1a0cb7bc1" integrity sha512-j8eamQJ7YcIhw7fneUfs8LYl3t01k4uHi4ZDmNRgtbmbmTTG3FZc2MotStZnp3nZB6vLiPF1o5aoJxWVvkzS6A== dependencies: tslib "^2.5.0" -"@aws-sdk/url-parser@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/url-parser/-/url-parser-3.310.0.tgz#928c9eac2e3d74c3c5db4c6e364a1de00185dcaa" - integrity sha512-mCLnCaSB9rQvAgx33u0DujLvr4d5yEm/W5r789GblwwQnlNXedVu50QRizMLTpltYWyAUoXjJgQnJHmJMaKXhw== +"@aws-sdk/url-parser@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/url-parser/-/url-parser-3.329.0.tgz#a2862834a832ec1d379791f5233e378b75fc63ad" + integrity sha512-/VcfL7vNJKJGSjYYHVQF3bYCDFs4fSzB7j5qeVDwRdWr870gE7O1Dar+sLWBRKFF3AX+4VzplqzUfpu9t44JVA== dependencies: - "@aws-sdk/querystring-parser" "3.310.0" - "@aws-sdk/types" "3.310.0" + "@aws-sdk/querystring-parser" "3.329.0" + "@aws-sdk/types" "3.329.0" tslib "^2.5.0" "@aws-sdk/util-arn-parser@3.310.0": @@ -1077,43 +1084,43 @@ dependencies: tslib "^2.5.0" -"@aws-sdk/util-defaults-mode-browser@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/util-defaults-mode-browser/-/util-defaults-mode-browser-3.310.0.tgz#db82bfdf339eea0bc8b1b059dfe9b62e5d3adbf4" - integrity sha512-Mr2AoQsjAYNM5oAS2YJlYJqhiCvkFV/hu48slOZgbY4G7ueW4cM0DPkR16wqjcRCGqZ4JmAZB8Q5R0DMrLjhOQ== +"@aws-sdk/util-defaults-mode-browser@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-defaults-mode-browser/-/util-defaults-mode-browser-3.329.0.tgz#49fc6836e85968ff86917c56c82fc9ef595c0565" + integrity sha512-2iSiy/pzX3OXMhtSxtAzOiEFr3viQEFnYOTeZuiheuyS+cea2L79F6SlZ1110b/nOIU/UOrxxtz83HVad8YFMQ== dependencies: - "@aws-sdk/property-provider" "3.310.0" - "@aws-sdk/types" "3.310.0" + "@aws-sdk/property-provider" "3.329.0" + "@aws-sdk/types" "3.329.0" bowser "^2.11.0" tslib "^2.5.0" -"@aws-sdk/util-defaults-mode-node@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/util-defaults-mode-node/-/util-defaults-mode-node-3.310.0.tgz#aee459c2da09e2c6e85c6db0406565312f45ccbb" - integrity sha512-JyBlvhQGR8w8NpFRZZXRVTDesafFKTu/gTWjcoxP7twa+fYHSIgPPFGnlcJ/iHaucjamSaWi5EQ+YQmnSZ8yHA== - dependencies: - "@aws-sdk/config-resolver" "3.310.0" - "@aws-sdk/credential-provider-imds" "3.310.0" - "@aws-sdk/node-config-provider" "3.310.0" - "@aws-sdk/property-provider" "3.310.0" - "@aws-sdk/types" "3.310.0" +"@aws-sdk/util-defaults-mode-node@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-defaults-mode-node/-/util-defaults-mode-node-3.329.0.tgz#2296652bcacd56c6abe159194aae283738a796b2" + integrity sha512-7A6C7YKjkZtmKtH29isYEtOCbhd7IcXPP8lftN8WAWlLOiZE4gV7PHveagUj7QserJzgRKGwwTQbBj53n18HYg== + dependencies: + "@aws-sdk/config-resolver" "3.329.0" + "@aws-sdk/credential-provider-imds" "3.329.0" + "@aws-sdk/node-config-provider" "3.329.0" + "@aws-sdk/property-provider" "3.329.0" + "@aws-sdk/types" "3.329.0" tslib "^2.5.0" -"@aws-sdk/util-endpoints@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/util-endpoints/-/util-endpoints-3.310.0.tgz#fea8757038b62d49dacd653061ba04a2ea102a36" - integrity sha512-zG+/d/O5KPmAaeOMPd6bW1abifdT0H03f42keLjYEoRZzYtHPC5DuPE0UayiWGckI6BCDgy0sRKXCYS49UNFaQ== +"@aws-sdk/util-endpoints@3.332.0": + version "3.332.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-endpoints/-/util-endpoints-3.332.0.tgz#e360f65d240c97661988e20f15bb5bca160f773a" + integrity sha512-nQx7AiOroMU2hj6h+umWOSZ+WECwxupaxFUK/PPKGW6NY/VdQE6LluYnXOtF5awlr8w1nPksT0Lq05PZutMDLA== dependencies: - "@aws-sdk/types" "3.310.0" + "@aws-sdk/types" "3.329.0" tslib "^2.5.0" -"@aws-sdk/util-format-url@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/util-format-url/-/util-format-url-3.310.0.tgz#4f89c18a23ec6515f50100deced5f236512c4e15" - integrity sha512-NBOvmvvVR3ydquHmznfgtakiSgDhq8Ww6fq8TUaEjM+Es6+iqY4AwZo0rZ9xTX3GpCcoZy391HUi6kiXRAFzuA== +"@aws-sdk/util-format-url@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-format-url/-/util-format-url-3.329.0.tgz#2856379da026adc6355d63bdf6f207a4f8b7c6cb" + integrity sha512-FMokjI10Vzpfb+jeJ0y6TnutPcyessdEz6aKMwn5Ee8etnHaEVDXf5tp8bPZ5ii5WRWwgNNrAa+IkJ2KH4E43g== dependencies: - "@aws-sdk/querystring-builder" "3.310.0" - "@aws-sdk/types" "3.310.0" + "@aws-sdk/querystring-builder" "3.329.0" + "@aws-sdk/types" "3.329.0" tslib "^2.5.0" "@aws-sdk/util-hex-encoding@3.310.0": @@ -1130,40 +1137,40 @@ dependencies: tslib "^2.5.0" -"@aws-sdk/util-middleware@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/util-middleware/-/util-middleware-3.310.0.tgz#713c5bfa296f4cf707150a0a1e911afd50dcf939" - integrity sha512-FTSUKL/eRb9X6uEZClrTe27QFXUNNp7fxYrPndZwk1hlaOP5ix+MIHBcI7pIiiY/JPfOUmPyZOu+HetlFXjWog== +"@aws-sdk/util-middleware@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-middleware/-/util-middleware-3.329.0.tgz#0d4056c8479d80760778928e807ff74c57fcead3" + integrity sha512-RhBOBaxzkTUghi4MSqr8S5qeeBCjgJ0XPJ6jIYkVkj1saCmqkuZCgl3zFaYdyhdxxPV6nflkFer+1HUoqT+Fqw== dependencies: tslib "^2.5.0" -"@aws-sdk/util-retry@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/util-retry/-/util-retry-3.310.0.tgz#4cdc35e2dfdacf2d928ab474ba8b67bbadd6be3c" - integrity sha512-FwWGhCBLfoivTMUHu1LIn4NjrN9JLJ/aX5aZmbcPIOhZVFJj638j0qDgZXyfvVqBuBZh7M8kGq0Oahy3dp69OA== +"@aws-sdk/util-retry@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-retry/-/util-retry-3.329.0.tgz#20b71504dd907e70a457cd56dcd131d08d6de39c" + integrity sha512-+3VQ9HZLinysnmryUs9Xjt1YVh4TYYHLt30ilu4iUnIHFQoamdzIbRCWseSVFPCxGroen9M9qmAleAsytHEKuA== dependencies: - "@aws-sdk/service-error-classification" "3.310.0" + "@aws-sdk/service-error-classification" "3.329.0" tslib "^2.5.0" -"@aws-sdk/util-stream-browser@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/util-stream-browser/-/util-stream-browser-3.310.0.tgz#223e60f7711f7a20fdc944e1b72c8dd4c1da28cf" - integrity sha512-bysXZHwFwvbqOTCScCdCnoLk1K3GCo0HRIYEZuL7O7MHrQmfaYRXcaft/p22+GUv9VeFXS/eJJZ5r4u32az94w== +"@aws-sdk/util-stream-browser@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-stream-browser/-/util-stream-browser-3.329.0.tgz#a85d5f0fecc0817e0b6ff0721a6de774bd1b3890" + integrity sha512-UF1fJNfgrdJLMxn8ZlfPkYdv7hoLvVgSk3GHgxYA4OQs5zKCzeZgVrbxtE147LxWwJbxi3Qf04vnaEHwzVESpg== dependencies: - "@aws-sdk/fetch-http-handler" "3.310.0" - "@aws-sdk/types" "3.310.0" + "@aws-sdk/fetch-http-handler" "3.329.0" + "@aws-sdk/types" "3.329.0" "@aws-sdk/util-base64" "3.310.0" "@aws-sdk/util-hex-encoding" "3.310.0" "@aws-sdk/util-utf8" "3.310.0" tslib "^2.5.0" -"@aws-sdk/util-stream-node@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/util-stream-node/-/util-stream-node-3.310.0.tgz#088c59b7f346669f501ce0ad08cda7e88de0ba1f" - integrity sha512-hueAXFK0GVvnfYFgqbF7587xZfMZff5jlIFZOHqx7XVU7bl7qrRUCnphHk8H6yZ7RoQbDPcfmHJgtEoAJg1T1Q== +"@aws-sdk/util-stream-node@3.331.0": + version "3.331.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-stream-node/-/util-stream-node-3.331.0.tgz#3412a6cbf94085ef59827d248c8664449afb2e4f" + integrity sha512-5YUatdh4vgkv7VFY+lSkF+b+6EFkiHvy+dlucfGoJEOcEzuA/NBZYebWbcJ5TiR6z3cQdA23OTyZz3ZofZY1hw== dependencies: - "@aws-sdk/node-http-handler" "3.310.0" - "@aws-sdk/types" "3.310.0" + "@aws-sdk/node-http-handler" "3.329.0" + "@aws-sdk/types" "3.329.0" "@aws-sdk/util-buffer-from" "3.310.0" tslib "^2.5.0" @@ -1174,22 +1181,22 @@ dependencies: tslib "^2.5.0" -"@aws-sdk/util-user-agent-browser@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.310.0.tgz#48d463a93351b78b678df324f3518a9798029c44" - integrity sha512-yU/4QnHHuQ5z3vsUqMQVfYLbZGYwpYblPiuZx4Zo9+x0PBkNjYMqctdDcrpoH9Z2xZiDN16AmQGK1tix117ZKw== +"@aws-sdk/util-user-agent-browser@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.329.0.tgz#6c3353a68f5d3d420156fabdcfab3bf4160f383b" + integrity sha512-8hLSmMCl8aw2++0Zuba8ELq8FkK6/VNyx470St201IpMn2GMbQMDl/rLolRKiTgji6wc+T3pOTidkJkz8/cIXA== dependencies: - "@aws-sdk/types" "3.310.0" + "@aws-sdk/types" "3.329.0" bowser "^2.11.0" tslib "^2.5.0" -"@aws-sdk/util-user-agent-node@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.310.0.tgz#ebefbedc5a4759adc958885741628ec0de1ab197" - integrity sha512-Ra3pEl+Gn2BpeE7KiDGpi4zj7WJXZA5GXnGo3mjbi9+Y3zrbuhJAbdZO3mO/o7xDgMC6ph4xCTbaSGzU6b6EDg== +"@aws-sdk/util-user-agent-node@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.329.0.tgz#eb0930a1f3315fa6ea6f72e4007bbfce1202a3e5" + integrity sha512-C50Zaeodc0+psEP+L4WpElrH8epuLWJPVN4hDOTORcM0cSoU2o025Ost9mbcU7UdoHNxF9vitLnzORGN9SHolg== dependencies: - "@aws-sdk/node-config-provider" "3.310.0" - "@aws-sdk/types" "3.310.0" + "@aws-sdk/node-config-provider" "3.329.0" + "@aws-sdk/types" "3.329.0" tslib "^2.5.0" "@aws-sdk/util-utf8-browser@^3.0.0": @@ -1207,13 +1214,13 @@ "@aws-sdk/util-buffer-from" "3.310.0" tslib "^2.5.0" -"@aws-sdk/util-waiter@3.310.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/util-waiter/-/util-waiter-3.310.0.tgz#a410739cfc637af9ccea21de079d00652e9b8363" - integrity sha512-AV5j3guH/Y4REu+Qh3eXQU9igljHuU4XjX2sADAgf54C0kkhcCCkkiuzk3IsX089nyJCqIcj5idbjdvpnH88Vw== +"@aws-sdk/util-waiter@3.329.0": + version "3.329.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-waiter/-/util-waiter-3.329.0.tgz#4e0d457548661e210cf716f8b18ff16a4dbd17c7" + integrity sha512-MIGs7snNL0ZV55zo1BDVPlrmbinUGV3260hp6HrW4zUbpYVoeIOGeewtrwAsF6FJ+vpZCxljPBB0X2jYR7Q7ZQ== dependencies: - "@aws-sdk/abort-controller" "3.310.0" - "@aws-sdk/types" "3.310.0" + "@aws-sdk/abort-controller" "3.329.0" + "@aws-sdk/types" "3.329.0" tslib "^2.5.0" "@aws-sdk/xml-builder@3.310.0": @@ -2487,25 +2494,25 @@ "@renovate/eslint-plugin@file:./tools/eslint": version "0.0.0" -"@renovatebot/osv-offline-db@1.3.2": - version "1.3.2" - resolved "https://registry.yarnpkg.com/@renovatebot/osv-offline-db/-/osv-offline-db-1.3.2.tgz#960f687fce4555f3d802ff855318eeb9d34a9215" - integrity sha512-02sMhxKjmRvHm6HIdTEyVIAIdEdYWLOU/ecQuiP2hvgXg28P6GWj/BkAbQ8GU0uLfBMZiqB4DK9MKoI4wx7BJw== +"@renovatebot/osv-offline-db@1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@renovatebot/osv-offline-db/-/osv-offline-db-1.4.0.tgz#45f4b580dd80012d78beac1188bece21d02b910a" + integrity sha512-VqR66WlewMLnDOVmnEAHIFZuATG46LwvNu6ZPjH0sEaH6bCqNxfJ6kBMFEiJOWWjGOxI1u2F+nr1vtdixC9UwA== dependencies: - "@seald-io/nedb" "^4.0.1" + "@seald-io/nedb" "^4.0.2" -"@renovatebot/osv-offline@1.2.4": - version "1.2.4" - resolved "https://registry.yarnpkg.com/@renovatebot/osv-offline/-/osv-offline-1.2.4.tgz#cf2d79e8aabf3b15570c8a3178372a3df04ef7b9" - integrity sha512-9r97Fn8dmdbAtqNAM4z3ECyxo6cpcQ1acMuAQoFcC0xemuFlzkrP+BY0KI/U/qQG2IojEfW+9TU+C3o0ZDS94w== +"@renovatebot/osv-offline@1.2.8": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@renovatebot/osv-offline/-/osv-offline-1.2.8.tgz#069cc078c414a5737bd963a39bc7d5cf196e2b7a" + integrity sha512-y0I1RQKUf0VI2XLuG8kr5j37NGxqOVcaFG9ozgwd9CGyGF1KMaaCOv6+MiQayeppcPNUGU6jBisI2XMQRneBmg== dependencies: "@octokit/rest" "^19.0.7" - "@renovatebot/osv-offline-db" "1.3.2" + "@renovatebot/osv-offline-db" "1.4.0" adm-zip "~0.5.10" fs-extra "^11.1.1" got "^11.8.6" luxon "^3.3.0" - node-fetch "^2.6.9" + node-fetch "^2.6.11" "@renovatebot/pep440@2.1.15": version "2.1.15" @@ -2522,10 +2529,10 @@ resolved "https://registry.yarnpkg.com/@seald-io/binary-search-tree/-/binary-search-tree-1.0.3.tgz#165a9a456eaa30d15885b25db83861bcce2c6a74" integrity sha512-qv3jnwoakeax2razYaMsGI/luWdliBLHTdC6jU55hQt1hcFqzauH/HsBollQ7IR4ySTtYhT+xyHoijpA16C+tA== -"@seald-io/nedb@^4.0.1": - version "4.0.1" - resolved "https://registry.yarnpkg.com/@seald-io/nedb/-/nedb-4.0.1.tgz#bfd62b5468e6b03e4f3a16dabd12c9d55aab8856" - integrity sha512-E2l7EUEMkSO3WLydRxRWjVWzijzWehzKmy/q9ekbgaOOQjYD7zHdS8z3KsM8+aQ910agfREZCR+3YCc5Xuc9dg== +"@seald-io/nedb@^4.0.2": + version "4.0.2" + resolved "https://registry.yarnpkg.com/@seald-io/nedb/-/nedb-4.0.2.tgz#44bc5f9b86e44f7434c5af8064cc7f8e079fc3a8" + integrity sha512-gJ91fT1sgh2cLXYVcTSh7khZ8LdemI8+SojCdpZ5wy+DUQ4fSrEwGqOwbdV49NDs2BBO6GeBpSb8CnhG2IW1rw== dependencies: "@seald-io/binary-search-tree" "^1.0.3" localforage "^1.9.0" @@ -3061,11 +3068,16 @@ dependencies: "@types/node" "*" -"@types/node@*", "@types/node@18.16.3": +"@types/node@*": version "18.16.3" resolved "https://registry.yarnpkg.com/@types/node/-/node-18.16.3.tgz#6bda7819aae6ea0b386ebc5b24bdf602f1b42b01" integrity sha512-OPs5WnnT1xkCBiuQrZA4+YAV4HEJejmHneyraIaxsbev5yCEr6KMwINNFP9wQeFIw8FWcoTqF3vQsa5CDaI+8Q== +"@types/node@18.16.8": + version "18.16.8" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.16.8.tgz#fcd9bd0a793aba2701caff4aeae7c988d4da6ce5" + integrity sha512-p0iAXcfWCOTCBbsExHIDFCfwsqFwBTgETJveKMT+Ci3LY9YqQCI91F5S+TB20+aRCXpcWfvx5Qr5EccnwCm2NA== + "@types/node@^13.7.0": version "13.13.52" resolved "https://registry.yarnpkg.com/@types/node/-/node-13.13.52.tgz#03c13be70b9031baaed79481c0c0cfb0045e53f7" @@ -3108,7 +3120,12 @@ resolved "https://registry.yarnpkg.com/@types/semver-utils/-/semver-utils-1.1.1.tgz#4260b9ce13344725069a1ff86bd2f4d6c70a443e" integrity sha512-WLZZQdwo5P+H6R+bDDCFqFSlP5Jtk6gyXpE0R0KAVQbcMGmxpVsNX8dah640hY4+PpRG2+Ph3dcwDHzrOAOZ7A== -"@types/semver@7.3.13", "@types/semver@^7.1.0", "@types/semver@^7.3.12": +"@types/semver@7.5.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.0.tgz#591c1ce3a702c45ee15f47a42ade72c2fd78978a" + integrity sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw== + +"@types/semver@^7.1.0", "@types/semver@^7.3.12": version "7.3.13" resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.13.tgz#da4bfd73f49bd541d28920ab0e2bf0ee80f71c91" integrity sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw== @@ -3130,10 +3147,10 @@ resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== -"@types/tar@6.1.4": - version "6.1.4" - resolved "https://registry.yarnpkg.com/@types/tar/-/tar-6.1.4.tgz#cf8497e1ebdc09212fd51625cd2eb5ca18365ad1" - integrity sha512-Cp4oxpfIzWt7mr2pbhHT2OTXGMAL0szYCzuf8lRWyIMCgsx6/Hfc3ubztuhvzXHXgraTQxyOCmmg7TDGIMIJJQ== +"@types/tar@6.1.5": + version "6.1.5" + resolved "https://registry.yarnpkg.com/@types/tar/-/tar-6.1.5.tgz#90ccb3b6a35430e7427410d50eed564e85feaaff" + integrity sha512-qm2I/RlZij5RofuY7vohTpYNaYcrSQlN2MyjucQc7ZweDwaEWkdN/EeNh6e9zjK6uEm6PwjdMXkcj05BxZdX1Q== dependencies: "@types/node" "*" minipass "^4.0.0" @@ -3519,7 +3536,7 @@ ajv@^6.10.0, ajv@^6.12.4: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ansi-escapes@^4.2.1, ansi-escapes@^4.3.0: +ansi-escapes@^4.2.1: version "4.3.2" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== @@ -3538,11 +3555,6 @@ ansi-regex@^5.0.1: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== -ansi-regex@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" - integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== - ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" @@ -3562,11 +3574,6 @@ ansi-styles@^5.0.0: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== -ansi-styles@^6.0.0: - version "6.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" - integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== - ansicolors@~0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/ansicolors/-/ansicolors-0.3.2.tgz#665597de86a9ffe3aa9bfbe6cae5c6ea426b4979" @@ -3702,11 +3709,6 @@ asn1.js@^5.0.0: minimalistic-assert "^1.0.0" safer-buffer "^2.1.0" -astral-regex@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" - integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== - auth-header@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/auth-header/-/auth-header-1.0.0.tgz#ea24fdc5588e1eb8b750df8655a396aa48fc9076" @@ -4082,11 +4084,6 @@ chalk@4.1.2, chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2: ansi-styles "^4.1.0" supports-color "^7.1.0" -chalk@5.2.0, chalk@^5.0.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.2.0.tgz#249623b7d66869c673699fb66d65723e54dfcfb3" - integrity sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA== - chalk@^2.0.0, chalk@^2.3.2, chalk@^2.4.1: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" @@ -4104,6 +4101,11 @@ chalk@^3.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" +chalk@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.2.0.tgz#249623b7d66869c673699fb66d65723e54dfcfb3" + integrity sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA== + changelog-filename-regex@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/changelog-filename-regex/-/changelog-filename-regex-2.0.1.tgz#88944bd89a076fc572c0ab6b4a4f2bc2572ac02d" @@ -4185,13 +4187,6 @@ cli-columns@^4.0.0: string-width "^4.2.3" strip-ansi "^6.0.1" -cli-cursor@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" - integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== - dependencies: - restore-cursor "^3.1.0" - cli-table3@^0.6.1, cli-table3@^0.6.3: version "0.6.3" resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.6.3.tgz#61ab765aac156b52f222954ffc607a6f01dbeeb2" @@ -4201,22 +4196,6 @@ cli-table3@^0.6.1, cli-table3@^0.6.3: optionalDependencies: "@colors/colors" "1.5.0" -cli-truncate@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-2.1.0.tgz#c39e28bf05edcde5be3b98992a22deed5a2b93c7" - integrity sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg== - dependencies: - slice-ansi "^3.0.0" - string-width "^4.2.0" - -cli-truncate@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-3.1.0.tgz#3f23ab12535e3d73e839bb43e73c9de487db1389" - integrity sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA== - dependencies: - slice-ansi "^5.0.0" - string-width "^5.0.0" - clipanion@3.2.0-rc.4: version "3.2.0-rc.4" resolved "https://registry.yarnpkg.com/clipanion/-/clipanion-3.2.0-rc.4.tgz#4df6e55e46c1287dd5d6d595eec3c785082e8e32" @@ -4294,11 +4273,6 @@ color-support@^1.1.3: resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== -colorette@^2.0.19: - version "2.0.20" - resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" - integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== - columnify@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/columnify/-/columnify-1.6.0.tgz#6989531713c9008bb29735e61e37acf5bd553cf3" @@ -4723,11 +4697,6 @@ duplexer2@~0.1.0: dependencies: readable-stream "^2.0.2" -eastasianwidth@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" - integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== - editorconfig@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/editorconfig/-/editorconfig-1.0.2.tgz#0e4ff2ce6bf392f3f9e4d50c1a9819b06d380d15" @@ -4763,11 +4732,6 @@ emoji-regex@^8.0.0: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== -emoji-regex@^9.2.2: - version "9.2.2" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" - integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== - emojibase-data@7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/emojibase-data/-/emojibase-data-7.0.1.tgz#a81d7fcd12247f7d94a96dcbdb143e6b6dd5c328" @@ -5621,7 +5585,18 @@ glob-parent@^6.0.2: dependencies: is-glob "^4.0.3" -glob@10.2.2, glob@^10.0.0, glob@^10.2.2: +glob@10.2.5: + version "10.2.5" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.2.5.tgz#73c1850ac8f077810d8370ba414b382ad1a86083" + integrity sha512-Gj+dFYPZ5hc5dazjXzB0iHg2jKWJZYMjITXYPBRQ/xc2Buw7H0BINknRTwURJ6IC6MEFpYbLvtgVb3qD+DwyuA== + dependencies: + foreground-child "^3.1.0" + jackspeak "^2.0.3" + minimatch "^9.0.0" + minipass "^5.0.0 || ^6.0.2" + path-scurry "^1.7.0" + +glob@^10.0.0, glob@^10.2.2: version "10.2.2" resolved "https://registry.yarnpkg.com/glob/-/glob-10.2.2.tgz#ce2468727de7e035e8ecf684669dc74d0526ab75" integrity sha512-Xsa0BcxIC6th9UwNjZkhrMtNo/MnyRL8jGCP+uEwhA5oFOCY1f2s1/oNKY47xQ0Bg5nkjsfAEIej1VeH62bDDQ== @@ -5740,14 +5715,14 @@ globrex@^0.1.2: resolved "https://registry.yarnpkg.com/globrex/-/globrex-0.1.2.tgz#dd5d9ec826232730cd6793a5e33a9302985e6098" integrity sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg== -good-enough-parser@1.1.22: - version "1.1.22" - resolved "https://registry.yarnpkg.com/good-enough-parser/-/good-enough-parser-1.1.22.tgz#1fcab50b385ead49cb89a847868631d588bc5716" - integrity sha512-fI4qWIeyqjleGazMcXnqgtvG8qBJGUoj5CtraqaUpZmk94ztMab6irx3Yz+EsJKKgIrwkSBM69WHLngfhAe7hg== +good-enough-parser@1.1.23: + version "1.1.23" + resolved "https://registry.yarnpkg.com/good-enough-parser/-/good-enough-parser-1.1.23.tgz#f80441698261d6d1722ca52cf1184bb504ac5d76" + integrity sha512-QUcQZutczESpdo2w9BMG6VpLFoq9ix7ER5HLM1mAdZdri2F3eISkCb8ep84W6YOo0grYWJdyT/8JkYqGjQfSSQ== dependencies: "@thi.ng/zipper" "1.0.3" "@types/moo" "0.5.5" - klona "2.0.5" + klona "2.0.6" moo "0.5.2" gopd@^1.0.1: @@ -6200,11 +6175,6 @@ is-fullwidth-code-point@^3.0.0: resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== -is-fullwidth-code-point@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz#fae3167c729e7463f8461ce512b080a49268aa88" - integrity sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ== - is-generator-fn@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" @@ -7003,10 +6973,10 @@ kleur@^3.0.3: resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== -klona@2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.5.tgz#d166574d90076395d9963aa7a928fabb8d76afbc" - integrity sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ== +klona@2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.6.tgz#85bffbf819c03b2f53270412420a4555ef882e22" + integrity sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA== leven@^3.1.0: version "3.1.0" @@ -7142,11 +7112,6 @@ lie@3.1.1: dependencies: immediate "~3.0.5" -lilconfig@2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52" - integrity sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ== - lines-and-columns@^1.1.6: version "1.2.4" resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" @@ -7164,39 +7129,6 @@ linkify-it@^4.0.1: dependencies: uc.micro "^1.0.1" -lint-staged@13.2.2: - version "13.2.2" - resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-13.2.2.tgz#5e711d3139c234f73402177be2f8dd312e6508ca" - integrity sha512-71gSwXKy649VrSU09s10uAT0rWCcY3aewhMaHyl2N84oBk4Xs9HgxvUp3AYu+bNsK4NrOYYxvSgg7FyGJ+jGcA== - dependencies: - chalk "5.2.0" - cli-truncate "^3.1.0" - commander "^10.0.0" - debug "^4.3.4" - execa "^7.0.0" - lilconfig "2.1.0" - listr2 "^5.0.7" - micromatch "^4.0.5" - normalize-path "^3.0.0" - object-inspect "^1.12.3" - pidtree "^0.6.0" - string-argv "^0.3.1" - yaml "^2.2.2" - -listr2@^5.0.7: - version "5.0.8" - resolved "https://registry.yarnpkg.com/listr2/-/listr2-5.0.8.tgz#a9379ffeb4bd83a68931a65fb223a11510d6ba23" - integrity sha512-mC73LitKHj9w6v30nLNGPetZIlfpUniNSsxxrbaPcWOjDb92SHPzJPi/t+v1YC/lxKz/AJ9egOjww0qUuFxBpA== - dependencies: - cli-truncate "^2.1.0" - colorette "^2.0.19" - log-update "^4.0.0" - p-map "^4.0.0" - rfdc "^1.3.0" - rxjs "^7.8.0" - through "^2.3.8" - wrap-ansi "^7.0.0" - load-json-file@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" @@ -7298,16 +7230,6 @@ lodash@^4.17.15, lodash@^4.17.21, lodash@^4.17.4: resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== -log-update@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/log-update/-/log-update-4.0.0.tgz#589ecd352471f2a1c0c570287543a64dfd20e0a1" - integrity sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg== - dependencies: - ansi-escapes "^4.3.0" - cli-cursor "^3.1.0" - slice-ansi "^4.0.0" - wrap-ansi "^6.2.0" - longest-streak@^2.0.0: version "2.0.4" resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-2.0.4.tgz#b8599957da5b5dab64dee3fe316fa774597d90e4" @@ -7602,7 +7524,7 @@ micromark@~2.11.0: debug "^4.0.0" parse-entities "^2.0.0" -micromatch@4.0.5, micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.5: +micromatch@4.0.5, micromatch@^4.0.2, micromatch@^4.0.4: version "4.0.5" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== @@ -7776,6 +7698,11 @@ minipass@^5.0.0: resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d" integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== +"minipass@^5.0.0 || ^6.0.2": + version "6.0.2" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-6.0.2.tgz#542844b6c4ce95b202c0995b0a471f1229de4c81" + integrity sha512-MzWSV5nYVT7mVyWCwn2o7JH13w2TBRmmSqSRCKzTw+lmft9X4z+3wjvs06Tzijo5z4W/kahUCDpRXTF+ZrmF/w== + minizlib@^2.1.1, minizlib@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" @@ -7923,7 +7850,14 @@ node-emoji@^1.11.0: dependencies: lodash "^4.17.21" -node-fetch@^2.6.7, node-fetch@^2.6.9: +node-fetch@^2.6.11: + version "2.6.11" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.11.tgz#cde7fc71deef3131ef80a738919f999e6edfff25" + integrity sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w== + dependencies: + whatwg-url "^5.0.0" + +node-fetch@^2.6.7: version "2.6.9" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.9.tgz#7c7f744b5cc6eb5fd404e0c7a9fec630a55657e6" integrity sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg== @@ -8281,7 +8215,7 @@ once@~1.3.0: dependencies: wrappy "1" -onetime@^5.1.0, onetime@^5.1.2: +onetime@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== @@ -8657,11 +8591,6 @@ pidtree@^0.3.0: resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.3.1.tgz#ef09ac2cc0533df1f3250ccf2c4d366b0d12114a" integrity sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA== -pidtree@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.6.0.tgz#90ad7b6d42d5841e69e0a2419ef38f8883aa057c" - integrity sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g== - pify@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" @@ -9162,14 +9091,6 @@ responselike@^2.0.0: dependencies: lowercase-keys "^2.0.0" -restore-cursor@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" - integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== - dependencies: - onetime "^5.1.0" - signal-exit "^3.0.2" - retry@^0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" @@ -9185,11 +9106,6 @@ reusify@^1.0.4: resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== -rfdc@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" - integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== - rimraf@5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-5.0.0.tgz#5bda14e410d7e4dd522154891395802ce032c2cb" @@ -9230,13 +9146,6 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -rxjs@^7.8.0: - version "7.8.1" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543" - integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg== - dependencies: - tslib "^2.1.0" - safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" @@ -9344,7 +9253,14 @@ semver-utils@1.1.4: resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== -semver@7.5.0, semver@7.x, semver@^7.0.0, semver@^7.1.1, semver@^7.1.2, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.0: +semver@7.5.1: + version "7.5.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.1.tgz#c90c4d631cf74720e46b21c1d37ea07edfab91ec" + integrity sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw== + dependencies: + lru-cache "^6.0.0" + +semver@7.x, semver@^7.0.0, semver@^7.1.1, semver@^7.1.2, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.0: version "7.5.0" resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.0.tgz#ed8c5dc8efb6c629c88b23d41dc9bf40c1d96cd0" integrity sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA== @@ -9480,32 +9396,6 @@ slash@^4.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-4.0.0.tgz#2422372176c4c6c5addb5e2ada885af984b396a7" integrity sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew== -slice-ansi@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-3.0.0.tgz#31ddc10930a1b7e0b67b08c96c2f49b77a789787" - integrity sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ== - dependencies: - ansi-styles "^4.0.0" - astral-regex "^2.0.0" - is-fullwidth-code-point "^3.0.0" - -slice-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" - integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== - dependencies: - ansi-styles "^4.0.0" - astral-regex "^2.0.0" - is-fullwidth-code-point "^3.0.0" - -slice-ansi@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-5.0.0.tgz#b73063c57aa96f9cd881654b15294d95d285c42a" - integrity sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ== - dependencies: - ansi-styles "^6.0.0" - is-fullwidth-code-point "^4.0.0" - slugify@1.6.6: version "1.6.6" resolved "https://registry.yarnpkg.com/slugify/-/slugify-1.6.6.tgz#2d4ac0eacb47add6af9e04d3be79319cbcc7924b" @@ -9673,11 +9563,6 @@ stream-to-promise@^2.2.0: end-of-stream "~1.1.0" stream-to-array "~2.3.0" -string-argv@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.1.tgz#95e2fbec0427ae19184935f816d74aaa4c5c19da" - integrity sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg== - string-length@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" @@ -9695,15 +9580,6 @@ string-length@^4.0.1: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" -string-width@^5.0.0: - version "5.1.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" - integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== - dependencies: - eastasianwidth "^0.2.0" - emoji-regex "^9.2.2" - strip-ansi "^7.0.1" - string.prototype.padend@^3.0.0: version "3.1.4" resolved "https://registry.yarnpkg.com/string.prototype.padend/-/string.prototype.padend-3.1.4.tgz#2c43bb3a89eb54b6750de5942c123d6c98dd65b6" @@ -9761,13 +9637,6 @@ strip-ansi@6.0.1, strip-ansi@^6.0.0, strip-ansi@^6.0.1: dependencies: ansi-regex "^5.0.1" -strip-ansi@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.0.1.tgz#61740a08ce36b61e50e65653f07060d000975fb2" - integrity sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw== - dependencies: - ansi-regex "^6.0.1" - strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" @@ -9867,7 +9736,19 @@ tapable@^2.2.0: resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== -tar@6.1.13, tar@^6.0.5, tar@^6.1.11, tar@^6.1.13, tar@^6.1.2: +tar@6.1.14: + version "6.1.14" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.14.tgz#e87926bec1cfe7c9e783a77a79f3e81c1cfa3b66" + integrity sha512-piERznXu0U7/pW7cdSn7hjqySIVTYT6F76icmFk7ptU7dDYlXTm5r9A6K04R2vU3olYgoKeo1Cg3eeu5nhftAw== + dependencies: + chownr "^2.0.0" + fs-minipass "^2.0.0" + minipass "^5.0.0" + minizlib "^2.1.1" + mkdirp "^1.0.3" + yallist "^4.0.0" + +tar@^6.0.5, tar@^6.1.11, tar@^6.1.13, tar@^6.1.2: version "6.1.13" resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.13.tgz#46e22529000f612180601a6fe0680e7da508847b" integrity sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw== @@ -9935,7 +9816,7 @@ through2@^4.0.0: dependencies: readable-stream "3" -through@2, "through@>=2.2.7 <3", through@^2.3.8: +through@2, "through@>=2.2.7 <3": version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== @@ -10116,10 +9997,10 @@ type-detect@4.0.8, type-detect@^4.0.8: resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== -type-fest@3.9.0, type-fest@^3.8.0: - version "3.9.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-3.9.0.tgz#36a9e46e6583649f9e6098b267bc577275e9e4f4" - integrity sha512-hR8JP2e8UiH7SME5JZjsobBlEiatFoxpzCP+R3ZeCo7kAaG1jXQE5X/buLzogM6GJu8le9Y4OcfNuIQX0rZskA== +type-fest@3.10.0: + version "3.10.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-3.10.0.tgz#d75f17a22be8816aea6315ab2739fe1c0c211863" + integrity sha512-hmAPf1datm+gt3c2mvu0sJyhFy6lTkIGf0GzyaZWxRLnabQfPUqg6tF95RPg6sLxKI7nFLGdFxBcf2/7+GXI+A== type-fest@^0.13.1: version "0.13.1" @@ -10161,6 +10042,11 @@ type-fest@^2.0.0, type-fest@^2.12.2, type-fest@^2.5.0: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.19.0.tgz#88068015bb33036a598b952e55e9311a60fd3a9b" integrity sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA== +type-fest@^3.8.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-3.9.0.tgz#36a9e46e6583649f9e6098b267bc577275e9e4f4" + integrity sha512-hR8JP2e8UiH7SME5JZjsobBlEiatFoxpzCP+R3ZeCo7kAaG1jXQE5X/buLzogM6GJu8le9Y4OcfNuIQX0rZskA== + typed-array-length@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.4.tgz#89d83785e5c4098bec72e08b319651f0eac9c1bb" @@ -10493,15 +10379,6 @@ wordwrap@^1.0.0: resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q== -wrap-ansi@^6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" - integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" @@ -10582,7 +10459,7 @@ yallist@^3.0.2: resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== -yaml@2.2.2, yaml@^2.2.2: +yaml@2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.2.2.tgz#ec551ef37326e6d42872dad1970300f8eb83a073" integrity sha512-CBKFWExMn46Foo4cldiChEzn7S7SRV+wqiluAb6xmueD/fGyRHIhX8m14vVGgeFWjN540nKCNVj6P21eQjgTuA==