From 18ddc2fe74011f5dda0ced239b46fefeeb6ca4f6 Mon Sep 17 00:00:00 2001 From: Boris Bera Date: Wed, 3 May 2023 15:05:39 -0400 Subject: [PATCH 01/57] feat(manager/dockerfile): support file names that are all lowercase (#21877) --- docs/usage/configuration-options.md | 2 +- lib/modules/manager/dockerfile/index.ts | 4 ++-- .../repository/extract/extract-fingerprint-config.spec.ts | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/usage/configuration-options.md b/docs/usage/configuration-options.md index 862fc39935e064..82061dc96c13d4 100644 --- a/docs/usage/configuration-options.md +++ b/docs/usage/configuration-options.md @@ -932,7 +932,7 @@ At other times, the possible files is too vague for Renovate to have any default For default, Kubernetes manifests can exist in any `*.yaml` file and we don't want Renovate to parse every single YAML file in every repository just in case some of them have a Kubernetes manifest, so Renovate's default `fileMatch` for manager `kubernetes` is actually empty (`[]`) and needs the user to tell Renovate what directories/files to look in. Finally, there are cases where Renovate's default `fileMatch` is good, but you may be using file patterns that a bot couldn't possibly guess about. -For example, Renovate's default `fileMatch` for `Dockerfile` is `['(^|/|\\.)Dockerfile$', '(^|/)Dockerfile[^/]*$']`. +For example, Renovate's default `fileMatch` for `Dockerfile` is `['(^|/|\\.)([Dd]ocker|[Cc]ontainer)file$', '(^|/)([Dd]ocker|[Cc]ontainer)file[^/]*$']`. This will catch files like `backend/Dockerfile`, `prefix.Dockerfile` or `Dockerfile-suffix`, but it will miss files like `ACTUALLY_A_DOCKERFILE.template`. Because `fileMatch` is mergeable, you don't need to duplicate the defaults and could just add the missing file like this: diff --git a/lib/modules/manager/dockerfile/index.ts b/lib/modules/manager/dockerfile/index.ts index 0e011c1730d1d4..febfd35a2a88d6 100644 --- a/lib/modules/manager/dockerfile/index.ts +++ b/lib/modules/manager/dockerfile/index.ts @@ -8,8 +8,8 @@ export { extractPackageFile }; export const defaultConfig = { fileMatch: [ - '(^|/|\\.)(Docker|Container)file$', - '(^|/)(Docker|Container)file[^/]*$', + '(^|/|\\.)([Dd]ocker|[Cc]ontainer)file$', + '(^|/)([Dd]ocker|[Cc]ontainer)file[^/]*$', ], }; diff --git a/lib/workers/repository/extract/extract-fingerprint-config.spec.ts b/lib/workers/repository/extract/extract-fingerprint-config.spec.ts index 76977db7552183..c0ac40404f4e46 100644 --- a/lib/workers/repository/extract/extract-fingerprint-config.spec.ts +++ b/lib/workers/repository/extract/extract-fingerprint-config.spec.ts @@ -100,8 +100,8 @@ describe('workers/repository/extract/extract-fingerprint-config', () => { enabled: true, fileList: [], fileMatch: [ - '(^|/|\\.)(Docker|Container)file$', - '(^|/)(Docker|Container)file[^/]*$', + '(^|/|\\.)([Dd]ocker|[Cc]ontainer)file$', + '(^|/)([Dd]ocker|[Cc]ontainer)file[^/]*$', ], ignorePaths: ['**/node_modules/**', '**/bower_components/**'], includePaths: [], From 665866a01e1660ce6ae00e8ca2bc1c21939778f2 Mon Sep 17 00:00:00 2001 From: Rhys Arkins Date: Thu, 4 May 2023 14:52:22 +0200 Subject: [PATCH 02/57] =?UTF-8?q?fix(onboarding):=20don=E2=80=99t=20check?= =?UTF-8?q?=20onboarding=20cache=20unless=20onboarding=3Dtrue=20(#21967)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/workers/repository/onboarding/branch/check.spec.ts | 1 + lib/workers/repository/onboarding/branch/check.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/lib/workers/repository/onboarding/branch/check.spec.ts b/lib/workers/repository/onboarding/branch/check.spec.ts index add73cf44a0076..e8f03bb6515a06 100644 --- a/lib/workers/repository/onboarding/branch/check.spec.ts +++ b/lib/workers/repository/onboarding/branch/check.spec.ts @@ -20,6 +20,7 @@ describe('workers/repository/onboarding/branch/check', () => { const config = partial({ requireConfig: 'required', suppressNotifications: [], + onboarding: true, }); it('skips normal onboarding check if onboardingCache is valid', async () => { diff --git a/lib/workers/repository/onboarding/branch/check.ts b/lib/workers/repository/onboarding/branch/check.ts index 25f7d21a229c54..3a3ec850809eb8 100644 --- a/lib/workers/repository/onboarding/branch/check.ts +++ b/lib/workers/repository/onboarding/branch/check.ts @@ -68,6 +68,7 @@ export async function isOnboarded(config: RenovateConfig): Promise { // 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 && onboardingBranchCache && onboardingBranchCache.defaultBranchSha === From 7bdf4d6269fdddda31336b2009d4730cde127d49 Mon Sep 17 00:00:00 2001 From: Michael Kriese Date: Thu, 4 May 2023 17:17:04 +0200 Subject: [PATCH 03/57] fix(manager/terraform): correctly extract oci charts (#21974) --- lib/modules/manager/terraform/extract.spec.ts | 25 +++++++-------- .../extractors/resources/helm-release.ts | 32 +++++++++++-------- 2 files changed, 30 insertions(+), 27 deletions(-) diff --git a/lib/modules/manager/terraform/extract.spec.ts b/lib/modules/manager/terraform/extract.spec.ts index 4c5d53346d459f..cbdea0323c7c01 100644 --- a/lib/modules/manager/terraform/extract.spec.ts +++ b/lib/modules/manager/terraform/extract.spec.ts @@ -7,18 +7,18 @@ import type { RepoGlobalConfig } from '../../../config/types'; import * as hashicorp from '../../versioning/hashicorp'; import { extractPackageFile } from '.'; -const modules = Fixtures?.get('modules.tf'); -const bitbucketModules = Fixtures?.get('bitbucketModules.tf'); -const azureDevOpsModules = Fixtures?.get('azureDevOpsModules.tf'); -const providers = Fixtures?.get('providers.tf'); -const docker = Fixtures?.get('docker.tf'); -const kubernetes = Fixtures?.get('kubernetes.tf'); +const modules = Fixtures.get('modules.tf'); +const bitbucketModules = Fixtures.get('bitbucketModules.tf'); +const azureDevOpsModules = Fixtures.get('azureDevOpsModules.tf'); +const providers = Fixtures.get('providers.tf'); +const docker = Fixtures.get('docker.tf'); +const kubernetes = Fixtures.get('kubernetes.tf'); -const helm = Fixtures?.get('helm.tf'); -const lockedVersion = Fixtures?.get('lockedVersion.tf'); -const lockedVersionLockfile = Fixtures?.get('rangeStrategy.hcl'); -const terraformBlock = Fixtures?.get('terraformBlock.tf'); -const tfeWorkspaceBlock = Fixtures?.get('tfeWorkspace.tf'); +const helm = Fixtures.get('helm.tf'); +const lockedVersion = Fixtures.get('lockedVersion.tf'); +const lockedVersionLockfile = Fixtures.get('rangeStrategy.hcl'); +const terraformBlock = Fixtures.get('terraformBlock.tf'); +const tfeWorkspaceBlock = Fixtures.get('tfeWorkspace.tf'); const adminConfig: RepoGlobalConfig = { // `join` fixes Windows CI @@ -602,7 +602,6 @@ describe('modules/manager/terraform/extract', () => { datasource: 'helm', depName: undefined, depType: 'helm_release', - registryUrls: ['https://charts.helm.sh/stable'], skipReason: 'invalid-name', }, { @@ -629,7 +628,7 @@ describe('modules/manager/terraform/extract', () => { datasource: 'docker', depName: 'karpenter', depType: 'helm_release', - registryUrls: ['https://public.ecr.aws/karpenter'], + packageName: 'public.ecr.aws/karpenter/karpenter', }, ]); }); diff --git a/lib/modules/manager/terraform/extractors/resources/helm-release.ts b/lib/modules/manager/terraform/extractors/resources/helm-release.ts index 87d6375a1bbef7..c0c54a3b20ce8f 100644 --- a/lib/modules/manager/terraform/extractors/resources/helm-release.ts +++ b/lib/modules/manager/terraform/extractors/resources/helm-release.ts @@ -1,5 +1,6 @@ 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 { isOCIRegistry } from '../../../helmv3/utils'; @@ -37,18 +38,10 @@ export class HelmReleaseExtractor extends DependencyExtractor { depName: helmRelease.chart, datasource: HelmDatasource.id, }; - if (is.nonEmptyString(helmRelease.repository)) { - if (isOCIRegistry(helmRelease.repository)) { - // For oci repos, we remove the oci:// and use the docker datasource - dep.registryUrls = [ - helmRelease.repository.replace('oci://', 'https://'), - ]; - dep.datasource = DockerDatasource.id; - } else { - dep.registryUrls = [helmRelease.repository]; - } - } - if (!helmRelease.chart) { + + dependencies.push(dep); + + if (!is.nonEmptyString(helmRelease.chart)) { dep.skipReason = 'invalid-name'; } else if (isOCIRegistry(helmRelease.chart)) { // For oci charts, we remove the oci:// and use the docker datasource @@ -56,9 +49,20 @@ export class HelmReleaseExtractor extends DependencyExtractor { dep.datasource = DockerDatasource.id; } 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( + helmRelease.repository.replace('oci://', ''), + helmRelease.chart + ); + dep.datasource = DockerDatasource.id; + } + } else { + dep.registryUrls = [helmRelease.repository]; + } } - - dependencies.push(dep); } return dependencies; From 836943ea43339e74a3bdc9274326981345c2acbc Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 4 May 2023 18:06:53 +0000 Subject: [PATCH 04/57] chore(deps): update dependency nock to v13.3.1 (#21976) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 7e79c608a9eb93..87cd90e252d38e 100644 --- a/package.json +++ b/package.json @@ -319,7 +319,7 @@ "memfs": "3.5.1", "mock-fs": "5.2.0", "mockdate": "3.0.5", - "nock": "13.3.0", + "nock": "13.3.1", "npm-run-all": "4.1.5", "rimraf": "5.0.0", "semantic-release": "21.0.1", diff --git a/yarn.lock b/yarn.lock index 3c83b670fd84c3..d149ac40f9c1a2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7846,10 +7846,10 @@ nise@^5.1.2: just-extend "^4.0.2" path-to-regexp "^1.7.0" -nock@13.3.0: - version "13.3.0" - resolved "https://registry.yarnpkg.com/nock/-/nock-13.3.0.tgz#b13069c1a03f1ad63120f994b04bfd2556925768" - integrity sha512-HHqYQ6mBeiMc+N038w8LkMpDCRquCHWeNmN3v6645P3NhN2+qXOBqvPqo7Rt1VyCMzKhJ733wZqw5B7cQVFNPg== +nock@13.3.1: + version "13.3.1" + resolved "https://registry.yarnpkg.com/nock/-/nock-13.3.1.tgz#f22d4d661f7a05ebd9368edae1b5dc0a62d758fc" + integrity sha512-vHnopocZuI93p2ccivFyGuUfzjq2fxNyNurp7816mlT5V5HF4SzXu8lvLrVzBbNqzs+ODooZ6OksuSUNM7Njkw== dependencies: debug "^4.1.0" json-stringify-safe "^5.0.1" From 3f68122e8e0b2eb8a3f2f2a53f290a4e3ac2a739 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 4 May 2023 19:03:46 +0000 Subject: [PATCH 05/57] build(deps): update dependency cacache to v17.0.6 (#21977) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 33 +++++++-------------------------- 2 files changed, 8 insertions(+), 27 deletions(-) diff --git a/package.json b/package.json index 87cd90e252d38e..ea3baf4a45c705 100644 --- a/package.json +++ b/package.json @@ -169,7 +169,7 @@ "aws4": "1.12.0", "azure-devops-node-api": "12.0.0", "bunyan": "1.8.15", - "cacache": "17.0.5", + "cacache": "17.0.6", "cacheable-lookup": "5.0.4", "chalk": "4.1.2", "changelog-filename-regex": "2.0.1", diff --git a/yarn.lock b/yarn.lock index d149ac40f9c1a2..02f94be2f9b0b5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3884,16 +3884,16 @@ bunyan@1.8.15: mv "~2" safe-json-stringify "~1" -cacache@17.0.5: - version "17.0.5" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-17.0.5.tgz#6dbec26c11f1f6a2b558bc11ed3316577c339ebc" - integrity sha512-Y/PRQevNSsjAPWykl9aeGz8Pr+OI6BYM9fYDNMvOkuUiG9IhG4LEmaYrZZZvioMUEQ+cBCxT0v8wrnCURccyKA== +cacache@17.0.6, cacache@^17.0.0, cacache@^17.0.4, cacache@^17.0.5: + version "17.0.6" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-17.0.6.tgz#faf9739a067e6dcfd31316df82fdf7e1ec460373" + integrity sha512-ixcYmEBExFa/+ajIPjcwypxL97CjJyOsH9A/W+4qgEPIpJvKlC+HmVY8nkIck6n3PwUTdgq9c489niJGwl+5Cw== dependencies: "@npmcli/fs" "^3.1.0" fs-minipass "^3.0.0" - glob "^9.3.1" + glob "^10.2.2" lru-cache "^7.7.1" - minipass "^4.0.0" + minipass "^5.0.0" minipass-collect "^1.0.2" minipass-flush "^1.0.5" minipass-pipeline "^1.2.4" @@ -3927,25 +3927,6 @@ cacache@^16.1.0: tar "^6.1.11" unique-filename "^2.0.0" -cacache@^17.0.0, cacache@^17.0.4, cacache@^17.0.5: - version "17.0.6" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-17.0.6.tgz#faf9739a067e6dcfd31316df82fdf7e1ec460373" - integrity sha512-ixcYmEBExFa/+ajIPjcwypxL97CjJyOsH9A/W+4qgEPIpJvKlC+HmVY8nkIck6n3PwUTdgq9c489niJGwl+5Cw== - dependencies: - "@npmcli/fs" "^3.1.0" - fs-minipass "^3.0.0" - glob "^10.2.2" - lru-cache "^7.7.1" - minipass "^5.0.0" - minipass-collect "^1.0.2" - minipass-flush "^1.0.5" - minipass-pipeline "^1.2.4" - p-map "^4.0.0" - promise-inflight "^1.0.1" - ssri "^10.0.0" - tar "^6.1.11" - unique-filename "^3.0.0" - cacheable-lookup@5.0.4, cacheable-lookup@^5.0.3: version "5.0.4" resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz#5a6b865b2c44357be3d5ebc2a467b032719a7005" @@ -5601,7 +5582,7 @@ glob@^8.0.1: minimatch "^5.0.1" once "^1.3.0" -glob@^9.3.1, glob@^9.3.2: +glob@^9.3.2: version "9.3.5" resolved "https://registry.yarnpkg.com/glob/-/glob-9.3.5.tgz#ca2ed8ca452781a3009685607fdf025a899dfe21" integrity sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q== From e3e6de9f1d3a667b60a6c1547c1a7a5dc6b099c8 Mon Sep 17 00:00:00 2001 From: cjtim <47479090+cjtim@users.noreply.github.com> Date: Fri, 5 May 2023 02:19:00 +0700 Subject: [PATCH 06/57] fix(managers/gradle): allow dot annotation in version.ref (#21820) Signed-off-by: Jinna C Co-authored-by: Johannes Feichtner <343448+Churro@users.noreply.github.com> --- .../gradle/__fixtures__/1/libs.versions.toml | 2 +- .../gradle/__fixtures__/3/libs.versions.toml | 2 +- lib/modules/manager/gradle/extract/catalog.ts | 13 +++++++++---- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/lib/modules/manager/gradle/__fixtures__/1/libs.versions.toml b/lib/modules/manager/gradle/__fixtures__/1/libs.versions.toml index fccce61156ba5a..8aac96c8ed1b95 100644 --- a/lib/modules/manager/gradle/__fixtures__/1/libs.versions.toml +++ b/lib/modules/manager/gradle/__fixtures__/1/libs.versions.toml @@ -17,5 +17,5 @@ kotest = [ "kotest-runner-junit5", "kotest-assertions-core-jvm" ] [plugins] detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" } -publish-on-central = { id = "org.danilopianini.publish-on-central", version.ref = "publish-on-central" } +publish-on-central = { id = "org.danilopianini.publish-on-central", version.ref = "publish.on.central" } grgit = { id = "org.ajoberstar.grgit", version.unknown = "this will fail" } diff --git a/lib/modules/manager/gradle/__fixtures__/3/libs.versions.toml b/lib/modules/manager/gradle/__fixtures__/3/libs.versions.toml index bddeb5947dfe1d..7188d1a6c6b443 100644 --- a/lib/modules/manager/gradle/__fixtures__/3/libs.versions.toml +++ b/lib/modules/manager/gradle/__fixtures__/3/libs.versions.toml @@ -7,4 +7,4 @@ junit = "1.4.9" [libraries] junit-legacy = { module = "junit:junit", version.ref = "junit" } -mocha-junit = { module = "mocha-junit:mocha-junit", version.ref = "mocha-junit-reporter" } +mocha-junit = { module = "mocha-junit:mocha-junit", version.ref = "mocha.junit.reporter" } diff --git a/lib/modules/manager/gradle/extract/catalog.ts b/lib/modules/manager/gradle/extract/catalog.ts index 49b21ccceea7bc..16483dcb895d30 100644 --- a/lib/modules/manager/gradle/extract/catalog.ts +++ b/lib/modules/manager/gradle/extract/catalog.ts @@ -55,6 +55,10 @@ function isVersionPointer( return hasKey('ref', obj); } +function normalizeVersionPointer(versionPointer: string): string { + return versionPointer.replace(regEx(/[._]/g), '-'); +} + interface VersionExtract { currentValue?: string; fileReplacePosition?: number; @@ -79,12 +83,13 @@ function extractVersion({ versionSubContent: string; }): VersionExtract { if (isVersionPointer(version)) { + const parsedVersion = normalizeVersionPointer(version.ref); // everything else is ignored return extractLiteralVersion({ - version: versions[version.ref], + version: versions[parsedVersion], depStartIndex: versionStartIndex, depSubContent: versionSubContent, - sectionKey: version.ref, + sectionKey: parsedVersion, }); } else { return extractLiteralVersion({ @@ -205,7 +210,7 @@ function extractDependency({ }; } const versionRef = isVersionPointer(descriptor.version) - ? descriptor.version.ref + ? normalizeVersionPointer(descriptor.version.ref) : null; if (isArtifactDescriptor(descriptor)) { const { group, name } = descriptor; @@ -284,7 +289,7 @@ export function parseCatalog( dependency.skipReason = skipReason; } if (isVersionPointer(version) && dependency.commitMessageTopic) { - dependency.groupName = version.ref; + dependency.groupName = normalizeVersionPointer(version.ref); delete dependency.commitMessageTopic; } From 7f6ca9737878b8f3c7878909b77f1e3e7e89fba1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 4 May 2023 19:54:45 +0000 Subject: [PATCH 07/57] build(deps): update dependency cacache to v17.1.0 (#21979) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 28 +++++++++++++++++++++++----- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index ea3baf4a45c705..ea16c8f11f1227 100644 --- a/package.json +++ b/package.json @@ -169,7 +169,7 @@ "aws4": "1.12.0", "azure-devops-node-api": "12.0.0", "bunyan": "1.8.15", - "cacache": "17.0.6", + "cacache": "17.1.0", "cacheable-lookup": "5.0.4", "chalk": "4.1.2", "changelog-filename-regex": "2.0.1", diff --git a/yarn.lock b/yarn.lock index 02f94be2f9b0b5..db20cb6ff0f21b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3884,10 +3884,10 @@ bunyan@1.8.15: mv "~2" safe-json-stringify "~1" -cacache@17.0.6, cacache@^17.0.0, cacache@^17.0.4, cacache@^17.0.5: - version "17.0.6" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-17.0.6.tgz#faf9739a067e6dcfd31316df82fdf7e1ec460373" - integrity sha512-ixcYmEBExFa/+ajIPjcwypxL97CjJyOsH9A/W+4qgEPIpJvKlC+HmVY8nkIck6n3PwUTdgq9c489niJGwl+5Cw== +cacache@17.1.0: + version "17.1.0" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-17.1.0.tgz#b7286ef941dafe55b461cdcdceda71cacc1eb98d" + integrity sha512-hXpFU+Z3AfVmNuiLve1qxWHMq0RSIt5gjCKAHi/M6DktwFwDdAXAtunl1i4WSKaaVcU9IsRvXFg42jTHigcC6Q== dependencies: "@npmcli/fs" "^3.1.0" fs-minipass "^3.0.0" @@ -3898,7 +3898,6 @@ cacache@17.0.6, cacache@^17.0.0, cacache@^17.0.4, cacache@^17.0.5: minipass-flush "^1.0.5" minipass-pipeline "^1.2.4" p-map "^4.0.0" - promise-inflight "^1.0.1" ssri "^10.0.0" tar "^6.1.11" unique-filename "^3.0.0" @@ -3927,6 +3926,25 @@ cacache@^16.1.0: tar "^6.1.11" unique-filename "^2.0.0" +cacache@^17.0.0, cacache@^17.0.4, cacache@^17.0.5: + version "17.0.6" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-17.0.6.tgz#faf9739a067e6dcfd31316df82fdf7e1ec460373" + integrity sha512-ixcYmEBExFa/+ajIPjcwypxL97CjJyOsH9A/W+4qgEPIpJvKlC+HmVY8nkIck6n3PwUTdgq9c489niJGwl+5Cw== + dependencies: + "@npmcli/fs" "^3.1.0" + fs-minipass "^3.0.0" + glob "^10.2.2" + lru-cache "^7.7.1" + minipass "^5.0.0" + minipass-collect "^1.0.2" + minipass-flush "^1.0.5" + minipass-pipeline "^1.2.4" + p-map "^4.0.0" + promise-inflight "^1.0.1" + ssri "^10.0.0" + tar "^6.1.11" + unique-filename "^3.0.0" + cacheable-lookup@5.0.4, cacheable-lookup@^5.0.3: version "5.0.4" resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz#5a6b865b2c44357be3d5ebc2a467b032719a7005" From 2f3b636f250fa7c9eefaad0f535bdd3fa14a628b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 4 May 2023 19:55:38 +0000 Subject: [PATCH 08/57] chore(deps): update github/codeql-action action to v2.3.3 (#21978) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/codeql-analysis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 6e8e5835f18a35..c8efa2c88f5165 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -30,7 +30,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@f3feb00acb00f31a6f60280e6ace9ca31d91c76a # v2.3.2 + uses: github/codeql-action/init@29b1f65c5e92e24fe6b6647da1eaabe529cec70f # v2.3.3 with: languages: javascript @@ -40,7 +40,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@f3feb00acb00f31a6f60280e6ace9ca31d91c76a # v2.3.2 + uses: github/codeql-action/autobuild@29b1f65c5e92e24fe6b6647da1eaabe529cec70f # v2.3.3 # ℹī¸ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -54,4 +54,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@f3feb00acb00f31a6f60280e6ace9ca31d91c76a # v2.3.2 + uses: github/codeql-action/analyze@29b1f65c5e92e24fe6b6647da1eaabe529cec70f # v2.3.3 From 44f22984ddaafe2fceae4965076d7cdb26bcd716 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 5 May 2023 01:08:07 +0000 Subject: [PATCH 09/57] build(deps): update dependency redis to v4.6.6 (#21981) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index ea16c8f11f1227..091bdf49379505 100644 --- a/package.json +++ b/package.json @@ -221,7 +221,7 @@ "parse-link-header": "2.0.0", "prettier": "2.8.8", "quick-lru": "5.1.1", - "redis": "4.6.5", + "redis": "4.6.6", "remark": "13.0.0", "remark-github": "10.1.0", "safe-stable-stringify": "2.4.3", diff --git a/yarn.lock b/yarn.lock index db20cb6ff0f21b..ad417556653eca 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2448,10 +2448,10 @@ resolved "https://registry.yarnpkg.com/@redis/bloom/-/bloom-1.2.0.tgz#d3fd6d3c0af3ef92f26767b56414a370c7b63b71" integrity sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg== -"@redis/client@1.5.6": - version "1.5.6" - resolved "https://registry.yarnpkg.com/@redis/client/-/client-1.5.6.tgz#869cc65718d7d5493ef655a71dc40f3bc64a1b28" - integrity sha512-dFD1S6je+A47Lj22jN/upVU2fj4huR7S9APd7/ziUXsIXDL+11GPYti4Suv5y8FuXaN+0ZG4JF+y1houEJ7ToA== +"@redis/client@1.5.7": + version "1.5.7" + resolved "https://registry.yarnpkg.com/@redis/client/-/client-1.5.7.tgz#92cc5c98c76f189e37d24f0e1e17e104c6af17d4" + integrity sha512-gaOBOuJPjK5fGtxSseaKgSvjiZXQCdLlGg9WYQst+/GRUjmXaiB5kVkeQMRtPc7Q2t93XZcJfBMSwzs/XS9UZw== dependencies: cluster-key-slot "1.1.2" generic-pool "3.9.0" @@ -8969,13 +8969,13 @@ redeyed@~2.1.0: dependencies: esprima "~4.0.0" -redis@4.6.5: - version "4.6.5" - resolved "https://registry.yarnpkg.com/redis/-/redis-4.6.5.tgz#f32fbde44429e96f562bb0c9b1db0143ab8cfa4f" - integrity sha512-O0OWA36gDQbswOdUuAhRL6mTZpHFN525HlgZgDaVNgCJIAZR3ya06NTESb0R+TUZ+BFaDpz6NnnVvoMx9meUFg== +redis@4.6.6: + version "4.6.6" + resolved "https://registry.yarnpkg.com/redis/-/redis-4.6.6.tgz#46d4f2d149d1634d6ef53db5747412a0ef7974ec" + integrity sha512-aLs2fuBFV/VJ28oLBqYykfnhGGkFxvx0HdCEBYdJ99FFbSEMZ7c1nVKwR6ZRv+7bb7JnC0mmCzaqu8frgOYhpA== dependencies: "@redis/bloom" "1.2.0" - "@redis/client" "1.5.6" + "@redis/client" "1.5.7" "@redis/graph" "1.1.0" "@redis/json" "1.0.4" "@redis/search" "1.1.2" From 4924973e9eb6ed592a94f153096d4db7cf9befb7 Mon Sep 17 00:00:00 2001 From: Michael Kriese Date: Fri, 5 May 2023 10:50:58 +0200 Subject: [PATCH 10/57] build: switch hcl parser (#21988) --- lib/logger/index.spec.ts | 52 +++++++++++-------- lib/modules/manager/bundler/artifacts.spec.ts | 1 - lib/modules/manager/terraform/extract.ts | 2 +- .../manager/terraform/hcl/index.spec.ts | 12 ++--- lib/modules/manager/terraform/hcl/index.ts | 10 ++-- lib/util/git/private-key.spec.ts | 3 +- lib/workers/global/index.spec.ts | 25 ++++++--- package.json | 2 +- test/fixtures.ts | 17 +++++- yarn.lock | 12 +++-- 10 files changed, 87 insertions(+), 49 deletions(-) diff --git a/lib/logger/index.spec.ts b/lib/logger/index.spec.ts index ccf5403a29f189..c8422d469e2be6 100644 --- a/lib/logger/index.spec.ts +++ b/lib/logger/index.spec.ts @@ -1,4 +1,6 @@ -import _fs from 'fs-extra'; +import type { WriteStream } from 'node:fs'; +import fs from 'fs-extra'; +import { partial } from '../../test/util'; import { add } from '../util/host-rules'; import { addSecretForSanitizing as addSecret } from '../util/sanitize'; import { @@ -16,9 +18,6 @@ import { jest.unmock('.'); -jest.mock('fs-extra'); -const fs: any = _fs; - describe('logger/index', () => { it('inits', () => { expect(logger).toBeDefined(); @@ -97,12 +96,15 @@ describe('logger/index', () => { it('supports file-based logging', () => { let chunk = ''; - fs.createWriteStream.mockReturnValueOnce({ - writable: true, - write(x: string) { - chunk = x; - }, - }); + jest.spyOn(fs, 'createWriteStream').mockReturnValueOnce( + partial({ + writable: true, + write(x: string): boolean { + chunk = x; + return true; + }, + }) + ); addStream({ name: 'logfile', @@ -117,12 +119,15 @@ describe('logger/index', () => { it('handles cycles', () => { let logged: Record = {}; - fs.createWriteStream.mockReturnValueOnce({ - writable: true, - write(x: string) { - logged = JSON.parse(x); - }, - }); + jest.spyOn(fs, 'createWriteStream').mockReturnValueOnce( + partial({ + writable: true, + write(x: string): boolean { + logged = JSON.parse(x); + return true; + }, + }) + ); addStream({ name: 'logfile', @@ -142,12 +147,15 @@ describe('logger/index', () => { it('sanitizes secrets', () => { let logged: Record = {}; - fs.createWriteStream.mockReturnValueOnce({ - writable: true, - write(x: string) { - logged = JSON.parse(x); - }, - }); + jest.spyOn(fs, 'createWriteStream').mockReturnValueOnce( + partial({ + writable: true, + write(x: string): boolean { + logged = JSON.parse(x); + return true; + }, + }) + ); addStream({ name: 'logfile', diff --git a/lib/modules/manager/bundler/artifacts.spec.ts b/lib/modules/manager/bundler/artifacts.spec.ts index a2eab121cdc71f..841f8ecc899d2d 100644 --- a/lib/modules/manager/bundler/artifacts.spec.ts +++ b/lib/modules/manager/bundler/artifacts.spec.ts @@ -23,7 +23,6 @@ import { updateArtifacts } from '.'; const datasource = mocked(_datasource); const bundlerHostRules = mocked(_bundlerHostRules); -jest.mock('fs-extra'); jest.mock('../../../util/exec/env'); jest.mock('../../datasource'); jest.mock('../../../util/fs'); diff --git a/lib/modules/manager/terraform/extract.ts b/lib/modules/manager/terraform/extract.ts index 605f4d364b41ba..e15cc17af3d58b 100644 --- a/lib/modules/manager/terraform/extract.ts +++ b/lib/modules/manager/terraform/extract.ts @@ -37,7 +37,7 @@ export async function extractPackageFile( ); const dependencies = []; - const hclMap = hcl.parseHCL(content); + const hclMap = await hcl.parseHCL(content, fileName); if (is.nullOrUndefined(hclMap)) { logger.trace({ fileName }, 'failed to parse HCL file'); return null; diff --git a/lib/modules/manager/terraform/hcl/index.spec.ts b/lib/modules/manager/terraform/hcl/index.spec.ts index bd9be234275687..70cf21a38a79a6 100644 --- a/lib/modules/manager/terraform/hcl/index.spec.ts +++ b/lib/modules/manager/terraform/hcl/index.spec.ts @@ -8,8 +8,8 @@ const lockedVersion = Fixtures.get('lockedVersion.tf'); describe('modules/manager/terraform/hcl/index', () => { describe('parseHCL()', () => { - it('should return flat modules', () => { - const res = parseHCL(modulesTF); + it('should return flat modules', async () => { + const res = await parseHCL(modulesTF, 'file.tf'); expect(res?.module).toBeDefined(); expect(Object.keys(res!.module!)).toBeArrayOfSize(6); expect(res).toMatchObject({ @@ -50,8 +50,8 @@ describe('modules/manager/terraform/hcl/index', () => { }); }); - it('should return nested terraform block', () => { - const res = parseHCL(lockedVersion); + it('should return nested terraform block', async () => { + const res = await parseHCL(lockedVersion, 'file.tf'); expect(res).toMatchObject({ terraform: [ { @@ -67,8 +67,8 @@ describe('modules/manager/terraform/hcl/index', () => { }); }); - it('should return resource blocks', () => { - const res = parseHCL(resourcesTF); + it('should return resource blocks', async () => { + const res = await parseHCL(resourcesTF, 'file.tf'); expect(res).toMatchObject({ resource: { docker_container: { diff --git a/lib/modules/manager/terraform/hcl/index.ts b/lib/modules/manager/terraform/hcl/index.ts index 61803c995dda4d..8691daf3801a5f 100644 --- a/lib/modules/manager/terraform/hcl/index.ts +++ b/lib/modules/manager/terraform/hcl/index.ts @@ -1,10 +1,12 @@ -import * as hcl_parser from 'hcl2-parser'; - +import { parse } from '@cdktf/hcl2json'; import type { TerraformDefinitionFile } from './types'; -export function parseHCL(content: string): TerraformDefinitionFile | null { +export async function parseHCL( + content: string, + fileName: string +): Promise { try { - return hcl_parser.parseToObject(content)[0]; + return await parse(fileName, content); } catch (err) /* istanbul ignore next */ { return null; } diff --git a/lib/util/git/private-key.spec.ts b/lib/util/git/private-key.spec.ts index d3921992b2df42..9ecbbe74f0b261 100644 --- a/lib/util/git/private-key.spec.ts +++ b/lib/util/git/private-key.spec.ts @@ -1,9 +1,10 @@ +import { Fixtures } from '../../../test/fixtures'; import { mocked } from '../../../test/util'; import * as exec_ from '../exec'; import { configSigningKey, writePrivateKey } from './private-key'; import { setPrivateKey } from '.'; -jest.mock('fs-extra'); +jest.mock('fs-extra', () => Fixtures.fsExtra()); jest.mock('../exec'); const exec = mocked(exec_); diff --git a/lib/workers/global/index.spec.ts b/lib/workers/global/index.spec.ts index daae4d825c3036..8c371725b1569a 100644 --- a/lib/workers/global/index.spec.ts +++ b/lib/workers/global/index.spec.ts @@ -1,11 +1,11 @@ import { expect } from '@jest/globals'; import { ERROR, WARN } from 'bunyan'; -import * as _fs from 'fs-extra'; +import fs from 'fs-extra'; import { logger, mocked } from '../../../test/util'; import * as _presets from '../../config/presets'; import { CONFIG_PRESETS_INVALID } from '../../constants/error-messages'; import { DockerDatasource } from '../../modules/datasource/docker'; -import * as _platform from '../../modules/platform'; +import * as platform from '../../modules/platform'; import * as secrets from '../../util/sanitize'; import * as repositoryWorker from '../repository'; import * as configParser from './config/parse'; @@ -16,20 +16,33 @@ jest.mock('../repository'); jest.mock('../../util/fs'); jest.mock('../../config/presets'); -jest.mock('fs-extra'); -const fs = mocked(_fs); -const platform = mocked(_platform); +jest.mock('fs-extra', () => { + const realFs = jest.requireActual('fs-extra'); + return { + ensureDir: jest.fn(), + remove: jest.fn(), + readFile: jest.fn((file: string, options: any) => { + if (file.endsWith('.wasm.gz')) { + return realFs.readFile(file, options); + } + return undefined; + }), + writeFile: jest.fn(), + outputFile: jest.fn(), + }; +}); // imports are readonly const presets = mocked(_presets); const addSecretForSanitizing = jest.spyOn(secrets, 'addSecretForSanitizing'); const parseConfigs = jest.spyOn(configParser, 'parseConfigs'); +const initPlatform = jest.spyOn(platform, 'initPlatform'); describe('workers/global/index', () => { beforeEach(() => { logger.getProblems.mockImplementationOnce(() => []); - platform.initPlatform.mockImplementation((input) => Promise.resolve(input)); + initPlatform.mockImplementation((input) => Promise.resolve(input)); delete process.env.AWS_SECRET_ACCESS_KEY; delete process.env.AWS_SESSION_TOKEN; }); diff --git a/package.json b/package.json index 091bdf49379505..f840ca80aff0c7 100644 --- a/package.json +++ b/package.json @@ -142,6 +142,7 @@ "@aws-sdk/client-rds": "3.314.0", "@aws-sdk/client-s3": "3.312.0", "@breejs/later": "4.1.0", + "@cdktf/hcl2json": "0.16.1", "@cheap-glitch/mi-cron": "1.0.1", "@iarna/toml": "3.0.0", "@opentelemetry/api": "1.4.1", @@ -198,7 +199,6 @@ "graph-data-structure": "3.3.0", "handlebars": "4.7.7", "hasha": "5.2.2", - "hcl2-parser": "1.0.3", "ignore": "5.2.4", "ini": "4.1.0", "js-yaml": "4.1.0", diff --git a/test/fixtures.ts b/test/fixtures.ts index 3b3198122074ca..35afd650a566ee 100644 --- a/test/fixtures.ts +++ b/test/fixtures.ts @@ -1,8 +1,10 @@ -import type fs from 'node:fs'; +import fs from 'node:fs'; import type { PathLike, Stats } from 'node:fs'; import { jest } from '@jest/globals'; import callsite from 'callsite'; import { DirectoryJSON, fs as memfs, vol } from 'memfs'; +import type { TDataOut } from 'memfs/lib/encoding'; +import type { IOptions } from 'memfs/lib/volume'; import upath from 'upath'; // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion @@ -93,7 +95,7 @@ export class Fixtures { ...memfs, pathExists: jest.fn(pathExists), remove: jest.fn(memfs.promises.rm), - readFile: jest.fn(memfs.promises.readFile), + readFile: jest.fn(readFile), writeFile: jest.fn(memfs.promises.writeFile), outputFile: jest.fn(outputFile), stat: jest.fn(stat), @@ -107,6 +109,17 @@ export class Fixtures { } } +export function readFile( + fileName: string, + options: IOptions +): Promise { + if (fileName.endsWith('.wasm') || fileName.endsWith('.wasm.gz')) { + return fs.promises.readFile(fileName, options as any); + } + + return memfs.promises.readFile(fileName, options); +} + export async function outputFile( file: string, data: string | Buffer | Uint8Array diff --git a/yarn.lock b/yarn.lock index ad417556653eca..2b353c2f2ca49e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1525,6 +1525,13 @@ resolved "https://registry.yarnpkg.com/@breejs/later/-/later-4.1.0.tgz#9246907f46cc9e9c9af37d791ab468d98921bcc1" integrity sha512-QgGnZ9b7o4k0Ai1ZbTJWwZpZcFK9d+Gb+DyNt4UT9x6IEIs5HVu0iIlmgzGqN+t9MoJSpSPo9S/Mm51UtHr3JA== +"@cdktf/hcl2json@0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@cdktf/hcl2json/-/hcl2json-0.16.1.tgz#c5d4c965e150d29579d6b53a9fe6c946fca7e614" + integrity sha512-c0AcAzpUYREmkonxai3Jjd7P0c0/TMB+ga3Ir/02MDSdyV8VQ+1CLK2nVMJJqJTsGZkxrZGVj/jlwA6coDYaqg== + dependencies: + fs-extra "^11.1.1" + "@cheap-glitch/mi-cron@1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@cheap-glitch/mi-cron/-/mi-cron-1.0.1.tgz#111f4ce746c269aedf74533ac806881763a68f99" @@ -5809,11 +5816,6 @@ hasha@5.2.2: is-stream "^2.0.0" type-fest "^0.8.0" -hcl2-parser@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/hcl2-parser/-/hcl2-parser-1.0.3.tgz#096d0ff5a3c46707ace54fcb7571317f5828ff0e" - integrity sha512-NQUm/BFF+2nrBfeqDhhsy4DxxiLHgkeE3FywtjFiXnjSUaio3w4Tz1MQ3vGJBUhyArzOXJ24pO7JwE5LAn7Ncg== - he@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" From f9f52a5dec1d7883b17dd9ce0ce0e15bd6997ad7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 5 May 2023 17:46:31 +0200 Subject: [PATCH 11/57] build(deps): update dependency @renovatebot/ruby-semver to v3 (#21984) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 10 ++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index f840ca80aff0c7..dbebde1b66332e 100644 --- a/package.json +++ b/package.json @@ -158,7 +158,7 @@ "@qnighy/marshal": "0.1.3", "@renovatebot/osv-offline": "1.2.4", "@renovatebot/pep440": "2.1.14", - "@renovatebot/ruby-semver": "2.1.12", + "@renovatebot/ruby-semver": "3.0.1", "@sindresorhus/is": "4.6.0", "@types/ms": "0.7.31", "@types/tmp": "0.2.3", diff --git a/yarn.lock b/yarn.lock index 2b353c2f2ca49e..3194c17cf4b8d3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2512,12 +2512,10 @@ resolved "https://registry.yarnpkg.com/@renovatebot/pep440/-/pep440-2.1.14.tgz#fc0e354cf6e892a8e17d61a4ea7b82b9e309476b" integrity sha512-Wl35WmAaflt/evQx3EOI6vhlbLJG9kw/+RxRabNOTB4aK2hyGDyha5h8yzjLDD14Gfp74z1RXivIetNsPjRgKA== -"@renovatebot/ruby-semver@2.1.12": - version "2.1.12" - resolved "https://registry.yarnpkg.com/@renovatebot/ruby-semver/-/ruby-semver-2.1.12.tgz#001ae01d3576336e5865fdae5970d9cb89241167" - integrity sha512-9j42JmVRqDmdeEauCcMCRyvy3NA7z7ftuVUkUhB98NU1HUwmxiz1OExgPvxeNRIW/MryNXvUvPNT9dfDT75anw== - dependencies: - tslib "^2.5.0" +"@renovatebot/ruby-semver@3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@renovatebot/ruby-semver/-/ruby-semver-3.0.1.tgz#968c7dcf8b46a97df15aeca393fe2b2cae564d26" + integrity sha512-sbNb8/J/bI8ZYFrgwpEnYAZl8WDrB9OvEPbnEw4hakAMNLJ4H9ByrzywmJa+xqmPXcF4rOqFqqURMiLZkBXwtQ== "@seald-io/binary-search-tree@^1.0.3": version "1.0.3" From 9015d104d8cb059d3189b6d5e7fbdcc89726486b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 6 May 2023 00:10:19 +0000 Subject: [PATCH 12/57] build(deps): update dependency semantic-release to v21.0.2 (#22002) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 36 ++++++++++++++++++------------------ 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/package.json b/package.json index dbebde1b66332e..c29d06a7264774 100644 --- a/package.json +++ b/package.json @@ -322,7 +322,7 @@ "nock": "13.3.1", "npm-run-all": "4.1.5", "rimraf": "5.0.0", - "semantic-release": "21.0.1", + "semantic-release": "21.0.2", "strip-ansi": "6.0.1", "tar": "6.1.13", "tmp-promise": "3.0.3", diff --git a/yarn.lock b/yarn.lock index 3194c17cf4b8d3..b5ba73157a114d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2602,10 +2602,10 @@ semver "^7.1.2" tempy "^3.0.0" -"@semantic-release/release-notes-generator@^10.0.0": - version "10.0.3" - resolved "https://registry.yarnpkg.com/@semantic-release/release-notes-generator/-/release-notes-generator-10.0.3.tgz#85f7ca78bfa6b01fb5fda0ac48112855d69171dc" - integrity sha512-k4x4VhIKneOWoBGHkx0qZogNjCldLPRiAjnIpMnlUh6PtaWXp/T+C9U7/TaNDDtgDa5HMbHl4WlREdxHio6/3w== +"@semantic-release/release-notes-generator@^11.0.0": + version "11.0.1" + resolved "https://registry.yarnpkg.com/@semantic-release/release-notes-generator/-/release-notes-generator-11.0.1.tgz#38a7d66e9a762915bea36a006dbb2d41fbcb4a66" + integrity sha512-4deWsiY4Rg80oc9Ms11N20BIDgYkPMys4scNYQpi2Njdrtw5Z55nXKNsUN3kn6Sy/nI9dqqbp5L63TL4luI5Bw== dependencies: conventional-changelog-angular "^5.0.0" conventional-changelog-writer "^5.0.0" @@ -2614,9 +2614,9 @@ debug "^4.0.0" get-stream "^6.0.0" import-from "^4.0.0" - into-stream "^6.0.0" - lodash "^4.17.4" - read-pkg-up "^7.0.0" + into-stream "^7.0.0" + lodash-es "^4.17.21" + read-pkg-up "^9.0.0" "@sigstore/protobuf-specs@^0.1.0": version "0.1.0" @@ -6020,10 +6020,10 @@ internal-slot@^1.0.5: has "^1.0.3" side-channel "^1.0.4" -into-stream@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/into-stream/-/into-stream-6.0.0.tgz#4bfc1244c0128224e18b8870e85b2de8e66c6702" - integrity sha512-XHbaOAvP+uFKUFsOgoNPRjLkwB+I22JFPFe5OjTkQ0nwgj6+pSjb4NmB6VMxaPshLiOf+zcpOCBQuLwC1KHhZA== +into-stream@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/into-stream/-/into-stream-7.0.0.tgz#d1a211e146be8acfdb84dabcbf00fe8205e72936" + integrity sha512-2dYz766i9HprMBasCMvHMuazJ7u4WzhJwo5kb3iPSiW/iRYV6uPari3zHoqZlnuaR7V1bEiNMxikhp37rdBXbw== dependencies: from2 "^2.3.0" p-is-promise "^3.0.0" @@ -8850,7 +8850,7 @@ read-package-json@^6.0.0, read-package-json@^6.0.1: normalize-package-data "^5.0.0" npm-normalize-package-bin "^3.0.0" -read-pkg-up@^7.0.0, read-pkg-up@^7.0.1: +read-pkg-up@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507" integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg== @@ -8859,7 +8859,7 @@ read-pkg-up@^7.0.0, read-pkg-up@^7.0.1: read-pkg "^5.2.0" type-fest "^0.8.1" -read-pkg-up@^9.1.0: +read-pkg-up@^9.0.0, read-pkg-up@^9.1.0: version "9.1.0" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-9.1.0.tgz#38ca48e0bc6c6b260464b14aad9bcd4e5b1fbdc3" integrity sha512-vaMRR1AC1nrd5CQM0PhlRsO5oc2AAigqr7cCrZ/MW/Rsaflz4RlgzkpL4qoU/z1F6wrbd85iFv1OQj/y5RdGvg== @@ -9215,16 +9215,16 @@ sax@^1.2.4: resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== -semantic-release@21.0.1: - version "21.0.1" - resolved "https://registry.yarnpkg.com/semantic-release/-/semantic-release-21.0.1.tgz#f2cb0eb1d0b1883efdac2883ec40342ac5c6ff30" - integrity sha512-UhGxTUXHJQCBFgEQRZszLOHDpMduDSHGq3Q+30Bu+g0GbXh/EW508+kuFHezP5m0mN8xINW8hooiR3dzSV5ZLA== +semantic-release@21.0.2: + version "21.0.2" + resolved "https://registry.yarnpkg.com/semantic-release/-/semantic-release-21.0.2.tgz#c8610c25864c761f3a3acc2eb39c166f4e0200e4" + integrity sha512-Hl6lyJdZ0pAYD07Z1FIUmg06UzSC3fEjHS7U31YppNQ8jOwjjt7pVzW9OfpoO0vbmqD3Tc+b/iZh5fqvKt01OA== dependencies: "@semantic-release/commit-analyzer" "^9.0.2" "@semantic-release/error" "^3.0.0" "@semantic-release/github" "^8.0.0" "@semantic-release/npm" "^10.0.2" - "@semantic-release/release-notes-generator" "^10.0.0" + "@semantic-release/release-notes-generator" "^11.0.0" aggregate-error "^4.0.1" cosmiconfig "^8.0.0" debug "^4.0.0" From da8ee606c2a652af4b4990b6d523e274d00e127b Mon Sep 17 00:00:00 2001 From: Ubiratan Soares Date: Sat, 6 May 2023 06:43:45 +0200 Subject: [PATCH 13/57] feat(manager/asdf): Add maestro, detekt and ktlint (#21999) --- lib/modules/manager/asdf/extract.spec.ts | 23 +++++++++++++++++++ .../manager/asdf/upgradeable-tooling.ts | 23 +++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/lib/modules/manager/asdf/extract.spec.ts b/lib/modules/manager/asdf/extract.spec.ts index bc77ae464bd7a4..e728dafd28eb9b 100644 --- a/lib/modules/manager/asdf/extract.spec.ts +++ b/lib/modules/manager/asdf/extract.spec.ts @@ -89,6 +89,9 @@ terraform 1.3.3 terragrunt 0.43.2 trivy 0.33.0 zig 0.9.1 +maestro 1.24.0 +detekt 1.21.0 +ktlint 0.48.1 dummy 1.2.3 ` ); @@ -398,6 +401,26 @@ dummy 1.2.3 packageName: 'ziglang/zig', depName: 'zig', }, + { + currentValue: '1.24.0', + datasource: 'github-releases', + packageName: 'mobile-dev-inc/maestro', + depName: 'maestro', + extractVersion: '^cli-(?\\S+)', + }, + { + currentValue: '1.21.0', + datasource: 'github-releases', + packageName: 'detekt/detekt', + depName: 'detekt', + extractVersion: '^v(?\\S+)', + }, + { + currentValue: '0.48.1', + datasource: 'github-releases', + packageName: 'pinterest/ktlint', + depName: 'ktlint', + }, { depName: 'dummy', skipReason: 'unsupported-datasource', diff --git a/lib/modules/manager/asdf/upgradeable-tooling.ts b/lib/modules/manager/asdf/upgradeable-tooling.ts index d076f0913e22ca..f52f3839217b76 100644 --- a/lib/modules/manager/asdf/upgradeable-tooling.ts +++ b/lib/modules/manager/asdf/upgradeable-tooling.ts @@ -414,4 +414,27 @@ export const upgradeableTooling: Record = { packageName: 'ziglang/zig', }, }, + maestro: { + asdfPluginUrl: 'https://github.com/dotanuki-labs/asdf-maestro', + config: { + datasource: GithubReleasesDatasource.id, + packageName: 'mobile-dev-inc/maestro', + extractVersion: '^cli-(?\\S+)', + }, + }, + detekt: { + asdfPluginUrl: 'https://github.com/dotanuki-labs/asdf-detekt', + config: { + datasource: GithubReleasesDatasource.id, + packageName: 'detekt/detekt', + extractVersion: '^v(?\\S+)', + }, + }, + ktlint: { + asdfPluginUrl: 'https://github.com/asdf-community/asdf-ktlint', + config: { + datasource: GithubReleasesDatasource.id, + packageName: 'pinterest/ktlint', + }, + }, }; From 1cd405b2b3c86a591796d36890b955058b47f548 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 6 May 2023 05:25:03 +0000 Subject: [PATCH 14/57] build(deps): update dependency @renovatebot/pep440 to v2.1.15 (#22003) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index c29d06a7264774..59258853236b25 100644 --- a/package.json +++ b/package.json @@ -157,7 +157,7 @@ "@opentelemetry/semantic-conventions": "1.12.0", "@qnighy/marshal": "0.1.3", "@renovatebot/osv-offline": "1.2.4", - "@renovatebot/pep440": "2.1.14", + "@renovatebot/pep440": "2.1.15", "@renovatebot/ruby-semver": "3.0.1", "@sindresorhus/is": "4.6.0", "@types/ms": "0.7.31", diff --git a/yarn.lock b/yarn.lock index b5ba73157a114d..61b4822cc0ca8d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2507,10 +2507,10 @@ luxon "^3.3.0" node-fetch "^2.6.9" -"@renovatebot/pep440@2.1.14": - version "2.1.14" - resolved "https://registry.yarnpkg.com/@renovatebot/pep440/-/pep440-2.1.14.tgz#fc0e354cf6e892a8e17d61a4ea7b82b9e309476b" - integrity sha512-Wl35WmAaflt/evQx3EOI6vhlbLJG9kw/+RxRabNOTB4aK2hyGDyha5h8yzjLDD14Gfp74z1RXivIetNsPjRgKA== +"@renovatebot/pep440@2.1.15": + version "2.1.15" + resolved "https://registry.yarnpkg.com/@renovatebot/pep440/-/pep440-2.1.15.tgz#b481ec1a9f2782debd8f3c787999529a46157019" + integrity sha512-zJQ6ZLzgD3HsyyBLnDiviimxfripKHzPYmRqgIHb9Ettre3ivrkaz6F1zbeowf0kRBxB8rh8qit0Ftn4oBsg+w== "@renovatebot/ruby-semver@3.0.1": version "3.0.1" From 9276a54069900e2eaedd5cbcab1cef74a116597d Mon Sep 17 00:00:00 2001 From: Rhys Arkins Date: Sun, 7 May 2023 06:12:15 +0200 Subject: [PATCH 15/57] refactor(scm): use scm for getFileList, checkoutBranch (#22006) --- lib/modules/manager/gradle/artifacts.spec.ts | 5 +-- lib/modules/manager/gradle/artifacts.ts | 5 +-- lib/modules/manager/nuget/artifacts.spec.ts | 4 +-- .../manager/nuget/package-tree.spec.ts | 18 +++++------ lib/modules/manager/nuget/package-tree.ts | 4 +-- lib/modules/platform/default-scm.spec.ts | 12 +++++++ lib/modules/platform/default-scm.ts | 8 +++++ lib/modules/platform/types.ts | 2 ++ .../config-migration/branch/create.spec.ts | 13 ++++---- .../config-migration/branch/create.ts | 3 +- .../config-migration/branch/index.spec.ts | 10 +++--- .../config-migration/branch/index.ts | 3 +- .../branch/migrated-data.spec.ts | 7 ++-- .../config-migration/branch/migrated-data.ts | 4 +-- .../config-migration/branch/rebase.spec.ts | 11 +++---- .../config-migration/branch/rebase.ts | 4 +-- lib/workers/repository/extract/index.spec.ts | 4 +-- lib/workers/repository/extract/index.ts | 4 +-- lib/workers/repository/init/merge.spec.ts | 32 +++++++++---------- lib/workers/repository/init/merge.ts | 4 +-- .../onboarding/branch/check.spec.ts | 5 +-- .../repository/onboarding/branch/check.ts | 5 +-- .../onboarding/branch/index.spec.ts | 31 +++++++++--------- .../repository/onboarding/branch/index.ts | 9 ++---- .../repository/process/extract-update.spec.ts | 12 +++---- .../repository/process/extract-update.ts | 3 +- .../update/branch/automerge.spec.ts | 6 ++-- .../repository/update/branch/automerge.ts | 5 +-- .../repository/update/branch/index.spec.ts | 6 ++-- lib/workers/repository/update/branch/index.ts | 5 ++- 30 files changed, 130 insertions(+), 114 deletions(-) diff --git a/lib/modules/manager/gradle/artifacts.spec.ts b/lib/modules/manager/gradle/artifacts.spec.ts index d42d22dc55c691..087952f444900b 100644 --- a/lib/modules/manager/gradle/artifacts.spec.ts +++ b/lib/modules/manager/gradle/artifacts.spec.ts @@ -12,6 +12,7 @@ import { logger, mockedFunction, partial, + scm, } from '../../../../test/util'; import { GlobalConfig } from '../../../config/global'; import type { RepoGlobalConfig } from '../../../config/types'; @@ -61,7 +62,7 @@ describe('modules/manager/gradle/artifacts', () => { }); fs.findUpLocal.mockResolvedValue('gradlew'); - git.getFileList.mockResolvedValue([ + scm.getFileList.mockResolvedValue([ 'gradlew', 'build.gradle', 'gradle.lockfile', @@ -92,7 +93,7 @@ describe('modules/manager/gradle/artifacts', () => { it('aborts if no lockfile is found', async () => { const execSnapshots = mockExecAll(); - git.getFileList.mockResolvedValue(['build.gradle', 'settings.gradle']); + scm.getFileList.mockResolvedValue(['build.gradle', 'settings.gradle']); expect( await updateArtifacts({ diff --git a/lib/modules/manager/gradle/artifacts.ts b/lib/modules/manager/gradle/artifacts.ts index 671aa24a628fc7..68efbcb4206c86 100644 --- a/lib/modules/manager/gradle/artifacts.ts +++ b/lib/modules/manager/gradle/artifacts.ts @@ -6,8 +6,9 @@ import { logger } from '../../../logger'; import { exec } from '../../../util/exec'; import type { ExecOptions } from '../../../util/exec/types'; import { findUpLocal, readLocalFile, writeLocalFile } from '../../../util/fs'; -import { getFileList, getFiles, getRepoStatus } from '../../../util/git'; +import { getFiles, getRepoStatus } from '../../../util/git'; import { regEx } from '../../../util/regex'; +import { scm } from '../../platform/scm'; import { extraEnv, extractGradleVersion, @@ -94,7 +95,7 @@ export async function updateArtifacts({ }: UpdateArtifact): Promise { logger.debug(`gradle.updateArtifacts(${packageFileName})`); - const fileList = await getFileList(); + const fileList = await scm.getFileList(); const lockFiles = fileList.filter((file) => isLockFile(file)); if (!lockFiles.length) { logger.debug('No Gradle dependency lockfiles found - skipping update'); diff --git a/lib/modules/manager/nuget/artifacts.spec.ts b/lib/modules/manager/nuget/artifacts.spec.ts index b6ae31d6cc5749..5520b23a89ea87 100644 --- a/lib/modules/manager/nuget/artifacts.spec.ts +++ b/lib/modules/manager/nuget/artifacts.spec.ts @@ -1,6 +1,6 @@ import { join } from 'upath'; import { envMock, mockExecAll } from '../../../../test/exec-util'; -import { env, fs, git, mocked } from '../../../../test/util'; +import { env, fs, git, mocked, scm } from '../../../../test/util'; import { GlobalConfig } from '../../../config/global'; import type { RepoGlobalConfig } from '../../../config/types'; import * as docker from '../../../util/exec/docker'; @@ -40,7 +40,7 @@ describe('modules/manager/nuget/artifacts', () => { getDefaultRegistries.mockReturnValue([]); env.getChildProcessEnv.mockReturnValue(envMock.basic); fs.privateCacheDir.mockImplementation(realFs.privateCacheDir); - git.getFileList.mockResolvedValueOnce([]); + scm.getFileList.mockResolvedValueOnce([]); GlobalConfig.set(adminConfig); docker.resetPrefetchedImages(); }); diff --git a/lib/modules/manager/nuget/package-tree.spec.ts b/lib/modules/manager/nuget/package-tree.spec.ts index a5541829293479..3b9e99e04c860e 100644 --- a/lib/modules/manager/nuget/package-tree.spec.ts +++ b/lib/modules/manager/nuget/package-tree.spec.ts @@ -1,7 +1,7 @@ import { fs as memfs } from 'memfs'; import upath from 'upath'; import { Fixtures } from '../../../../test/fixtures'; -import { git } from '../../../../test/util'; +import { scm } from '../../../../test/util'; import { GlobalConfig } from '../../../config/global'; import type { RepoGlobalConfig } from '../../../config/types'; import { getDependentPackageFiles } from './package-tree'; @@ -27,7 +27,7 @@ describe('modules/manager/nuget/package-tree', () => { }); it('returns self for single project', async () => { - git.getFileList.mockResolvedValue(['single.csproj']); + scm.getFileList.mockResolvedValue(['single.csproj']); Fixtures.mock({ '/tmp/repo/single.csproj': Fixtures.get( 'single-project-file/single.csproj' @@ -40,7 +40,7 @@ describe('modules/manager/nuget/package-tree', () => { }); it('returns self for two projects with no references', async () => { - git.getFileList.mockResolvedValue(['one.csproj', 'two.csproj']); + scm.getFileList.mockResolvedValue(['one.csproj', 'two.csproj']); Fixtures.mock({ '/tmp/repo/one.csproj': Fixtures.get('two-no-reference/one.csproj'), '/tmp/repo/two.csproj': Fixtures.get('two-no-reference/two.csproj'), @@ -55,7 +55,7 @@ describe('modules/manager/nuget/package-tree', () => { }); it('returns projects for two projects with one reference', async () => { - git.getFileList.mockResolvedValue(['one/one.csproj', 'two/two.csproj']); + scm.getFileList.mockResolvedValue(['one/one.csproj', 'two/two.csproj']); Fixtures.mock({ '/tmp/repo/one/one.csproj': Fixtures.get( 'two-one-reference/one/one.csproj' @@ -72,7 +72,7 @@ describe('modules/manager/nuget/package-tree', () => { }); it('returns project for two projects with one reference and central versions', async () => { - git.getFileList.mockResolvedValue(['one/one.csproj', 'two/two.csproj']); + scm.getFileList.mockResolvedValue(['one/one.csproj', 'two/two.csproj']); Fixtures.mock({ '/tmp/repo/one/one.csproj': Fixtures.get( 'two-one-reference-with-central-versions/one/one.csproj' @@ -94,7 +94,7 @@ describe('modules/manager/nuget/package-tree', () => { }); it('returns projects for three projects with two linear references', async () => { - git.getFileList.mockResolvedValue([ + scm.getFileList.mockResolvedValue([ 'one/one.csproj', 'two/two.csproj', 'three/three.csproj', @@ -128,7 +128,7 @@ describe('modules/manager/nuget/package-tree', () => { }); it('returns projects for three projects with two tree-like references', async () => { - git.getFileList.mockResolvedValue([ + scm.getFileList.mockResolvedValue([ 'one/one.csproj', 'two/two.csproj', 'three/three.csproj', @@ -160,7 +160,7 @@ describe('modules/manager/nuget/package-tree', () => { }); it('throws error on circular reference', async () => { - git.getFileList.mockResolvedValue(['one/one.csproj', 'two/two.csproj']); + scm.getFileList.mockResolvedValue(['one/one.csproj', 'two/two.csproj']); Fixtures.mock({ '/tmp/repo/one/one.csproj': Fixtures.get( 'circular-reference/one/one.csproj' @@ -176,7 +176,7 @@ describe('modules/manager/nuget/package-tree', () => { }); it('skips on invalid xml file', async () => { - git.getFileList.mockResolvedValue(['foo/bar.csproj']); + scm.getFileList.mockResolvedValue(['foo/bar.csproj']); Fixtures.mock({ '/tmp/repo/foo/bar.csproj': ' { - const allFiles = await getFileList(); + const allFiles = await scm.getFileList(); const filteredPackageFiles = allFiles.filter( minimatch.filter('*.{cs,vb,fs}proj', { matchBase: true, nocase: true }) ); diff --git a/lib/modules/platform/default-scm.spec.ts b/lib/modules/platform/default-scm.spec.ts index 023948fa3dacae..7c9f7128d8de3a 100644 --- a/lib/modules/platform/default-scm.spec.ts +++ b/lib/modules/platform/default-scm.spec.ts @@ -48,4 +48,16 @@ describe('modules/platform/default-scm', () => { await defaultGitScm.isBranchModified('branchName'); expect(git.isBranchModified).toHaveBeenCalledTimes(1); }); + + it('delegate getFileList to util/git', async () => { + git.getFileList.mockResolvedValueOnce([]); + await defaultGitScm.getFileList(); + expect(git.getFileList).toHaveBeenCalledTimes(1); + }); + + it('delegate checkoutBranch to util/git', async () => { + git.checkoutBranch.mockResolvedValueOnce(''); + await defaultGitScm.checkoutBranch('branchName'); + expect(git.checkoutBranch).toHaveBeenCalledTimes(1); + }); }); diff --git a/lib/modules/platform/default-scm.ts b/lib/modules/platform/default-scm.ts index d21f3cff0b832e..f210500a9a0d42 100644 --- a/lib/modules/platform/default-scm.ts +++ b/lib/modules/platform/default-scm.ts @@ -30,4 +30,12 @@ export class DefaultGitScm implements PlatformScm { isBranchModified(branchName: string): Promise { return git.isBranchModified(branchName); } + + getFileList(): Promise { + return git.getFileList(); + } + + checkoutBranch(branchName: string): Promise { + return git.checkoutBranch(branchName); + } } diff --git a/lib/modules/platform/types.ts b/lib/modules/platform/types.ts index 57917c8ca690e3..12205f74099bb2 100644 --- a/lib/modules/platform/types.ts +++ b/lib/modules/platform/types.ts @@ -225,4 +225,6 @@ export interface PlatformScm { getBranchCommit(branchName: string): Promise; deleteBranch(branchName: string): Promise; commitAndPush(commitConfig: CommitFilesConfig): Promise; + getFileList(): Promise; + checkoutBranch(branchName: string): Promise; } diff --git a/lib/workers/repository/config-migration/branch/create.spec.ts b/lib/workers/repository/config-migration/branch/create.spec.ts index d1e450be9d8598..6f854ccc3c0075 100644 --- a/lib/workers/repository/config-migration/branch/create.spec.ts +++ b/lib/workers/repository/config-migration/branch/create.spec.ts @@ -2,7 +2,6 @@ import type { Indent } from 'detect-indent'; import { Fixtures } from '../../../../../test/fixtures'; import { RenovateConfig, getConfig, partial } from '../../../../../test/util'; import { scm } from '../../../../modules/platform/scm'; -import { checkoutBranch } from '../../../../util/git'; import { createConfigMigrationBranch } from './create'; import { MigratedDataFactory } from './migrated-data'; import type { MigratedData } from './migrated-data'; @@ -37,7 +36,7 @@ describe('workers/repository/config-migration/branch/create', () => { describe('createConfigMigrationBranch', () => { it('applies the default commit message', async () => { await createConfigMigrationBranch(config, migratedConfigData); - expect(checkoutBranch).toHaveBeenCalledWith(config.defaultBranch); + expect(scm.checkoutBranch).toHaveBeenCalledWith(config.defaultBranch); expect(scm.commitAndPush).toHaveBeenCalledWith({ branchName: 'renovate/migrate-config', baseBranch: 'dev', @@ -60,7 +59,7 @@ describe('workers/repository/config-migration/branch/create', () => { await createConfigMigrationBranch(config, migratedConfigData); - expect(checkoutBranch).toHaveBeenCalledWith(config.defaultBranch); + expect(scm.checkoutBranch).toHaveBeenCalledWith(config.defaultBranch); expect(scm.commitAndPush).toHaveBeenCalledWith({ branchName: 'renovate/migrate-config', baseBranch: 'dev', @@ -84,7 +83,7 @@ describe('workers/repository/config-migration/branch/create', () => { const message = `PREFIX: migrate config renovate.json`; await createConfigMigrationBranch(config, migratedConfigData); - expect(checkoutBranch).toHaveBeenCalledWith(config.defaultBranch); + expect(scm.checkoutBranch).toHaveBeenCalledWith(config.defaultBranch); expect(scm.commitAndPush).toHaveBeenCalledWith({ branchName: 'renovate/migrate-config', baseBranch: 'dev', @@ -109,7 +108,7 @@ describe('workers/repository/config-migration/branch/create', () => { const message = `Migrate config renovate.json ${suffix}`; await createConfigMigrationBranch(config, migratedConfigData); - expect(checkoutBranch).toHaveBeenCalledWith(config.defaultBranch); + expect(scm.checkoutBranch).toHaveBeenCalledWith(config.defaultBranch); expect(scm.commitAndPush).toHaveBeenCalledWith({ branchName: 'renovate/migrate-config', baseBranch: 'dev', @@ -135,7 +134,7 @@ describe('workers/repository/config-migration/branch/create', () => { await createConfigMigrationBranch(config, migratedConfigData); - expect(checkoutBranch).toHaveBeenCalledWith(config.defaultBranch); + expect(scm.checkoutBranch).toHaveBeenCalledWith(config.defaultBranch); expect(scm.commitAndPush).toHaveBeenCalledWith({ branchName: 'renovate/migrate-config', baseBranch: 'dev', @@ -160,7 +159,7 @@ describe('workers/repository/config-migration/branch/create', () => { await createConfigMigrationBranch(config, migratedConfigData); - expect(checkoutBranch).toHaveBeenCalledWith(config.defaultBranch); + expect(scm.checkoutBranch).toHaveBeenCalledWith(config.defaultBranch); expect(scm.commitAndPush).toHaveBeenCalledWith({ branchName: 'renovate/migrate-config', baseBranch: 'dev', diff --git a/lib/workers/repository/config-migration/branch/create.ts b/lib/workers/repository/config-migration/branch/create.ts index e29fa072495720..e188e212f5a82e 100644 --- a/lib/workers/repository/config-migration/branch/create.ts +++ b/lib/workers/repository/config-migration/branch/create.ts @@ -2,7 +2,6 @@ import { GlobalConfig } from '../../../../config/global'; import type { RenovateConfig } from '../../../../config/types'; import { logger } from '../../../../logger'; import { scm } from '../../../../modules/platform/scm'; -import { checkoutBranch } from '../../../../util/git'; import { getMigrationBranchName } from '../common'; import { ConfigMigrationCommitMessageFactory } from './commit-message'; import { MigratedDataFactory } from './migrated-data'; @@ -29,7 +28,7 @@ export async function createConfigMigrationBranch( return Promise.resolve(null); } - await checkoutBranch(config.defaultBranch!); + await scm.checkoutBranch(config.defaultBranch!); const contents = await MigratedDataFactory.applyPrettierFormatting( migratedConfigData ); diff --git a/lib/workers/repository/config-migration/branch/index.spec.ts b/lib/workers/repository/config-migration/branch/index.spec.ts index a9f89c60599ebb..34edd71ef7c3b7 100644 --- a/lib/workers/repository/config-migration/branch/index.spec.ts +++ b/lib/workers/repository/config-migration/branch/index.spec.ts @@ -56,7 +56,7 @@ describe('workers/repository/config-migration/branch/index', () => { const res = await checkConfigMigrationBranch(config, migratedData); // TODO: types (#7154) expect(res).toBe(`${config.branchPrefix!}migrate-config`); - expect(git.checkoutBranch).toHaveBeenCalledTimes(1); + expect(scm.checkoutBranch).toHaveBeenCalledTimes(1); expect(git.commitFiles).toHaveBeenCalledTimes(0); expect(logger.debug).toHaveBeenCalledWith( 'Config Migration PR already exists' @@ -72,7 +72,7 @@ describe('workers/repository/config-migration/branch/index', () => { const res = await checkConfigMigrationBranch(config, migratedData); // TODO: types (#7154) expect(res).toBe(`${config.branchPrefix!}migrate-config`); - expect(git.checkoutBranch).toHaveBeenCalledTimes(0); + expect(scm.checkoutBranch).toHaveBeenCalledTimes(0); expect(git.commitFiles).toHaveBeenCalledTimes(0); }); @@ -83,7 +83,7 @@ describe('workers/repository/config-migration/branch/index', () => { const res = await checkConfigMigrationBranch(config, migratedData); // TODO: types (#7154) expect(res).toBe(`${config.branchPrefix!}migrate-config`); - expect(git.checkoutBranch).toHaveBeenCalledTimes(1); + expect(scm.checkoutBranch).toHaveBeenCalledTimes(1); expect(git.commitFiles).toHaveBeenCalledTimes(0); expect(logger.debug).toHaveBeenCalledWith('Need to create migration PR'); }); @@ -98,7 +98,7 @@ describe('workers/repository/config-migration/branch/index', () => { const res = await checkConfigMigrationBranch(config, migratedData); // TODO: types (#7154) expect(res).toBe(`${config.branchPrefix!}migrate-config`); - expect(git.checkoutBranch).toHaveBeenCalledTimes(0); + expect(scm.checkoutBranch).toHaveBeenCalledTimes(0); expect(git.commitFiles).toHaveBeenCalledTimes(0); }); @@ -112,7 +112,7 @@ describe('workers/repository/config-migration/branch/index', () => { scm.branchExists.mockResolvedValueOnce(true); const res = await checkConfigMigrationBranch(config, migratedData); expect(res).toBeNull(); - expect(git.checkoutBranch).toHaveBeenCalledTimes(0); + expect(scm.checkoutBranch).toHaveBeenCalledTimes(0); expect(scm.commitAndPush).toHaveBeenCalledTimes(0); expect(scm.deleteBranch).toHaveBeenCalledTimes(1); expect(logger.debug).toHaveBeenCalledWith( diff --git a/lib/workers/repository/config-migration/branch/index.ts b/lib/workers/repository/config-migration/branch/index.ts index 25ee7ea7bc960b..3142269212c71e 100644 --- a/lib/workers/repository/config-migration/branch/index.ts +++ b/lib/workers/repository/config-migration/branch/index.ts @@ -4,7 +4,6 @@ import { logger } from '../../../../logger'; import { FindPRConfig, Pr, platform } from '../../../../modules/platform'; import { ensureComment } from '../../../../modules/platform/comment'; import { scm } from '../../../../modules/platform/scm'; -import { checkoutBranch } from '../../../../util/git'; import { getMigrationBranchName } from '../common'; import { ConfigMigrationCommitMessageFactory } from './commit-message'; import { createConfigMigrationBranch } from './create'; @@ -67,7 +66,7 @@ export async function checkConfigMigrationBranch( await createConfigMigrationBranch(config, migratedConfigData); } if (!GlobalConfig.get('dryRun')) { - await checkoutBranch(configMigrationBranch); + await scm.checkoutBranch(configMigrationBranch); } return configMigrationBranch; } diff --git a/lib/workers/repository/config-migration/branch/migrated-data.spec.ts b/lib/workers/repository/config-migration/branch/migrated-data.spec.ts index 09f7bcecc13af8..3f1b32301a0d61 100644 --- a/lib/workers/repository/config-migration/branch/migrated-data.spec.ts +++ b/lib/workers/repository/config-migration/branch/migrated-data.spec.ts @@ -1,11 +1,10 @@ import detectIndent from 'detect-indent'; import { Fixtures } from '../../../../../test/fixtures'; -import { mockedFunction } from '../../../../../test/util'; +import { mockedFunction, scm } from '../../../../../test/util'; import { migrateConfig } from '../../../../config/migration'; import { logger } from '../../../../logger'; import { readLocalFile } from '../../../../util/fs'; -import { getFileList } from '../../../../util/git'; import { detectRepoFileConfig } from '../../init/merge'; import { MigratedDataFactory } from './migrated-data'; @@ -141,7 +140,7 @@ describe('workers/repository/config-migration/branch/migrated-data', () => { }); beforeEach(() => { - mockedFunction(getFileList).mockResolvedValue([]); + mockedFunction(scm.getFileList).mockResolvedValue([]); }); it('does not format when no prettier config is present', async () => { @@ -173,7 +172,7 @@ describe('workers/repository/config-migration/branch/migrated-data', () => { it('formats when prettier config file is found', async () => { const formatted = formattedMigratedData.content; - mockedFunction(getFileList).mockResolvedValue(['.prettierrc']); + mockedFunction(scm.getFileList).mockResolvedValue(['.prettierrc']); await MigratedDataFactory.getAsync(); await expect( MigratedDataFactory.applyPrettierFormatting(migratedData) diff --git a/lib/workers/repository/config-migration/branch/migrated-data.ts b/lib/workers/repository/config-migration/branch/migrated-data.ts index e0f1ec79832ed5..1961a817ad96d5 100644 --- a/lib/workers/repository/config-migration/branch/migrated-data.ts +++ b/lib/workers/repository/config-migration/branch/migrated-data.ts @@ -5,8 +5,8 @@ import upath from 'upath'; import { migrateConfig } from '../../../../config/migration'; import { prettier } from '../../../../expose.cjs'; import { logger } from '../../../../logger'; +import { scm } from '../../../../modules/platform/scm'; import { readLocalFile } from '../../../../util/fs'; -import { getFileList } from '../../../../util/git'; import { detectRepoFileConfig } from '../../init/merge'; export interface MigratedData { @@ -43,7 +43,7 @@ export async function applyPrettierFormatting( ): Promise { try { logger.trace('applyPrettierFormatting - START'); - const fileList = await getFileList(); + const fileList = await scm.getFileList(); let prettierExists = fileList.some((file) => prettierConfigFilenames.has(file) ); diff --git a/lib/workers/repository/config-migration/branch/rebase.spec.ts b/lib/workers/repository/config-migration/branch/rebase.spec.ts index 1ac78e49ad3322..4f7ebdb6884e06 100644 --- a/lib/workers/repository/config-migration/branch/rebase.spec.ts +++ b/lib/workers/repository/config-migration/branch/rebase.spec.ts @@ -9,7 +9,6 @@ import { scm, } from '../../../../../test/util'; import { GlobalConfig } from '../../../../config/global'; -import { checkoutBranch } from '../../../../util/git'; import { MigratedDataFactory } from './migrated-data'; import type { MigratedData } from './migrated-data'; import { jsonStripWhitespaces, rebaseMigrationBranch } from './rebase'; @@ -60,7 +59,7 @@ describe('workers/repository/config-migration/branch/rebase', () => { await rebaseMigrationBranch(config, migratedConfigData); - expect(checkoutBranch).toHaveBeenCalledTimes(0); + expect(scm.checkoutBranch).toHaveBeenCalledTimes(0); expect(scm.commitAndPush).toHaveBeenCalledTimes(0); }); @@ -76,7 +75,7 @@ describe('workers/repository/config-migration/branch/rebase', () => { await rebaseMigrationBranch(config, migratedConfigData); - expect(checkoutBranch).toHaveBeenCalledTimes(0); + expect(scm.checkoutBranch).toHaveBeenCalledTimes(0); expect(scm.commitAndPush).toHaveBeenCalledTimes(0); expect(git.getFile).toHaveBeenCalledTimes(1); } @@ -93,7 +92,7 @@ describe('workers/repository/config-migration/branch/rebase', () => { await rebaseMigrationBranch(config, migratedConfigData); - expect(checkoutBranch).toHaveBeenCalledWith(config.defaultBranch); + expect(scm.checkoutBranch).toHaveBeenCalledWith(config.defaultBranch); expect(scm.commitAndPush).toHaveBeenCalledTimes(1); }); @@ -111,7 +110,7 @@ describe('workers/repository/config-migration/branch/rebase', () => { await rebaseMigrationBranch(config, migratedConfigData); - expect(checkoutBranch).toHaveBeenCalledWith(config.defaultBranch); + expect(scm.checkoutBranch).toHaveBeenCalledWith(config.defaultBranch); expect(scm.commitAndPush).toHaveBeenCalledTimes(1); expect(scm.commitAndPush).toHaveBeenCalledWith({ branchName: 'renovate/migrate-config', @@ -144,7 +143,7 @@ describe('workers/repository/config-migration/branch/rebase', () => { await rebaseMigrationBranch(config, migratedConfigData); - expect(checkoutBranch).toHaveBeenCalledTimes(0); + expect(scm.checkoutBranch).toHaveBeenCalledTimes(0); expect(scm.commitAndPush).toHaveBeenCalledTimes(0); } ); diff --git a/lib/workers/repository/config-migration/branch/rebase.ts b/lib/workers/repository/config-migration/branch/rebase.ts index cb932c11484244..a638401972ea06 100644 --- a/lib/workers/repository/config-migration/branch/rebase.ts +++ b/lib/workers/repository/config-migration/branch/rebase.ts @@ -3,7 +3,7 @@ import { GlobalConfig } from '../../../../config/global'; import type { RenovateConfig } from '../../../../config/types'; import { logger } from '../../../../logger'; import { scm } from '../../../../modules/platform/scm'; -import { checkoutBranch, getFile } from '../../../../util/git'; +import { getFile } from '../../../../util/git'; import { quickStringify } from '../../../../util/stringify'; import { getMigrationBranchName } from '../common'; import { ConfigMigrationCommitMessageFactory } from './commit-message'; @@ -42,7 +42,7 @@ export async function rebaseMigrationBranch( ); const commitMessage = commitMessageFactory.getCommitMessage(); - await checkoutBranch(config.defaultBranch!); + await scm.checkoutBranch(config.defaultBranch!); contents = await MigratedDataFactory.applyPrettierFormatting( migratedConfigData ); diff --git a/lib/workers/repository/extract/index.spec.ts b/lib/workers/repository/extract/index.spec.ts index 4b39cf0be52636..ca553db2971951 100644 --- a/lib/workers/repository/extract/index.spec.ts +++ b/lib/workers/repository/extract/index.spec.ts @@ -1,4 +1,4 @@ -import { getConfig, git, mocked } from '../../../../test/util'; +import { getConfig, mocked, scm } from '../../../../test/util'; import type { RenovateConfig } from '../../../config/types'; import { logger } from '../../../logger'; import * as _managerFiles from './manager-files'; @@ -16,7 +16,7 @@ describe('workers/repository/extract/index', () => { beforeEach(() => { jest.resetAllMocks(); - git.getFileList.mockResolvedValue(fileList); + scm.getFileList.mockResolvedValue(fileList); config = getConfig(); }); diff --git a/lib/workers/repository/extract/index.ts b/lib/workers/repository/extract/index.ts index a2337de4a45d26..9f4f45cc9bcb39 100644 --- a/lib/workers/repository/extract/index.ts +++ b/lib/workers/repository/extract/index.ts @@ -3,7 +3,7 @@ import { getManagerConfig, mergeChildConfig } from '../../../config'; import type { ManagerConfig, RenovateConfig } from '../../../config/types'; import { logger } from '../../../logger'; import { getManagerList, hashMap } from '../../../modules/manager'; -import { getFileList } from '../../../util/git'; +import { scm } from '../../../modules/platform/scm'; import type { ExtractResult, WorkerExtractConfig } from '../../types'; import { getMatchingFiles } from './file-match'; import { getManagerPackageFiles } from './manager-files'; @@ -20,7 +20,7 @@ export async function extractAllDependencies( ); } const extractList: WorkerExtractConfig[] = []; - const fileList = await getFileList(); + const fileList = await scm.getFileList(); const tryConfig = (managerConfig: ManagerConfig): void => { const matchingFileList = getMatchingFiles(managerConfig, fileList); diff --git a/lib/workers/repository/init/merge.spec.ts b/lib/workers/repository/init/merge.spec.ts index 5a03b80b845ced..595275293d4223 100644 --- a/lib/workers/repository/init/merge.spec.ts +++ b/lib/workers/repository/init/merge.spec.ts @@ -2,11 +2,11 @@ import { RenovateConfig, fs, getConfig, - git, logger, mocked, partial, platform, + scm, } from '../../../../test/util'; import * as _migrateAndValidate from '../../../config/migrate-validate'; import * as _migrate from '../../../config/migration'; @@ -44,7 +44,7 @@ describe('workers/repository/init/merge', () => { }); it('returns config if not found', async () => { - git.getFileList.mockResolvedValue(['package.json']); + scm.getFileList.mockResolvedValue(['package.json']); fs.readLocalFile.mockResolvedValue('{}'); expect(await detectRepoFileConfig()).toEqual({}); }); @@ -56,7 +56,7 @@ describe('workers/repository/init/merge', () => { partial({ configFileName: 'renovate.json' }) ); platform.getRawFile.mockRejectedValueOnce(new Error()); - git.getFileList.mockResolvedValue(['package.json']); + scm.getFileList.mockResolvedValue(['package.json']); fs.readLocalFile.mockResolvedValue('{}'); expect(await detectRepoFileConfig()).toEqual({}); expect(logger.logger.debug).toHaveBeenCalledWith( @@ -65,7 +65,7 @@ describe('workers/repository/init/merge', () => { }); it('uses package.json config if found', async () => { - git.getFileList.mockResolvedValue(['package.json']); + scm.getFileList.mockResolvedValue(['package.json']); const pJson = JSON.stringify({ name: 'something', renovate: { @@ -86,7 +86,7 @@ describe('workers/repository/init/merge', () => { }); it('massages package.json renovate string', async () => { - git.getFileList.mockResolvedValue(['package.json']); + scm.getFileList.mockResolvedValue(['package.json']); const pJson = JSON.stringify({ name: 'something', renovate: 'github>renovatebot/renovate', @@ -100,7 +100,7 @@ describe('workers/repository/init/merge', () => { }); it('returns error if cannot parse', async () => { - git.getFileList.mockResolvedValue(['package.json', 'renovate.json']); + scm.getFileList.mockResolvedValue(['package.json', 'renovate.json']); fs.readLocalFile.mockResolvedValue('cannot parse'); expect(await detectRepoFileConfig()).toEqual({ configFileName: 'renovate.json', @@ -112,7 +112,7 @@ describe('workers/repository/init/merge', () => { }); it('throws error if duplicate keys', async () => { - git.getFileList.mockResolvedValue(['package.json', '.renovaterc']); + scm.getFileList.mockResolvedValue(['package.json', '.renovaterc']); fs.readLocalFile.mockResolvedValue( '{ "enabled": true, "enabled": false }' ); @@ -130,7 +130,7 @@ describe('workers/repository/init/merge', () => { const configFileRaw = `{ // this is json5 format }`; - git.getFileList.mockResolvedValue(['package.json', 'renovate.json5']); + scm.getFileList.mockResolvedValue(['package.json', 'renovate.json5']); fs.readLocalFile.mockResolvedValue(configFileRaw); expect(await detectRepoFileConfig()).toEqual({ configFileName: 'renovate.json5', @@ -140,7 +140,7 @@ describe('workers/repository/init/merge', () => { }); it('finds .github/renovate.json', async () => { - git.getFileList.mockResolvedValue([ + scm.getFileList.mockResolvedValue([ 'package.json', '.github/renovate.json', ]); @@ -153,7 +153,7 @@ describe('workers/repository/init/merge', () => { }); it('finds .gitlab/renovate.json', async () => { - git.getFileList.mockResolvedValue([ + scm.getFileList.mockResolvedValue([ 'package.json', '.gitlab/renovate.json', ]); @@ -166,7 +166,7 @@ describe('workers/repository/init/merge', () => { }); it('finds .renovaterc.json', async () => { - git.getFileList.mockResolvedValue(['package.json', '.renovaterc.json']); + scm.getFileList.mockResolvedValue(['package.json', '.renovaterc.json']); fs.readLocalFile.mockResolvedValue('{}'); platform.getRawFile.mockResolvedValueOnce('{"something":"new"}'); expect(await detectRepoFileConfig()).toEqual({ @@ -184,7 +184,7 @@ describe('workers/repository/init/merge', () => { }); it('finds .renovaterc.json5', async () => { - git.getFileList.mockResolvedValue(['package.json', '.renovaterc.json5']); + scm.getFileList.mockResolvedValue(['package.json', '.renovaterc.json5']); fs.readLocalFile.mockResolvedValue('{}'); platform.getRawFile.mockResolvedValueOnce('{"something":"new"}'); expect(await detectRepoFileConfig()).toEqual({ @@ -225,7 +225,7 @@ describe('workers/repository/init/merge', () => { }); it('throws error if misconfigured', async () => { - git.getFileList.mockResolvedValue(['package.json', '.renovaterc.json']); + scm.getFileList.mockResolvedValue(['package.json', '.renovaterc.json']); fs.readLocalFile.mockResolvedValue('{}'); migrateAndValidate.migrateAndValidate.mockResolvedValueOnce({ errors: [{ topic: 'dep', message: 'test error' }], @@ -241,7 +241,7 @@ describe('workers/repository/init/merge', () => { }); it('migrates nested config', async () => { - git.getFileList.mockResolvedValue(['renovate.json']); + scm.getFileList.mockResolvedValue(['renovate.json']); fs.readLocalFile.mockResolvedValue('{}'); migrateAndValidate.migrateAndValidate.mockImplementation((_, c) => { // We shouldn't see packageRules here (avoids #14827). @@ -271,7 +271,7 @@ describe('workers/repository/init/merge', () => { }); it('ignores presets', async () => { - git.getFileList.mockResolvedValue(['renovate.json']); + scm.getFileList.mockResolvedValue(['renovate.json']); fs.readLocalFile.mockResolvedValue('{}'); migrateAndValidate.migrateAndValidate.mockResolvedValue({ extends: ['config:base'], @@ -290,7 +290,7 @@ describe('workers/repository/init/merge', () => { }); it('continues if no errors', async () => { - git.getFileList.mockResolvedValue(['package.json', '.renovaterc.json']); + scm.getFileList.mockResolvedValue(['package.json', '.renovaterc.json']); fs.readLocalFile.mockResolvedValue('{}'); migrateAndValidate.migrateAndValidate.mockResolvedValue({ warnings: [], diff --git a/lib/workers/repository/init/merge.ts b/lib/workers/repository/init/merge.ts index 04c3cba0e61cba..38d6a2ba0d6188 100644 --- a/lib/workers/repository/init/merge.ts +++ b/lib/workers/repository/init/merge.ts @@ -17,17 +17,17 @@ import { import { logger } from '../../../logger'; import * as npmApi from '../../../modules/datasource/npm'; import { platform } from '../../../modules/platform'; +import { scm } from '../../../modules/platform/scm'; import { ExternalHostError } from '../../../types/errors/external-host-error'; import { getCache } from '../../../util/cache/repository'; import { readLocalFile } from '../../../util/fs'; -import { getFileList } from '../../../util/git'; import * as hostRules from '../../../util/host-rules'; import * as queue from '../../../util/http/queue'; import * as throttle from '../../../util/http/throttle'; import type { RepoFileConfig } from './types'; async function detectConfigFile(): Promise { - const fileList = await getFileList(); + const fileList = await scm.getFileList(); for (const fileName of configFileNames) { if (fileName === 'package.json') { try { diff --git a/lib/workers/repository/onboarding/branch/check.spec.ts b/lib/workers/repository/onboarding/branch/check.spec.ts index e8f03bb6515a06..74684f8f809352 100644 --- a/lib/workers/repository/onboarding/branch/check.spec.ts +++ b/lib/workers/repository/onboarding/branch/check.spec.ts @@ -4,6 +4,7 @@ import { mocked, partial, platform, + scm, } from '../../../../../test/util'; import { REPOSITORY_CLOSED_ONBOARDING } from '../../../../constants/error-messages'; import { logger } from '../../../../logger'; @@ -49,7 +50,7 @@ describe('workers/repository/onboarding/branch/check', () => { onboardingBranchSha: 'onboarding-sha', }, }); - git.getFileList.mockResolvedValue([]); + scm.getFileList.mockResolvedValue([]); await isOnboarded(config); expect(logger.debug).not.toHaveBeenCalledWith( 'Onboarding cache is valid. Repo is not onboarded' @@ -59,7 +60,7 @@ describe('workers/repository/onboarding/branch/check', () => { it('continues with normal logic if closedPr exists', async () => { cache.getCache.mockReturnValue({}); platform.findPr.mockResolvedValue(partial()); - git.getFileList.mockResolvedValue([]); + scm.getFileList.mockResolvedValue([]); await expect(isOnboarded(config)).rejects.toThrow( REPOSITORY_CLOSED_ONBOARDING ); diff --git a/lib/workers/repository/onboarding/branch/check.ts b/lib/workers/repository/onboarding/branch/check.ts index 3a3ec850809eb8..bf3abf09f1fe03 100644 --- a/lib/workers/repository/onboarding/branch/check.ts +++ b/lib/workers/repository/onboarding/branch/check.ts @@ -7,13 +7,14 @@ import { import { logger } from '../../../../logger'; import { Pr, platform } from '../../../../modules/platform'; import { ensureComment } from '../../../../modules/platform/comment'; +import { scm } from '../../../../modules/platform/scm'; import { getCache } from '../../../../util/cache/repository'; import { readLocalFile } from '../../../../util/fs'; -import { getBranchCommit, getFileList } from '../../../../util/git'; +import { getBranchCommit } from '../../../../util/git'; async function findFile(fileName: string): Promise { logger.debug(`findFile(${fileName})`); - const fileList = await getFileList(); + const fileList = await scm.getFileList(); return fileList.includes(fileName); } diff --git a/lib/workers/repository/onboarding/branch/index.spec.ts b/lib/workers/repository/onboarding/branch/index.spec.ts index 04fc5ed1856d67..d9821294b5880b 100644 --- a/lib/workers/repository/onboarding/branch/index.spec.ts +++ b/lib/workers/repository/onboarding/branch/index.spec.ts @@ -3,7 +3,6 @@ import { RenovateConfig, fs, getConfig, - git, mocked, platform, scm, @@ -55,7 +54,7 @@ describe('workers/repository/onboarding/branch/index', () => { config = getConfig(); config.repository = 'some/repo'; OnboardingState.prUpdateRequested = false; - git.getFileList.mockResolvedValue([]); + scm.getFileList.mockResolvedValue([]); cache.getCache.mockReturnValue({}); }); @@ -96,7 +95,7 @@ describe('workers/repository/onboarding/branch/index', () => { ' "$schema": "https://docs.renovatebot.com/renovate-schema.json"\n' + '}\n' ); - git.getFileList.mockResolvedValue(['package.json']); + scm.getFileList.mockResolvedValue(['package.json']); fs.readLocalFile.mockResolvedValue('{}'); await checkOnboardingBranch(config); const file = scm.commitAndPush.mock.calls[0][0] @@ -121,7 +120,7 @@ describe('workers/repository/onboarding/branch/index', () => { ' "extends": ["some/renovate-config"]\n' + '}\n' ); - git.getFileList.mockResolvedValue(['package.json']); + scm.getFileList.mockResolvedValue(['package.json']); fs.readLocalFile.mockResolvedValue('{}'); await checkOnboardingBranch(config); const expectConfig = { @@ -156,7 +155,7 @@ describe('workers/repository/onboarding/branch/index', () => { it('handles skipped onboarding, requireConfig=required, and a config file', async () => { config.requireConfig = 'required'; config.onboarding = false; - git.getFileList.mockResolvedValueOnce(['renovate.json']); + scm.getFileList.mockResolvedValueOnce(['renovate.json']); const res = await checkOnboardingBranch(config); expect(res.repoIsOnboarded).toBeTrue(); }); @@ -171,7 +170,7 @@ describe('workers/repository/onboarding/branch/index', () => { it('handles skipped onboarding, requireConfig=required, and no config file', async () => { config.requireConfig = 'required'; config.onboarding = false; - git.getFileList.mockResolvedValueOnce(['package.json']); + scm.getFileList.mockResolvedValueOnce(['package.json']); fs.readLocalFile.mockResolvedValueOnce('{}'); const onboardingResult = checkOnboardingBranch(config); await expect(onboardingResult).rejects.toThrow('disabled'); @@ -179,7 +178,7 @@ describe('workers/repository/onboarding/branch/index', () => { it('detects repo is onboarded via file', async () => { cache.getCache.mockReturnValue(dummyCache); - git.getFileList.mockResolvedValueOnce(['renovate.json']); + scm.getFileList.mockResolvedValueOnce(['renovate.json']); const res = await checkOnboardingBranch(config); expect(res.repoIsOnboarded).toBeTrue(); expect(onboardingCache.deleteOnboardingCache).toHaveBeenCalledTimes(1); // removes onboarding cache when repo is onboarded @@ -187,7 +186,7 @@ describe('workers/repository/onboarding/branch/index', () => { it('handles removed cached file name', async () => { cache.getCache.mockReturnValue({ configFileName: '.renovaterc' }); - git.getFileList.mockResolvedValueOnce(['renovate.json']); + scm.getFileList.mockResolvedValueOnce(['renovate.json']); const res = await checkOnboardingBranch(config); expect(res.repoIsOnboarded).toBeTrue(); }); @@ -236,7 +235,7 @@ describe('workers/repository/onboarding/branch/index', () => { }); it('detects repo is onboarded via package.json config', async () => { - git.getFileList.mockResolvedValueOnce(['package.json']); + scm.getFileList.mockResolvedValueOnce(['package.json']); fs.readLocalFile.mockResolvedValueOnce('{"renovate":{}}'); const res = await checkOnboardingBranch(config); expect(res.repoIsOnboarded).toBeTrue(); @@ -264,14 +263,14 @@ describe('workers/repository/onboarding/branch/index', () => { it('updates onboarding branch', async () => { cache.getCache.mockReturnValue(dummyCache); - git.getFileList.mockResolvedValue(['package.json']); + 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(git.checkoutBranch).toHaveBeenCalledTimes(1); + expect(scm.checkoutBranch).toHaveBeenCalledTimes(1); expect(onboardingCache.setOnboardingCache).toHaveBeenCalledTimes(1); // update onboarding cache expect(scm.commitAndPush).toHaveBeenCalledTimes(0); }); @@ -281,7 +280,7 @@ describe('workers/repository/onboarding/branch/index', () => { GlobalConfig.set({ platform: 'github' }); config.onboardingRebaseCheckbox = true; OnboardingState.prUpdateRequested = false; - git.getFileList.mockResolvedValueOnce(['package.json']); + scm.getFileList.mockResolvedValueOnce(['package.json']); platform.findPr.mockResolvedValueOnce(null); rebase.rebaseOnboardingBranch.mockResolvedValueOnce(null); }); @@ -297,7 +296,7 @@ describe('workers/repository/onboarding/branch/index', () => { `Platform '${pl}' does not support extended markdown` ); expect(OnboardingState.prUpdateRequested).toBeTrue(); - expect(git.checkoutBranch).toHaveBeenCalledTimes(1); + expect(scm.checkoutBranch).toHaveBeenCalledTimes(1); expect(scm.commitAndPush).toHaveBeenCalledTimes(0); }); @@ -311,7 +310,7 @@ describe('workers/repository/onboarding/branch/index', () => { `No rebase checkbox was found in the onboarding PR` ); expect(OnboardingState.prUpdateRequested).toBeTrue(); - expect(git.checkoutBranch).toHaveBeenCalledTimes(1); + expect(scm.checkoutBranch).toHaveBeenCalledTimes(1); expect(scm.commitAndPush).toHaveBeenCalledTimes(0); }); @@ -326,7 +325,7 @@ describe('workers/repository/onboarding/branch/index', () => { ); expect(OnboardingState.prUpdateRequested).toBeTrue(); ``; - expect(git.checkoutBranch).toHaveBeenCalledTimes(1); + expect(scm.checkoutBranch).toHaveBeenCalledTimes(1); expect(scm.commitAndPush).toHaveBeenCalledTimes(0); }); @@ -337,7 +336,7 @@ describe('workers/repository/onboarding/branch/index', () => { await checkOnboardingBranch(config); expect(OnboardingState.prUpdateRequested).toBeFalse(); - expect(git.checkoutBranch).toHaveBeenCalledTimes(1); + expect(scm.checkoutBranch).toHaveBeenCalledTimes(1); expect(scm.commitAndPush).toHaveBeenCalledTimes(0); }); }); diff --git a/lib/workers/repository/onboarding/branch/index.ts b/lib/workers/repository/onboarding/branch/index.ts index c8f50ecefa8575..e131f8069a4a66 100644 --- a/lib/workers/repository/onboarding/branch/index.ts +++ b/lib/workers/repository/onboarding/branch/index.ts @@ -8,11 +8,8 @@ import { } from '../../../../constants/error-messages'; import { logger } from '../../../../logger'; import { Pr, platform } from '../../../../modules/platform'; -import { - checkoutBranch, - getBranchCommit, - setGitAuthor, -} from '../../../../util/git'; +import { scm } from '../../../../modules/platform/scm'; +import { getBranchCommit, setGitAuthor } from '../../../../util/git'; import { extractAllDependencies } from '../../extract'; import { mergeRenovateConfig } from '../../init/merge'; import { OnboardingState } from '../common'; @@ -108,7 +105,7 @@ export async function checkOnboardingBranch( if (!GlobalConfig.get('dryRun')) { logger.debug('Checkout onboarding branch.'); // TODO #7154 - await checkoutBranch(onboardingBranch!); + await scm.checkoutBranch(onboardingBranch!); } // TODO #7154 const branchList = [onboardingBranch!]; diff --git a/lib/workers/repository/process/extract-update.spec.ts b/lib/workers/repository/process/extract-update.spec.ts index 47b8e67e3a232f..2dc09dccfd6def 100644 --- a/lib/workers/repository/process/extract-update.spec.ts +++ b/lib/workers/repository/process/extract-update.spec.ts @@ -1,4 +1,4 @@ -import { git, logger, mocked, scm } from '../../../../test/util'; +import { logger, mocked, scm } from '../../../../test/util'; import type { PackageFile } from '../../../modules/manager/types'; import * as _repositoryCache from '../../../util/cache/repository'; import type { BaseBranchCache } from '../../../util/cache/repository/types'; @@ -50,7 +50,7 @@ describe('workers/repository/process/extract-update', () => { suppressNotifications: ['deprecationWarningIssues'], }; repositoryCache.getCache.mockReturnValueOnce({ scan: {} }); - git.checkoutBranch.mockResolvedValueOnce('123test'); + scm.checkoutBranch.mockResolvedValueOnce('123test'); const packageFiles = await extract(config); const res = await lookup(config, packageFiles); expect(res).toEqual({ @@ -81,7 +81,7 @@ describe('workers/repository/process/extract-update', () => { addLabels: 'npm', }, }; - git.checkoutBranch.mockResolvedValueOnce('123test'); + scm.checkoutBranch.mockResolvedValueOnce('123test'); repositoryCache.getCache.mockReturnValueOnce({ scan: {} }); const packageFiles = await extract(config); expect(packageFiles).toBeUndefined(); @@ -105,7 +105,7 @@ describe('workers/repository/process/extract-update', () => { }, }); scm.getBranchCommit.mockResolvedValueOnce('123test'); - git.checkoutBranch.mockResolvedValueOnce('123test'); + scm.checkoutBranch.mockResolvedValueOnce('123test'); const res = await extract(config); expect(res).toEqual(packageFiles); }); @@ -121,7 +121,7 @@ describe('workers/repository/process/extract-update', () => { appendVulnerabilityPackageRules: appendVulnerabilityPackageRulesMock, }); repositoryCache.getCache.mockReturnValueOnce({ scan: {} }); - git.checkoutBranch.mockResolvedValueOnce('123test'); + scm.checkoutBranch.mockResolvedValueOnce('123test'); const packageFiles = await extract(config); await lookup(config, packageFiles); @@ -138,7 +138,7 @@ describe('workers/repository/process/extract-update', () => { }; createVulnerabilitiesMock.mockRejectedValueOnce(new Error()); repositoryCache.getCache.mockReturnValueOnce({ scan: {} }); - git.checkoutBranch.mockResolvedValueOnce('123test'); + scm.checkoutBranch.mockResolvedValueOnce('123test'); const packageFiles = await extract(config); await lookup(config, packageFiles); diff --git a/lib/workers/repository/process/extract-update.ts b/lib/workers/repository/process/extract-update.ts index d10df7303bbaee..66e0c14bdf36db 100644 --- a/lib/workers/repository/process/extract-update.ts +++ b/lib/workers/repository/process/extract-update.ts @@ -8,7 +8,6 @@ import { getCache } from '../../../util/cache/repository'; import type { BaseBranchCache } from '../../../util/cache/repository/types'; import { checkGithubToken as ensureGithubToken } from '../../../util/check-token'; import { fingerprint } from '../../../util/fingerprint'; -import { checkoutBranch } from '../../../util/git'; import type { BranchConfig } from '../../types'; import { extractAllDependencies } from '../extract'; import { generateFingerprintConfig } from '../extract/extract-fingerprint-config'; @@ -137,7 +136,7 @@ export async function extract( logger.info({ err }, 'Error deleting cached dep updates'); } } else { - await checkoutBranch(baseBranch!); + await scm.checkoutBranch(baseBranch!); const extractResult = (await extractAllDependencies(config)) || {}; packageFiles = extractResult.packageFiles; const { extractionFingerprints } = extractResult; diff --git a/lib/workers/repository/update/branch/automerge.spec.ts b/lib/workers/repository/update/branch/automerge.spec.ts index 81bafafe388f26..87bb468913a999 100644 --- a/lib/workers/repository/update/branch/automerge.spec.ts +++ b/lib/workers/repository/update/branch/automerge.spec.ts @@ -1,4 +1,4 @@ -import { getConfig, git, platform } from '../../../../../test/util'; +import { getConfig, git, platform, scm } from '../../../../../test/util'; import { GlobalConfig } from '../../../../config/global'; import type { RenovateConfig } from '../../../../config/types'; import * as schedule from '../branch/schedule'; @@ -70,7 +70,7 @@ describe('workers/repository/update/branch/automerge', () => { const res = await tryBranchAutomerge(config); expect(res).toBe('failed'); - expect(git.checkoutBranch).toHaveBeenCalled(); + expect(scm.checkoutBranch).toHaveBeenCalled(); }); it('returns true if automerge succeeds', async () => { @@ -82,7 +82,7 @@ describe('workers/repository/update/branch/automerge', () => { const res = await tryBranchAutomerge(config); expect(res).toBe('automerged'); - expect(git.checkoutBranch).toHaveBeenCalledWith('test-branch'); + expect(scm.checkoutBranch).toHaveBeenCalledWith('test-branch'); }); it('returns true if automerge succeeds (dry-run)', async () => { diff --git a/lib/workers/repository/update/branch/automerge.ts b/lib/workers/repository/update/branch/automerge.ts index 8db027b4cc24f1..b6595e2ec118e9 100644 --- a/lib/workers/repository/update/branch/automerge.ts +++ b/lib/workers/repository/update/branch/automerge.ts @@ -2,7 +2,8 @@ import { GlobalConfig } from '../../../../config/global'; import type { RenovateConfig } from '../../../../config/types'; import { logger } from '../../../../logger'; import { platform } from '../../../../modules/platform'; -import { checkoutBranch, mergeBranch } from '../../../../util/git'; +import { scm } from '../../../../modules/platform/scm'; +import { mergeBranch } from '../../../../util/git'; import { isScheduledNow } from './schedule'; import { resolveBranchStatus } from './status-checks'; @@ -42,7 +43,7 @@ export async function tryBranchAutomerge( // TODO: types (#7154) logger.info(`DRY-RUN: Would automerge branch ${config.branchName!}`); } else { - await checkoutBranch(config.baseBranch!); + await scm.checkoutBranch(config.baseBranch!); await mergeBranch(config.branchName!); } logger.info({ branch: config.branchName }, 'Branch automerged'); diff --git a/lib/workers/repository/update/branch/index.spec.ts b/lib/workers/repository/update/branch/index.spec.ts index 636803ec391f9d..aaec7534c8499c 100644 --- a/lib/workers/repository/update/branch/index.spec.ts +++ b/lib/workers/repository/update/branch/index.spec.ts @@ -2253,13 +2253,13 @@ describe('workers/repository/update/branch/index', () => { }); config.baseBranch = 'main'; await branchWorker.processBranch(config); - expect(git.checkoutBranch).toHaveBeenLastCalledWith('main'); + expect(scm.checkoutBranch).toHaveBeenLastCalledWith('main'); // Check that the last checkoutBranch call is after the only commitFilesToBranch call - const checkoutBranchCalledTimes = git.checkoutBranch.mock.calls.length; + const checkoutBranchCalledTimes = scm.checkoutBranch.mock.calls.length; expect( commit.commitFilesToBranch.mock.invocationCallOrder[0] ).toBeLessThan( - git.checkoutBranch.mock.invocationCallOrder[ + scm.checkoutBranch.mock.invocationCallOrder[ checkoutBranchCalledTimes - 1 ] ); diff --git a/lib/workers/repository/update/branch/index.ts b/lib/workers/repository/update/branch/index.ts index ba93eee78e8414..7b61df3f669645 100644 --- a/lib/workers/repository/update/branch/index.ts +++ b/lib/workers/repository/update/branch/index.ts @@ -25,7 +25,6 @@ import { scm } from '../../../../modules/platform/scm'; import { ExternalHostError } from '../../../../types/errors/external-host-error'; import { getElapsedMs } from '../../../../util/date'; import { emojify } from '../../../../util/emoji'; -import { checkoutBranch } from '../../../../util/git'; import { getMergeConfidenceLevel, isActiveConfidenceLevel, @@ -406,7 +405,7 @@ export async function processBranch( // TODO: types (#7154) logger.debug(`Using reuseExistingBranch: ${config.reuseExistingBranch!}`); if (!(config.reuseExistingBranch && config.skipBranchUpdate)) { - await checkoutBranch(config.baseBranch); + await scm.checkoutBranch(config.baseBranch); const res = await getUpdatedPackageFiles(config); // istanbul ignore if if (res.artifactErrors && config.artifactErrors) { @@ -524,7 +523,7 @@ export async function processBranch( commitSha = await commitFilesToBranch(config); // Checkout to base branch to ensure that the next branch processing always starts with git being on the baseBranch // baseBranch is not checked out at the start of processBranch() due to pull/16246 - await checkoutBranch(config.baseBranch); + await scm.checkoutBranch(config.baseBranch); updatesVerified = true; } // istanbul ignore if From 2112ea26461491fd7afb60b8b57011a134f3cbdf Mon Sep 17 00:00:00 2001 From: guicamest Date: Sun, 7 May 2023 17:47:06 +0200 Subject: [PATCH 16/57] feat(manager/gradle): Support properties map in gradle kts (#21792) --- lib/modules/manager/gradle/parser.spec.ts | 1 + lib/modules/manager/gradle/parser/common.spec.ts | 9 ++++++++- lib/modules/manager/gradle/parser/common.ts | 8 +++++++- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/lib/modules/manager/gradle/parser.spec.ts b/lib/modules/manager/gradle/parser.spec.ts index 2462903b8fe3d5..4cf790ce64404f 100644 --- a/lib/modules/manager/gradle/parser.spec.ts +++ b/lib/modules/manager/gradle/parser.spec.ts @@ -363,6 +363,7 @@ describe('modules/manager/gradle/parser', () => { ${'baz = "1.2.3"'} | ${'"foo:bar:${ext.baz}"'} | ${{ depName: 'foo:bar', currentValue: '1.2.3', groupName: 'baz' }} ${'baz = "1.2.3"'} | ${'"foo:bar:${project.ext[\'baz\']}"'} | ${{ depName: 'foo:bar', currentValue: '1.2.3', groupName: 'baz' }} ${'a = "foo"; b = "bar"; c="1.2.3"'} | ${'"${a}:${b}:${property("c")}"'} | ${{ depName: 'foo:bar', currentValue: '1.2.3', groupName: 'c' }} + ${'a = "foo"; b = "bar"; c="1.2.3"'} | ${'"${a}:${b}:${properties["c"]}"'} | ${{ depName: 'foo:bar', currentValue: '1.2.3', groupName: 'c' }} `('$def | $str', ({ def, str, output }) => { const { deps } = parseGradle([def, str].join('\n')); expect(deps).toMatchObject([output].filter(is.truthy)); diff --git a/lib/modules/manager/gradle/parser/common.spec.ts b/lib/modules/manager/gradle/parser/common.spec.ts index 8c377a1345911c..77a7df15e851c5 100644 --- a/lib/modules/manager/gradle/parser/common.spec.ts +++ b/lib/modules/manager/gradle/parser/common.spec.ts @@ -94,7 +94,14 @@ describe('modules/manager/gradle/parser/common', () => { }); it('stripReservedPrefixFromKeyTokens', () => { - const tokenValues = ['rootProject', 'project', 'ext', 'extra', 'foo']; + const tokenValues = [ + 'rootProject', + 'project', + 'ext', + 'extra', + 'properties', + 'foo', + ]; ctx.varTokens.push( ...tokenValues.map((value) => partial({ value })) diff --git a/lib/modules/manager/gradle/parser/common.ts b/lib/modules/manager/gradle/parser/common.ts index e72d582ea0ac8f..6379bb5644893c 100644 --- a/lib/modules/manager/gradle/parser/common.ts +++ b/lib/modules/manager/gradle/parser/common.ts @@ -82,7 +82,13 @@ export function cleanupTempVars(ctx: Ctx): Ctx { } export function stripReservedPrefixFromKeyTokens(ctx: Ctx): Ctx { - const unwantedPrefixes = ['ext', 'extra', 'project', 'rootProject']; + const unwantedPrefixes = [ + 'ext', + 'extra', + 'project', + 'rootProject', + 'properties', + ]; while ( ctx.varTokens.length > 1 && // ensures there will be always at least one token ctx.varTokens[0] && From 546a52cbe67c119143a3144f833d10ecbe389aa9 Mon Sep 17 00:00:00 2001 From: HonkingGoose <34918129+HonkingGoose@users.noreply.github.com> Date: Sun, 7 May 2023 21:17:21 +0200 Subject: [PATCH 17/57] docs(`azure-pipelines` manager): explain missing features (#22005) --- lib/modules/manager/azure-pipelines/readme.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/modules/manager/azure-pipelines/readme.md b/lib/modules/manager/azure-pipelines/readme.md index 7903346f2ba24e..aee00bea3e63ae 100644 --- a/lib/modules/manager/azure-pipelines/readme.md +++ b/lib/modules/manager/azure-pipelines/readme.md @@ -58,7 +58,7 @@ stages: Read the [resources block][resources-docs] and the [tasks block][tasks-docs] Azure Pipelines documentation for more information. -Files that are processed by the manager includes: +The `azure-pipelines` manager can process these files: - `.azure-pipelines/**/*.yaml` - `.azure-pipelines.yaml` @@ -70,5 +70,10 @@ Files that are processed by the manager includes: - `azure-pipeline.yaml` - `azure-pipeline.yml` + +!!! warning + Renovate can't update (root) container-element in containers jobs, see [issue #21987](https://github.com/renovatebot/renovate/issues/21987). + Renovate can't read Azure repositories defined in resource blocks, see [issue #15028](https://github.com/renovatebot/renovate/issues/15028). + [resources-docs]: https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema/resources?view=azure-pipelines [tasks-docs]: https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema/steps-task?view=azure-pipelines From 664dc808e7a95747134d9793a4df36deec7b2a88 Mon Sep 17 00:00:00 2001 From: Sergei Zharinov Date: Sun, 7 May 2023 23:51:20 +0300 Subject: [PATCH 18/57] refactor(composer): Use schema for parsing (#21520) --- lib/modules/manager/composer/artifacts.ts | 28 +- lib/modules/manager/composer/extract.spec.ts | 2 +- lib/modules/manager/composer/extract.ts | 212 +----------- lib/modules/manager/composer/schema.spec.ts | 115 +++++++ lib/modules/manager/composer/schema.ts | 318 ++++++++++++++++++ lib/modules/manager/composer/types.ts | 46 --- lib/modules/manager/composer/update-locked.ts | 12 +- lib/modules/manager/composer/utils.spec.ts | 185 +++++----- lib/modules/manager/composer/utils.ts | 58 ++-- 9 files changed, 589 insertions(+), 387 deletions(-) create mode 100644 lib/modules/manager/composer/schema.spec.ts create mode 100644 lib/modules/manager/composer/schema.ts diff --git a/lib/modules/manager/composer/artifacts.ts b/lib/modules/manager/composer/artifacts.ts index cc6acbbf266ff0..a902bf827db023 100644 --- a/lib/modules/manager/composer/artifacts.ts +++ b/lib/modules/manager/composer/artifacts.ts @@ -1,5 +1,6 @@ import is from '@sindresorhus/is'; import { quote } from 'shlex'; +import { z } from 'zod'; import { SYSTEM_INSUFFICIENT_DISK_SPACE, TEMPORARY_ERROR, @@ -18,10 +19,12 @@ import { import { getRepoStatus } from '../../../util/git'; import * as hostRules from '../../../util/host-rules'; import { regEx } from '../../../util/regex'; +import { Json } from '../../../util/schema-utils'; import { GitTagsDatasource } from '../../datasource/git-tags'; import { PackagistDatasource } from '../../datasource/packagist'; import type { UpdateArtifact, UpdateArtifactsResult } from '../types'; -import type { AuthJson, ComposerLock } from './types'; +import { Lockfile, PackageFile } from './schema'; +import type { AuthJson } from './types'; import { extractConstraints, findGithubToken, @@ -105,10 +108,19 @@ export async function updateArtifacts({ }: UpdateArtifact): Promise { logger.debug(`composer.updateArtifacts(${packageFileName})`); + const file = Json.pipe(PackageFile).parse(newPackageFileContent); + const lockFileName = packageFileName.replace(regEx(/\.json$/), '.lock'); - const existingLockFileContent = await readLocalFile(lockFileName, 'utf8'); - if (!existingLockFileContent) { - logger.debug('No composer.lock found'); + const lockfile = await z + .string() + .transform((f) => readLocalFile(f, 'utf8')) + .pipe(Json) + .pipe(Lockfile) + .nullable() + .catch(null) + .parseAsync(lockFileName); + if (!lockfile) { + logger.debug('Composer: unable to read lockfile'); return null; } @@ -118,12 +130,8 @@ export async function updateArtifacts({ try { await writeLocalFile(packageFileName, newPackageFileContent); - const existingLockFile: ComposerLock = JSON.parse(existingLockFileContent); const constraints = { - ...extractConstraints( - JSON.parse(newPackageFileContent), - existingLockFile - ), + ...extractConstraints(file, lockfile), ...config.constraints, }; @@ -150,7 +158,7 @@ export async function updateArtifacts({ const commands: string[] = []; // Determine whether install is required before update - if (requireComposerDependencyInstallation(existingLockFile)) { + if (requireComposerDependencyInstallation(lockfile)) { const preCmd = 'composer'; const preArgs = 'install' + getComposerArguments(config, composerToolConstraint); diff --git a/lib/modules/manager/composer/extract.spec.ts b/lib/modules/manager/composer/extract.spec.ts index 617db0e7245fe2..9c7d71a4cfd14b 100644 --- a/lib/modules/manager/composer/extract.spec.ts +++ b/lib/modules/manager/composer/extract.spec.ts @@ -279,7 +279,7 @@ describe('modules/manager/composer/extract', () => { }); it('extracts dependencies with lock file', async () => { - fs.readLocalFile.mockResolvedValue('some content'); + fs.readLocalFile.mockResolvedValue('{}'); const res = await extractPackageFile(requirements1, packageFile); expect(res).toMatchSnapshot(); expect(res?.deps).toHaveLength(33); diff --git a/lib/modules/manager/composer/extract.ts b/lib/modules/manager/composer/extract.ts index ae40abec469249..22eb4bdae316d4 100644 --- a/lib/modules/manager/composer/extract.ts +++ b/lib/modules/manager/composer/extract.ts @@ -1,215 +1,15 @@ -import is from '@sindresorhus/is'; import { logger } from '../../../logger'; -import { readLocalFile } from '../../../util/fs'; -import { regEx } from '../../../util/regex'; -import { GitTagsDatasource } from '../../datasource/git-tags'; -import { GithubTagsDatasource } from '../../datasource/github-tags'; -import { PackagistDatasource } from '../../datasource/packagist'; -import { api as semverComposer } from '../../versioning/composer'; -import type { PackageDependency, PackageFileContent } from '../types'; -import type { - ComposerConfig, - ComposerLock, - ComposerManagerData, - ComposerRepositories, - Repo, -} from './types'; - -/** - * The regUrl is expected to be a base URL. GitLab composer repository installation guide specifies - * to use a base URL containing packages.json. Composer still works in this scenario by determining - * whether to add / remove packages.json from the URL. - * - * See https://github.com/composer/composer/blob/750a92b4b7aecda0e5b2f9b963f1cb1421900675/src/Composer/Repository/ComposerRepository.php#L815 - */ -function transformRegUrl(url: string): string { - return url.replace(regEx(/(\/packages\.json)$/), ''); -} - -/** - * Parse the repositories field from a composer.json - * - * Entries with type vcs or git will be added to repositories, - * other entries will be added to registryUrls - */ -function parseRepositories( - repoJson: ComposerRepositories, - repositories: Record, - registryUrls: string[] -): void { - try { - let packagist = true; - Object.entries(repoJson).forEach(([key, repo]) => { - if (is.object(repo)) { - const name = is.array(repoJson) ? repo.name : key; - - switch (repo.type) { - case 'vcs': - case 'git': - case 'path': - repositories[name!] = repo; - break; - case 'composer': - registryUrls.push(transformRegUrl(repo.url)); - break; - case 'package': - logger.debug( - { url: repo.url }, - 'type package is not supported yet' - ); - } - if (repo.packagist === false || repo['packagist.org'] === false) { - packagist = false; - } - } // istanbul ignore else: invalid repo - else if (['packagist', 'packagist.org'].includes(key) && repo === false) { - packagist = false; - } - }); - if (packagist) { - registryUrls.push('https://packagist.org'); - } else { - logger.debug('Disabling packagist.org'); - } - } catch (e) /* istanbul ignore next */ { - logger.debug( - { repositories: repoJson }, - 'Error parsing composer.json repositories config' - ); - } -} +import type { PackageFileContent } from '../types'; +import { ComposerExtract } from './schema'; export async function extractPackageFile( content: string, fileName: string ): Promise { - logger.trace(`composer.extractPackageFile(${fileName})`); - let composerJson: ComposerConfig; - try { - composerJson = JSON.parse(content); - } catch (err) { - logger.debug(`Invalid JSON in ${fileName}`); + const res = await ComposerExtract.safeParseAsync({ content, fileName }); + if (!res.success) { + logger.debug({ fileName, err: res.error }, 'Composer: extract failed'); return null; } - const repositories: Record = {}; - const registryUrls: string[] = []; - const res: PackageFileContent = { deps: [] }; - - // handle lockfile - const lockfilePath = fileName.replace(regEx(/\.json$/), '.lock'); - const lockContents = await readLocalFile(lockfilePath, 'utf8'); - let lockParsed: ComposerLock | undefined; - if (lockContents) { - logger.debug(`Found composer lock file ${fileName}`); - res.lockFiles = [lockfilePath]; - try { - lockParsed = JSON.parse(lockContents) as ComposerLock; - } catch (err) /* istanbul ignore next */ { - logger.warn({ err }, 'Error processing composer.lock'); - } - } - - // handle composer.json repositories - if (composerJson.repositories) { - parseRepositories(composerJson.repositories, repositories, registryUrls); - } - - const deps: PackageDependency[] = []; - const depTypes: ('require' | 'require-dev')[] = ['require', 'require-dev']; - for (const depType of depTypes) { - if (composerJson[depType]) { - try { - for (const [depName, version] of Object.entries( - composerJson[depType]! - )) { - const currentValue = version.trim(); - if (depName === 'php') { - deps.push({ - depType, - depName, - currentValue, - datasource: GithubTagsDatasource.id, - packageName: 'php/php-src', - extractVersion: '^php-(?.*)$', - }); - } else { - // Default datasource and packageName - let datasource = PackagistDatasource.id; - let packageName = depName; - - // Check custom repositories by type - if (repositories[depName]) { - switch (repositories[depName].type) { - case 'vcs': - case 'git': - datasource = GitTagsDatasource.id; - packageName = repositories[depName].url; - break; - case 'path': - deps.push({ - depType, - depName, - currentValue, - skipReason: 'path-dependency', - }); - continue; - } - } - const dep: PackageDependency = { - depType, - depName, - currentValue, - datasource, - }; - if (depName !== packageName) { - dep.packageName = packageName; - } - if (!depName.includes('/')) { - dep.skipReason = 'unsupported'; - } - if (lockParsed) { - const lockField = - depType === 'require' - ? 'packages' - : /* istanbul ignore next */ 'packages-dev'; - const lockedDep = lockParsed[lockField]?.find( - (item) => item.name === dep.depName - ); - if (lockedDep && semverComposer.isVersion(lockedDep.version)) { - dep.lockedVersion = lockedDep.version.replace(regEx(/^v/i), ''); - } - } - if ( - !dep.skipReason && - (!repositories[depName] || - repositories[depName].type === 'composer') && - registryUrls.length !== 0 - ) { - dep.registryUrls = registryUrls; - } - deps.push(dep); - } - } - } catch (err) /* istanbul ignore next */ { - logger.debug({ fileName, depType, err }, 'Error parsing composer.json'); - return null; - } - } - } - if (!deps.length) { - return null; - } - res.deps = deps; - if (is.string(composerJson.type)) { - const managerData: ComposerManagerData = { - composerJsonType: composerJson.type, - }; - res.managerData = managerData; - } - - if (composerJson.require?.php) { - res.extractedConstraints = { php: composerJson.require.php }; - } - - return res; + return res.data; } diff --git a/lib/modules/manager/composer/schema.spec.ts b/lib/modules/manager/composer/schema.spec.ts new file mode 100644 index 00000000000000..d105b70690e926 --- /dev/null +++ b/lib/modules/manager/composer/schema.spec.ts @@ -0,0 +1,115 @@ +import { Repos, ReposArray, ReposRecord } from './schema'; + +describe('modules/manager/composer/schema', () => { + describe('ReposRecord', () => { + it('parses default values', () => { + expect(ReposRecord.parse({})).toEqual([]); + }); + + it('parses repositories', () => { + expect( + ReposRecord.parse({ + wpackagist: { type: 'composer', url: 'https://wpackagist.org' }, + someGit: { type: 'vcs', url: 'https://some-vcs.com' }, + somePath: { type: 'path', url: '/some/path' }, + packagist: false, + 'packagist.org': false, + foo: 'bar', + }) + ).toEqual([ + { type: 'composer', url: 'https://wpackagist.org' }, + { name: 'someGit', type: 'git', url: 'https://some-vcs.com' }, + { name: 'somePath', type: 'path', url: '/some/path' }, + { type: 'disable-packagist' }, + { type: 'disable-packagist' }, + ]); + }); + }); + + describe('ReposArray', () => { + it('parses default values', () => { + expect(ReposArray.parse([])).toEqual([]); + }); + + it('parses repositories', () => { + expect( + ReposArray.parse([ + { + type: 'composer', + url: 'https://wpackagist.org', + }, + { name: 'someGit', type: 'vcs', url: 'https://some-vcs.com' }, + { name: 'somePath', type: 'path', url: '/some/path' }, + { packagist: false }, + { 'packagist.org': false }, + { foo: 'bar' }, + ]) + ).toEqual([ + { type: 'composer', url: 'https://wpackagist.org' }, + { name: 'someGit', type: 'git', url: 'https://some-vcs.com' }, + { name: 'somePath', type: 'path', url: '/some/path' }, + { type: 'disable-packagist' }, + { type: 'disable-packagist' }, + ]); + }); + }); + + describe('Repos', () => { + it('parses default values', () => { + expect(Repos.parse(null)).toEqual({ + pathRepos: {}, + gitRepos: {}, + registryUrls: null, + }); + }); + + it('parses repositories', () => { + expect( + Repos.parse([ + { + name: 'wpackagist', + type: 'composer', + url: 'https://wpackagist.org', + }, + { name: 'someGit', type: 'vcs', url: 'https://some-vcs.com' }, + { name: 'somePath', type: 'path', url: '/some/path' }, + ]) + ).toEqual({ + pathRepos: { + somePath: { name: 'somePath', type: 'path', url: '/some/path' }, + }, + registryUrls: ['https://wpackagist.org', 'https://packagist.org'], + gitRepos: { + someGit: { + name: 'someGit', + type: 'git', + url: 'https://some-vcs.com', + }, + }, + }); + }); + + it(`parses repositories with packagist disabled`, () => { + expect( + Repos.parse({ + wpackagist: { type: 'composer', url: 'https://wpackagist.org' }, + someGit: { type: 'vcs', url: 'https://some-vcs.com' }, + somePath: { type: 'path', url: '/some/path' }, + packagist: false, + }) + ).toEqual({ + pathRepos: { + somePath: { name: 'somePath', type: 'path', url: '/some/path' }, + }, + registryUrls: ['https://wpackagist.org'], + gitRepos: { + someGit: { + name: 'someGit', + type: 'git', + url: 'https://some-vcs.com', + }, + }, + }); + }); + }); +}); diff --git a/lib/modules/manager/composer/schema.ts b/lib/modules/manager/composer/schema.ts new file mode 100644 index 00000000000000..fb8c2a8af2c9d7 --- /dev/null +++ b/lib/modules/manager/composer/schema.ts @@ -0,0 +1,318 @@ +import { z } from 'zod'; +import { logger } from '../../../logger'; +import { readLocalFile } from '../../../util/fs'; +import { regEx } from '../../../util/regex'; +import { Json, LooseArray, LooseRecord } from '../../../util/schema-utils'; +import { GitTagsDatasource } from '../../datasource/git-tags'; +import { GithubTagsDatasource } from '../../datasource/github-tags'; +import { PackagistDatasource } from '../../datasource/packagist'; +import { api as semverComposer } from '../../versioning/composer'; +import type { PackageDependency, PackageFileContent } from '../types'; +import type { ComposerManagerData } from './types'; + +export const ComposerRepo = z.object({ + type: z.literal('composer'), + /** + * The regUrl is expected to be a base URL. GitLab composer repository installation guide specifies + * to use a base URL containing packages.json. Composer still works in this scenario by determining + * whether to add / remove packages.json from the URL. + * + * See https://github.com/composer/composer/blob/750a92b4b7aecda0e5b2f9b963f1cb1421900675/src/Composer/Repository/ComposerRepository.php#L815 + */ + url: z.string().transform((url) => url.replace(/\/packages\.json$/, '')), +}); +export type ComposerRepo = z.infer; + +export const GitRepo = z.object({ + type: z.enum(['vcs', 'git']).transform(() => 'git' as const), + url: z.string(), +}); +export type GitRepo = z.infer; + +export const PathRepo = z.object({ + type: z.literal('path'), + url: z.string(), +}); +export type PathRepo = z.infer; + +export const Repo = z.discriminatedUnion('type', [ + ComposerRepo, + GitRepo, + PathRepo, +]); +export type Repo = z.infer; + +export const NamedRepo = z.discriminatedUnion('type', [ + ComposerRepo, + GitRepo.extend({ name: z.string() }), + PathRepo.extend({ name: z.string() }), +]); +export type NamedRepo = z.infer; + +const DisablePackagist = z.object({ type: z.literal('disable-packagist') }); +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'); + }, +}).transform((repos) => { + const result: (NamedRepo | DisablePackagist)[] = []; + for (const [name, repo] of Object.entries(repos)) { + if (repo === false) { + if (name === 'packagist' || name === 'packagist.org') { + result.push({ type: 'disable-packagist' }); + } + continue; + } + + if (repo.type === 'path' || repo.type === 'git') { + result.push({ name, ...repo }); + continue; + } + + if (repo.type === 'composer') { + result.push(repo); + continue; + } + } + + return result; +}); +export type ReposRecord = z.infer; + +export const ReposArray = LooseArray( + z.union([ + NamedRepo, + z + .union([ + z.object({ packagist: z.literal(false) }), + z.object({ 'packagist.org': z.literal(false) }), + ]) + .transform((): DisablePackagist => ({ type: 'disable-packagist' })), + ]), + { + onError: ({ error: err }) => { + logger.warn({ err }, 'Composer: error parsing repositories array'); + }, + } +).transform((repos) => repos.filter((x): x is NamedRepo => x !== null)); +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'); + return []; + }) + .transform((repos) => { + let packagist = true; + const repoUrls: string[] = []; + const gitRepos: Record = {}; + const pathRepos: Record = {}; + + for (const repo of repos) { + if (repo.type === 'composer') { + repoUrls.push(repo.url); + } else if (repo.type === 'git') { + gitRepos[repo.name] = repo; + } else if (repo.type === 'path') { + pathRepos[repo.name] = repo; + } else if (repo.type === 'disable-packagist') { + packagist = false; + } + } + + if (packagist && repoUrls.length) { + repoUrls.push('https://packagist.org'); + } + const registryUrls = repoUrls.length ? repoUrls : null; + + return { registryUrls, gitRepos, pathRepos }; + }); +export type Repos = z.infer; + +const RequireDefs = LooseRecord(z.string().transform((x) => x.trim())).catch( + {} +); + +export const PackageFile = z + .object({ + type: z.string().optional(), + config: z + .object({ + platform: z.object({ + php: z.string(), + }), + }) + .nullable() + .catch(null), + repositories: Repos, + require: RequireDefs, + 'require-dev': RequireDefs, + }) + .transform( + ({ + type: composerJsonType, + config, + repositories, + require, + 'require-dev': requireDev, + }) => ({ + composerJsonType, + config, + repositories, + require, + requireDev, + }) + ); +export type PackageFile = z.infer; + +const LockedPackage = z.object({ + name: z.string(), + version: z.string(), +}); +type LockedPackage = z.infer; + +export const Lockfile = z + .object({ + 'plugin-api-version': z.string().optional(), + packages: LooseArray(LockedPackage).catch([]), + 'packages-dev': LooseArray(LockedPackage).catch([]), + }) + .transform( + ({ + 'plugin-api-version': pluginApiVersion, + packages, + 'packages-dev': packagesDev, + }) => ({ pluginApiVersion, packages, packagesDev }) + ); +export type Lockfile = z.infer; + +export const ComposerExtract = z + .object({ + content: z.string(), + fileName: z.string(), + }) + .transform(({ content, fileName }) => { + const lockfileName = fileName.replace(/\.json$/, '.lock'); + return { + file: content, + lockfileName, + lockfile: lockfileName, + }; + }) + .pipe( + z.object({ + file: Json.pipe(PackageFile), + lockfileName: z.string(), + 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; + }), + }) + ) + .transform(({ file, lockfile, lockfileName }) => { + const { composerJsonType, require, requireDev } = file; + const { registryUrls, gitRepos, pathRepos } = file.repositories; + + const deps: PackageDependency[] = []; + + const profiles = [ + { + depType: 'require', + req: require, + locked: lockfile?.packages ?? [], + }, + { + depType: 'require-dev', + req: requireDev, + locked: lockfile?.packagesDev ?? [], + }, + ]; + + for (const { depType, req, locked } of profiles) { + for (const [depName, currentValue] of Object.entries(req)) { + if (depName === 'php') { + deps.push({ + depType, + depName, + currentValue, + datasource: GithubTagsDatasource.id, + packageName: 'php/php-src', + extractVersion: '^php-(?.*)$', + }); + continue; + } + + if (pathRepos[depName]) { + deps.push({ + depType, + depName, + currentValue, + skipReason: 'path-dependency', + }); + continue; + } + + const dep: PackageDependency = { + depType, + depName, + currentValue, + }; + + if (!depName.includes('/')) { + dep.skipReason = 'unsupported'; + } + + const lockedDep = locked.find((item) => item.name === depName); + if (lockedDep && semverComposer.isVersion(lockedDep.version)) { + dep.lockedVersion = lockedDep.version.replace(regEx(/^v/i), ''); + } + + const gitRepo = gitRepos[depName]; + if (gitRepo) { + dep.datasource = GitTagsDatasource.id; + dep.packageName = gitRepo.url; + deps.push(dep); + continue; + } + + dep.datasource = PackagistDatasource.id; + + if (registryUrls) { + dep.registryUrls = registryUrls; + } + + deps.push(dep); + } + } + + if (!deps.length) { + return null; + } + + const res: PackageFileContent = { deps }; + + if (composerJsonType) { + res.managerData = { composerJsonType }; + } + + if (require.php) { + res.extractedConstraints = { php: require.php }; + } + + if (lockfile) { + res.lockFiles = [lockfileName]; + } + + return res; + }); +export type ComposerExtract = z.infer; diff --git a/lib/modules/manager/composer/types.ts b/lib/modules/manager/composer/types.ts index c46f294d0cf861..491dc7eac3f78c 100644 --- a/lib/modules/manager/composer/types.ts +++ b/lib/modules/manager/composer/types.ts @@ -1,49 +1,3 @@ -// istanbul ignore file: types only -export interface Repo { - name?: string; - type: 'composer' | 'git' | 'package' | 'path' | 'vcs'; - packagist?: boolean; - 'packagist.org'?: boolean; - url: string; -} -export type ComposerRepositories = Record | Repo[]; - -export interface ComposerConfig { - type?: string; - /** - * Setting a fixed PHP version (e.g. {"php": "7.0.3"}) will let you fake the - * platform version so that you can emulate a production env or define your - * target platform in the config. - * See https://getcomposer.org/doc/06-config.md#platform - */ - config?: { - platform?: { - php?: string; - }; - }; - /** - * A repositories field can be an array of Repo objects or an object of repoName: Repo - * Also it can be a boolean (usually false) to disable packagist. - * (Yes this can be confusing, as it is also not properly documented in the composer docs) - * See https://getcomposer.org/doc/05-repositories.md#disabling-packagist-org - */ - repositories?: ComposerRepositories; - - require?: Record; - 'require-dev'?: Record; -} - -export interface ComposerLockPackage { - name: string; - version: string; -} - -export interface ComposerLock { - 'plugin-api-version'?: string; - packages?: ComposerLockPackage[]; - 'packages-dev'?: ComposerLockPackage[]; -} - export interface ComposerManagerData { composerJsonType?: string; } diff --git a/lib/modules/manager/composer/update-locked.ts b/lib/modules/manager/composer/update-locked.ts index fcfaa89d2f11c9..469ac1a81df64b 100644 --- a/lib/modules/manager/composer/update-locked.ts +++ b/lib/modules/manager/composer/update-locked.ts @@ -1,7 +1,8 @@ import { logger } from '../../../logger'; +import { Json } from '../../../util/schema-utils'; import { api as composer } from '../../versioning/composer'; import type { UpdateLockedConfig, UpdateLockedResult } from '../types'; -import type { ComposerLock } from './types'; +import { Lockfile } from './schema'; export function updateLockedDependency( config: UpdateLockedConfig @@ -12,12 +13,11 @@ export function updateLockedDependency( `composer.updateLockedDependency: ${depName}@${currentVersion} -> ${newVersion} [${lockFile}]` ); try { - const locked = JSON.parse(lockFileContent!) as ComposerLock; + const lockfile = Json.pipe(Lockfile).parse(lockFileContent); if ( - locked.packages?.find( - (entry) => - entry.name === depName && - composer.equals(entry.version || '', newVersion) + lockfile?.packages.find( + ({ name, version }) => + name === depName && composer.equals(version, newVersion) ) ) { return { status: 'already-updated' }; diff --git a/lib/modules/manager/composer/utils.spec.ts b/lib/modules/manager/composer/utils.spec.ts index 481df517e6f260..c9e6117fccfd5b 100644 --- a/lib/modules/manager/composer/utils.spec.ts +++ b/lib/modules/manager/composer/utils.spec.ts @@ -1,6 +1,7 @@ import { GlobalConfig } from '../../../config/global'; import * as hostRules from '../../../util/host-rules'; import { GitTagsDatasource } from '../../datasource/git-tags'; +import { Lockfile, PackageFile } from './schema'; import { extractConstraints, findGithubToken, @@ -21,114 +22,121 @@ describe('modules/manager/composer/utils', () => { describe('extractConstraints', () => { it('returns from require', () => { - expect( - extractConstraints( - { require: { php: '>=5.3.2', 'composer/composer': '1.1.0' } }, - {} - ) - ).toEqual({ php: '>=5.3.2', composer: '1.1.0' }); + const file = PackageFile.parse({ + require: { php: '>=5.3.2', 'composer/composer': '1.1.0' }, + }); + const lockfile = Lockfile.parse({}); + expect(extractConstraints(file, lockfile)).toEqual({ + php: '>=5.3.2', + composer: '1.1.0', + }); }); it('returns platform php version', () => { - expect( - extractConstraints( - { - config: { platform: { php: '7.4.27' } }, - require: { php: '~7.4 || ~8.0' }, - }, - {} - ) - ).toEqual({ composer: '1.*', php: '<=7.4.27' }); + const file = PackageFile.parse({ + config: { platform: { php: '7.4.27' } }, + require: { php: '~7.4 || ~8.0' }, + }); + const lockfile = Lockfile.parse({}); + expect(extractConstraints(file, lockfile)).toEqual({ + composer: '1.*', + php: '<=7.4.27', + }); }); it('returns platform 0 minor php version', () => { - expect( - extractConstraints( - { - config: { platform: { php: '7.0.5' } }, - require: { php: '^7.0 || ~8.0' }, - }, - {} - ) - ).toEqual({ composer: '1.*', php: '<=7.0.5' }); + const file = PackageFile.parse({ + config: { platform: { php: '7.0.5' } }, + require: { php: '^7.0 || ~8.0' }, + }); + const lockfile = Lockfile.parse({}); + expect(extractConstraints(file, lockfile)).toEqual({ + composer: '1.*', + php: '<=7.0.5', + }); }); it('returns platform 0 patch php version', () => { - expect( - extractConstraints( - { - config: { platform: { php: '7.4.0' } }, - require: { php: '^7.0 || ~8.0' }, - }, - {} - ) - ).toEqual({ composer: '1.*', php: '<=7.4.0' }); + const file = PackageFile.parse({ + config: { platform: { php: '7.4.0' } }, + require: { php: '^7.0 || ~8.0' }, + }); + const lockfile = Lockfile.parse({}); + expect(extractConstraints(file, lockfile)).toEqual({ + composer: '1.*', + php: '<=7.4.0', + }); }); it('returns platform lowest minor php version', () => { - expect( - extractConstraints( - { - config: { platform: { php: '7' } }, - require: { php: '^7.0 || ~8.0' }, - }, - {} - ) - ).toEqual({ composer: '1.*', php: '<=7.0.0' }); + const file = PackageFile.parse({ + config: { platform: { php: '7' } }, + require: { php: '^7.0 || ~8.0' }, + }); + const lockfile = Lockfile.parse({}); + expect(extractConstraints(file, lockfile)).toEqual({ + composer: '1.*', + php: '<=7.0.0', + }); }); it('returns platform lowest patch php version', () => { - expect( - extractConstraints( - { - config: { platform: { php: '7.4' } }, - require: { php: '~7.4 || ~8.0' }, - }, - {} - ) - ).toEqual({ composer: '1.*', php: '<=7.4.0' }); + const file = PackageFile.parse({ + config: { platform: { php: '7.4' } }, + require: { php: '~7.4 || ~8.0' }, + }); + const lockfile = Lockfile.parse({}); + expect(extractConstraints(file, lockfile)).toEqual({ + composer: '1.*', + php: '<=7.4.0', + }); }); it('returns from require-dev', () => { - expect( - extractConstraints( - { 'require-dev': { 'composer/composer': '1.1.0' } }, - {} - ) - ).toEqual({ composer: '1.1.0' }); + const file = PackageFile.parse({ + 'require-dev': { 'composer/composer': '1.1.0' }, + }); + const lockfile = Lockfile.parse({}); + expect(extractConstraints(file, lockfile)).toEqual({ composer: '1.1.0' }); }); it('returns from composer platform require', () => { - expect( - extractConstraints({ require: { php: '^8.1', composer: '2.2.0' } }, {}) - ).toEqual({ php: '^8.1', composer: '2.2.0' }); + const file = PackageFile.parse({ + require: { php: '^8.1', composer: '2.2.0' }, + }); + const lockfile = Lockfile.parse({}); + expect(extractConstraints(file, lockfile)).toEqual({ + php: '^8.1', + composer: '2.2.0', + }); }); it('returns from composer platform require-dev', () => { - expect( - extractConstraints({ 'require-dev': { composer: '^2.2' } }, {}) - ).toEqual({ composer: '^2.2' }); + const file = PackageFile.parse({ 'require-dev': { composer: '^2.2' } }); + const lockfile = Lockfile.parse({}); + expect(extractConstraints(file, lockfile)).toEqual({ composer: '^2.2' }); }); it('returns from composer-runtime-api', () => { - expect( - extractConstraints( - { require: { 'composer-runtime-api': '^1.1.0' } }, - {} - ) - ).toEqual({ composer: '^1.1' }); + const file = PackageFile.parse({ + require: { 'composer-runtime-api': '^1.1.0' }, + }); + const lockfile = Lockfile.parse({}); + expect(extractConstraints(file, lockfile)).toEqual({ composer: '^1.1' }); }); it('returns from plugin-api-version', () => { - expect(extractConstraints({}, { 'plugin-api-version': '1.1.0' })).toEqual( - { - composer: '^1.1', - } - ); + const file = PackageFile.parse({}); + const lockfile = Lockfile.parse({ 'plugin-api-version': '1.1.0' }); + expect(extractConstraints(file, lockfile)).toEqual({ + composer: '^1.1', + }); }); it('fallback to 1.*', () => { - expect(extractConstraints({}, {})).toEqual({ composer: '1.*' }); + const file = PackageFile.parse({}); + const lockfile = Lockfile.parse({}); + expect(extractConstraints(file, lockfile)).toEqual({ composer: '1.*' }); }); }); @@ -276,27 +284,24 @@ describe('modules/manager/composer/utils', () => { describe('requireComposerDependencyInstallation', () => { it('returns true when symfony/flex has been installed', () => { - expect( - requireComposerDependencyInstallation({ - packages: [{ name: 'symfony/flex', version: '1.17.1' }], - }) - ).toBeTrue(); + const lockfile = Lockfile.parse({ + packages: [{ name: 'symfony/flex', version: '1.17.1' }], + }); + expect(requireComposerDependencyInstallation(lockfile)).toBeTrue(); }); it('returns true when symfony/flex has been installed as dev dependency', () => { - expect( - requireComposerDependencyInstallation({ - 'packages-dev': [{ name: 'symfony/flex', version: '1.17.1' }], - }) - ).toBeTrue(); + const lockfile = Lockfile.parse({ + 'packages-dev': [{ name: 'symfony/flex', version: '1.17.1' }], + }); + expect(requireComposerDependencyInstallation(lockfile)).toBeTrue(); }); it('returns false when symfony/flex has not been installed', () => { - expect( - requireComposerDependencyInstallation({ - packages: [{ name: 'symfony/console', version: '5.4.0' }], - }) - ).toBeFalse(); + const lockfile = Lockfile.parse({ + packages: [{ name: 'symfony/console', version: '5.4.0' }], + }); + expect(requireComposerDependencyInstallation(lockfile)).toBeFalse(); }); }); diff --git a/lib/modules/manager/composer/utils.ts b/lib/modules/manager/composer/utils.ts index 8342798971adb7..5a73be6c9120ac 100644 --- a/lib/modules/manager/composer/utils.ts +++ b/lib/modules/manager/composer/utils.ts @@ -7,7 +7,7 @@ import type { HostRuleSearchResult } from '../../../types'; import type { ToolConstraint } from '../../../util/exec/types'; import { api, id as composerVersioningId } from '../../versioning/composer'; import type { UpdateArtifactsConfig } from '../types'; -import type { ComposerConfig, ComposerLock } from './types'; +import type { Lockfile, PackageFile } from './schema'; export { composerVersioningId }; @@ -59,53 +59,55 @@ export function getPhpConstraint( return null; } -export function requireComposerDependencyInstallation( - lock: ComposerLock -): boolean { +export function requireComposerDependencyInstallation({ + packages, + packagesDev, +}: Lockfile): boolean { return ( - lock.packages?.some((p) => depRequireInstall.has(p.name)) === true || - lock['packages-dev']?.some((p) => depRequireInstall.has(p.name)) === true + packages.some((p) => depRequireInstall.has(p.name)) === true || + packagesDev.some((p) => depRequireInstall.has(p.name)) === true ); } export function extractConstraints( - composerJson: ComposerConfig, - lockParsed: ComposerLock + { config, require, requireDev }: PackageFile, + { pluginApiVersion }: Lockfile ): Record { const res: Record = { composer: '1.*' }; // extract php - if (composerJson.config?.platform?.php) { - const major = api.getMajor(composerJson.config.platform.php); - const minor = api.getMinor(composerJson.config.platform.php) ?? 0; - const patch = api.getPatch(composerJson.config.platform.php) ?? 0; + const phpVersion = config?.platform.php; + if (phpVersion) { + const major = api.getMajor(phpVersion); + const minor = api.getMinor(phpVersion) ?? 0; + const patch = api.getPatch(phpVersion) ?? 0; res.php = `<=${major}.${minor}.${patch}`; - } else if (composerJson.require?.php) { - res.php = composerJson.require.php; + } else if (require.php) { + res.php = require.php; } // extract direct composer dependency - if (composerJson.require?.['composer/composer']) { - res.composer = composerJson.require?.['composer/composer']; - } else if (composerJson['require-dev']?.['composer/composer']) { - res.composer = composerJson['require-dev']?.['composer/composer']; + if (require['composer/composer']) { + res.composer = require['composer/composer']; + } else if (requireDev['composer/composer']) { + res.composer = requireDev['composer/composer']; } // composer platform package - else if (composerJson.require?.['composer']) { - res.composer = composerJson.require?.['composer']; - } else if (composerJson['require-dev']?.['composer']) { - res.composer = composerJson['require-dev']?.['composer']; + else if (require['composer']) { + res.composer = require['composer']; + } else if (requireDev['composer']) { + res.composer = requireDev['composer']; } // check last used composer version - else if (lockParsed?.['plugin-api-version']) { - const major = api.getMajor(lockParsed?.['plugin-api-version']); - const minor = api.getMinor(lockParsed?.['plugin-api-version']); + else if (pluginApiVersion) { + const major = api.getMajor(pluginApiVersion); + const minor = api.getMinor(pluginApiVersion); res.composer = `^${major}.${minor}`; } // check composer api dependency - else if (composerJson.require?.['composer-runtime-api']) { - const major = api.getMajor(composerJson.require?.['composer-runtime-api']); - const minor = api.getMinor(composerJson.require?.['composer-runtime-api']); + else if (require['composer-runtime-api']) { + const major = api.getMajor(require['composer-runtime-api']); + const minor = api.getMinor(require['composer-runtime-api']); res.composer = `^${major}.${minor}`; } return res; From 79313fa68b3e1b5596f95f7cc931221138daa518 Mon Sep 17 00:00:00 2001 From: Sergei Zharinov Date: Mon, 8 May 2023 00:17:14 +0300 Subject: [PATCH 19/57] test(rubygems): Inline params for better readability (#22017) --- lib/modules/datasource/rubygems/index.spec.ts | 158 +++++++++++++----- 1 file changed, 112 insertions(+), 46 deletions(-) diff --git a/lib/modules/datasource/rubygems/index.spec.ts b/lib/modules/datasource/rubygems/index.spec.ts index 0ab48107c352c4..3f62ca70cb9014 100644 --- a/lib/modules/datasource/rubygems/index.spec.ts +++ b/lib/modules/datasource/rubygems/index.spec.ts @@ -13,16 +13,6 @@ const emptyMarshalArray = Buffer.from([4, 8, 91, 0]); describe('modules/datasource/rubygems/index', () => { describe('getReleases', () => { - const params = { - versioning: rubyVersioning.id, - datasource: RubyGemsDatasource.id, - packageName: 'rails', - registryUrls: [ - 'https://thirdparty.com', - 'https://firstparty.com/basepath/', - ], - }; - beforeEach(() => { memCache.clear(); jest.resetAllMocks(); @@ -42,26 +32,34 @@ describe('modules/datasource/rubygems/index', () => { .scope('https://thirdparty.com') .get('/api/v1/gems/rails.json') .reply(200); - expect(await getPkgReleases(params)).toBeNull(); + expect( + await getPkgReleases({ + versioning: rubyVersioning.id, + datasource: RubyGemsDatasource.id, + packageName: 'rails', + registryUrls: [ + 'https://thirdparty.com', + 'https://firstparty.com/basepath/', + ], + }) + ).toBeNull(); }); it('returns null for rubygems.org package miss', async () => { - const newparams = { ...params }; - newparams.registryUrls = []; httpMock .scope('https://rubygems.org') .get('/versions') .reply(404, rubygemsOrgVersions); - const res = await getPkgReleases(newparams); + const res = await getPkgReleases({ + versioning: rubyVersioning.id, + datasource: RubyGemsDatasource.id, + packageName: 'rails', + registryUrls: [], + }); expect(res).toBeNull(); }); it('returns null for an error without "not_supported" reason', async () => { - const newparams = { - ...params, - registryUrls: [], - }; - const versionsdataSourceSpy = jest .spyOn(VersionsDatasource.prototype, 'syncVersions') .mockImplementationOnce(() => { @@ -69,7 +67,12 @@ describe('modules/datasource/rubygems/index', () => { }); try { - const res = await getPkgReleases(newparams); + const res = await getPkgReleases({ + versioning: rubyVersioning.id, + datasource: RubyGemsDatasource.id, + packageName: 'rails', + registryUrls: [], + }); expect(res).toBeNull(); } finally { versionsdataSourceSpy.mockRestore(); @@ -77,16 +80,16 @@ describe('modules/datasource/rubygems/index', () => { }); it('returns a dep for rubygems.org package hit', async () => { - const newparams = { - ...params, - packageName: '1pass', - registryUrls: [], - }; httpMock .scope('https://rubygems.org') .get('/versions') .reply(200, rubygemsOrgVersions); - const res = await getPkgReleases(newparams); + const res = await getPkgReleases({ + versioning: rubyVersioning.id, + datasource: RubyGemsDatasource.id, + packageName: '1pass', + registryUrls: [], + }); expect(res).not.toBeNull(); expect(res?.releases).toHaveLength(2); expect(res).toMatchSnapshot(); @@ -104,16 +107,16 @@ describe('modules/datasource/rubygems/index', () => { --- sidekiq-ent 0.7.10,1.0.0,1.0.1,1.2.4,2.0.0,2.1.2 4c0f62a49b15b4775b7fb6824ec34d45 `; - const newparams = { - ...params, - packageName: 'sidekiq-ent', - registryUrls: ['https://enterprise.contribsys.com'], - }; httpMock .scope('https://enterprise.contribsys.com') .get('/versions') .reply(200, contribsysComVersions); - const res = await getPkgReleases(newparams); + const res = await getPkgReleases({ + versioning: rubyVersioning.id, + datasource: RubyGemsDatasource.id, + packageName: 'sidekiq-ent', + registryUrls: ['https://enterprise.contribsys.com'], + }); expect(res).not.toBeNull(); expect(res?.releases).toHaveLength(6); expect(res).toMatchObject({ @@ -143,13 +146,16 @@ describe('modules/datasource/rubygems/index', () => { expect( await getPkgReleases({ - ...params, + versioning: rubyVersioning.id, + datasource: RubyGemsDatasource.id, + packageName: 'rails', registryUrls: [], }) ).toBeNull(); const res = await getPkgReleases({ - ...params, + versioning: rubyVersioning.id, + datasource: RubyGemsDatasource.id, packageName: '1pass', registryUrls: [], }); @@ -168,7 +174,15 @@ describe('modules/datasource/rubygems/index', () => { .get('/api/v1/versions/rails.json') .reply(200, railsVersions); - const res = await getPkgReleases(params); + const res = await getPkgReleases({ + versioning: rubyVersioning.id, + datasource: RubyGemsDatasource.id, + packageName: 'rails', + registryUrls: [ + 'https://thirdparty.com', + 'https://firstparty.com/basepath/', + ], + }); expect(res?.releases).toHaveLength(339); expect(res).toMatchSnapshot(); }); @@ -189,7 +203,15 @@ describe('modules/datasource/rubygems/index', () => { .get('/basepath/api/v1/versions/rails.json') .reply(200, railsVersions); - const res = await getPkgReleases(params); + const res = await getPkgReleases({ + versioning: rubyVersioning.id, + datasource: RubyGemsDatasource.id, + packageName: 'rails', + registryUrls: [ + 'https://thirdparty.com', + 'https://firstparty.com/basepath/', + ], + }); expect(res?.releases).toHaveLength(339); expect(res).toMatchSnapshot(); }); @@ -207,7 +229,17 @@ describe('modules/datasource/rubygems/index', () => { .reply(404) .get('/basepath/api/v1/gems/rails.json') .reply(200); - expect(await getPkgReleases(params)).toBeNull(); + expect( + await getPkgReleases({ + versioning: rubyVersioning.id, + datasource: RubyGemsDatasource.id, + packageName: 'rails', + registryUrls: [ + 'https://thirdparty.com', + 'https://firstparty.com/basepath/', + ], + }) + ).toBeNull(); }); it('falls back to info when version request fails', async () => { @@ -219,7 +251,15 @@ describe('modules/datasource/rubygems/index', () => { .reply(200, railsInfo) .get('/api/v1/versions/rails.json') .reply(400, {}); - const res = await getPkgReleases(params); + const res = await getPkgReleases({ + versioning: rubyVersioning.id, + datasource: RubyGemsDatasource.id, + packageName: 'rails', + registryUrls: [ + 'https://thirdparty.com', + 'https://firstparty.com/basepath/', + ], + }); expect(res?.releases).toHaveLength(1); expect(res?.releases[0].version).toBe(railsInfo.version); }); @@ -239,7 +279,17 @@ describe('modules/datasource/rubygems/index', () => { .reply(404) .get('/api/v1/gems/rails.json') .reply(500); - expect(await getPkgReleases(params)).toBeNull(); + expect( + await getPkgReleases({ + versioning: rubyVersioning.id, + datasource: RubyGemsDatasource.id, + packageName: 'rails', + registryUrls: [ + 'https://thirdparty.com', + 'https://firstparty.com/basepath/', + ], + }) + ).toBeNull(); }); it('falls back to dependencies api', async () => { @@ -252,32 +302,48 @@ describe('modules/datasource/rubygems/index', () => { .get('/api/v1/dependencies?gems=rails') .reply(200, railsDependencies); - const res = await getPkgReleases(params); + const res = await getPkgReleases({ + versioning: rubyVersioning.id, + datasource: RubyGemsDatasource.id, + packageName: 'rails', + registryUrls: [ + 'https://thirdparty.com', + 'https://firstparty.com/basepath/', + ], + }); expect(res?.releases).toHaveLength(339); }); it('returns null for GitHub Packages package miss', async () => { - const newparams = { ...params }; - newparams.registryUrls = ['https://rubygems.pkg.github.com/example']; httpMock .scope('https://rubygems.pkg.github.com/example') .get('/versions') .reply(404) .get('/api/v1/dependencies?gems=rails') .reply(200, emptyMarshalArray); - expect(await getPkgReleases(newparams)).toBeNull(); + expect( + await getPkgReleases({ + versioning: rubyVersioning.id, + datasource: RubyGemsDatasource.id, + packageName: 'rails', + registryUrls: ['https://rubygems.pkg.github.com/example'], + }) + ).toBeNull(); }); it('returns a dep for GitHub Packages package hit', async () => { - const newparams = { ...params }; - newparams.registryUrls = ['https://rubygems.pkg.github.com/example']; httpMock .scope('https://rubygems.pkg.github.com/example') .get('/versions') .reply(404) .get('/api/v1/dependencies?gems=rails') .reply(200, railsDependencies); - const res = await getPkgReleases(newparams); + const res = await getPkgReleases({ + versioning: rubyVersioning.id, + datasource: RubyGemsDatasource.id, + packageName: 'rails', + registryUrls: ['https://rubygems.pkg.github.com/example'], + }); expect(res?.releases).toHaveLength(339); expect(res).toMatchSnapshot(); }); From 1fa64d5b021c8a0135577b12bd9e2ef1ab4f778d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 8 May 2023 00:56:51 +0000 Subject: [PATCH 20/57] docs: update references to renovate/renovate to v35.73.0 (#22019) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- docs/usage/docker.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/usage/docker.md b/docs/usage/docker.md index 11b5aa17944e9d..c28ce0c59b73ee 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.66.3 +FROM renovate/renovate:35.73.0 # Include the "Docker tip" which you can find here https://cloud.google.com/sdk/docs/install # under "Installation" for "Debian/Ubuntu" RUN ... From 5d3549fcd0b5b07da1886e9baefcf2a2fe5e3070 Mon Sep 17 00:00:00 2001 From: Rhys Arkins Date: Mon, 8 May 2023 08:32:46 +0200 Subject: [PATCH 21/57] build(docs): exclude References if urls empty (#21986) --- tools/docs/manager.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tools/docs/manager.ts b/tools/docs/manager.ts index a3c0641526be6f..03f089130f7263 100644 --- a/tools/docs/manager.ts +++ b/tools/docs/manager.ts @@ -75,9 +75,10 @@ sidebar_label: ${displayName} .join(', '); md += `This manager supports extracting the following datasources: ${escapedDatasources}.\n\n`; - md += '## References'; - md += formatUrls(urls).replace('**References**:', ''); - + if (urls?.length) { + md += '## References'; + md += formatUrls(urls).replace('**References**:', ''); + } md += '## Default config\n\n'; md += '```json\n'; md += JSON.stringify(definition.defaultConfig, null, 2) + '\n'; From 0b36f97bd3e5086ac408f9212ecd036bbea171f9 Mon Sep 17 00:00:00 2001 From: RahulGautamSingh Date: Mon, 8 May 2023 12:06:40 +0530 Subject: [PATCH 22/57] refactor: replace as with partial/satisfies (#21982) --- .../datasource/github-tags/index.spec.ts | 5 ++-- lib/modules/manager/gomod/artifacts.spec.ts | 16 ++++++----- .../branch/__snapshots__/commit.spec.ts.snap | 22 --------------- .../update/branch/artifacts.spec.ts | 7 +++-- .../update/branch/check-existing.spec.ts | 9 ++++--- .../repository/update/branch/commit.spec.ts | 27 +++++++++++++++---- .../update/branch/get-updated.spec.ts | 9 ++++--- .../repository/update/pr/automerge.spec.ts | 10 ++++--- .../update/pr/changelog/release-notes.spec.ts | 12 ++++----- 9 files changed, 59 insertions(+), 58 deletions(-) delete mode 100644 lib/workers/repository/update/branch/__snapshots__/commit.spec.ts.snap diff --git a/lib/modules/datasource/github-tags/index.spec.ts b/lib/modules/datasource/github-tags/index.spec.ts index 72ae3f11f2421b..cf276d32b32c12 100644 --- a/lib/modules/datasource/github-tags/index.spec.ts +++ b/lib/modules/datasource/github-tags/index.spec.ts @@ -1,5 +1,6 @@ import { getPkgReleases } from '..'; import * as httpMock from '../../../../test/http-mock'; +import { partial } from '../../../../test/util'; import * as githubGraphql from '../../../util/github/graphql'; import type { GithubTagItem } from '../../../util/github/graphql/types'; import * as hostRules from '../../../util/host-rules'; @@ -77,11 +78,11 @@ describe('modules/datasource/github-tags/index', () => { releaseTimestamp: '2021-01-01', hash: '123', }, - { + partial({ version: 'v2.0.0', gitRef: 'v2.0.0', releaseTimestamp: '2022-01-01', - } as GithubTagItem, + }), ]); const res = await github.getDigest({ packageName }, 'v2.0.0'); expect(res).toBeNull(); diff --git a/lib/modules/manager/gomod/artifacts.spec.ts b/lib/modules/manager/gomod/artifacts.spec.ts index b7370430da197d..aee0645b62011a 100644 --- a/lib/modules/manager/gomod/artifacts.spec.ts +++ b/lib/modules/manager/gomod/artifacts.spec.ts @@ -1362,9 +1362,11 @@ describe('modules/manager/gomod/artifacts', () => { fs.readLocalFile.mockResolvedValueOnce('Current go.sum'); fs.readLocalFile.mockResolvedValueOnce(null); // vendor modules filename const execSnapshots = mockExecAll(); - git.getRepoStatus.mockResolvedValueOnce({ - modified: ['go.sum'], - } as StatusResult); + git.getRepoStatus.mockResolvedValueOnce( + partial({ + modified: ['go.sum'], + }) + ); fs.readLocalFile .mockResolvedValueOnce('New go.sum') .mockResolvedValueOnce('New go.mod'); @@ -1405,9 +1407,11 @@ describe('modules/manager/gomod/artifacts', () => { fs.readLocalFile.mockResolvedValueOnce('Current go.sum'); fs.readLocalFile.mockResolvedValueOnce(null); // vendor modules filename const execSnapshots = mockExecAll(); - git.getRepoStatus.mockResolvedValueOnce({ - modified: ['go.sum'], - } as StatusResult); + git.getRepoStatus.mockResolvedValueOnce( + partial({ + modified: ['go.sum'], + }) + ); fs.readLocalFile .mockResolvedValueOnce('New go.sum') .mockResolvedValueOnce('New go.mod'); diff --git a/lib/workers/repository/update/branch/__snapshots__/commit.spec.ts.snap b/lib/workers/repository/update/branch/__snapshots__/commit.spec.ts.snap deleted file mode 100644 index 9de011dc077203..00000000000000 --- a/lib/workers/repository/update/branch/__snapshots__/commit.spec.ts.snap +++ /dev/null @@ -1,22 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`workers/repository/update/branch/commit commitFilesToBranch commits files 1`] = ` -[ - [ - { - "baseBranch": undefined, - "branchName": "renovate/some-branch", - "files": [ - { - "contents": "some contents", - "path": "package.json", - "type": "addition", - }, - ], - "force": false, - "message": "some commit message", - "platformCommit": false, - }, - ], -] -`; diff --git a/lib/workers/repository/update/branch/artifacts.spec.ts b/lib/workers/repository/update/branch/artifacts.spec.ts index ca63fa5ec3db7b..1744205fbcfbf5 100644 --- a/lib/workers/repository/update/branch/artifacts.spec.ts +++ b/lib/workers/repository/update/branch/artifacts.spec.ts @@ -1,4 +1,4 @@ -import { getConfig, platform } from '../../../../../test/util'; +import { platform } from '../../../../../test/util'; import { GlobalConfig } from '../../../../config/global'; import type { BranchConfig } from '../../../types'; import { setArtifactErrorStatus } from './artifacts'; @@ -9,14 +9,13 @@ describe('workers/repository/update/branch/artifacts', () => { beforeEach(() => { GlobalConfig.set({}); jest.resetAllMocks(); - // TODO #7154 incompatible types config = { - ...getConfig(), + baseBranch: 'base-branch', manager: 'some-manager', branchName: 'renovate/pin', upgrades: [], artifactErrors: [{ lockFile: 'some' }], - } as BranchConfig; + } satisfies BranchConfig; }); describe('setArtifactsErrorStatus', () => { diff --git a/lib/workers/repository/update/branch/check-existing.spec.ts b/lib/workers/repository/update/branch/check-existing.spec.ts index c8cee3ed04366e..2e1af5eef1a7cd 100644 --- a/lib/workers/repository/update/branch/check-existing.spec.ts +++ b/lib/workers/repository/update/branch/check-existing.spec.ts @@ -1,4 +1,4 @@ -import { getConfig, partial, platform } from '../../../../../test/util'; +import { partial, platform } from '../../../../../test/util'; import { logger } from '../../../../logger'; import type { Pr } from '../../../../modules/platform'; import type { BranchConfig } from '../../../types'; @@ -9,12 +9,13 @@ describe('workers/repository/update/branch/check-existing', () => { let config: BranchConfig; beforeEach(() => { - // TODO: incompatible types (#7154) config = { - ...getConfig(), + baseBranch: 'base-branch', + manager: 'some-manager', + upgrades: [], branchName: 'some-branch', prTitle: 'some-title', - } as BranchConfig; + } satisfies BranchConfig; jest.resetAllMocks(); }); diff --git a/lib/workers/repository/update/branch/commit.spec.ts b/lib/workers/repository/update/branch/commit.spec.ts index 9147cf48e428f8..f98f3b57f7d842 100644 --- a/lib/workers/repository/update/branch/commit.spec.ts +++ b/lib/workers/repository/update/branch/commit.spec.ts @@ -1,4 +1,4 @@ -import { getConfig, scm } from '../../../../../test/util'; +import { scm } from '../../../../../test/util'; import { GlobalConfig } from '../../../../config/global'; import type { BranchConfig } from '../../../types'; import { commitFilesToBranch } from './commit'; @@ -8,9 +8,9 @@ describe('workers/repository/update/branch/commit', () => { let config: BranchConfig; beforeEach(() => { - // TODO: incompatible types (#7154) config = { - ...getConfig(), + baseBranch: 'base-branch', + manager: 'some-manager', branchName: 'renovate/some-branch', commitMessage: 'some commit message', semanticCommits: 'disabled', @@ -19,7 +19,7 @@ describe('workers/repository/update/branch/commit', () => { updatedPackageFiles: [], updatedArtifacts: [], upgrades: [], - } as BranchConfig; + } satisfies BranchConfig; jest.resetAllMocks(); scm.commitAndPush.mockResolvedValueOnce('123test'); GlobalConfig.reset(); @@ -38,7 +38,24 @@ describe('workers/repository/update/branch/commit', () => { }); await commitFilesToBranch(config); expect(scm.commitAndPush).toHaveBeenCalledTimes(1); - expect(scm.commitAndPush.mock.calls).toMatchSnapshot(); + expect(scm.commitAndPush.mock.calls).toEqual([ + [ + { + baseBranch: 'base-branch', + branchName: 'renovate/some-branch', + files: [ + { + contents: 'some contents', + path: 'package.json', + type: 'addition', + }, + ], + force: false, + message: 'some commit message', + platformCommit: false, + }, + ], + ]); }); it('dry runs', async () => { diff --git a/lib/workers/repository/update/branch/get-updated.spec.ts b/lib/workers/repository/update/branch/get-updated.spec.ts index 9dc3d2702d20c1..f6ec285d2f4a0e 100644 --- a/lib/workers/repository/update/branch/get-updated.spec.ts +++ b/lib/workers/repository/update/branch/get-updated.spec.ts @@ -1,4 +1,4 @@ -import { getConfig, git, mocked } from '../../../../../test/util'; +import { git, mocked } from '../../../../../test/util'; import { GitRefsDatasource } from '../../../../modules/datasource/git-refs'; import * as _batectWrapper from '../../../../modules/manager/batect-wrapper'; import * as _bundler from '../../../../modules/manager/bundler'; @@ -32,11 +32,12 @@ describe('workers/repository/update/branch/get-updated', () => { let config: BranchConfig; beforeEach(() => { - // TODO: incompatible types (#7154) config = { - ...getConfig(), + baseBranch: 'base-branch', + manager: 'some-manager', + branchName: 'renovate/pin', upgrades: [], - } as BranchConfig; + } satisfies BranchConfig; npm.updateDependency = jest.fn(); git.getFile.mockResolvedValueOnce('existing content'); }); diff --git a/lib/workers/repository/update/pr/automerge.spec.ts b/lib/workers/repository/update/pr/automerge.spec.ts index dfe4913afb4770..b602de45160ef3 100644 --- a/lib/workers/repository/update/pr/automerge.spec.ts +++ b/lib/workers/repository/update/pr/automerge.spec.ts @@ -1,4 +1,4 @@ -import { getConfig, partial, platform, scm } from '../../../../../test/util'; +import { partial, platform, scm } from '../../../../../test/util'; import { GlobalConfig } from '../../../../config/global'; import type { Pr } from '../../../../modules/platform'; import type { BranchConfig } from '../../../types'; @@ -12,10 +12,12 @@ describe('workers/repository/update/pr/automerge', () => { let pr: Pr; beforeEach(() => { - // TODO #7154 incompatible types config = { - ...getConfig(), - } as BranchConfig; + baseBranch: 'base-branch', + manager: 'some-manager', + branchName: 'renovate/pin', + upgrades: [], + } satisfies BranchConfig; pr = partial(); }); diff --git a/lib/workers/repository/update/pr/changelog/release-notes.spec.ts b/lib/workers/repository/update/pr/changelog/release-notes.spec.ts index 978bef659f4a44..500c1ed58936bc 100644 --- a/lib/workers/repository/update/pr/changelog/release-notes.spec.ts +++ b/lib/workers/repository/update/pr/changelog/release-notes.spec.ts @@ -87,9 +87,11 @@ describe('workers/repository/update/pr/changelog/release-notes', () => { describe('addReleaseNotes()', () => { it('returns null if input is null/undefined', async () => { - expect(await addReleaseNotes(null, {} as BranchUpgradeConfig)).toBeNull(); expect( - await addReleaseNotes(undefined, {} as BranchUpgradeConfig) + await addReleaseNotes(null, partial()) + ).toBeNull(); + expect( + await addReleaseNotes(undefined, partial()) ).toBeNull(); }); @@ -108,7 +110,6 @@ describe('workers/repository/update/pr/changelog/release-notes', () => { it('returns ChangeLogResult', async () => { const input = { - a: 1, project: { type: 'github', repository: 'https://github.com/nodeca/js-yaml', @@ -118,7 +119,6 @@ describe('workers/repository/update/pr/changelog/release-notes', () => { expect( await addReleaseNotes(input as never, partial()) ).toEqual({ - a: 1, hasReleaseNotes: false, project: { repository: 'https://github.com/nodeca/js-yaml', @@ -138,7 +138,6 @@ describe('workers/repository/update/pr/changelog/release-notes', () => { it('returns ChangeLogResult without release notes', async () => { const input = { - a: 1, project: partial({ type: 'gitlab', repository: 'https://gitlab.com/gitlab-org/gitter/webapp/', @@ -149,11 +148,10 @@ describe('workers/repository/update/pr/changelog/release-notes', () => { compare: { url: '' }, }), ], - } as ChangeLogResult; + } satisfies ChangeLogResult; expect( await addReleaseNotes(input, partial()) ).toEqual({ - a: 1, hasReleaseNotes: false, project: { repository: 'https://gitlab.com/gitlab-org/gitter/webapp/', From 6ac9a842090ecb2ef4aed60daa23d37d0f8632d8 Mon Sep 17 00:00:00 2001 From: RahulGautamSingh Date: Mon, 8 May 2023 13:24:19 +0530 Subject: [PATCH 23/57] fix(pnpm): extract engine constraint (#21959) --- lib/modules/manager/npm/extract/__snapshots__/index.spec.ts.snap | 1 + lib/modules/manager/npm/extract/index.spec.ts | 1 + lib/modules/manager/npm/extract/index.ts | 1 + 3 files changed, 3 insertions(+) diff --git a/lib/modules/manager/npm/extract/__snapshots__/index.spec.ts.snap b/lib/modules/manager/npm/extract/__snapshots__/index.spec.ts.snap index 668bbac7b8a309..06e92a81a48d4c 100644 --- a/lib/modules/manager/npm/extract/__snapshots__/index.spec.ts.snap +++ b/lib/modules/manager/npm/extract/__snapshots__/index.spec.ts.snap @@ -129,6 +129,7 @@ exports[`modules/manager/npm/extract/index .extractPackageFile() extracts engine "extractedConstraints": { "node": ">= 8.9.2", "npm": "^8.0.0", + "pnpm": "^1.2.0", "vscode": ">=1.49.3", "yarn": "disabled", }, diff --git a/lib/modules/manager/npm/extract/index.spec.ts b/lib/modules/manager/npm/extract/index.spec.ts index 1932f6fd8525ab..6013a242400032 100644 --- a/lib/modules/manager/npm/extract/index.spec.ts +++ b/lib/modules/manager/npm/extract/index.spec.ts @@ -418,6 +418,7 @@ describe('modules/manager/npm/extract/index', () => { extractedConstraints: { node: '>= 8.9.2', npm: '^8.0.0', + pnpm: '^1.2.0', vscode: '>=1.49.3', yarn: 'disabled', }, diff --git a/lib/modules/manager/npm/extract/index.ts b/lib/modules/manager/npm/extract/index.ts index 05803936be9f3e..4af1aefdcaa7cb 100644 --- a/lib/modules/manager/npm/extract/index.ts +++ b/lib/modules/manager/npm/extract/index.ts @@ -233,6 +233,7 @@ export async function extractPackageFile( } else if (depName === 'pnpm') { dep.datasource = NpmDatasource.id; dep.commitMessageTopic = 'pnpm'; + extractedConstraints.pnpm = dep.currentValue; } else if (depName === 'vscode') { dep.datasource = GithubTagsDatasource.id; dep.packageName = 'microsoft/vscode'; From 44271cca8a564c92384f619e5c462653edc108b5 Mon Sep 17 00:00:00 2001 From: IKEDA Sho Date: Mon, 8 May 2023 17:32:57 +0900 Subject: [PATCH 24/57] feat(manager/asdf): add ecspresso (#22021) --- lib/modules/manager/asdf/extract.spec.ts | 8 ++++++++ lib/modules/manager/asdf/upgradeable-tooling.ts | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/lib/modules/manager/asdf/extract.spec.ts b/lib/modules/manager/asdf/extract.spec.ts index e728dafd28eb9b..4b9e67bf232326 100644 --- a/lib/modules/manager/asdf/extract.spec.ts +++ b/lib/modules/manager/asdf/extract.spec.ts @@ -53,6 +53,7 @@ dart 2.19.3 deno 1.26.2 direnv 2.32.1 dprint 0.32.2 +ecspresso 2.1.0 elixir 1.14.1 elm 0.19.1 erlang 25.1.2 @@ -162,6 +163,13 @@ dummy 1.2.3 packageName: 'dprint/dprint', depName: 'dprint', }, + { + currentValue: '2.1.0', + datasource: 'github-releases', + packageName: 'kayac/ecspresso', + depName: 'ecspresso', + extractVersion: '^v(?\\S+)', + }, { currentValue: '1.14.1', datasource: 'hexpm-bob', diff --git a/lib/modules/manager/asdf/upgradeable-tooling.ts b/lib/modules/manager/asdf/upgradeable-tooling.ts index f52f3839217b76..921d1274af0276 100644 --- a/lib/modules/manager/asdf/upgradeable-tooling.ts +++ b/lib/modules/manager/asdf/upgradeable-tooling.ts @@ -112,6 +112,14 @@ export const upgradeableTooling: Record = { packageName: 'dprint/dprint', }, }, + ecspresso: { + asdfPluginUrl: 'https://github.com/kayac/asdf-ecspresso', + config: { + datasource: GithubReleasesDatasource.id, + packageName: 'kayac/ecspresso', + extractVersion: '^v(?\\S+)', + }, + }, elixir: { asdfPluginUrl: 'https://github.com/asdf-vm/asdf-elixir', config: { From 72f165ace1e76bf381750cb7a535431f7831d6f9 Mon Sep 17 00:00:00 2001 From: HonkingGoose <34918129+HonkingGoose@users.noreply.github.com> Date: Mon, 8 May 2023 12:13:37 +0200 Subject: [PATCH 25/57] docs(config options): link to regex manager presets (#22023) --- docs/usage/configuration-options.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/usage/configuration-options.md b/docs/usage/configuration-options.md index 82061dc96c13d4..6b01f12bebe36b 100644 --- a/docs/usage/configuration-options.md +++ b/docs/usage/configuration-options.md @@ -2853,14 +2853,14 @@ Typically you shouldn't need to modify this setting. Use `regexManagers` entries to configure the `regex` manager in Renovate. -You can define custom managers for cases such as: +You can define custom managers to handle: - Proprietary file formats or conventions - Popular file formats not yet supported as a manager by Renovate The custom manager concept is based on using Regular Expression named capture groups. -You must have a named capture group matching (e.g. `(?.*)`) _or_ configure it's corresponding template (e.g. `depNameTemplate`) for these fields: +You must have a named capture group matching (e.g. `(?.*)`) _or_ configure its corresponding template (e.g. `depNameTemplate`) for these fields: - `datasource` - `depName` @@ -2875,6 +2875,10 @@ If the `versioning` field is missing, then Renovate defaults to using `semver` v For more details and examples, see our [documentation for the `regex` manager](/modules/manager/regex/). For template fields, use the triple brace `{{{ }}}` notation to avoid Handlebars escaping any special characters. + +!!! tip + Look at our [Regex Manager Presets](https://docs.renovatebot.com/presets-regexManagers/), they may have what you need. + ### matchStrings `matchStrings` should each be a valid regular expression, optionally with named capture groups. From 8b06cdc2cb38811e80280062552b85007ef65e95 Mon Sep 17 00:00:00 2001 From: HonkingGoose <34918129+HonkingGoose@users.noreply.github.com> Date: Mon, 8 May 2023 12:22:32 +0200 Subject: [PATCH 26/57] chore(regex-managers): improve `helmChartYamlAppVersions` description (#22024) --- lib/config/presets/internal/regex-managers.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/config/presets/internal/regex-managers.ts b/lib/config/presets/internal/regex-managers.ts index afaf9f19156832..d3021f96ee7649 100644 --- a/lib/config/presets/internal/regex-managers.ts +++ b/lib/config/presets/internal/regex-managers.ts @@ -27,7 +27,7 @@ export const presets: Record = { ], }, helmChartYamlAppVersions: { - description: 'Update `appVersion` value in Helm chart Chart.yaml.', + description: 'Update `appVersion` value in Helm chart `Chart.yaml`.', regexManagers: [ { datasourceTemplate: 'docker', From 723a9a26dad7463943ec8dea2c1c97a5b0c3f4c9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 8 May 2023 18:36:46 +0000 Subject: [PATCH 27/57] chore(deps): update linters to v5.59.2 (#22033) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 4 +-- yarn.lock | 88 ++++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 70 insertions(+), 22 deletions(-) diff --git a/package.json b/package.json index 59258853236b25..7d334b0c41d5d3 100644 --- a/package.json +++ b/package.json @@ -288,8 +288,8 @@ "@types/url-join": "4.0.1", "@types/validate-npm-package-name": "4.0.0", "@types/xmldoc": "1.1.6", - "@typescript-eslint/eslint-plugin": "5.59.1", - "@typescript-eslint/parser": "5.59.1", + "@typescript-eslint/eslint-plugin": "5.59.2", + "@typescript-eslint/parser": "5.59.2", "aws-sdk-client-mock": "2.1.1", "callsite": "1.0.0", "common-tags": "1.8.2", diff --git a/yarn.lock b/yarn.lock index 61b4822cc0ca8d..d7421110880beb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3192,15 +3192,15 @@ dependencies: "@types/node" "*" -"@typescript-eslint/eslint-plugin@5.59.1": - version "5.59.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.1.tgz#9b09ee1541bff1d2cebdcb87e7ce4a4003acde08" - integrity sha512-AVi0uazY5quFB9hlp2Xv+ogpfpk77xzsgsIEWyVS7uK/c7MZ5tw7ZPbapa0SbfkqE0fsAMkz5UwtgMLVk2BQAg== +"@typescript-eslint/eslint-plugin@5.59.2": + version "5.59.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.2.tgz#684a2ce7182f3b4dac342eef7caa1c2bae476abd" + integrity sha512-yVrXupeHjRxLDcPKL10sGQ/QlVrA8J5IYOEWVqk0lJaSZP7X5DfnP7Ns3cc74/blmbipQ1htFNVGsHX6wsYm0A== dependencies: "@eslint-community/regexpp" "^4.4.0" - "@typescript-eslint/scope-manager" "5.59.1" - "@typescript-eslint/type-utils" "5.59.1" - "@typescript-eslint/utils" "5.59.1" + "@typescript-eslint/scope-manager" "5.59.2" + "@typescript-eslint/type-utils" "5.59.2" + "@typescript-eslint/utils" "5.59.2" debug "^4.3.4" grapheme-splitter "^1.0.4" ignore "^5.2.0" @@ -3215,14 +3215,14 @@ dependencies: "@typescript-eslint/utils" "5.59.1" -"@typescript-eslint/parser@5.59.1": - version "5.59.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.59.1.tgz#73c2c12127c5c1182d2e5b71a8fa2a85d215cbb4" - integrity sha512-nzjFAN8WEu6yPRDizIFyzAfgK7nybPodMNFGNH0M9tei2gYnYszRDqVA0xlnRjkl7Hkx2vYrEdb6fP2a21cG1g== +"@typescript-eslint/parser@5.59.2": + version "5.59.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.59.2.tgz#c2c443247901d95865b9f77332d9eee7c55655e8" + integrity sha512-uq0sKyw6ao1iFOZZGk9F8Nro/8+gfB5ezl1cA06SrqbgJAt0SRoFhb9pXaHvkrxUpZaoLxt8KlovHNk8Gp6/HQ== dependencies: - "@typescript-eslint/scope-manager" "5.59.1" - "@typescript-eslint/types" "5.59.1" - "@typescript-eslint/typescript-estree" "5.59.1" + "@typescript-eslint/scope-manager" "5.59.2" + "@typescript-eslint/types" "5.59.2" + "@typescript-eslint/typescript-estree" "5.59.2" debug "^4.3.4" "@typescript-eslint/scope-manager@5.59.1": @@ -3233,13 +3233,21 @@ "@typescript-eslint/types" "5.59.1" "@typescript-eslint/visitor-keys" "5.59.1" -"@typescript-eslint/type-utils@5.59.1": - version "5.59.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.59.1.tgz#63981d61684fd24eda2f9f08c0a47ecb000a2111" - integrity sha512-ZMWQ+Oh82jWqWzvM3xU+9y5U7MEMVv6GLioM3R5NJk6uvP47kZ7YvlgSHJ7ERD6bOY7Q4uxWm25c76HKEwIjZw== +"@typescript-eslint/scope-manager@5.59.2": + version "5.59.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.59.2.tgz#f699fe936ee4e2c996d14f0fdd3a7da5ba7b9a4c" + integrity sha512-dB1v7ROySwQWKqQ8rEWcdbTsFjh2G0vn8KUyvTXdPoyzSL6lLGkiXEV5CvpJsEe9xIdKV+8Zqb7wif2issoOFA== dependencies: - "@typescript-eslint/typescript-estree" "5.59.1" - "@typescript-eslint/utils" "5.59.1" + "@typescript-eslint/types" "5.59.2" + "@typescript-eslint/visitor-keys" "5.59.2" + +"@typescript-eslint/type-utils@5.59.2": + version "5.59.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.59.2.tgz#0729c237503604cd9a7084b5af04c496c9a4cdcf" + integrity sha512-b1LS2phBOsEy/T381bxkkywfQXkV1dWda/z0PhnIy3bC5+rQWQDS7fk9CSpcXBccPY27Z6vBEuaPBCKCgYezyQ== + dependencies: + "@typescript-eslint/typescript-estree" "5.59.2" + "@typescript-eslint/utils" "5.59.2" debug "^4.3.4" tsutils "^3.21.0" @@ -3248,6 +3256,11 @@ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.59.1.tgz#03f3fedd1c044cb336ebc34cc7855f121991f41d" integrity sha512-dg0ICB+RZwHlysIy/Dh1SP+gnXNzwd/KS0JprD3Lmgmdq+dJAJnUPe1gNG34p0U19HvRlGX733d/KqscrGC1Pg== +"@typescript-eslint/types@5.59.2": + version "5.59.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.59.2.tgz#b511d2b9847fe277c5cb002a2318bd329ef4f655" + integrity sha512-LbJ/HqoVs2XTGq5shkiKaNTuVv5tTejdHgfdjqRUGdYhjW1crm/M7og2jhVskMt8/4wS3T1+PfFvL1K3wqYj4w== + "@typescript-eslint/typescript-estree@5.59.1": version "5.59.1" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.1.tgz#4aa546d27fd0d477c618f0ca00b483f0ec84c43c" @@ -3261,6 +3274,19 @@ semver "^7.3.7" tsutils "^3.21.0" +"@typescript-eslint/typescript-estree@5.59.2": + version "5.59.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.2.tgz#6e2fabd3ba01db5d69df44e0b654c0b051fe9936" + integrity sha512-+j4SmbwVmZsQ9jEyBMgpuBD0rKwi9RxRpjX71Brr73RsYnEr3Lt5QZ624Bxphp8HUkSKfqGnPJp1kA5nl0Sh7Q== + dependencies: + "@typescript-eslint/types" "5.59.2" + "@typescript-eslint/visitor-keys" "5.59.2" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + semver "^7.3.7" + tsutils "^3.21.0" + "@typescript-eslint/utils@5.59.1", "@typescript-eslint/utils@^5.10.0": version "5.59.1" resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.59.1.tgz#d89fc758ad23d2157cfae53f0b429bdf15db9473" @@ -3275,6 +3301,20 @@ eslint-scope "^5.1.1" semver "^7.3.7" +"@typescript-eslint/utils@5.59.2": + version "5.59.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.59.2.tgz#0c45178124d10cc986115885688db6abc37939f4" + integrity sha512-kSuF6/77TZzyGPhGO4uVp+f0SBoYxCDf+lW3GKhtKru/L8k/Hd7NFQxyWUeY7Z/KGB2C6Fe3yf2vVi4V9TsCSQ== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@types/json-schema" "^7.0.9" + "@types/semver" "^7.3.12" + "@typescript-eslint/scope-manager" "5.59.2" + "@typescript-eslint/types" "5.59.2" + "@typescript-eslint/typescript-estree" "5.59.2" + eslint-scope "^5.1.1" + semver "^7.3.7" + "@typescript-eslint/visitor-keys@5.59.1": version "5.59.1" resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.1.tgz#0d96c36efb6560d7fb8eb85de10442c10d8f6058" @@ -3283,6 +3323,14 @@ "@typescript-eslint/types" "5.59.1" eslint-visitor-keys "^3.3.0" +"@typescript-eslint/visitor-keys@5.59.2": + version "5.59.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.2.tgz#37a419dc2723a3eacbf722512b86d6caf7d3b750" + integrity sha512-EEpsO8m3RASrKAHI9jpavNv9NlEUebV4qmF1OWxSTtKSFBpC1NCmWazDQHFivRf0O1DV11BA645yrLEVQ0/Lig== + dependencies: + "@typescript-eslint/types" "5.59.2" + eslint-visitor-keys "^3.3.0" + "@yarnpkg/core@3.4.0": version "3.4.0" resolved "https://registry.yarnpkg.com/@yarnpkg/core/-/core-3.4.0.tgz#1684dfcbd4e68ff28a11a25154d415f7de2c8224" From 5b0a0b8bcfb36d7330544d44e6d8dd5afcc0e1fc Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 8 May 2023 19:26:26 +0000 Subject: [PATCH 28/57] chore(deps): update linters (#22034) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 6 +-- yarn.lock | 147 ++++++++++++++++++++++++++------------------------- 2 files changed, 79 insertions(+), 74 deletions(-) diff --git a/package.json b/package.json index 7d334b0c41d5d3..ad9b28a9d2837d 100644 --- a/package.json +++ b/package.json @@ -288,8 +288,8 @@ "@types/url-join": "4.0.1", "@types/validate-npm-package-name": "4.0.0", "@types/xmldoc": "1.1.6", - "@typescript-eslint/eslint-plugin": "5.59.2", - "@typescript-eslint/parser": "5.59.2", + "@typescript-eslint/eslint-plugin": "5.59.5", + "@typescript-eslint/parser": "5.59.5", "aws-sdk-client-mock": "2.1.1", "callsite": "1.0.0", "common-tags": "1.8.2", @@ -297,7 +297,7 @@ "cross-env": "7.0.3", "diff": "5.1.0", "emojibase-data": "7.0.1", - "eslint": "8.39.0", + "eslint": "8.40.0", "eslint-config-prettier": "8.8.0", "eslint-formatter-gha": "1.4.2", "eslint-import-resolver-typescript": "3.5.5", diff --git a/yarn.lock b/yarn.lock index d7421110880beb..27352b9a381c46 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1571,14 +1571,14 @@ resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.5.1.tgz#cdd35dce4fa1a89a4fd42b1599eb35b3af408884" integrity sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ== -"@eslint/eslintrc@^2.0.2": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.0.2.tgz#01575e38707add677cf73ca1589abba8da899a02" - integrity sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ== +"@eslint/eslintrc@^2.0.3": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.0.3.tgz#4910db5505f4d503f27774bf356e3704818a0331" + integrity sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ== dependencies: ajv "^6.12.4" debug "^4.3.2" - espree "^9.5.1" + espree "^9.5.2" globals "^13.19.0" ignore "^5.2.0" import-fresh "^3.2.1" @@ -1586,10 +1586,10 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/js@8.39.0": - version "8.39.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.39.0.tgz#58b536bcc843f4cd1e02a7e6171da5c040f4d44b" - integrity sha512-kf9RB0Fg7NZfap83B3QOqOGg9QmD9yBudqQXzzOtn3i4y7ZUXe5ONeW34Gwi+TxhH4mvj72R1Zc300KUMa9Bng== +"@eslint/js@8.40.0": + version "8.40.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.40.0.tgz#3ba73359e11f5a7bd3e407f70b3528abfae69cec" + integrity sha512-ElyB54bJIhXQYVKjDSvCkPO1iU1tSAeVQJbllWJq1XQSmmA4dgFk8CbiBGpiOPxleE48vDogxCtmMYku4HSVLA== "@gar/promisify@^1.1.3": version "1.1.3" @@ -3192,15 +3192,15 @@ dependencies: "@types/node" "*" -"@typescript-eslint/eslint-plugin@5.59.2": - version "5.59.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.2.tgz#684a2ce7182f3b4dac342eef7caa1c2bae476abd" - integrity sha512-yVrXupeHjRxLDcPKL10sGQ/QlVrA8J5IYOEWVqk0lJaSZP7X5DfnP7Ns3cc74/blmbipQ1htFNVGsHX6wsYm0A== +"@typescript-eslint/eslint-plugin@5.59.5": + version "5.59.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.5.tgz#f156827610a3f8cefc56baeaa93cd4a5f32966b4" + integrity sha512-feA9xbVRWJZor+AnLNAr7A8JRWeZqHUf4T9tlP+TN04b05pFVhO5eN7/O93Y/1OUlLMHKbnJisgDURs/qvtqdg== dependencies: "@eslint-community/regexpp" "^4.4.0" - "@typescript-eslint/scope-manager" "5.59.2" - "@typescript-eslint/type-utils" "5.59.2" - "@typescript-eslint/utils" "5.59.2" + "@typescript-eslint/scope-manager" "5.59.5" + "@typescript-eslint/type-utils" "5.59.5" + "@typescript-eslint/utils" "5.59.5" debug "^4.3.4" grapheme-splitter "^1.0.4" ignore "^5.2.0" @@ -3215,14 +3215,14 @@ dependencies: "@typescript-eslint/utils" "5.59.1" -"@typescript-eslint/parser@5.59.2": - version "5.59.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.59.2.tgz#c2c443247901d95865b9f77332d9eee7c55655e8" - integrity sha512-uq0sKyw6ao1iFOZZGk9F8Nro/8+gfB5ezl1cA06SrqbgJAt0SRoFhb9pXaHvkrxUpZaoLxt8KlovHNk8Gp6/HQ== +"@typescript-eslint/parser@5.59.5": + version "5.59.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.59.5.tgz#63064f5eafbdbfb5f9dfbf5c4503cdf949852981" + integrity sha512-NJXQC4MRnF9N9yWqQE2/KLRSOLvrrlZb48NGVfBa+RuPMN6B7ZcK5jZOvhuygv4D64fRKnZI4L4p8+M+rfeQuw== dependencies: - "@typescript-eslint/scope-manager" "5.59.2" - "@typescript-eslint/types" "5.59.2" - "@typescript-eslint/typescript-estree" "5.59.2" + "@typescript-eslint/scope-manager" "5.59.5" + "@typescript-eslint/types" "5.59.5" + "@typescript-eslint/typescript-estree" "5.59.5" debug "^4.3.4" "@typescript-eslint/scope-manager@5.59.1": @@ -3233,21 +3233,21 @@ "@typescript-eslint/types" "5.59.1" "@typescript-eslint/visitor-keys" "5.59.1" -"@typescript-eslint/scope-manager@5.59.2": - version "5.59.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.59.2.tgz#f699fe936ee4e2c996d14f0fdd3a7da5ba7b9a4c" - integrity sha512-dB1v7ROySwQWKqQ8rEWcdbTsFjh2G0vn8KUyvTXdPoyzSL6lLGkiXEV5CvpJsEe9xIdKV+8Zqb7wif2issoOFA== +"@typescript-eslint/scope-manager@5.59.5": + version "5.59.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.59.5.tgz#33ffc7e8663f42cfaac873de65ebf65d2bce674d" + integrity sha512-jVecWwnkX6ZgutF+DovbBJirZcAxgxC0EOHYt/niMROf8p4PwxxG32Qdhj/iIQQIuOflLjNkxoXyArkcIP7C3A== dependencies: - "@typescript-eslint/types" "5.59.2" - "@typescript-eslint/visitor-keys" "5.59.2" + "@typescript-eslint/types" "5.59.5" + "@typescript-eslint/visitor-keys" "5.59.5" -"@typescript-eslint/type-utils@5.59.2": - version "5.59.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.59.2.tgz#0729c237503604cd9a7084b5af04c496c9a4cdcf" - integrity sha512-b1LS2phBOsEy/T381bxkkywfQXkV1dWda/z0PhnIy3bC5+rQWQDS7fk9CSpcXBccPY27Z6vBEuaPBCKCgYezyQ== +"@typescript-eslint/type-utils@5.59.5": + version "5.59.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.59.5.tgz#485b0e2c5b923460bc2ea6b338c595343f06fc9b" + integrity sha512-4eyhS7oGym67/pSxA2mmNq7X164oqDYNnZCUayBwJZIRVvKpBCMBzFnFxjeoDeShjtO6RQBHBuwybuX3POnDqg== dependencies: - "@typescript-eslint/typescript-estree" "5.59.2" - "@typescript-eslint/utils" "5.59.2" + "@typescript-eslint/typescript-estree" "5.59.5" + "@typescript-eslint/utils" "5.59.5" debug "^4.3.4" tsutils "^3.21.0" @@ -3256,10 +3256,10 @@ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.59.1.tgz#03f3fedd1c044cb336ebc34cc7855f121991f41d" integrity sha512-dg0ICB+RZwHlysIy/Dh1SP+gnXNzwd/KS0JprD3Lmgmdq+dJAJnUPe1gNG34p0U19HvRlGX733d/KqscrGC1Pg== -"@typescript-eslint/types@5.59.2": - version "5.59.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.59.2.tgz#b511d2b9847fe277c5cb002a2318bd329ef4f655" - integrity sha512-LbJ/HqoVs2XTGq5shkiKaNTuVv5tTejdHgfdjqRUGdYhjW1crm/M7og2jhVskMt8/4wS3T1+PfFvL1K3wqYj4w== +"@typescript-eslint/types@5.59.5": + version "5.59.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.59.5.tgz#e63c5952532306d97c6ea432cee0981f6d2258c7" + integrity sha512-xkfRPHbqSH4Ggx4eHRIO/eGL8XL4Ysb4woL8c87YuAo8Md7AUjyWKa9YMwTL519SyDPrfEgKdewjkxNCVeJW7w== "@typescript-eslint/typescript-estree@5.59.1": version "5.59.1" @@ -3274,13 +3274,13 @@ semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/typescript-estree@5.59.2": - version "5.59.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.2.tgz#6e2fabd3ba01db5d69df44e0b654c0b051fe9936" - integrity sha512-+j4SmbwVmZsQ9jEyBMgpuBD0rKwi9RxRpjX71Brr73RsYnEr3Lt5QZ624Bxphp8HUkSKfqGnPJp1kA5nl0Sh7Q== +"@typescript-eslint/typescript-estree@5.59.5": + version "5.59.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.5.tgz#9b252ce55dd765e972a7a2f99233c439c5101e42" + integrity sha512-+XXdLN2CZLZcD/mO7mQtJMvCkzRfmODbeSKuMY/yXbGkzvA9rJyDY5qDYNoiz2kP/dmyAxXquL2BvLQLJFPQIg== dependencies: - "@typescript-eslint/types" "5.59.2" - "@typescript-eslint/visitor-keys" "5.59.2" + "@typescript-eslint/types" "5.59.5" + "@typescript-eslint/visitor-keys" "5.59.5" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" @@ -3301,17 +3301,17 @@ eslint-scope "^5.1.1" semver "^7.3.7" -"@typescript-eslint/utils@5.59.2": - version "5.59.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.59.2.tgz#0c45178124d10cc986115885688db6abc37939f4" - integrity sha512-kSuF6/77TZzyGPhGO4uVp+f0SBoYxCDf+lW3GKhtKru/L8k/Hd7NFQxyWUeY7Z/KGB2C6Fe3yf2vVi4V9TsCSQ== +"@typescript-eslint/utils@5.59.5": + version "5.59.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.59.5.tgz#15b3eb619bb223302e60413adb0accd29c32bcae" + integrity sha512-sCEHOiw+RbyTii9c3/qN74hYDPNORb8yWCoPLmB7BIflhplJ65u2PBpdRla12e3SSTJ2erRkPjz7ngLHhUegxA== dependencies: "@eslint-community/eslint-utils" "^4.2.0" "@types/json-schema" "^7.0.9" "@types/semver" "^7.3.12" - "@typescript-eslint/scope-manager" "5.59.2" - "@typescript-eslint/types" "5.59.2" - "@typescript-eslint/typescript-estree" "5.59.2" + "@typescript-eslint/scope-manager" "5.59.5" + "@typescript-eslint/types" "5.59.5" + "@typescript-eslint/typescript-estree" "5.59.5" eslint-scope "^5.1.1" semver "^7.3.7" @@ -3323,12 +3323,12 @@ "@typescript-eslint/types" "5.59.1" eslint-visitor-keys "^3.3.0" -"@typescript-eslint/visitor-keys@5.59.2": - version "5.59.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.2.tgz#37a419dc2723a3eacbf722512b86d6caf7d3b750" - integrity sha512-EEpsO8m3RASrKAHI9jpavNv9NlEUebV4qmF1OWxSTtKSFBpC1NCmWazDQHFivRf0O1DV11BA645yrLEVQ0/Lig== +"@typescript-eslint/visitor-keys@5.59.5": + version "5.59.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.5.tgz#ba5b8d6791a13cf9fea6716af1e7626434b29b9b" + integrity sha512-qL+Oz+dbeBRTeyJTIy0eniD3uvqU7x+y1QceBismZ41hd4aBSRh8UAw4pZP0+XzLuPZmx4raNMq/I+59W2lXKA== dependencies: - "@typescript-eslint/types" "5.59.2" + "@typescript-eslint/types" "5.59.5" eslint-visitor-keys "^3.3.0" "@yarnpkg/core@3.4.0": @@ -5053,20 +5053,25 @@ eslint-scope@^7.2.0: esrecurse "^4.3.0" estraverse "^5.2.0" -eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.0: +eslint-visitor-keys@^3.3.0: version "3.4.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz#c7f0f956124ce677047ddbc192a68f999454dedc" integrity sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ== -eslint@8.39.0: - version "8.39.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.39.0.tgz#7fd20a295ef92d43809e914b70c39fd5a23cf3f1" - integrity sha512-mwiok6cy7KTW7rBpo05k6+p4YVZByLNjAZ/ACB9DRCu4YDRwjXI01tWHp6KAUWelsBetTxKK/2sHB0vdS8Z2Og== +eslint-visitor-keys@^3.4.1: + version "3.4.1" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz#c22c48f48942d08ca824cc526211ae400478a994" + integrity sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA== + +eslint@8.40.0: + version "8.40.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.40.0.tgz#a564cd0099f38542c4e9a2f630fa45bf33bc42a4" + integrity sha512-bvR+TsP9EHL3TqNtj9sCNJVAFK3fBN8Q7g5waghxyRsPLIMwL73XSKnZFK0hk/O2ANC+iAoq6PWMQ+IfBAJIiQ== dependencies: "@eslint-community/eslint-utils" "^4.2.0" "@eslint-community/regexpp" "^4.4.0" - "@eslint/eslintrc" "^2.0.2" - "@eslint/js" "8.39.0" + "@eslint/eslintrc" "^2.0.3" + "@eslint/js" "8.40.0" "@humanwhocodes/config-array" "^0.11.8" "@humanwhocodes/module-importer" "^1.0.1" "@nodelib/fs.walk" "^1.2.8" @@ -5077,8 +5082,8 @@ eslint@8.39.0: doctrine "^3.0.0" escape-string-regexp "^4.0.0" eslint-scope "^7.2.0" - eslint-visitor-keys "^3.4.0" - espree "^9.5.1" + eslint-visitor-keys "^3.4.1" + espree "^9.5.2" esquery "^1.4.2" esutils "^2.0.2" fast-deep-equal "^3.1.3" @@ -5104,14 +5109,14 @@ eslint@8.39.0: strip-json-comments "^3.1.0" text-table "^0.2.0" -espree@^9.5.1: - version "9.5.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-9.5.1.tgz#4f26a4d5f18905bf4f2e0bd99002aab807e96dd4" - integrity sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg== +espree@^9.5.2: + version "9.5.2" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.5.2.tgz#e994e7dc33a082a7a82dceaf12883a829353215b" + integrity sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw== dependencies: acorn "^8.8.0" acorn-jsx "^5.3.2" - eslint-visitor-keys "^3.4.0" + eslint-visitor-keys "^3.4.1" esprima@^4.0.0, esprima@~4.0.0: version "4.0.1" From 85631e8b45cf9edb6c166335c3f51d3429b8572d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 8 May 2023 20:21:12 +0000 Subject: [PATCH 29/57] build(deps): update dependency @yarnpkg/core to v3.5.1 (#22035) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 36 ++++++++++++++++++++++-------------- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/package.json b/package.json index ad9b28a9d2837d..3a6de6cd1a198e 100644 --- a/package.json +++ b/package.json @@ -162,7 +162,7 @@ "@sindresorhus/is": "4.6.0", "@types/ms": "0.7.31", "@types/tmp": "0.2.3", - "@yarnpkg/core": "3.4.0", + "@yarnpkg/core": "3.5.1", "@yarnpkg/parsers": "2.5.1", "agentkeepalive": "4.3.0", "aggregate-error": "3.1.0", diff --git a/yarn.lock b/yarn.lock index 27352b9a381c46..3320dcf3262f78 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3331,19 +3331,19 @@ "@typescript-eslint/types" "5.59.5" eslint-visitor-keys "^3.3.0" -"@yarnpkg/core@3.4.0": - version "3.4.0" - resolved "https://registry.yarnpkg.com/@yarnpkg/core/-/core-3.4.0.tgz#1684dfcbd4e68ff28a11a25154d415f7de2c8224" - integrity sha512-EwkRU7TjZrpAPA2cqVBtMD95unti9uSXefGJbhCVANOfuY6tjBoqSt8uSf6BSXUUoJkxBWwewjTn0v0tgoLBkQ== +"@yarnpkg/core@3.5.1": + version "3.5.1" + resolved "https://registry.yarnpkg.com/@yarnpkg/core/-/core-3.5.1.tgz#bb1f13ffed9828a8b4d22980615bb7f1569daefe" + integrity sha512-BkbqhE7Ti/Kk2zl0MF2TPosUSh7yS9iaZWnmcXfzKPcPatY0NTg1wX+OuW/eXMFAHudXXmMMte9Ve2f6Kj7itQ== dependencies: "@arcanis/slice-ansi" "^1.1.1" "@types/semver" "^7.1.0" "@types/treeify" "^1.0.0" - "@yarnpkg/fslib" "^2.10.1" + "@yarnpkg/fslib" "^2.10.3" "@yarnpkg/json-proxy" "^2.1.1" - "@yarnpkg/libzip" "^2.2.4" + "@yarnpkg/libzip" "^2.3.0" "@yarnpkg/parsers" "^2.5.1" - "@yarnpkg/pnp" "^3.3.0" + "@yarnpkg/pnp" "^3.3.2" "@yarnpkg/shell" "^3.2.5" camelcase "^5.3.1" chalk "^3.0.0" @@ -3369,7 +3369,15 @@ tslib "^1.13.0" tunnel "^0.0.6" -"@yarnpkg/fslib@^2.10.1", "@yarnpkg/fslib@^2.10.2", "@yarnpkg/fslib@^2.5.0", "@yarnpkg/fslib@^2.9.0": +"@yarnpkg/fslib@^2.10.3": + version "2.10.3" + resolved "https://registry.yarnpkg.com/@yarnpkg/fslib/-/fslib-2.10.3.tgz#a8c9893df5d183cf6362680b9f1c6d7504dd5717" + integrity sha512-41H+Ga78xT9sHvWLlFOZLIhtU6mTGZ20pZ29EiZa97vnxdohJD2AF42rCoAoWfqUz486xY6fhjMH+DYEM9r14A== + dependencies: + "@yarnpkg/libzip" "^2.3.0" + tslib "^1.13.0" + +"@yarnpkg/fslib@^2.5.0", "@yarnpkg/fslib@^2.9.0": version "2.10.2" resolved "https://registry.yarnpkg.com/@yarnpkg/fslib/-/fslib-2.10.2.tgz#16e419a1412084f152e8eec16183a7f80bc73684" integrity sha512-6WfQrPEV8QVpDPw5kd5s5jsb3QLqwVFSGZy3rEjl3p2FZ3OtIfYcLbFirOxXj2jXiKQDe7XbYsw1WjSf8K94gw== @@ -3385,7 +3393,7 @@ "@yarnpkg/fslib" "^2.5.0" tslib "^1.13.0" -"@yarnpkg/libzip@^2.2.4", "@yarnpkg/libzip@^2.3.0": +"@yarnpkg/libzip@^2.3.0": version "2.3.0" resolved "https://registry.yarnpkg.com/@yarnpkg/libzip/-/libzip-2.3.0.tgz#fe1e762e47669f6e2c960fc118436608d834e3be" integrity sha512-6xm38yGVIa6mKm/DUCF2zFFJhERh/QWp1ufm4cNUvxsONBmfPg8uZ9pZBdOmF6qFGr/HlT6ABBkCSx/dlEtvWg== @@ -3401,13 +3409,13 @@ js-yaml "^3.10.0" tslib "^1.13.0" -"@yarnpkg/pnp@^3.3.0": - version "3.3.1" - resolved "https://registry.yarnpkg.com/@yarnpkg/pnp/-/pnp-3.3.1.tgz#8ce0777f2950cbadc9978ba3bd3407b4b9c2a640" - integrity sha512-iA2IKk2hOQqEBBHBZ3j004mCfzsPGx5PNjgGn8kb6/VMXokX4mhZzPNI/q7ipI0+UaIMeDXvIzwdGL2GSmgsTA== +"@yarnpkg/pnp@^3.3.2": + version "3.3.2" + resolved "https://registry.yarnpkg.com/@yarnpkg/pnp/-/pnp-3.3.2.tgz#348e1c4ac3ad4ff60a2ba5f274ec7d6f97fe2727" + integrity sha512-3rJbY9/wB7fLrjZtgcYyqtWHK3ihmCbFFqnjghH3MnBYABeh5IgB83BjSfbIT5s/BtVIg583yBHok02OO4ighg== dependencies: "@types/node" "^13.7.0" - "@yarnpkg/fslib" "^2.10.2" + "@yarnpkg/fslib" "^2.10.3" "@yarnpkg/shell@^3.2.5": version "3.2.5" From ad78e851aae85d6c2ed9f874842f3c56ed10bf02 Mon Sep 17 00:00:00 2001 From: Florian Greinacher Date: Tue, 9 May 2023 05:38:37 +0200 Subject: [PATCH 30/57] docs: add config-validation chapter (#21969) Co-authored-by: HonkingGoose <34918129+HonkingGoose@users.noreply.github.com> --- docs/usage/.pages | 1 + docs/usage/config-validation.md | 22 +++++++++++++++++++ .../getting-started/installing-onboarding.md | 8 +------ docs/usage/troubleshooting.md | 5 +++++ 4 files changed, 29 insertions(+), 7 deletions(-) create mode 100644 docs/usage/config-validation.md diff --git a/docs/usage/.pages b/docs/usage/.pages index e6e2117b871bdd..f5d466abd10b82 100644 --- a/docs/usage/.pages +++ b/docs/usage/.pages @@ -6,6 +6,7 @@ nav: - 'Self-hosted': 'self-hosted-configuration.md' - 'Repository': 'configuration-options.md' - 'Presets': 'config-presets.md' + - 'Validation': 'config-validation.md' - ... | key-concepts - ... | modules - Language Support: diff --git a/docs/usage/config-validation.md b/docs/usage/config-validation.md new file mode 100644 index 00000000000000..7871cc5367d072 --- /dev/null +++ b/docs/usage/config-validation.md @@ -0,0 +1,22 @@ +--- +title: Config Validation +description: How to validate Renovate's configuration. +--- + +# Config Validation + +All [`renovate` distributions](getting-started/running.md#available-distributions) contain a standalone validator program (`renovate-config-validator`) that can be used to validate Renovate's configuration. + +The validator program checks files passed as CLI arguments. +If no argument is given, all [default locations](configuration-options.md) (if files exist) and the `RENOVATE_CONFIG_FILE` environment variable are checked. + +```console +$ npm install --global renovate +added 750 packages, and audited 751 packages in 51s +$ renovate-config-validator +INFO: Validating renovate.json +INFO: Config validated successfully +``` + +You can configure a [pre-commit](https://pre-commit.com) hook to validate your configuration automatically. +Please check out the [`renovatebot/pre-commit-hooks` repository](https://github.com/renovatebot/pre-commit-hooks) for more information. diff --git a/docs/usage/getting-started/installing-onboarding.md b/docs/usage/getting-started/installing-onboarding.md index f681575fcedea2..7b3275c2adde70 100644 --- a/docs/usage/getting-started/installing-onboarding.md +++ b/docs/usage/getting-started/installing-onboarding.md @@ -133,15 +133,9 @@ If you want to make config edits directly, follow these steps: 1. Create a new Git branch to work on 1. Install or update the `renovate` package globally (`npm i -g renovate` or `yarn global add renovate`) to get the `renovate-config-validator` program 1. Edit your Renovate configuration file -1. Validate your config by running `renovate-config-validator` +1. [Validate your config](../config-validation.md) 1. If the improved config passes the validation, merge the branch into your mainline branch -The validator program checks files passed as CLI arguments. -If no argument is given, all [default locations](../configuration-options.md) (if files exist) and the `RENOVATE_CONFIG_FILE` environment variable are checked. - -You can configure a [pre-commit](https://pre-commit.com) hook to validate your configuration automatically. -Please check out the [`renovatebot/pre-commit-hooks` repository](https://github.com/renovatebot/pre-commit-hooks) for more information. - ### Nuke config and re-onboard Perhaps you really liked the interactive onboarding PR and want to use it again. diff --git a/docs/usage/troubleshooting.md b/docs/usage/troubleshooting.md index 3ad9a414486f11..75d1ee1bb00777 100644 --- a/docs/usage/troubleshooting.md +++ b/docs/usage/troubleshooting.md @@ -64,3 +64,8 @@ If none of these steps have helped you, then create a new discussion post to get Please locate the relevant parts of the logs as described earlier before asking for help or posting a bug report. Do not expect the Renovate maintainers to read through the full logs when trying to help you, as that takes a lot of time on our part. If later it turns out that the full logs are necessary, you will be asked for them then. + +## Validating configuration changes + +Sometimes you will have to change your Renovate configuration to solve a problem. +The [`renovate-config-validator` program](config-validation.md) helps validate such configuration changes without commiting them to your repository. From 347c2d02d73d4e7d1e02310af39e9769e4715450 Mon Sep 17 00:00:00 2001 From: Malte Hviid-Magnussen Date: Tue, 9 May 2023 11:47:31 +0200 Subject: [PATCH 31/57] docs(gitlab): add hostType to registry hostRules guide (#22055) --- lib/modules/platform/gitlab/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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. From f63f3647ec03e004179e3a8847b65b68ac1c1090 Mon Sep 17 00:00:00 2001 From: Michael Kriese Date: Tue, 9 May 2023 11:50:37 +0200 Subject: [PATCH 32/57] test(manager/terraform): refactor some tests (#22039) --- lib/modules/manager/terraform/extract.spec.ts | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/lib/modules/manager/terraform/extract.spec.ts b/lib/modules/manager/terraform/extract.spec.ts index cbdea0323c7c01..62d7b53f00a3dd 100644 --- a/lib/modules/manager/terraform/extract.spec.ts +++ b/lib/modules/manager/terraform/extract.spec.ts @@ -404,15 +404,14 @@ describe('modules/manager/terraform/extract', () => { const res = await extractPackageFile(docker, 'docker.tf', {}); expect(res?.deps).toHaveLength(6); 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 +420,11 @@ 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: @@ -577,26 +577,7 @@ describe('modules/manager/terraform/extract', () => { const res = await extractPackageFile(helm, 'helm.tf', {}); expect(res?.deps).toHaveLength(8); 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 +611,25 @@ 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: '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'], + }, ]); }); From 004b383bd061df48521b1028d845841d3a757e6e Mon Sep 17 00:00:00 2001 From: HonkingGoose <34918129+HonkingGoose@users.noreply.github.com> Date: Tue, 9 May 2023 12:50:25 +0200 Subject: [PATCH 33/57] chore: add GitHub Actions VS Code extension (#21350) Co-authored-by: Sebastian Poxhofer --- .devcontainer/devcontainer.json | 3 ++- .vscode/extensions.json | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) 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/.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" ] } From 3f33995ab92ff0cf188ea407e7cef3b58fea869c Mon Sep 17 00:00:00 2001 From: Michael Kriese Date: Tue, 9 May 2023 17:26:00 +0200 Subject: [PATCH 34/57] feat(manager/terraform): support registry aliases for docker images and oci helm charts (#22022) Co-authored-by: Sebastian Poxhofer --- docs/usage/configuration-options.md | 1 + lib/modules/manager/dockerfile/extract.ts | 2 +- .../manager/terraform/__fixtures__/docker.tf | 4 ++ .../manager/terraform/__fixtures__/helm.tf | 8 ++++ lib/modules/manager/terraform/base.ts | 5 ++- lib/modules/manager/terraform/extract.spec.ts | 28 +++++++++++-- lib/modules/manager/terraform/extract.ts | 2 +- .../generic-docker-image-ref.spec.ts | 2 +- .../resources/generic-docker-image-ref.ts | 22 ++++++---- .../extractors/resources/helm-release.spec.ts | 2 +- .../extractors/resources/helm-release.ts | 40 ++++++++++++++----- 11 files changed, 89 insertions(+), 27 deletions(-) diff --git a/docs/usage/configuration-options.md b/docs/usage/configuration-options.md index 6b01f12bebe36b..d18d6dd44335e8 100644 --- a/docs/usage/configuration-options.md +++ b/docs/usage/configuration-options.md @@ -3140,6 +3140,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/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/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 62d7b53f00a3dd..c4e8246a9adc16 100644 --- a/lib/modules/manager/terraform/extract.spec.ts +++ b/lib/modules/manager/terraform/extract.spec.ts @@ -401,8 +401,10 @@ 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).toMatchObject([ { @@ -426,6 +428,15 @@ describe('modules/manager/terraform/extract', () => { depType: 'docker_image', 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: '{{depName}}{{#if newValue}}:{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}', @@ -574,8 +585,10 @@ 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).toMatchObject([ { @@ -617,6 +630,13 @@ describe('modules/manager/terraform/extract', () => { 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', 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; + } } From 77bd389582cbd725720721c847cb4aa451febc50 Mon Sep 17 00:00:00 2001 From: Rhys Arkins Date: Tue, 9 May 2023 17:50:22 +0200 Subject: [PATCH 35/57] fix: RENOVATE_X_CLEAR_HOOKS --- lib/util/git/index.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/util/git/index.ts b/lib/util/git/index.ts index 806bda394b9889..1ab24e34acf71f 100644 --- a/lib/util/git/index.ts +++ b/lib/util/git/index.ts @@ -377,6 +377,10 @@ 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; } gitInitialized = true; From 0755daa4818ed05e151afe8d35b3c43bd22529ca Mon Sep 17 00:00:00 2001 From: Rhys Arkins Date: Tue, 9 May 2023 19:34:40 +0200 Subject: [PATCH 36/57] chore: add pr:discussion-first and needs-details label actions (#22060) --- .github/label-actions.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/.github/label-actions.yml b/.github/label-actions.yml index e0f3205b11fd67..fc769f744e506f 100644 --- a/.github/label-actions.yml +++ b/.github/label-actions.yml @@ -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' From decd35eaac04f81e90ee9cf6eadeddeca56bccd4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 10 May 2023 01:57:39 +0000 Subject: [PATCH 37/57] chore(deps): update dependency tar to v6.1.14 (#22064) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 14 +++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 3a6de6cd1a198e..ac4d8d9b3429aa 100644 --- a/package.json +++ b/package.json @@ -324,7 +324,7 @@ "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", diff --git a/yarn.lock b/yarn.lock index 3320dcf3262f78..bfcda089a3488a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9867,7 +9867,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== From 198b2fdf2b7d5618e493bb9d13854d0a3b793586 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 10 May 2023 02:55:09 +0000 Subject: [PATCH 38/57] chore(deps): update dependency @types/tar to v6.1.5 (#22066) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index ac4d8d9b3429aa..0fe3870314db92 100644 --- a/package.json +++ b/package.json @@ -283,7 +283,7 @@ "@types/semver": "7.3.13", "@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", diff --git a/yarn.lock b/yarn.lock index bfcda089a3488a..703a47d702b927 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3130,10 +3130,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" From 93052ec9178a3ae57912703cdae2e9f959f36431 Mon Sep 17 00:00:00 2001 From: Rhys Arkins Date: Wed, 10 May 2023 06:30:12 +0200 Subject: [PATCH 39/57] feat: platform=local (#22010) Co-authored-by: Jamie Magee --- lib/config/presets/local/index.ts | 1 + lib/constants/platforms.ts | 3 +- lib/modules/platform/api.ts | 2 + lib/modules/platform/local/index.spec.ts | 128 +++++++++++++++++++++++ lib/modules/platform/local/index.ts | 123 ++++++++++++++++++++++ lib/modules/platform/local/scm.spec.ts | 68 ++++++++++++ lib/modules/platform/local/scm.ts | 51 +++++++++ lib/modules/platform/scm.ts | 2 + lib/util/fs/index.spec.ts | 5 + lib/util/fs/index.ts | 4 + lib/util/git/index.ts | 4 + lib/workers/global/autodiscover.spec.ts | 13 +++ lib/workers/global/autodiscover.ts | 13 +++ lib/workers/global/index.spec.ts | 9 ++ lib/workers/global/index.ts | 11 +- lib/workers/repository/process/index.ts | 2 +- package.json | 2 +- 17 files changed, 434 insertions(+), 7 deletions(-) create mode 100644 lib/modules/platform/local/index.spec.ts create mode 100644 lib/modules/platform/local/index.ts create mode 100644 lib/modules/platform/local/scm.spec.ts create mode 100644 lib/modules/platform/local/scm.ts 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/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/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/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/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.ts b/lib/util/git/index.ts index 1ab24e34acf71f..5d086bef8612ca 100644 --- a/lib/util/git/index.ts +++ b/lib/util/git/index.ts @@ -383,6 +383,10 @@ export async function syncGit(): Promise { } 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}`); 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/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/package.json b/package.json index 0fe3870314db92..78aa5863febcc9 100644 --- a/package.json +++ b/package.json @@ -196,6 +196,7 @@ "global-agent": "3.0.0", "good-enough-parser": "1.1.22", "got": "11.8.6", + "glob": "10.2.2", "graph-data-structure": "3.3.0", "handlebars": "4.7.7", "hasha": "5.2.2", @@ -307,7 +308,6 @@ "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", From 32cb5e1ad7818cfd7573d75e7a62f9e793ac5255 Mon Sep 17 00:00:00 2001 From: Rhys Arkins Date: Wed, 10 May 2023 07:35:18 +0200 Subject: [PATCH 40/57] docs: local platform --- lib/modules/platform/local/index.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 lib/modules/platform/local/index.md diff --git a/lib/modules/platform/local/index.md b/lib/modules/platform/local/index.md new file mode 100644 index 00000000000000..7edadcb2770676 --- /dev/null +++ b/lib/modules/platform/local/index.md @@ -0,0 +1,20 @@ +# Local + +The "local" platform exists to allow users to perform dry runs against the local file system, such as to test out new config. + +## Usage + +Run `renovate --platform=local` in the directory you want Renovate to run in. +In this mode, Renovate will default to `dryRun=lookup`. +No "repositories" arguments should be provided, as you cannot run against multiple directories or run in the non-working directory. + +It is possible to run on both a git and non-git directory. +Config is optional - so it will run either with or without any "repo config" found. + +It does not do any "compare" or before and after analysis - if your purpose is to test a new config then you will need to manually compare. + +## Limitations + +- `local>` presets cannot 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 From 2e2570c2fd97a9254c330095a75e8a64db1a2d20 Mon Sep 17 00:00:00 2001 From: Rhys Arkins Date: Wed, 10 May 2023 07:38:03 +0200 Subject: [PATCH 41/57] feat(poetry): detect constraint from lock file (#22038) Co-authored-by: Mathieu Kniewallner --- .../manager/poetry/__fixtures__/poetry12.lock | 482 +++++++++++ .../poetry/__fixtures__/poetry142.lock | 18 + lib/modules/manager/poetry/artifacts.spec.ts | 786 +++++++++--------- lib/modules/manager/poetry/artifacts.ts | 56 +- lib/modules/manager/poetry/types.ts | 1 + 5 files changed, 941 insertions(+), 402 deletions(-) create mode 100644 lib/modules/manager/poetry/__fixtures__/poetry12.lock create mode 100644 lib/modules/manager/poetry/__fixtures__/poetry142.lock 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[]; From 06b8dcdca118d8af372b3107d96089f10410b652 Mon Sep 17 00:00:00 2001 From: Marcus Crane Date: Wed, 10 May 2023 17:39:20 +1200 Subject: [PATCH 42/57] feat(platform/github): Skip archived repos at earliest point when retrieving repo listings (#22057) --- lib/modules/platform/github/index.spec.ts | 12 ++++++++++++ lib/modules/platform/github/index.ts | 10 +++++++--- lib/modules/platform/github/types.ts | 1 + 3 files changed, 20 insertions(+), 3 deletions(-) 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..1fb1e521a00e74 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`); 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 { From bf2f9db59d87f0b07290d4f35ce169c3eb494328 Mon Sep 17 00:00:00 2001 From: HonkingGoose <34918129+HonkingGoose@users.noreply.github.com> Date: Wed, 10 May 2023 11:28:57 +0200 Subject: [PATCH 43/57] docs: rewrite local platform (#22067) --- lib/modules/platform/local/index.md | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/lib/modules/platform/local/index.md b/lib/modules/platform/local/index.md index 7edadcb2770676..15ede0932e21cb 100644 --- a/lib/modules/platform/local/index.md +++ b/lib/modules/platform/local/index.md @@ -1,20 +1,22 @@ # Local -The "local" platform exists to allow users to perform dry runs against the local file system, such as to test out new config. +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 `renovate --platform=local` in the directory you want Renovate to run in. -In this mode, Renovate will default to `dryRun=lookup`. -No "repositories" arguments should be provided, as you cannot run against multiple directories or run in the non-working directory. +Run the `renovate --platform=local` command in the directory you want Renovate to run in. +In this mode, Renovate defaults to `dryRun=lookup`. -It is possible to run on both a git and non-git directory. -Config is optional - so it will run either with or without any "repo config" found. +Avoid giving "repositories" arguments, as this command can only run in a _single_ directory, and it can only run in the _current working_ directory. -It does not do any "compare" or before and after analysis - if your purpose is to test a new config then you will need to manually compare. +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 cannot be resolved. Normally these would point to the local platform such as GitHub, but in the case of running locally, it does not exist +- `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 From eec46d1880b9d972f6d5546cc83451a5b017e5e6 Mon Sep 17 00:00:00 2001 From: Johannes Feichtner <343448+Churro@users.noreply.github.com> Date: Wed, 10 May 2023 21:36:05 +0200 Subject: [PATCH 44/57] feat(gradle/manager): add support for Kotlin objects in `buildSrc` files (#21892) --- lib/modules/manager/gradle/extract.spec.ts | 120 ++++++++++++++++++ lib/modules/manager/gradle/extract.ts | 26 +++- lib/modules/manager/gradle/index.ts | 1 + lib/modules/manager/gradle/parser.spec.ts | 105 ++++++++++++++- lib/modules/manager/gradle/parser.ts | 29 +++++ .../manager/gradle/parser/assignments.ts | 2 +- .../manager/gradle/parser/common.spec.ts | 12 ++ lib/modules/manager/gradle/parser/common.ts | 12 ++ lib/modules/manager/gradle/parser/objects.ts | 54 ++++++++ lib/modules/manager/gradle/utils.ts | 5 + 10 files changed, 358 insertions(+), 8 deletions(-) create mode 100644 lib/modules/manager/gradle/parser/objects.ts 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'); From 08233ff7054a87608f704edeaaa1f93b0093c73f Mon Sep 17 00:00:00 2001 From: horihel Date: Thu, 11 May 2023 07:15:33 +0200 Subject: [PATCH 45/57] feat(platform/azure): Recreate Auto-Approve on PR-Update (#22028) Signed-off-by: Heiko Helmle Co-authored-by: Jamie Magee Co-authored-by: Rhys Arkins --- .../azure/__snapshots__/index.spec.ts.snap | 10 +++-- lib/modules/platform/azure/index.spec.ts | 39 ++++++++++++++++++- lib/modules/platform/azure/index.ts | 16 ++++++++ 3 files changed, 60 insertions(+), 5 deletions(-) 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..f5b39106638bb2 100644 --- a/lib/modules/platform/azure/index.ts +++ b/lib/modules/platform/azure/index.ts @@ -506,6 +506,7 @@ export async function updatePr({ prTitle: title, prBody: body, state, + platformOptions, }: UpdatePrConfig): Promise { logger.debug(`updatePr(${prNo}, ${title}, body)`); @@ -527,6 +528,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); } From b5d87c67b368610fd5c95d1740725578bec74249 Mon Sep 17 00:00:00 2001 From: Rhys Arkins Date: Thu, 11 May 2023 09:40:02 +0200 Subject: [PATCH 46/57] fix(regex): limit regex manager iterations to 10k to avoid OoM (#22084) --- lib/modules/manager/regex/utils.spec.ts | 14 ++++++++++++++ lib/modules/manager/regex/utils.ts | 8 +++++++- 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 lib/modules/manager/regex/utils.spec.ts 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; } From ebf064e75bf98b01b59c37d62212fb2388fcd8aa Mon Sep 17 00:00:00 2001 From: Chuck Grindel Date: Thu, 11 May 2023 04:26:59 -0600 Subject: [PATCH 47/57] chore(utils/array): add isNotNullOrUndefined (#22081) --- lib/util/array.spec.ts | 12 ++++++++++++ lib/util/array.ts | 9 +++++++++ 2 files changed, 21 insertions(+) create mode 100644 lib/util/array.spec.ts 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); +} From a2e036e3349d1712cc0027919b7b1bda5401141b Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Thu, 11 May 2023 11:00:20 -0400 Subject: [PATCH 48/57] feat(vulnerabilities): set, maintain and expose vulnerabilitySeverity for templated fields (#21939) --- lib/config/index.spec.ts | 55 ++++---- lib/config/types.ts | 3 + lib/config/utils.ts | 11 ++ lib/modules/manager/types.ts | 1 + lib/util/template/index.ts | 3 + lib/util/vulnerability/utils.spec.ts | 129 ++++++++++++++++++ lib/util/vulnerability/utils.ts | 26 ++++ lib/workers/repository/process/types.ts | 6 + .../repository/process/vulnerabilities.ts | 73 +++++++--- 9 files changed, 264 insertions(+), 43 deletions(-) create mode 100644 lib/util/vulnerability/utils.spec.ts create mode 100644 lib/util/vulnerability/utils.ts 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/types.ts b/lib/config/types.ts index 0df00b27a9a688..4286c5a512e242 100644 --- a/lib/config/types.ts +++ b/lib/config/types.ts @@ -251,6 +251,7 @@ export interface RenovateConfig warnings?: ValidationMessage[]; vulnerabilityAlerts?: RenovateSharedConfig; osvVulnerabilityAlerts?: boolean; + vulnerabilitySeverity?: string; regexManagers?: RegExManager[]; fetchReleaseNotes?: boolean; @@ -309,6 +310,7 @@ export interface PackageRule UpdateConfig, Record { description?: string | string[]; + isVulnerabilityAlert?: boolean; matchFiles?: string[]; matchPaths?: string[]; matchLanguages?: string[]; @@ -333,6 +335,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/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/util/template/index.ts b/lib/util/template/index.ts index f3e4a8809c7e6f..da16eaa90f8cfd 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 (eg: LOW, MODERATE, HIGH, CRITICAL)', }; const prBodyFields = [ diff --git a/lib/util/vulnerability/utils.spec.ts b/lib/util/vulnerability/utils.spec.ts new file mode 100644 index 00000000000000..0d9aa2ee34bae1 --- /dev/null +++ b/lib/util/vulnerability/utils.spec.ts @@ -0,0 +1,129 @@ +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('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('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..5607a6de9237b8 --- /dev/null +++ b/lib/util/vulnerability/utils.ts @@ -0,0 +1,26 @@ +const severityOrder: Record = { + LOW: 1, + MODERATE: 2, + HIGH: 3, + CRITICAL: 4, +}; + +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/repository/process/types.ts b/lib/workers/repository/process/types.ts index fd739b99a7d1c3..e59c569da1d8ab 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.ts b/lib/workers/repository/process/vulnerabilities.ts index b3745a7692d463..93483f716a0009 100644 --- a/lib/workers/repository/process/vulnerabilities.ts +++ b/lib/workers/repository/process/vulnerabilities.ts @@ -18,7 +18,11 @@ import { import { sanitizeMarkdown } from '../../../util/markdown'; import * as p from '../../../util/promises'; import { regEx } from '../../../util/regex'; -import type { DependencyVulnerabilities, Vulnerability } from './types'; +import type { + DependencyVulnerabilities, + SeverityDetails, + Vulnerability, +} from './types'; export class Vulnerabilities { private osvOffline: OsvOffline | undefined; @@ -454,12 +458,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?.toUpperCase(), prBodyNotes: this.generatePrBodyNotes(vulnerability, affected), force: { ...packageFileConfig.vulnerabilityAlerts, @@ -513,24 +524,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 if (severityDetails.severityLevel) { + content += `${severityDetails.severityLevel}\n`; } else { content += 'Unknown severity.\n'; } @@ -558,4 +561,36 @@ export class Vulnerabilities { return [sanitizeMarkdown(content)]; } + + private extractSeverityDetails( + vulnerability: Osv.Vulnerability, + affected: Osv.Affected + ): SeverityDetails { + let severityLevel: string | undefined; + 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; + score = baseScore ? `${baseScore} / 10 (${severityLevel})` : 'Unknown'; + } else if ( + vulnerability.id.startsWith('GHSA-') && + vulnerability.database_specific?.severity + ) { + const severity = vulnerability.database_specific.severity as string; + severityLevel = + severity.charAt(0).toUpperCase() + severity.slice(1).toLowerCase(); + } + + return { + cvssVector, + score, + severityLevel, + }; + } } From 15dacb54a76d0a433cc2e8b90722b9b4496524de Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 11 May 2023 20:32:39 +0200 Subject: [PATCH 49/57] chore(deps): update dependency type-fest to v3.10.0 (#22101) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 13 +++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 78aa5863febcc9..7b012059da5637 100644 --- a/package.json +++ b/package.json @@ -328,7 +328,7 @@ "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/yarn.lock b/yarn.lock index 703a47d702b927..eb7f397258a0b1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10128,10 +10128,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" @@ -10173,6 +10173,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" From 9b96e073913d9bab31a268ef7149134494843c82 Mon Sep 17 00:00:00 2001 From: Liora Milbaum Date: Fri, 12 May 2023 06:59:16 +0200 Subject: [PATCH 50/57] chore(regex-managers): Support Contailerfile (#22115) --- lib/config/presets/internal/regex-managers.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) 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', ], From b02856b1fce818ad5f2e8cb1cc70805fa7033c6a Mon Sep 17 00:00:00 2001 From: Rhys Arkins Date: Fri, 12 May 2023 08:18:49 +0200 Subject: [PATCH 51/57] fix: massage rebase check PR comment (#22079) --- lib/modules/platform/azure/index.ts | 4 ++++ lib/modules/platform/bitbucket-server/index.ts | 4 ++++ lib/modules/platform/bitbucket/index.ts | 4 ++++ lib/modules/platform/codecommit/index.ts | 4 ++++ 4 files changed, 16 insertions(+) diff --git a/lib/modules/platform/azure/index.ts b/lib/modules/platform/azure/index.ts index f5b39106638bb2..3790df6c7524fa 100644 --- a/lib/modules/platform/azure/index.ts +++ b/lib/modules/platform/azure/index.ts @@ -775,6 +775,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..5ce4aa5e9a443f 100644 --- a/lib/modules/platform/bitbucket-server/index.ts +++ b/lib/modules/platform/bitbucket-server/index.ts @@ -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..979384249c6666 100644 --- a/lib/modules/platform/bitbucket/index.ts +++ b/lib/modules/platform/bitbucket/index.ts @@ -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`), '') diff --git a/lib/modules/platform/codecommit/index.ts b/lib/modules/platform/codecommit/index.ts index e689415cb39457..0e93116c889c0b 100644 --- a/lib/modules/platform/codecommit/index.ts +++ b/lib/modules/platform/codecommit/index.ts @@ -307,6 +307,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`), '') From e371ddb9ca1fd6cff84317cfc242a8516eeca4a5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 12 May 2023 08:59:32 +0000 Subject: [PATCH 52/57] chore(deps): update dependency @types/node to v18.16.4 (#22121) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 7b012059da5637..231bad645da803 100644 --- a/package.json +++ b/package.json @@ -279,7 +279,7 @@ "@types/marshal": "0.5.1", "@types/moo": "0.5.5", "@types/nock": "10.0.3", - "@types/node": "18.16.3", + "@types/node": "18.16.4", "@types/parse-link-header": "2.0.1", "@types/semver": "7.3.13", "@types/semver-stable": "3.0.0", diff --git a/yarn.lock b/yarn.lock index eb7f397258a0b1..1efc8e9ae0f91b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3061,11 +3061,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.4": + version "18.16.4" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.16.4.tgz#dfb38f0f3fb045fca84ffa7783233c63009d8a92" + integrity sha512-LUhvPmAKAbgm+p/K11IWszLZVoZDlMF4NRmqbhEzDz/CnCuehPkZXwZbBCKGJsgjnuVejotBwM7B3Scrq4EqDw== + "@types/node@^13.7.0": version "13.13.52" resolved "https://registry.yarnpkg.com/@types/node/-/node-13.13.52.tgz#03c13be70b9031baaed79481c0c0cfb0045e53f7" From 6585875119dbfc90dc1074d073ba61ea4223f645 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 12 May 2023 09:50:51 +0000 Subject: [PATCH 53/57] chore(deps): update dependency @types/node to v18.16.8 (#22124) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 231bad645da803..1f0666f57a3bf9 100644 --- a/package.json +++ b/package.json @@ -279,7 +279,7 @@ "@types/marshal": "0.5.1", "@types/moo": "0.5.5", "@types/nock": "10.0.3", - "@types/node": "18.16.4", + "@types/node": "18.16.8", "@types/parse-link-header": "2.0.1", "@types/semver": "7.3.13", "@types/semver-stable": "3.0.0", diff --git a/yarn.lock b/yarn.lock index 1efc8e9ae0f91b..8a68d67d06b67b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3066,10 +3066,10 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-18.16.3.tgz#6bda7819aae6ea0b386ebc5b24bdf602f1b42b01" integrity sha512-OPs5WnnT1xkCBiuQrZA4+YAV4HEJejmHneyraIaxsbev5yCEr6KMwINNFP9wQeFIw8FWcoTqF3vQsa5CDaI+8Q== -"@types/node@18.16.4": - version "18.16.4" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.16.4.tgz#dfb38f0f3fb045fca84ffa7783233c63009d8a92" - integrity sha512-LUhvPmAKAbgm+p/K11IWszLZVoZDlMF4NRmqbhEzDz/CnCuehPkZXwZbBCKGJsgjnuVejotBwM7B3Scrq4EqDw== +"@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" From 2aae5118b941a7639135e083d3c7cdb962da061f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 12 May 2023 10:40:21 +0000 Subject: [PATCH 54/57] build(deps): update dependency @renovatebot/osv-offline to v1.2.5 (#22126) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 28 ++++++++++++++-------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/package.json b/package.json index 1f0666f57a3bf9..96a630697c56d0 100644 --- a/package.json +++ b/package.json @@ -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.5", "@renovatebot/pep440": "2.1.15", "@renovatebot/ruby-semver": "3.0.1", "@sindresorhus/is": "4.6.0", diff --git a/yarn.lock b/yarn.lock index 8a68d67d06b67b..928f04e5d55747 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2487,20 +2487,20 @@ "@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.3.3": + version "1.3.3" + resolved "https://registry.yarnpkg.com/@renovatebot/osv-offline-db/-/osv-offline-db-1.3.3.tgz#371d0a22ece6b2f1012c525dfd4005ee4e6580f1" + integrity sha512-Q7PNdRbMio2GYFqanuHByln20viVpyNhE4CmcY6ly2TVx42YbuRBrZ57JY5RVid0icArVagkW4mjrDh9CawOgA== 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.5": + version "1.2.5" + resolved "https://registry.yarnpkg.com/@renovatebot/osv-offline/-/osv-offline-1.2.5.tgz#40bdb5c22eb1cd66ec3a79d3a25de40fbdce6bb4" + integrity sha512-PRzSyAhel/coD68Z8WK5nFw9UJ8vLCvQQb+aRzwwmMEuSzAbe1FnVbvEZ/wae3sDy57nvMuVhk358InMYHYyVQ== dependencies: "@octokit/rest" "^19.0.7" - "@renovatebot/osv-offline-db" "1.3.2" + "@renovatebot/osv-offline-db" "1.3.3" adm-zip "~0.5.10" fs-extra "^11.1.1" got "^11.8.6" @@ -2522,10 +2522,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" From 976a5a1a8273e9932f9f9cc879f5a949ff1e1751 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Sat, 13 May 2023 02:52:09 -0400 Subject: [PATCH 55/57] feat(bitbucket): add paginate http option (#22135) --- lib/util/http/bitbucket.spec.ts | 30 +++++++++++++ lib/util/http/bitbucket.ts | 80 ++++++++++++++++++++++++++++++--- 2 files changed, 103 insertions(+), 7 deletions(-) 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); +} From d82a81115398a55edf3d8e99970628ec7f8e591d Mon Sep 17 00:00:00 2001 From: HonkingGoose <34918129+HonkingGoose@users.noreply.github.com> Date: Sat, 13 May 2023 13:15:05 +0200 Subject: [PATCH 56/57] docs(config template editing): bump to v18 of React in example (#22162) --- docs/usage/configuration-templates.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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: From 0e27bd18cffa3ad684766e830c50f74dfb2b881f Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Sat, 13 May 2023 08:19:24 -0400 Subject: [PATCH 57/57] feat(bitbucket): use paginated effective default reviewers response (#22164) --- lib/modules/platform/bitbucket/index.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/modules/platform/bitbucket/index.ts b/lib/modules/platform/bitbucket/index.ts index 979384249c6666..17fe0cd5bc36a0 100644 --- a/lib/modules/platform/bitbucket/index.ts +++ b/lib/modules/platform/bitbucket/index.ts @@ -802,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) => ({