From 2836301973c13d1f84950720ba30166986a32b72 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 8 Dec 2023 15:17:29 +0000 Subject: [PATCH 001/173] docs: update references to renovate/renovate to v37.89.4 (#26198) 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 cb823e09145cbd..ae3c0370a6d73d 100644 --- a/docs/usage/docker.md +++ b/docs/usage/docker.md @@ -383,7 +383,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:37.83.4 +FROM renovate/renovate:37.89.4 # Include the "Docker tip" which you can find here https://cloud.google.com/sdk/docs/install # under "Installation" for "Debian/Ubuntu" RUN ... From 74014fdf6d24983f41852ecfd21a2f337c67bc2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mah=C3=A9?= Date: Fri, 8 Dec 2023 17:59:27 +0100 Subject: [PATCH 002/173] fix(git): set `--recurse-submodules` flag for checkout (#26163) Co-authored-by: Michael Kriese --- lib/util/git/index.spec.ts | 54 ++++++++++++++++++++++++++++++++++++++ lib/util/git/index.ts | 8 +++++- 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/lib/util/git/index.spec.ts b/lib/util/git/index.spec.ts index c2be59f4a42910..6b2c85027bf7fe 100644 --- a/lib/util/git/index.spec.ts +++ b/lib/util/git/index.spec.ts @@ -190,6 +190,60 @@ describe('util/git/index', () => { it('sets non-master base branch', async () => { await expect(git.checkoutBranch('develop')).resolves.not.toThrow(); }); + + describe('submodules', () => { + beforeEach(async () => { + const repo = Git(base.path); + + const submoduleBasePath = base.path + '/submodule'; + await fs.mkdir(submoduleBasePath); + const submodule = Git(submoduleBasePath); + await submodule.init(); + await submodule.addConfig('user.email', 'Jest@example.com'); + await submodule.addConfig('user.name', 'Jest'); + + await fs.writeFile(submoduleBasePath + '/init_file', 'init'); + await submodule.add('init_file'); + await submodule.commit('init submodule'); + + await repo.submoduleAdd('./submodule', './submodule'); + await repo.commit('add submodule'); + await repo.branch(['stable']); + + await fs.writeFile(submoduleBasePath + '/current_file', 'current'); + await submodule.add('current_file'); + await submodule.commit('update'); + await repo.add('submodule'); + await repo.commit('update submodule'); + }); + + it('verifies that the --recurse-submodule flag is needed', async () => { + const repo = Git(base.path); + expect((await repo.status()).isClean()).toBeTrue(); + await repo.checkout('stable'); + expect((await repo.status()).isClean()).toBeFalse(); + }); + + it('sets non-master base branch with submodule update', async () => { + await git.initRepo({ + cloneSubmodules: true, + url: base.path, + }); + expect((await git.getRepoStatus()).isClean()).toBeTrue(); + await git.checkoutBranch('stable'); + expect((await git.getRepoStatus()).isClean()).toBeTrue(); + }); + + afterEach(async () => { + const repo = Git(base.path); + const defaultBranch = + (await repo.getConfig('init.defaultbranch')).value ?? 'master'; + await repo.checkout(defaultBranch); + await repo.reset(['--hard', 'HEAD~2']); + await repo.branch(['-D', 'stable']); + await fs.rm(base.path + '/submodule', { recursive: true }); + }); + }); }); describe('getFileList()', () => { diff --git a/lib/util/git/index.ts b/lib/util/git/index.ts index 466d151cf4cc14..36c6c12675b295 100644 --- a/lib/util/git/index.ts +++ b/lib/util/git/index.ts @@ -520,7 +520,13 @@ export async function checkoutBranch( logger.debug(`Setting current branch to ${branchName}`); await syncGit(); try { - await gitRetry(() => git.checkout(['-f', branchName, '--'])); + await gitRetry(() => + git.checkout( + submodulesInitizialized + ? ['-f', '--recurse-submodules', branchName, '--'] + : ['-f', branchName, '--'], + ), + ); config.currentBranch = branchName; config.currentBranchSha = ( await git.raw(['rev-parse', 'HEAD']) From 28798197d31c2b16cba3a9b9b3f109d0b577abce Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 9 Dec 2023 13:33:32 +0000 Subject: [PATCH 003/173] chore(deps): update dependency type-fest to v4.8.3 (#26208) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index cb3383fb386641..994e6a9fdfc720 100644 --- a/package.json +++ b/package.json @@ -344,7 +344,7 @@ "tmp-promise": "3.0.3", "ts-jest": "29.1.1", "ts-node": "10.9.1", - "type-fest": "4.8.2", + "type-fest": "4.8.3", "typescript": "5.3.3", "unified": "9.2.2" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e386e45f2304b7..3669089f18a12d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -596,8 +596,8 @@ importers: specifier: 10.9.1 version: 10.9.1(@swc/core@1.3.100)(@types/node@18.19.2)(typescript@5.3.3) type-fest: - specifier: 4.8.2 - version: 4.8.2 + specifier: 4.8.3 + version: 4.8.3 typescript: specifier: 5.3.3 version: 5.3.3 @@ -8867,7 +8867,7 @@ packages: dependencies: '@babel/code-frame': 7.23.5 index-to-position: 0.1.2 - type-fest: 4.8.2 + type-fest: 4.8.3 dev: true /parse-link-header@2.0.0: @@ -9137,7 +9137,7 @@ packages: dependencies: find-up-simple: 1.0.0 read-pkg: 9.0.1 - type-fest: 4.8.2 + type-fest: 4.8.3 dev: true /read-pkg-up@7.0.1: @@ -9175,7 +9175,7 @@ packages: '@types/normalize-package-data': 2.4.4 normalize-package-data: 6.0.0 parse-json: 8.1.0 - type-fest: 4.8.2 + type-fest: 4.8.3 unicorn-magic: 0.1.0 dev: true @@ -10284,8 +10284,8 @@ packages: engines: {node: '>=14.16'} dev: true - /type-fest@4.8.2: - resolution: {integrity: sha512-mcvrCjixA5166hSrUoJgGb9gBQN4loMYyj9zxuMs/66ibHNEFd5JXMw37YVDx58L4/QID9jIzdTBB4mDwDJ6KQ==} + /type-fest@4.8.3: + resolution: {integrity: sha512-//BaTm14Q/gHBn09xlnKNqfI8t6bmdzx2DXYfPBNofN0WUybCEUDcbCWcTa0oF09lzLjZgPphXAsvRiMK0V6Bw==} engines: {node: '>=16'} dev: true From 498a605d2dbbf9ec0cbe2a533760f5b6d45c4eab Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 10 Dec 2023 10:39:08 +0000 Subject: [PATCH 004/173] build(deps): update dependency prettier to v3.1.1 (#26212) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 994e6a9fdfc720..085cc9a5d33bbd 100644 --- a/package.json +++ b/package.json @@ -230,7 +230,7 @@ "p-queue": "6.6.2", "p-throttle": "4.1.1", "parse-link-header": "2.0.0", - "prettier": "3.1.0", + "prettier": "3.1.1", "redis": "4.6.11", "remark": "13.0.0", "remark-github": "10.1.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3669089f18a12d..918d6e5a5df8e0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -264,8 +264,8 @@ importers: specifier: 2.0.0 version: 2.0.0 prettier: - specifier: 3.1.0 - version: 3.1.0 + specifier: 3.1.1 + version: 3.1.1 redis: specifier: 4.6.11 version: 4.6.11 @@ -8996,8 +8996,8 @@ packages: engines: {node: '>= 0.8.0'} dev: true - /prettier@3.1.0: - resolution: {integrity: sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw==} + /prettier@3.1.1: + resolution: {integrity: sha512-22UbSzg8luF4UuZtzgiUOfcGM8s4tjBv6dJRT7j275NXsy2jb4aJa4NNveul5x4eqlF1wuhuR2RElK71RvmVaw==} engines: {node: '>=14'} hasBin: true dev: false From 882099312075024df3f746c51d0bb806e2f04733 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 10 Dec 2023 21:40:29 +0000 Subject: [PATCH 005/173] build(deps): update emojibase monorepo to v15.3.0 (#26214) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 6 +++--- pnpm-lock.yaml | 26 +++++++++++++------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/package.json b/package.json index 085cc9a5d33bbd..323754e04610eb 100644 --- a/package.json +++ b/package.json @@ -192,8 +192,8 @@ "editorconfig": "2.0.0", "email-addresses": "5.0.0", "emoji-regex": "10.3.0", - "emojibase": "15.2.0", - "emojibase-regex": "15.2.0", + "emojibase": "15.3.0", + "emojibase-regex": "15.3.0", "extract-zip": "2.0.1", "find-packages": "10.0.4", "find-up": "5.0.0", @@ -313,7 +313,7 @@ "common-tags": "1.8.2", "conventional-changelog-conventionalcommits": "7.0.2", "diff": "5.1.0", - "emojibase-data": "15.2.0", + "emojibase-data": "15.3.0", "eslint": "8.55.0", "eslint-config-prettier": "9.1.0", "eslint-formatter-gha": "1.4.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 918d6e5a5df8e0..45ed8ce664911f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -150,11 +150,11 @@ importers: specifier: 10.3.0 version: 10.3.0 emojibase: - specifier: 15.2.0 - version: 15.2.0 + specifier: 15.3.0 + version: 15.3.0 emojibase-regex: - specifier: 15.2.0 - version: 15.2.0 + specifier: 15.3.0 + version: 15.3.0 extract-zip: specifier: 2.0.1 version: 2.0.1 @@ -503,8 +503,8 @@ importers: specifier: 5.1.0 version: 5.1.0 emojibase-data: - specifier: 15.2.0 - version: 15.2.0(emojibase@15.2.0) + specifier: 15.3.0 + version: 15.3.0(emojibase@15.3.0) eslint: specifier: 8.55.0 version: 8.55.0 @@ -5397,20 +5397,20 @@ packages: /emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - /emojibase-data@15.2.0(emojibase@15.2.0): - resolution: {integrity: sha512-hDiw4ugxnI4pcVQO+73NlKx6aZP/A+BAPfDgK/3A83RVbHZa0Ut6GHpd5r5XUV9G7BZhKejlIRuxhXialpbt6Q==} + /emojibase-data@15.3.0(emojibase@15.3.0): + resolution: {integrity: sha512-cYsGq57W8wOd1CqQCjmtP1DpmlTVvJY+Um5UobWUQuTnqb8cO2cuqrxJxSIqxLcYZ3rtialT5kivoWigszdslg==} peerDependencies: emojibase: '*' dependencies: - emojibase: 15.2.0 + emojibase: 15.3.0 dev: true - /emojibase-regex@15.2.0: - resolution: {integrity: sha512-65H5YepRW3gdrghV/Ed9kW3Qry8/qeKJmMlm31nTsOrEZfuAgyr28FmloXpyak86+chR8cukZA7dlafZzrJXbw==} + /emojibase-regex@15.3.0: + resolution: {integrity: sha512-EBz/292VBF9naBPBsGzkZUccgIv1xJibTXIINl8SezgVRnTCpKJx7MgZcR+UAd2RwjGkRJJZ/lhP7riOFZLicA==} dev: false - /emojibase@15.2.0: - resolution: {integrity: sha512-gB6rIVtyJPersQvAo4nOGYPeILMhlcfZdiwCWVeRAtkJ7sm0tExZETGyLhrTQcHvZQhDEYI1vlCeqUhn5gZkQA==} + /emojibase@15.3.0: + resolution: {integrity: sha512-lFdQb14hoznwDh1xDoOFzkPdeeexmbuJdhUUjDaJZf/+jK+6Z3HkI5hWOemWfEdaMxtTujc1vNRx9DKtdtiOXA==} /emojilib@2.4.0: resolution: {integrity: sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw==} From e0af05d96f6ba20eff50af1dc94eaaf4caff21db Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 11 Dec 2023 01:41:36 +0000 Subject: [PATCH 006/173] docs: update references to renovate/renovate to v37.89.6 (#26216) 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 ae3c0370a6d73d..b02875b26906db 100644 --- a/docs/usage/docker.md +++ b/docs/usage/docker.md @@ -383,7 +383,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:37.89.4 +FROM renovate/renovate:37.89.6 # Include the "Docker tip" which you can find here https://cloud.google.com/sdk/docs/install # under "Installation" for "Debian/Ubuntu" RUN ... From 18779f597331a6447dad4b3db53bde77875ada0f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 11 Dec 2023 01:45:36 +0000 Subject: [PATCH 007/173] chore(deps): lock file maintenance (#26217) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- pnpm-lock.yaml | 86 +++++++++++++++++++++++++------------------------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 45ed8ce664911f..0a86c6b4fe68d2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1852,7 +1852,7 @@ packages: resolution: {integrity: sha512-7+ziVclejQTLYhXl+Oi1f6gTGD1XDCeLa4R472TNGQxb08zbEJ0OdNoh5Piz+57Ltmui6xR88BXR4gS3/Toslw==} engines: {node: '>=6.9.0'} dependencies: - core-js-pure: 3.33.3 + core-js-pure: 3.34.0 regenerator-runtime: 0.14.0 dev: false @@ -1943,7 +1943,7 @@ packages: ajv: 6.12.6 debug: 4.3.4 espree: 9.6.1 - globals: 13.23.0 + globals: 13.24.0 ignore: 5.3.0 import-fresh: 3.3.0 js-yaml: 4.1.0 @@ -2349,7 +2349,7 @@ packages: '@octokit/graphql': 7.0.2 '@octokit/request': 8.1.6 '@octokit/request-error': 5.0.1 - '@octokit/types': 12.3.0 + '@octokit/types': 12.4.0 before-after-hook: 2.2.3 universal-user-agent: 6.0.1 @@ -2357,7 +2357,7 @@ packages: resolution: {integrity: sha512-DWPLtr1Kz3tv8L0UvXTDP1fNwM0S+z6EJpRcvH66orY6Eld4XBMCSYsaWp4xIm61jTWxK68BrR7ibO+vSDnZqw==} engines: {node: '>= 18'} dependencies: - '@octokit/types': 12.3.0 + '@octokit/types': 12.4.0 universal-user-agent: 6.0.1 /@octokit/graphql@7.0.2: @@ -2365,20 +2365,20 @@ packages: engines: {node: '>= 18'} dependencies: '@octokit/request': 8.1.6 - '@octokit/types': 12.3.0 + '@octokit/types': 12.4.0 universal-user-agent: 6.0.1 /@octokit/openapi-types@19.1.0: resolution: {integrity: sha512-6G+ywGClliGQwRsjvqVYpklIfa7oRPA0vyhPQG/1Feh+B+wU0vGH1JiJ5T25d3g1JZYBHzR2qefLi9x8Gt+cpw==} - /@octokit/plugin-paginate-rest@9.1.4(@octokit/core@5.0.2): - resolution: {integrity: sha512-MvZx4WvfhBnt7PtH5XE7HORsO7bBk4er1FgRIUr1qJ89NR2I6bWjGyKsxk8z42FPQ34hFQm0Baanh4gzdZR4gQ==} + /@octokit/plugin-paginate-rest@9.1.5(@octokit/core@5.0.2): + resolution: {integrity: sha512-WKTQXxK+bu49qzwv4qKbMMRXej1DU2gq017euWyKVudA6MldaSSQuxtz+vGbhxV4CjxpUxjZu6rM2wfc1FiWVg==} engines: {node: '>= 18'} peerDependencies: '@octokit/core': '>=5' dependencies: '@octokit/core': 5.0.2 - '@octokit/types': 12.3.0 + '@octokit/types': 12.4.0 /@octokit/plugin-request-log@4.0.0(@octokit/core@5.0.2): resolution: {integrity: sha512-2uJI1COtYCq8Z4yNSnM231TgH50bRkheQ9+aH8TnZanB6QilOnx8RMD2qsnamSOXtDj0ilxvevf5fGsBhBBzKA==} @@ -2396,7 +2396,7 @@ packages: '@octokit/core': '>=5' dependencies: '@octokit/core': 5.0.2 - '@octokit/types': 12.3.0 + '@octokit/types': 12.4.0 dev: false /@octokit/plugin-retry@6.0.1(@octokit/core@5.0.2): @@ -2407,7 +2407,7 @@ packages: dependencies: '@octokit/core': 5.0.2 '@octokit/request-error': 5.0.1 - '@octokit/types': 12.3.0 + '@octokit/types': 12.4.0 bottleneck: 2.19.5 dev: true @@ -2418,7 +2418,7 @@ packages: '@octokit/core': ^5.0.0 dependencies: '@octokit/core': 5.0.2 - '@octokit/types': 12.3.0 + '@octokit/types': 12.4.0 bottleneck: 2.19.5 dev: true @@ -2426,7 +2426,7 @@ packages: resolution: {integrity: sha512-X7pnyTMV7MgtGmiXBwmO6M5kIPrntOXdyKZLigNfQWSEQzVxR4a4vo49vJjTWX70mPndj8KhfT4Dx+2Ng3vnBQ==} engines: {node: '>= 18'} dependencies: - '@octokit/types': 12.3.0 + '@octokit/types': 12.4.0 deprecation: 2.3.1 once: 1.4.0 @@ -2436,7 +2436,7 @@ packages: dependencies: '@octokit/endpoint': 9.0.4 '@octokit/request-error': 5.0.1 - '@octokit/types': 12.3.0 + '@octokit/types': 12.4.0 universal-user-agent: 6.0.1 /@octokit/rest@20.0.2: @@ -2444,13 +2444,13 @@ packages: engines: {node: '>= 18'} dependencies: '@octokit/core': 5.0.2 - '@octokit/plugin-paginate-rest': 9.1.4(@octokit/core@5.0.2) + '@octokit/plugin-paginate-rest': 9.1.5(@octokit/core@5.0.2) '@octokit/plugin-request-log': 4.0.0(@octokit/core@5.0.2) '@octokit/plugin-rest-endpoint-methods': 10.2.0(@octokit/core@5.0.2) dev: false - /@octokit/types@12.3.0: - resolution: {integrity: sha512-nJ8X2HRr234q3w/FcovDlA+ttUU4m1eJAourvfUUtwAWeqL8AsyRqfnLvVnYn3NFbUnsmzQCzLNdFerPwdmcDQ==} + /@octokit/types@12.4.0: + resolution: {integrity: sha512-FLWs/AvZllw/AGVs+nJ+ELCDZZJk+kY0zMen118xhL2zD0s1etIUHm1odgjP7epxYU1ln7SZxEUWYop5bhsdgQ==} dependencies: '@octokit/openapi-types': 19.1.0 @@ -2906,14 +2906,14 @@ packages: - supports-color dev: true - /@semantic-release/github@9.2.4(semantic-release@22.0.8): - resolution: {integrity: sha512-VMzqiuSLhHc0/1Q8M/FmWnOaclh5aXL2pQWceldWBYSWLNzQu8GOR4bkGl57ciUtvm+MCMi4FaStZxSDJGEfUg==} + /@semantic-release/github@9.2.5(semantic-release@22.0.8): + resolution: {integrity: sha512-XWumFEOHiWllekymZjeVgkQCJ4YnD8020ZspAHYIIBNX8O4d/1ldeU5iNXu6NGkKlOCokyXh13KwVP0UEMm5kw==} engines: {node: '>=18'} peerDependencies: semantic-release: '>=20.1.0' dependencies: '@octokit/core': 5.0.2 - '@octokit/plugin-paginate-rest': 9.1.4(@octokit/core@5.0.2) + '@octokit/plugin-paginate-rest': 9.1.5(@octokit/core@5.0.2) '@octokit/plugin-retry': 6.0.1(@octokit/core@5.0.2) '@octokit/plugin-throttling': 8.1.3(@octokit/core@5.0.2) '@semantic-release/error': 4.0.0 @@ -2933,8 +2933,8 @@ packages: - supports-color dev: true - /@semantic-release/npm@11.0.1(semantic-release@22.0.8): - resolution: {integrity: sha512-nFcT0pgVwpXsPkzjqP3ObH+pILeN1AbYscCDuYwgZEPZukL+RsGhrtdT4HA1Gjb/y1bVbE90JNtMIcgRi5z/Fg==} + /@semantic-release/npm@11.0.2(semantic-release@22.0.8): + resolution: {integrity: sha512-owtf3RjyPvRE63iUKZ5/xO4uqjRpVQDUB9+nnXj0xwfIeM9pRl+cG+zGDzdftR4m3f2s4Wyf3SexW+kF5DFtWA==} engines: {node: ^18.17 || >=20} peerDependencies: semantic-release: '>=20.1.0' @@ -2946,7 +2946,7 @@ packages: lodash-es: 4.17.21 nerf-dart: 1.0.0 normalize-url: 8.0.0 - npm: 10.2.4 + npm: 10.2.5 rc: 1.2.8 read-pkg: 9.0.1 registry-auth-token: 5.0.2 @@ -4272,8 +4272,8 @@ packages: acorn: 8.11.2 dev: true - /acorn-walk@8.3.0: - resolution: {integrity: sha512-FS7hV565M5l1R08MXqo8odwMTB02C2UqzB17RVgu9EyuYFBqJZ3/ZY97sQD5FewVu1UyDFc1yztUDrAwT0EypA==} + /acorn-walk@8.3.1: + resolution: {integrity: sha512-TgUZgYvqZprrl7YldZNoa9OciCAyZR+Ejm9eXzKCmjsF5IKp/wgQ7Z/ZpjpGTIUPwrHQIcYeI8qDh4PsEwxMbw==} engines: {node: '>=0.4.0'} dev: true @@ -4667,8 +4667,8 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true dependencies: - caniuse-lite: 1.0.30001566 - electron-to-chromium: 1.4.601 + caniuse-lite: 1.0.30001568 + electron-to-chromium: 1.4.609 node-releases: 2.0.14 update-browserslist-db: 1.0.13(browserslist@4.22.2) dev: true @@ -4794,8 +4794,8 @@ packages: engines: {node: '>=10'} dev: true - /caniuse-lite@1.0.30001566: - resolution: {integrity: sha512-ggIhCsTxmITBAMmK8yZjEhCO5/47jKXPu6Dha/wuCS4JePVL+3uiDEBuhu2aIoT+bqTOR8L76Ip1ARL9xYsEJA==} + /caniuse-lite@1.0.30001568: + resolution: {integrity: sha512-vSUkH84HontZJ88MiNrOau1EBrCqEQYgkC5gIySiDlpsm8sGVrhU7Kx4V6h0tnqaHzIHZv08HlJIwPbL4XL9+A==} dev: true /cardinal@2.1.1: @@ -5052,8 +5052,8 @@ packages: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} dev: true - /core-js-pure@3.33.3: - resolution: {integrity: sha512-taJ00IDOP+XYQEA2dAe4ESkmHt1fL8wzYDo3mRWQey8uO9UojlBFMneA65kMyxfYP7106c6LzWaq7/haDT6BCQ==} + /core-js-pure@3.34.0: + resolution: {integrity: sha512-pmhivkYXkymswFfbXsANmBAewXx86UBfmagP+w0wkK06kLsLlTK5oQmsURPivzMkIBQiYq2cjamcZExIwlFQIg==} requiresBuild: true dev: false @@ -5374,8 +5374,8 @@ packages: semver: 7.5.4 dev: false - /electron-to-chromium@1.4.601: - resolution: {integrity: sha512-SpwUMDWe9tQu8JX5QCO1+p/hChAi9AE9UpoC3rcHVc+gdCGlbT3SGb5I1klgb952HRIyvt9wZhSz9bNBYz9swA==} + /electron-to-chromium@1.4.609: + resolution: {integrity: sha512-ihiCP7PJmjoGNuLpl7TjNA8pCQWu09vGyjlPYw1Rqww4gvNuCcmvl+44G+2QyJ6S2K4o+wbTS++Xz0YN8Q9ERw==} dev: true /email-addresses@5.0.0: @@ -5795,7 +5795,7 @@ packages: file-entry-cache: 6.0.1 find-up: 5.0.0 glob-parent: 6.0.2 - globals: 13.23.0 + globals: 13.24.0 graphemer: 1.4.0 ignore: 5.3.0 imurmurhash: 0.1.4 @@ -6357,8 +6357,8 @@ packages: engines: {node: '>=4'} dev: true - /globals@13.23.0: - resolution: {integrity: sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==} + /globals@13.24.0: + resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} engines: {node: '>=8'} dependencies: type-fest: 0.20.2 @@ -8011,7 +8011,7 @@ packages: tslib: '2' dependencies: json-joy: 9.9.1(quill-delta@5.1.0)(rxjs@7.8.1)(tslib@2.6.2) - thingies: 1.14.2(tslib@2.6.2) + thingies: 1.15.0(tslib@2.6.2) tslib: 2.6.2 transitivePeerDependencies: - quill-delta @@ -8475,8 +8475,8 @@ packages: path-key: 4.0.0 dev: true - /npm@10.2.4: - resolution: {integrity: sha512-umEuYneVEYO9KoEEI8n2sSGmNQeqco/3BSeacRlqIkCzw4E7XGtYSWMeJobxzr6hZ2n9cM+u5TsMTcC5bAgoWA==} + /npm@10.2.5: + resolution: {integrity: sha512-lXdZ7titEN8CH5YJk9C/aYRU9JeDxQ4d8rwIIDsvH3SMjLjHTukB2CFstMiB30zXs4vCrPN2WH6cDq1yHBeJAw==} engines: {node: ^18.17.0 || >=20.5.0} hasBin: true dev: true @@ -9469,8 +9469,8 @@ packages: dependencies: '@semantic-release/commit-analyzer': 11.1.0(semantic-release@22.0.8) '@semantic-release/error': 4.0.0 - '@semantic-release/github': 9.2.4(semantic-release@22.0.8) - '@semantic-release/npm': 11.0.1(semantic-release@22.0.8) + '@semantic-release/github': 9.2.5(semantic-release@22.0.8) + '@semantic-release/npm': 11.0.2(semantic-release@22.0.8) '@semantic-release/release-notes-generator': 12.1.0(semantic-release@22.0.8) aggregate-error: 5.0.0 cosmiconfig: 8.3.6(typescript@5.3.3) @@ -10021,8 +10021,8 @@ packages: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} dev: true - /thingies@1.14.2(tslib@2.6.2): - resolution: {integrity: sha512-sbwAaWmbosdmuDJH3xfQXoUmgGOcrhC1YPAqN5kHEyylQpnm5DadUC2lgYb7fvLGgAf3RlwOp9f9qZ65Lh9iqA==} + /thingies@1.15.0(tslib@2.6.2): + resolution: {integrity: sha512-ZSJlvEpD8QllYim0VSGlbAoob/iPrTWNlV/m8ltizMvMmzzU2gVJvHfH9ijLstyciWF70ZiQXqz+BCXWJq+ZQw==} engines: {node: '>=10.18'} peerDependencies: tslib: ^2 @@ -10185,7 +10185,7 @@ packages: '@tsconfig/node16': 1.0.4 '@types/node': 18.19.2 acorn: 8.11.2 - acorn-walk: 8.3.0 + acorn-walk: 8.3.1 arg: 4.1.3 create-require: 1.1.1 diff: 4.0.2 From 52c9f7a8ae5b0c8fbc7fe8ba27fcc6b85f5dfb2e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 11 Dec 2023 03:22:09 +0000 Subject: [PATCH 008/173] chore(deps): lock file maintenance (#26219) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> From f7bde82f662e8e2852daea2835ced40a5920237c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 11 Dec 2023 10:45:25 +0000 Subject: [PATCH 009/173] chore(deps): lock file maintenance (#26226) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> From c1b4739525919c2d12ff4e30f891419ea1a5c508 Mon Sep 17 00:00:00 2001 From: Rhys Arkins Date: Mon, 11 Dec 2023 14:54:29 +0100 Subject: [PATCH 010/173] fix(config): ignore GITHUB_COM_TOKEN when detectHostRulesFromEnv=true (#26224) --- lib/workers/global/config/parse/host-rules-from-env.spec.ts | 3 +++ lib/workers/global/config/parse/host-rules-from-env.ts | 3 +++ 2 files changed, 6 insertions(+) diff --git a/lib/workers/global/config/parse/host-rules-from-env.spec.ts b/lib/workers/global/config/parse/host-rules-from-env.spec.ts index a23234e4a1aa99..59776044e78705 100644 --- a/lib/workers/global/config/parse/host-rules-from-env.spec.ts +++ b/lib/workers/global/config/parse/host-rules-from-env.spec.ts @@ -1,3 +1,4 @@ +import { logger } from '../../../../../test/util'; import { hostRulesFromEnv } from './host-rules-from-env'; describe('workers/global/config/parse/host-rules-from-env', () => { @@ -91,6 +92,7 @@ describe('workers/global/config/parse/host-rules-from-env', () => { it('supports platform env token', () => { const envParam: NodeJS.ProcessEnv = { + GITHUB_COM_TOKEN: 'this-should-be-ignored-here', GITHUB_SOME_GITHUB__ENTERPRISE_HOST_TOKEN: 'some-token', }; expect(hostRulesFromEnv(envParam)).toMatchObject([ @@ -100,6 +102,7 @@ describe('workers/global/config/parse/host-rules-from-env', () => { token: 'some-token', }, ]); + expect(logger.logger.warn).not.toHaveBeenCalled(); }); it('rejects incomplete datasource env token', () => { diff --git a/lib/workers/global/config/parse/host-rules-from-env.ts b/lib/workers/global/config/parse/host-rules-from-env.ts index 58936a5ac3aaf8..552b8d89ad8e84 100644 --- a/lib/workers/global/config/parse/host-rules-from-env.ts +++ b/lib/workers/global/config/parse/host-rules-from-env.ts @@ -61,6 +61,9 @@ export function hostRulesFromEnv(env: NodeJS.ProcessEnv): HostRule[] { const npmEnvPrefixes = ['npm_config_', 'npm_lifecycle_', 'npm_package_']; for (const envName of Object.keys(env).sort()) { + if (envName === 'GITHUB_COM_TOKEN') { + continue; + } if (npmEnvPrefixes.some((prefix) => envName.startsWith(prefix))) { logger.trace('Ignoring npm env: ' + envName); continue; From 2438616996e92095b42a96ed3a923d5dc20e05ef Mon Sep 17 00:00:00 2001 From: Roman <491247+moltar@users.noreply.github.com> Date: Mon, 11 Dec 2023 14:18:49 +0000 Subject: [PATCH 011/173] feat(templating): adds encodeBase64 handlebars helper (#26197) Co-authored-by: Rhys Arkins Co-authored-by: Michael Kriese --- docs/usage/templates.md | 8 ++++++++ lib/util/template/index.spec.ts | 24 ++++++++++++++++++++++++ lib/util/template/index.ts | 4 ++++ 3 files changed, 36 insertions(+) diff --git a/docs/usage/templates.md b/docs/usage/templates.md index e72e7182576e45..f355135754ea02 100644 --- a/docs/usage/templates.md +++ b/docs/usage/templates.md @@ -59,6 +59,14 @@ In the example above `depName` is the string you want to decode. Read the [MDN Web Docs, decodeURIComponent()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent) to learn more. +### encodeBase64 + +If you want to convert a string to Base64, use the built-in function `encodeBase64` like this: + +`{{{encodeBase64 body}}}` + +In the example above `body` is the string you want to transform into a Base64-encoded value. + ### replace The `replace` helper replaces _all_ found strings matching the given regex with the replacement string. diff --git a/lib/util/template/index.spec.ts b/lib/util/template/index.spec.ts index 308de561931112..0b86af09154cf1 100644 --- a/lib/util/template/index.spec.ts +++ b/lib/util/template/index.spec.ts @@ -219,6 +219,30 @@ describe('util/template/index', () => { }); }); + describe('base64 encoding', () => { + it('encodes values', () => { + const output = template.compile( + '{{{encodeBase64 "@fsouza/prettierd"}}}', + undefined as never, + ); + expect(output).toBe('QGZzb3V6YS9wcmV0dGllcmQ='); + }); + + it('handles null values gracefully', () => { + const output = template.compile('{{{encodeBase64 packageName}}}', { + packageName: null, + }); + expect(output).toBe(''); + }); + + it('handles undefined values gracefully', () => { + const output = template.compile('{{{encodeBase64 packageName}}}', { + packageName: undefined, + }); + expect(output).toBe(''); + }); + }); + describe('equals', () => { it('equals', () => { const output = template.compile( diff --git a/lib/util/template/index.ts b/lib/util/template/index.ts index 228dbea040bee6..f9a7c215217350 100644 --- a/lib/util/template/index.ts +++ b/lib/util/template/index.ts @@ -8,6 +8,10 @@ import { regEx } from '../regex'; handlebars.registerHelper('encodeURIComponent', encodeURIComponent); handlebars.registerHelper('decodeURIComponent', decodeURIComponent); +handlebars.registerHelper('encodeBase64', (str: string) => + Buffer.from(str ?? '').toString('base64'), +); + handlebars.registerHelper('stringToPrettyJSON', (input: string): string => JSON.stringify(JSON.parse(input), null, 2), ); From f88353c671493b4e35d59e86283b89754c0fd492 Mon Sep 17 00:00:00 2001 From: Michael Kriese Date: Mon, 11 Dec 2023 15:35:55 +0100 Subject: [PATCH 012/173] fix(gitea): disable issues on external tracker (#26228) --- lib/modules/platform/gitea/index.ts | 2 +- lib/modules/platform/gitea/types.ts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/modules/platform/gitea/index.ts b/lib/modules/platform/gitea/index.ts index 7bf3d624a7ea0f..de33ac3623a889 100644 --- a/lib/modules/platform/gitea/index.ts +++ b/lib/modules/platform/gitea/index.ts @@ -335,7 +335,7 @@ const platform: Platform = { config.prList = null; config.issueList = null; config.labelList = null; - config.hasIssuesEnabled = repo.has_issues; + config.hasIssuesEnabled = !repo.external_tracker && repo.has_issues; return { defaultBranch: config.defaultBranch, diff --git a/lib/modules/platform/gitea/types.ts b/lib/modules/platform/gitea/types.ts index d6061357a28324..939495f998614e 100644 --- a/lib/modules/platform/gitea/types.ts +++ b/lib/modules/platform/gitea/types.ts @@ -64,6 +64,7 @@ export interface Repo { allow_squash_merge: boolean; archived: boolean; clone_url?: string; + external_tracker?: unknown; has_issues: boolean; ssh_url?: string; default_branch: string; From c39aa7e5b1880d992251221f3eb2258d95536e1d Mon Sep 17 00:00:00 2001 From: Mike Date: Mon, 11 Dec 2023 10:24:51 -0500 Subject: [PATCH 013/173] feat(manager/azure-pipelines): Deployment jobs support (#26048) --- .../__fixtures__/azure-pipelines-jobs.yaml | 6 - .../__fixtures__/azure-pipelines-stages.yaml | 8 - .../__fixtures__/azure-pipelines-steps.yaml | 4 - .../manager/azure-pipelines/extract.spec.ts | 237 ++++++++++++++++-- .../manager/azure-pipelines/extract.ts | 102 +++++--- lib/modules/manager/azure-pipelines/schema.ts | 81 ++++++ lib/modules/manager/azure-pipelines/types.ts | 30 --- 7 files changed, 359 insertions(+), 109 deletions(-) delete mode 100644 lib/modules/manager/azure-pipelines/__fixtures__/azure-pipelines-jobs.yaml delete mode 100644 lib/modules/manager/azure-pipelines/__fixtures__/azure-pipelines-stages.yaml delete mode 100644 lib/modules/manager/azure-pipelines/__fixtures__/azure-pipelines-steps.yaml create mode 100644 lib/modules/manager/azure-pipelines/schema.ts delete mode 100644 lib/modules/manager/azure-pipelines/types.ts diff --git a/lib/modules/manager/azure-pipelines/__fixtures__/azure-pipelines-jobs.yaml b/lib/modules/manager/azure-pipelines/__fixtures__/azure-pipelines-jobs.yaml deleted file mode 100644 index c75ec9374b0ff6..00000000000000 --- a/lib/modules/manager/azure-pipelines/__fixtures__/azure-pipelines-jobs.yaml +++ /dev/null @@ -1,6 +0,0 @@ -jobs: - - job: job_one - steps: - - task: Bash@3 - inputs: - script: 'echo Hello World' diff --git a/lib/modules/manager/azure-pipelines/__fixtures__/azure-pipelines-stages.yaml b/lib/modules/manager/azure-pipelines/__fixtures__/azure-pipelines-stages.yaml deleted file mode 100644 index 8dbff5f31f5897..00000000000000 --- a/lib/modules/manager/azure-pipelines/__fixtures__/azure-pipelines-stages.yaml +++ /dev/null @@ -1,8 +0,0 @@ -stages: - - stage: stage_one - jobs: - - job: job_one - steps: - - task: Bash@3 - inputs: - script: 'echo Hello World' diff --git a/lib/modules/manager/azure-pipelines/__fixtures__/azure-pipelines-steps.yaml b/lib/modules/manager/azure-pipelines/__fixtures__/azure-pipelines-steps.yaml deleted file mode 100644 index 28c203d03b993e..00000000000000 --- a/lib/modules/manager/azure-pipelines/__fixtures__/azure-pipelines-steps.yaml +++ /dev/null @@ -1,4 +0,0 @@ -steps: - - task: Bash@3 - inputs: - script: 'echo Hello World' diff --git a/lib/modules/manager/azure-pipelines/extract.spec.ts b/lib/modules/manager/azure-pipelines/extract.spec.ts index 7e4f6e40423e03..e53b41639e5495 100644 --- a/lib/modules/manager/azure-pipelines/extract.spec.ts +++ b/lib/modules/manager/azure-pipelines/extract.spec.ts @@ -1,3 +1,4 @@ +import { codeBlock } from 'common-tags'; import { Fixtures } from '../../../../test/fixtures'; import { GlobalConfig } from '../../../config/global'; import { AzurePipelinesTasksDatasource } from '../../datasource/azure-pipelines-tasks'; @@ -15,9 +16,6 @@ const azurePipelines = Fixtures.get('azure-pipelines.yaml'); const azurePipelinesNoDependency = Fixtures.get( 'azure-pipelines-no-dependency.yaml', ); -const azurePipelinesStages = Fixtures.get('azure-pipelines-stages.yaml'); -const azurePipelinesJobs = Fixtures.get('azure-pipelines-jobs.yaml'); -const azurePipelinesSteps = Fixtures.get('azure-pipelines-steps.yaml'); describe('modules/manager/azure-pipelines/extract', () => { afterEach(() => { @@ -58,12 +56,11 @@ describe('modules/manager/azure-pipelines/extract', () => { ).toBeNull(); }); - it('should return null when reference is not defined', () => { + it('should return null when reference is not defined specified', () => { expect( extractRepository({ type: 'github', name: 'user/repo', - ref: null, }), ).toBeNull(); }); @@ -138,10 +135,6 @@ describe('modules/manager/azure-pipelines/extract', () => { datasource: 'docker', }); }); - - it('should return null if image field is missing', () => { - expect(extractContainer({ image: null })).toBeNull(); - }); }); describe('extractAzurePipelinesTasks()', () => { @@ -191,11 +184,196 @@ describe('modules/manager/azure-pipelines/extract', () => { ).toBeNull(); }); + it('should extract deployment jobs runonce', () => { + const packageFile = codeBlock` + jobs: + - deployment: deployment_one + strategy: + runOnce: + deploy: + steps: + - task: Bash@3 + inputs: + script: 'echo Hello World' + `; + const res = extractPackageFile(packageFile, azurePipelinesFilename); + expect(res?.deps).toEqual([ + { + depName: 'Bash', + currentValue: '3', + datasource: AzurePipelinesTasksDatasource.id, + }, + ]); + }); + + it('should extract deployment jobs on failure', () => { + const packageFile = codeBlock` + jobs: + - deployment: deployment_one + strategy: + runOnce: + on: + failure: + steps: + - task: Bash@3 + inputs: + script: 'echo Hello World' + `; + const res = extractPackageFile(packageFile, azurePipelinesFilename); + expect(res?.deps).toEqual([ + { + depName: 'Bash', + currentValue: '3', + datasource: AzurePipelinesTasksDatasource.id, + }, + ]); + }); + + it('should extract deployment jobs on success', () => { + const packageFile = codeBlock` + jobs: + - deployment: deployment_one + strategy: + runOnce: + on: + success: + steps: + - task: Bash@3 + inputs: + script: 'echo Hello World' + `; + const res = extractPackageFile(packageFile, azurePipelinesFilename); + expect(res?.deps).toEqual([ + { + depName: 'Bash', + currentValue: '3', + datasource: AzurePipelinesTasksDatasource.id, + }, + ]); + }); + + it('should extract deployment jobs postroute', () => { + const packageFile = codeBlock` + jobs: + - deployment: deployment_one + strategy: + runOnce: + postRouteTraffic: + steps: + - task: Bash@3 + inputs: + script: 'echo Hello World' + `; + const res = extractPackageFile(packageFile, azurePipelinesFilename); + expect(res?.deps).toEqual([ + { + depName: 'Bash', + currentValue: '3', + datasource: AzurePipelinesTasksDatasource.id, + }, + ]); + }); + + it('should extract deployment jobs predeploy', () => { + const packageFile = codeBlock` + jobs: + - deployment: deployment_one + strategy: + runOnce: + preDeploy: + steps: + - task: Bash@3 + inputs: + script: 'echo Hello World' + `; + const res = extractPackageFile(packageFile, azurePipelinesFilename); + expect(res?.deps).toEqual([ + { + depName: 'Bash', + currentValue: '3', + datasource: AzurePipelinesTasksDatasource.id, + }, + ]); + }); + + it('should extract deployment jobs route', () => { + const packageFile = codeBlock` + jobs: + - deployment: deployment_one + strategy: + runOnce: + routeTraffic: + steps: + - task: Bash@3 + inputs: + script: 'echo Hello World' + `; + const res = extractPackageFile(packageFile, azurePipelinesFilename); + expect(res?.deps).toEqual([ + { + depName: 'Bash', + currentValue: '3', + datasource: AzurePipelinesTasksDatasource.id, + }, + ]); + }); + + it('should extract deployment jobs rolling', () => { + const packageFile = codeBlock` + jobs: + - deployment: deployment_one + strategy: + rolling: + deploy: + steps: + - task: Bash@3 + inputs: + script: 'echo Hello World' + `; + const res = extractPackageFile(packageFile, azurePipelinesFilename); + expect(res?.deps).toEqual([ + { + depName: 'Bash', + currentValue: '3', + datasource: AzurePipelinesTasksDatasource.id, + }, + ]); + }); + + it('should extract deployment jobs canary', () => { + const packageFile = codeBlock` + jobs: + - deployment: deployment_one + strategy: + canary: + deploy: + steps: + - task: Bash@3 + inputs: + script: 'echo Hello World' + `; + const res = extractPackageFile(packageFile, azurePipelinesFilename); + expect(res?.deps).toEqual([ + { + depName: 'Bash', + currentValue: '3', + datasource: AzurePipelinesTasksDatasource.id, + }, + ]); + }); + it('should extract stages', () => { - const res = extractPackageFile( - azurePipelinesStages, - azurePipelinesFilename, - ); + const packageFile = codeBlock` + stages: + - stage: stage_one + jobs: + - job: job_one + steps: + - task: Bash@3 + inputs: + script: 'echo Hello World' + `; + const res = extractPackageFile(packageFile, azurePipelinesFilename); expect(res?.deps).toEqual([ { depName: 'Bash', @@ -206,10 +384,15 @@ describe('modules/manager/azure-pipelines/extract', () => { }); it('should extract jobs', () => { - const res = extractPackageFile( - azurePipelinesJobs, - azurePipelinesFilename, - ); + const packageFile = codeBlock` + jobs: + - job: job_one + steps: + - task: Bash@3 + inputs: + script: 'echo Hello World' + `; + const res = extractPackageFile(packageFile, azurePipelinesFilename); expect(res?.deps).toEqual([ { depName: 'Bash', @@ -220,10 +403,13 @@ describe('modules/manager/azure-pipelines/extract', () => { }); it('should extract steps', () => { - const res = extractPackageFile( - azurePipelinesSteps, - azurePipelinesFilename, - ); + const packageFile = codeBlock` + steps: + - task: Bash@3 + inputs: + script: 'echo Hello World' + `; + const res = extractPackageFile(packageFile, azurePipelinesFilename); expect(res?.deps).toEqual([ { depName: 'Bash', @@ -234,10 +420,11 @@ describe('modules/manager/azure-pipelines/extract', () => { }); it('should return null when task alias used', () => { - const content = ` - steps: - - bash: 'echo Hello World'`; - const res = extractPackageFile(content, azurePipelinesFilename); + const packageFile = codeBlock` + steps: + - bash: 'echo Hello World'; + `; + const res = extractPackageFile(packageFile, azurePipelinesFilename); expect(res).toBeNull(); }); }); diff --git a/lib/modules/manager/azure-pipelines/extract.ts b/lib/modules/manager/azure-pipelines/extract.ts index 5f2a1c7f2c81a5..433d4b7c2f987f 100644 --- a/lib/modules/manager/azure-pipelines/extract.ts +++ b/lib/modules/manager/azure-pipelines/extract.ts @@ -3,12 +3,21 @@ import { logger } from '../../../logger'; import { coerceArray } from '../../../util/array'; import { regEx } from '../../../util/regex'; import { joinUrlParts } from '../../../util/url'; -import { parseSingleYaml } from '../../../util/yaml'; import { AzurePipelinesTasksDatasource } from '../../datasource/azure-pipelines-tasks'; import { GitTagsDatasource } from '../../datasource/git-tags'; import { getDep } from '../dockerfile/extract'; import type { PackageDependency, PackageFileContent } from '../types'; -import type { AzurePipelines, Container, Repository } from './types'; +import { + AzurePipelines, + AzurePipelinesYaml, + Container, + Deploy, + Deployment, + Job, + Jobs, + Repository, + Step, +} from './schema'; const AzurePipelinesTaskRegex = regEx(/^(?[^@]+)@(?.*)$/); @@ -68,10 +77,6 @@ export function extractRepository( export function extractContainer( container: Container, ): PackageDependency | null { - if (!container.image) { - return null; - } - const dep = getDep(container.image); logger.debug( { @@ -104,15 +109,60 @@ export function parseAzurePipelines( content: string, packageFile: string, ): AzurePipelines | null { - let pkg: AzurePipelines | null = null; - try { - pkg = parseSingleYaml(content, { json: true }) as AzurePipelines; - } catch (err) /* istanbul ignore next */ { - logger.debug({ packageFile, err }, 'Error parsing azure-pipelines content'); - return null; + const res = AzurePipelinesYaml.safeParse(content); + if (res.success) { + return res.data; + } else { + logger.debug( + { err: res.error, packageFile }, + 'Error parsing pubspec lockfile.', + ); + } + return null; +} + +function extractSteps( + steps: Step[] | undefined, +): PackageDependency>[] { + const deps = []; + for (const step of coerceArray(steps)) { + const task = extractAzurePipelinesTasks(step.task); + if (task) { + deps.push(task); + } } + return deps; +} + +function extractJob(job: Job | undefined): PackageDependency[] { + return extractSteps(job?.steps); +} + +function extractDeploy(deploy: Deploy | undefined): PackageDependency[] { + const deps = extractJob(deploy?.deploy); + deps.push(...extractJob(deploy?.postRouteTraffic)); + deps.push(...extractJob(deploy?.preDeploy)); + deps.push(...extractJob(deploy?.routeTraffic)); + deps.push(...extractJob(deploy?.on?.failure)); + deps.push(...extractJob(deploy?.on?.success)); + return deps; +} + +function extractJobs(jobs: Jobs | undefined): PackageDependency[] { + const deps: PackageDependency[] = []; + for (const jobOrDeployment of coerceArray(jobs)) { + const deployment = jobOrDeployment as Deployment; + if (deployment.strategy) { + deps.push(...extractDeploy(deployment.strategy.canary)); + deps.push(...extractDeploy(deployment.strategy.rolling)); + deps.push(...extractDeploy(deployment.strategy.runOnce)); + continue; + } - return pkg; + const job = jobOrDeployment as Job; + deps.push(...extractJob(job)); + } + return deps; } export function extractPackageFile( @@ -142,31 +192,11 @@ export function extractPackageFile( } for (const { jobs } of coerceArray(pkg.stages)) { - for (const { steps } of coerceArray(jobs)) { - for (const step of coerceArray(steps)) { - const task = extractAzurePipelinesTasks(step.task); - if (task) { - deps.push(task); - } - } - } - } - - for (const { steps } of coerceArray(pkg.jobs)) { - for (const step of coerceArray(steps)) { - const task = extractAzurePipelinesTasks(step.task); - if (task) { - deps.push(task); - } - } + deps.push(...extractJobs(jobs)); } - for (const step of coerceArray(pkg.steps)) { - const task = extractAzurePipelinesTasks(step.task); - if (task) { - deps.push(task); - } - } + deps.push(...extractJobs(pkg.jobs)); + deps.push(...extractSteps(pkg.steps)); if (!deps.length) { return null; diff --git a/lib/modules/manager/azure-pipelines/schema.ts b/lib/modules/manager/azure-pipelines/schema.ts new file mode 100644 index 00000000000000..1a1c3252546b95 --- /dev/null +++ b/lib/modules/manager/azure-pipelines/schema.ts @@ -0,0 +1,81 @@ +import { z } from 'zod'; +import { LooseArray, Yaml } from '../../../util/schema-utils'; + +export const Step = z.object({ + task: z.string(), +}); +export type Step = z.infer; + +export const Job = z.object({ + steps: LooseArray(Step), +}); +export type Job = z.infer; + +export const Deploy = z + .object({ + deploy: Job, + preDeploy: Job, + routeTraffic: Job, + postRouteTraffic: Job, + on: z + .object({ + failure: Job, + success: Job, + }) + .partial(), + }) + .partial(); +export type Deploy = z.infer; + +export const Deployment = z + .object({ + strategy: z + .object({ + runOnce: Deploy, + rolling: Deploy, + canary: Deploy, + }) + .partial(), + }) + .partial(); +export type Deployment = z.infer; + +export const Jobs = LooseArray(z.union([Job, Deployment])); +export type Jobs = z.infer; + +export const Stage = z.object({ + jobs: Jobs, +}); +export type Stage = z.infer; + +export const Container = z.object({ + image: z.string(), +}); +export type Container = z.infer; + +export const Repository = z.object({ + type: z.enum(['git', 'github', 'bitbucket']), + name: z.string(), + ref: z.string().optional(), +}); +export type Repository = z.infer; + +export const Resources = z + .object({ + repositories: LooseArray(Repository), + containers: LooseArray(Container), + }) + .partial(); +export type Resources = z.infer; + +export const AzurePipelines = z + .object({ + resources: Resources, + stages: LooseArray(Stage), + jobs: Jobs, + steps: LooseArray(Step), + }) + .partial(); +export type AzurePipelines = z.infer; + +export const AzurePipelinesYaml = Yaml.pipe(AzurePipelines); diff --git a/lib/modules/manager/azure-pipelines/types.ts b/lib/modules/manager/azure-pipelines/types.ts deleted file mode 100644 index f532a4fb83eb9a..00000000000000 --- a/lib/modules/manager/azure-pipelines/types.ts +++ /dev/null @@ -1,30 +0,0 @@ -export interface Container { - image?: string | null; -} -export interface Repository { - type: 'git' | 'github' | 'bitbucket'; - name: string; - ref?: string | null; -} -export interface Resources { - repositories?: Repository[]; - containers?: Container[]; -} -export interface AzurePipelines { - resources?: Resources; - stages?: Stage[]; - jobs?: Job[]; - steps?: Step[]; -} - -export interface Stage { - jobs?: Job[]; -} - -export interface Job { - steps?: Step[]; -} - -export interface Step { - task: string; -} From ef543f8c070af49fa569939f08f1746432c3ae62 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 12 Dec 2023 03:45:49 +0000 Subject: [PATCH 014/173] build(deps): update dependency @renovatebot/pep440 to v3.0.13 (#26239) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 323754e04610eb..1bf4c82c5801c1 100644 --- a/package.json +++ b/package.json @@ -165,7 +165,7 @@ "@opentelemetry/semantic-conventions": "1.18.1", "@qnighy/marshal": "0.1.3", "@renovatebot/osv-offline": "1.3.10", - "@renovatebot/pep440": "3.0.12", + "@renovatebot/pep440": "3.0.13", "@renovatebot/ruby-semver": "3.0.19", "@sindresorhus/is": "4.6.0", "@types/ms": "0.7.34", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0a86c6b4fe68d2..0d3a39947266d6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -69,8 +69,8 @@ importers: specifier: 1.3.10 version: 1.3.10 '@renovatebot/pep440': - specifier: 3.0.12 - version: 3.0.12 + specifier: 3.0.13 + version: 3.0.13 '@renovatebot/ruby-semver': specifier: 3.0.19 version: 3.0.19 @@ -2839,8 +2839,8 @@ packages: - encoding dev: false - /@renovatebot/pep440@3.0.12: - resolution: {integrity: sha512-l5qdcpsS+tpOhPf/lChoCv+Fd52ajMeq7t7oXmmDwBG5Nfuv5P4QVs5v9mP/dxBta/uRCNFnKVJmbFpPHTBrrw==} + /@renovatebot/pep440@3.0.13: + resolution: {integrity: sha512-lweg1JT8Eu4rN/l3t8KxOFakwGHOA72MUrfaUBc8ErAWE379H1vbykGitHxkJ/jFQe999FoaYIz9sI17exUE1w==} engines: {node: ^18.12.0 || >= 20.0.0, pnpm: ^8.6.11} dev: false From 435220e925e3f2f4cb7364e3c72c7b6cb976debc Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 12 Dec 2023 04:46:34 +0100 Subject: [PATCH 015/173] build(deps): update dependency semantic-release to v22.0.9 (#26240) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 48 +++++++++++++++++++++++------------------------- 2 files changed, 24 insertions(+), 26 deletions(-) diff --git a/package.json b/package.json index 1bf4c82c5801c1..0f828a3afaab42 100644 --- a/package.json +++ b/package.json @@ -339,7 +339,7 @@ "nyc": "15.1.0", "pretty-format": "29.7.0", "rimraf": "5.0.5", - "semantic-release": "22.0.8", + "semantic-release": "22.0.9", "tar": "6.2.0", "tmp-promise": "3.0.3", "ts-jest": "29.1.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0d3a39947266d6..801137e8f91fde 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -360,7 +360,7 @@ importers: version: file:tools/eslint '@semantic-release/exec': specifier: 6.0.3 - version: 6.0.3(semantic-release@22.0.8) + version: 6.0.3(semantic-release@22.0.9) '@swc/core': specifier: 1.3.100 version: 1.3.100 @@ -581,8 +581,8 @@ importers: specifier: 5.0.5 version: 5.0.5 semantic-release: - specifier: 22.0.8 - version: 22.0.8(typescript@5.3.3) + specifier: 22.0.9 + version: 22.0.9(typescript@5.3.3) tar: specifier: 6.2.0 version: 6.2.0 @@ -2861,7 +2861,7 @@ packages: util: 0.12.5 dev: false - /@semantic-release/commit-analyzer@11.1.0(semantic-release@22.0.8): + /@semantic-release/commit-analyzer@11.1.0(semantic-release@22.0.9): resolution: {integrity: sha512-cXNTbv3nXR2hlzHjAMgbuiQVtvWHTlwwISt60B+4NZv01y/QRY7p2HcJm8Eh2StzcTJoNnflvKjHH/cjFS7d5g==} engines: {node: ^18.17 || >=20.6.1} peerDependencies: @@ -2874,7 +2874,7 @@ packages: import-from-esm: 1.3.3 lodash-es: 4.17.21 micromatch: 4.0.5 - semantic-release: 22.0.8(typescript@5.3.3) + semantic-release: 22.0.9(typescript@5.3.3) transitivePeerDependencies: - supports-color dev: true @@ -2889,7 +2889,7 @@ packages: engines: {node: '>=18'} dev: true - /@semantic-release/exec@6.0.3(semantic-release@22.0.8): + /@semantic-release/exec@6.0.3(semantic-release@22.0.9): resolution: {integrity: sha512-bxAq8vLOw76aV89vxxICecEa8jfaWwYITw6X74zzlO0mc/Bgieqx9kBRz9z96pHectiTAtsCwsQcUyLYWnp3VQ==} engines: {node: '>=14.17'} peerDependencies: @@ -2901,12 +2901,12 @@ packages: execa: 5.1.1 lodash: 4.17.21 parse-json: 5.2.0 - semantic-release: 22.0.8(typescript@5.3.3) + semantic-release: 22.0.9(typescript@5.3.3) transitivePeerDependencies: - supports-color dev: true - /@semantic-release/github@9.2.5(semantic-release@22.0.8): + /@semantic-release/github@9.2.5(semantic-release@22.0.9): resolution: {integrity: sha512-XWumFEOHiWllekymZjeVgkQCJ4YnD8020ZspAHYIIBNX8O4d/1ldeU5iNXu6NGkKlOCokyXh13KwVP0UEMm5kw==} engines: {node: '>=18'} peerDependencies: @@ -2927,13 +2927,13 @@ packages: lodash-es: 4.17.21 mime: 4.0.0 p-filter: 3.0.0 - semantic-release: 22.0.8(typescript@5.3.3) + semantic-release: 22.0.9(typescript@5.3.3) url-join: 5.0.0 transitivePeerDependencies: - supports-color dev: true - /@semantic-release/npm@11.0.2(semantic-release@22.0.8): + /@semantic-release/npm@11.0.2(semantic-release@22.0.9): resolution: {integrity: sha512-owtf3RjyPvRE63iUKZ5/xO4uqjRpVQDUB9+nnXj0xwfIeM9pRl+cG+zGDzdftR4m3f2s4Wyf3SexW+kF5DFtWA==} engines: {node: ^18.17 || >=20} peerDependencies: @@ -2950,12 +2950,12 @@ packages: rc: 1.2.8 read-pkg: 9.0.1 registry-auth-token: 5.0.2 - semantic-release: 22.0.8(typescript@5.3.3) + semantic-release: 22.0.9(typescript@5.3.3) semver: 7.5.4 tempy: 3.1.0 dev: true - /@semantic-release/release-notes-generator@12.1.0(semantic-release@22.0.8): + /@semantic-release/release-notes-generator@12.1.0(semantic-release@22.0.9): resolution: {integrity: sha512-g6M9AjUKAZUZnxaJZnouNBeDNTCUrJ5Ltj+VJ60gJeDaRRahcHsry9HW8yKrnKkKNkx5lbWiEP1FPMqVNQz8Kg==} engines: {node: ^18.17 || >=20.6.1} peerDependencies: @@ -2971,7 +2971,7 @@ packages: into-stream: 7.0.0 lodash-es: 4.17.21 read-pkg-up: 11.0.0 - semantic-release: 22.0.8(typescript@5.3.3) + semantic-release: 22.0.9(typescript@5.3.3) transitivePeerDependencies: - supports-color dev: true @@ -5060,8 +5060,8 @@ packages: /core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} - /cosmiconfig@8.3.6(typescript@5.3.3): - resolution: {integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==} + /cosmiconfig@9.0.0(typescript@5.3.3): + resolution: {integrity: sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==} engines: {node: '>=14'} peerDependencies: typescript: '>=4.9.5' @@ -5069,10 +5069,10 @@ packages: typescript: optional: true dependencies: + env-paths: 2.2.1 import-fresh: 3.3.0 js-yaml: 4.1.0 parse-json: 5.2.0 - path-type: 4.0.0 typescript: 5.3.3 dev: true @@ -5459,8 +5459,6 @@ packages: resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} engines: {node: '>=6'} requiresBuild: true - dev: false - optional: true /err-code@2.0.3: resolution: {integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==} @@ -9462,18 +9460,18 @@ packages: resolution: {integrity: sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==} dev: false - /semantic-release@22.0.8(typescript@5.3.3): - resolution: {integrity: sha512-55rb31jygqIYsGU/rY+gXXm2fnxBIWo9azOjxbqKsPnq7p70zwZ5v+xnD7TxJC+zvS3sy1eHLGXYWCaX3WI76A==} + /semantic-release@22.0.9(typescript@5.3.3): + resolution: {integrity: sha512-4uDzd0r57oqExHsVad4LS86CagqEblCsWBZ3cZSxsWex4nkfLX0L+e5ImBDjeuzot1Ad8K3eE+Cm2OLJE7TsvQ==} engines: {node: ^18.17 || >=20.6.1} hasBin: true dependencies: - '@semantic-release/commit-analyzer': 11.1.0(semantic-release@22.0.8) + '@semantic-release/commit-analyzer': 11.1.0(semantic-release@22.0.9) '@semantic-release/error': 4.0.0 - '@semantic-release/github': 9.2.5(semantic-release@22.0.8) - '@semantic-release/npm': 11.0.2(semantic-release@22.0.8) - '@semantic-release/release-notes-generator': 12.1.0(semantic-release@22.0.8) + '@semantic-release/github': 9.2.5(semantic-release@22.0.9) + '@semantic-release/npm': 11.0.2(semantic-release@22.0.9) + '@semantic-release/release-notes-generator': 12.1.0(semantic-release@22.0.9) aggregate-error: 5.0.0 - cosmiconfig: 8.3.6(typescript@5.3.3) + cosmiconfig: 9.0.0(typescript@5.3.3) debug: 4.3.4 env-ci: 10.0.0 execa: 8.0.1 From 2d066fb3c88bedeef6d84cf113bb0af65ba441f0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 12 Dec 2023 07:36:50 +0000 Subject: [PATCH 016/173] build(deps): update dependency semantic-release to v22.0.12 (#26242) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 48 +++++++++++++++++++++++++----------------------- 2 files changed, 26 insertions(+), 24 deletions(-) diff --git a/package.json b/package.json index 0f828a3afaab42..7cb4c7ede05ac5 100644 --- a/package.json +++ b/package.json @@ -339,7 +339,7 @@ "nyc": "15.1.0", "pretty-format": "29.7.0", "rimraf": "5.0.5", - "semantic-release": "22.0.9", + "semantic-release": "22.0.12", "tar": "6.2.0", "tmp-promise": "3.0.3", "ts-jest": "29.1.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 801137e8f91fde..46c0536cea02df 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -360,7 +360,7 @@ importers: version: file:tools/eslint '@semantic-release/exec': specifier: 6.0.3 - version: 6.0.3(semantic-release@22.0.9) + version: 6.0.3(semantic-release@22.0.12) '@swc/core': specifier: 1.3.100 version: 1.3.100 @@ -581,8 +581,8 @@ importers: specifier: 5.0.5 version: 5.0.5 semantic-release: - specifier: 22.0.9 - version: 22.0.9(typescript@5.3.3) + specifier: 22.0.12 + version: 22.0.12(typescript@5.3.3) tar: specifier: 6.2.0 version: 6.2.0 @@ -2861,7 +2861,7 @@ packages: util: 0.12.5 dev: false - /@semantic-release/commit-analyzer@11.1.0(semantic-release@22.0.9): + /@semantic-release/commit-analyzer@11.1.0(semantic-release@22.0.12): resolution: {integrity: sha512-cXNTbv3nXR2hlzHjAMgbuiQVtvWHTlwwISt60B+4NZv01y/QRY7p2HcJm8Eh2StzcTJoNnflvKjHH/cjFS7d5g==} engines: {node: ^18.17 || >=20.6.1} peerDependencies: @@ -2874,7 +2874,7 @@ packages: import-from-esm: 1.3.3 lodash-es: 4.17.21 micromatch: 4.0.5 - semantic-release: 22.0.9(typescript@5.3.3) + semantic-release: 22.0.12(typescript@5.3.3) transitivePeerDependencies: - supports-color dev: true @@ -2889,7 +2889,7 @@ packages: engines: {node: '>=18'} dev: true - /@semantic-release/exec@6.0.3(semantic-release@22.0.9): + /@semantic-release/exec@6.0.3(semantic-release@22.0.12): resolution: {integrity: sha512-bxAq8vLOw76aV89vxxICecEa8jfaWwYITw6X74zzlO0mc/Bgieqx9kBRz9z96pHectiTAtsCwsQcUyLYWnp3VQ==} engines: {node: '>=14.17'} peerDependencies: @@ -2901,12 +2901,12 @@ packages: execa: 5.1.1 lodash: 4.17.21 parse-json: 5.2.0 - semantic-release: 22.0.9(typescript@5.3.3) + semantic-release: 22.0.12(typescript@5.3.3) transitivePeerDependencies: - supports-color dev: true - /@semantic-release/github@9.2.5(semantic-release@22.0.9): + /@semantic-release/github@9.2.5(semantic-release@22.0.12): resolution: {integrity: sha512-XWumFEOHiWllekymZjeVgkQCJ4YnD8020ZspAHYIIBNX8O4d/1ldeU5iNXu6NGkKlOCokyXh13KwVP0UEMm5kw==} engines: {node: '>=18'} peerDependencies: @@ -2927,13 +2927,13 @@ packages: lodash-es: 4.17.21 mime: 4.0.0 p-filter: 3.0.0 - semantic-release: 22.0.9(typescript@5.3.3) + semantic-release: 22.0.12(typescript@5.3.3) url-join: 5.0.0 transitivePeerDependencies: - supports-color dev: true - /@semantic-release/npm@11.0.2(semantic-release@22.0.9): + /@semantic-release/npm@11.0.2(semantic-release@22.0.12): resolution: {integrity: sha512-owtf3RjyPvRE63iUKZ5/xO4uqjRpVQDUB9+nnXj0xwfIeM9pRl+cG+zGDzdftR4m3f2s4Wyf3SexW+kF5DFtWA==} engines: {node: ^18.17 || >=20} peerDependencies: @@ -2950,12 +2950,12 @@ packages: rc: 1.2.8 read-pkg: 9.0.1 registry-auth-token: 5.0.2 - semantic-release: 22.0.9(typescript@5.3.3) + semantic-release: 22.0.12(typescript@5.3.3) semver: 7.5.4 tempy: 3.1.0 dev: true - /@semantic-release/release-notes-generator@12.1.0(semantic-release@22.0.9): + /@semantic-release/release-notes-generator@12.1.0(semantic-release@22.0.12): resolution: {integrity: sha512-g6M9AjUKAZUZnxaJZnouNBeDNTCUrJ5Ltj+VJ60gJeDaRRahcHsry9HW8yKrnKkKNkx5lbWiEP1FPMqVNQz8Kg==} engines: {node: ^18.17 || >=20.6.1} peerDependencies: @@ -2971,7 +2971,7 @@ packages: into-stream: 7.0.0 lodash-es: 4.17.21 read-pkg-up: 11.0.0 - semantic-release: 22.0.9(typescript@5.3.3) + semantic-release: 22.0.12(typescript@5.3.3) transitivePeerDependencies: - supports-color dev: true @@ -5060,8 +5060,8 @@ packages: /core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} - /cosmiconfig@9.0.0(typescript@5.3.3): - resolution: {integrity: sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==} + /cosmiconfig@8.3.6(typescript@5.3.3): + resolution: {integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==} engines: {node: '>=14'} peerDependencies: typescript: '>=4.9.5' @@ -5069,10 +5069,10 @@ packages: typescript: optional: true dependencies: - env-paths: 2.2.1 import-fresh: 3.3.0 js-yaml: 4.1.0 parse-json: 5.2.0 + path-type: 4.0.0 typescript: 5.3.3 dev: true @@ -5459,6 +5459,8 @@ packages: resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} engines: {node: '>=6'} requiresBuild: true + dev: false + optional: true /err-code@2.0.3: resolution: {integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==} @@ -9460,18 +9462,18 @@ packages: resolution: {integrity: sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==} dev: false - /semantic-release@22.0.9(typescript@5.3.3): - resolution: {integrity: sha512-4uDzd0r57oqExHsVad4LS86CagqEblCsWBZ3cZSxsWex4nkfLX0L+e5ImBDjeuzot1Ad8K3eE+Cm2OLJE7TsvQ==} + /semantic-release@22.0.12(typescript@5.3.3): + resolution: {integrity: sha512-0mhiCR/4sZb00RVFJIUlMuiBkW3NMpVIW2Gse7noqEMoFGkvfPPAImEQbkBV8xga4KOPP4FdTRYuLLy32R1fPw==} engines: {node: ^18.17 || >=20.6.1} hasBin: true dependencies: - '@semantic-release/commit-analyzer': 11.1.0(semantic-release@22.0.9) + '@semantic-release/commit-analyzer': 11.1.0(semantic-release@22.0.12) '@semantic-release/error': 4.0.0 - '@semantic-release/github': 9.2.5(semantic-release@22.0.9) - '@semantic-release/npm': 11.0.2(semantic-release@22.0.9) - '@semantic-release/release-notes-generator': 12.1.0(semantic-release@22.0.9) + '@semantic-release/github': 9.2.5(semantic-release@22.0.12) + '@semantic-release/npm': 11.0.2(semantic-release@22.0.12) + '@semantic-release/release-notes-generator': 12.1.0(semantic-release@22.0.12) aggregate-error: 5.0.0 - cosmiconfig: 9.0.0(typescript@5.3.3) + cosmiconfig: 8.3.6(typescript@5.3.3) debug: 4.3.4 env-ci: 10.0.0 execa: 8.0.1 From aa1f47c980b36dfd5532ae35956ecfa051d86bce Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 12 Dec 2023 07:37:54 +0000 Subject: [PATCH 017/173] chore(deps): update dependency @types/ini to v1.3.34 (#26243) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 7cb4c7ede05ac5..66422844177cd6 100644 --- a/package.json +++ b/package.json @@ -283,7 +283,7 @@ "@types/git-url-parse": "9.0.3", "@types/github-url-from-git": "1.5.3", "@types/global-agent": "2.1.3", - "@types/ini": "1.3.33", + "@types/ini": "1.3.34", "@types/js-yaml": "4.0.9", "@types/json-dup-key-validator": "1.0.2", "@types/linkify-markdown": "1.0.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 46c0536cea02df..9e7b2fa73eb96f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -413,8 +413,8 @@ importers: specifier: 2.1.3 version: 2.1.3 '@types/ini': - specifier: 1.3.33 - version: 1.3.33 + specifier: 1.3.34 + version: 1.3.34 '@types/js-yaml': specifier: 4.0.9 version: 4.0.9 @@ -3739,8 +3739,8 @@ packages: resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==} dev: false - /@types/ini@1.3.33: - resolution: {integrity: sha512-YZDzdPTDxy084i5eVxUKfAHLenhAMVHupzCIg1dzFJNs6xp/UGyWk+8Lp1YxoZH+Hvv7C9OcHEDPndSMwaPVsQ==} + /@types/ini@1.3.34: + resolution: {integrity: sha512-FafeLhwmWucTi31ZYg/6aHBZNyrogQ35aDvSW7zMAz3HMhUqQ4G/NBya8c5pe2jwoYsDFwra8O9/yZotong76g==} dev: true /@types/istanbul-lib-coverage@2.0.6: From 3c87df28830a54050856d7415ea0563c546dada2 Mon Sep 17 00:00:00 2001 From: Sergei Zharinov Date: Tue, 12 Dec 2023 04:39:06 -0300 Subject: [PATCH 018/173] refactor: Clarify `VersioningApi` validation methods (#26235) --- lib/modules/versioning/types.ts | 44 +++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/lib/modules/versioning/types.ts b/lib/modules/versioning/types.ts index 6c9807d7c30e6c..e9e686470eac9e 100644 --- a/lib/modules/versioning/types.ts +++ b/lib/modules/versioning/types.ts @@ -12,33 +12,51 @@ export interface VersioningApi { // validation /** - * Check whether the `version` is compatible with the `current` value - * constraint. + * Check whether the `input` is the valid version or range. + * + * For some managers, ranges are called "constraints","specifiers", "requirements", etc. + * We stick to the term "range" for all of it. */ - isCompatible(version: string, current?: string): boolean; + isValid(input: string): boolean; /** - * Check whether the `version` constraint is not a range, i.e. it only allows a - * single specific version. + * Check whether the `input` is a valid version. + * + * There is no direct way to determine whether the `input` is the range, + * but combination of `isVersion` and `isValid` can be used for that: + * + * `isValid(input) && !isVersion(input)` */ - isSingleVersion(version: string): boolean; + isVersion(input: string | undefined | null): boolean; /** - * Check whether the `version` is considered to be "stable". + * Check whether the `input` is the: + * + * 1. Version, or + * 2. Range with the special syntax of matching exactly one version: + * - `==1.2.3` or `===1.2.3` for Python, + * - `=1.2.3` for NPM, + * - `[1.2.3]` for Maven or NuGet. * - * Example: in SemVer the version must not have a pre-release marker. + * This is used to provide pinning functionality. */ - isStable(version: string): boolean; + isSingleVersion(input: string): boolean; /** - * Check whether the `input` is a valid version or a valid version range constraint. + * Check whether the `version` is considered to be "stable". */ - isValid(input: string): boolean; + isStable(version: string): boolean; /** - * Check whether the `input` is a valid version string. + * Determines whether the version is compatible with the current one, + * in some manager-dependent way. + * + * For most managers, all valid versions are compatible between each other. + * + * However, for example, Docker versions `1.2.3` and `1.2.4-alpine` are not compatible, + * i.e. `1.2.4-alpine` is not a valid upgrade for `1.2.3`. */ - isVersion(input: string | undefined | null): boolean; + isCompatible(version: string, current?: string): boolean; // digestion of version From eeb102490186144674bae3951eabda457f3b9950 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 12 Dec 2023 08:05:32 +0000 Subject: [PATCH 019/173] chore(deps): update ghcr.io/containerbase/devcontainer docker tag to v9.30.2 (#26245) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .devcontainer/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index b72bdf6676dae5..ebfc563ce0fdbf 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1 +1 @@ -FROM ghcr.io/containerbase/devcontainer:9.30.0 +FROM ghcr.io/containerbase/devcontainer:9.30.2 From 1fd0c5cb4d9ed5d9f06f953a168c2d027b563e8a Mon Sep 17 00:00:00 2001 From: Rhys Arkins Date: Tue, 12 Dec 2023 09:48:22 +0100 Subject: [PATCH 020/173] refactor: increase regex validation debugging (#26244) --- lib/config/validation.ts | 7 ++++++- lib/util/regex.ts | 4 +++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/config/validation.ts b/lib/config/validation.ts index 7e928b23b66b5e..d83a0694cedf68 100644 --- a/lib/config/validation.ts +++ b/lib/config/validation.ts @@ -1,4 +1,5 @@ import is from '@sindresorhus/is'; +import { logger } from '../logger'; import { allManagersList, getManagerList } from '../modules/manager'; import { isCustomManager } from '../modules/manager/custom'; import type { @@ -667,7 +668,11 @@ function validateRegexManagerFields( for (const matchString of customManager.matchStrings) { try { regEx(matchString); - } catch (e) { + } catch (err) { + logger.debug( + { err }, + 'customManager.matchStrings regEx validation error', + ); errors.push({ topic: 'Configuration Error', message: `Invalid regExp for ${currentPath}: \`${matchString}\``, diff --git a/lib/util/regex.ts b/lib/util/regex.ts index 64630d0f3cf671..60289ad1ee8643 100644 --- a/lib/util/regex.ts +++ b/lib/util/regex.ts @@ -49,9 +49,11 @@ export function regEx( } return instance; } catch (err) { + logger.trace({ err }, 'RegEx constructor error'); const error = new Error(CONFIG_VALIDATION); + error.validationMessage = err.message; error.validationSource = pattern.toString(); - error.validationError = `Invalid regular expression: ${pattern.toString()}`; + error.validationError = `Invalid regular expression (re2): ${pattern.toString()}`; throw error; } } From 79c7335712cd1bf0aca3d4ab845ba7c7a010d2f1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 12 Dec 2023 10:50:49 +0000 Subject: [PATCH 021/173] build(deps): update dependency @renovatebot/ruby-semver to v3.0.20 (#26247) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 66422844177cd6..3a2798819ecd8d 100644 --- a/package.json +++ b/package.json @@ -166,7 +166,7 @@ "@qnighy/marshal": "0.1.3", "@renovatebot/osv-offline": "1.3.10", "@renovatebot/pep440": "3.0.13", - "@renovatebot/ruby-semver": "3.0.19", + "@renovatebot/ruby-semver": "3.0.20", "@sindresorhus/is": "4.6.0", "@types/ms": "0.7.34", "@types/tmp": "0.2.6", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9e7b2fa73eb96f..2cee5073c562d1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -72,8 +72,8 @@ importers: specifier: 3.0.13 version: 3.0.13 '@renovatebot/ruby-semver': - specifier: 3.0.19 - version: 3.0.19 + specifier: 3.0.20 + version: 3.0.20 '@sindresorhus/is': specifier: 4.6.0 version: 4.6.0 @@ -2844,8 +2844,8 @@ packages: engines: {node: ^18.12.0 || >= 20.0.0, pnpm: ^8.6.11} dev: false - /@renovatebot/ruby-semver@3.0.19: - resolution: {integrity: sha512-VuTIcDyC6MDp7G8QCLVY28XlXZKXSe7eSfnweNxwqGrcMKONS5qFtvrj0ZxPo5mM685Z2P8S1f8p0dfdEiH+ow==} + /@renovatebot/ruby-semver@3.0.20: + resolution: {integrity: sha512-HOn6SWkSfbMNBPFa/Bqwb30LIoCwlxxYQihL2dqX2n+OPzSXT5ZmmTabFF6Gso65T3dc5g67Tdt57mICxmn3SQ==} engines: {node: ^18.12.0 || >= 20.0.0, pnpm: ^8.6.11} dev: false From 2677033e4401bff2df2062c6fd8fd82e3003f5e3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 12 Dec 2023 17:02:33 +0000 Subject: [PATCH 022/173] fix(deps): update ghcr.io/containerbase/sidecar docker tag to v9.30.2 (#26257) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- lib/config/options/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/config/options/index.ts b/lib/config/options/index.ts index 4adbd14ccbcbfc..5824df5d87c40d 100644 --- a/lib/config/options/index.ts +++ b/lib/config/options/index.ts @@ -380,7 +380,7 @@ const options: RenovateOptions[] = [ description: 'Change this value to override the default Renovate sidecar image.', type: 'string', - default: 'ghcr.io/containerbase/sidecar:9.30.0', + default: 'ghcr.io/containerbase/sidecar:9.30.2', globalOnly: true, }, { From 5ff18174495251d2e3e204be770547776a14fa9c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 12 Dec 2023 17:03:49 +0000 Subject: [PATCH 023/173] chore(deps): update github/codeql-action action to v2.22.10 (#26256) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/codeql-analysis.yml | 6 +++--- .github/workflows/scorecard.yml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 46141798cb498f..5fc59f8e477f53 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -39,7 +39,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@c0d1daa7f7e14667747d73a7dbbe8c074bc8bfe2 # v2.22.9 + uses: github/codeql-action/init@305f6546310b9203e892c28c1484e82977f4f63d # v2.22.10 with: languages: javascript @@ -49,7 +49,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@c0d1daa7f7e14667747d73a7dbbe8c074bc8bfe2 # v2.22.9 + uses: github/codeql-action/autobuild@305f6546310b9203e892c28c1484e82977f4f63d # v2.22.10 # ℹ️ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -63,4 +63,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@c0d1daa7f7e14667747d73a7dbbe8c074bc8bfe2 # v2.22.9 + uses: github/codeql-action/analyze@305f6546310b9203e892c28c1484e82977f4f63d # v2.22.10 diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 59eb40cbdcf8de..c00a69e5df5290 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -50,6 +50,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: 'Upload to code-scanning' - uses: github/codeql-action/upload-sarif@c0d1daa7f7e14667747d73a7dbbe8c074bc8bfe2 # v2.22.9 + uses: github/codeql-action/upload-sarif@305f6546310b9203e892c28c1484e82977f4f63d # v2.22.10 with: sarif_file: results.sarif From e1a6dd1e106453c4f039335062972dd1ef39252e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 12 Dec 2023 19:23:42 +0000 Subject: [PATCH 024/173] chore(deps): update ghcr.io/containerbase/devcontainer docker tag to v9.30.3 (#26261) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .devcontainer/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index ebfc563ce0fdbf..7c3bbdf9499baf 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1 +1 @@ -FROM ghcr.io/containerbase/devcontainer:9.30.2 +FROM ghcr.io/containerbase/devcontainer:9.30.3 From b52cfab3e5777831524ba9d4fae7f5bd514a615b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 13 Dec 2023 07:45:14 +0000 Subject: [PATCH 025/173] chore(deps): update dependency @types/diff to v5.0.9 (#26264) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 3a2798819ecd8d..5a647ed536acff 100644 --- a/package.json +++ b/package.json @@ -277,7 +277,7 @@ "@types/clean-git-ref": "2.0.2", "@types/common-tags": "1.8.4", "@types/conventional-commits-detector": "1.0.2", - "@types/diff": "5.0.8", + "@types/diff": "5.0.9", "@types/eslint": "8.44.8", "@types/fs-extra": "11.0.4", "@types/git-url-parse": "9.0.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2cee5073c562d1..95449f45486e94 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -395,8 +395,8 @@ importers: specifier: 1.0.2 version: 1.0.2 '@types/diff': - specifier: 5.0.8 - version: 5.0.8 + specifier: 5.0.9 + version: 5.0.9 '@types/eslint': specifier: 8.44.8 version: 8.44.8 @@ -3691,8 +3691,8 @@ packages: resolution: {integrity: sha512-Yzo8dW+b2vziyDD9WNY+IPq4rcZyguHNuyNZC3wv0igpVFRd7VWHufl+vRQaCzDR2ftPTB1VPwbvXxWVpzBo+g==} dev: true - /@types/diff@5.0.8: - resolution: {integrity: sha512-kR0gRf0wMwpxQq6ME5s+tWk9zVCfJUl98eRkD05HWWRbhPB/eu4V1IbyZAsvzC1Gn4znBJ0HN01M4DGXdBEV8Q==} + /@types/diff@5.0.9: + resolution: {integrity: sha512-RWVEhh/zGXpAVF/ZChwNnv7r4rvqzJ7lYNSmZSVTxjV0PBLf6Qu7RNg+SUtkpzxmiNkjCx0Xn2tPp7FIkshJwQ==} dev: true /@types/emscripten@1.39.10: From 15d3b4f02d2fd408d01a9e3965684247b4649547 Mon Sep 17 00:00:00 2001 From: Michael Kriese Date: Wed, 13 Dec 2023 09:02:00 +0100 Subject: [PATCH 026/173] chore: migrate vscode settings (#26265) --- .vscode/settings.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 42a102533e72a0..9e9e9e57616939 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -9,7 +9,7 @@ "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[md]": { - "editor.wordBasedSuggestions": false + "editor.wordBasedSuggestions": "off" }, "files.associations": { "Dockerfile.*": "dockerfile", @@ -21,6 +21,6 @@ "npm.packageManager": "pnpm", "editor.formatOnSave": true, "editor.codeActionsOnSave": { - "source.fixAll.eslint": true + "source.fixAll.eslint": "explicit" } } From 95c2a315c1f4fe44e8211c8aba8f340b43d5e7f5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 13 Dec 2023 08:09:25 +0000 Subject: [PATCH 027/173] build(deps): update dependency @renovatebot/pep440 to v3.0.14 (#26267) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 5a647ed536acff..b885a20bda4dcd 100644 --- a/package.json +++ b/package.json @@ -165,7 +165,7 @@ "@opentelemetry/semantic-conventions": "1.18.1", "@qnighy/marshal": "0.1.3", "@renovatebot/osv-offline": "1.3.10", - "@renovatebot/pep440": "3.0.13", + "@renovatebot/pep440": "3.0.14", "@renovatebot/ruby-semver": "3.0.20", "@sindresorhus/is": "4.6.0", "@types/ms": "0.7.34", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 95449f45486e94..063a7a3382aa28 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -69,8 +69,8 @@ importers: specifier: 1.3.10 version: 1.3.10 '@renovatebot/pep440': - specifier: 3.0.13 - version: 3.0.13 + specifier: 3.0.14 + version: 3.0.14 '@renovatebot/ruby-semver': specifier: 3.0.20 version: 3.0.20 @@ -2839,8 +2839,8 @@ packages: - encoding dev: false - /@renovatebot/pep440@3.0.13: - resolution: {integrity: sha512-lweg1JT8Eu4rN/l3t8KxOFakwGHOA72MUrfaUBc8ErAWE379H1vbykGitHxkJ/jFQe999FoaYIz9sI17exUE1w==} + /@renovatebot/pep440@3.0.14: + resolution: {integrity: sha512-ijhB6zyR20xUyhKR9zOy+9wBBAUD6D+LiBjbVMjMTF+8rEfPMA2mTGh+EJ0t44h8ysV41iKNzC0dQmYjxSw9BA==} engines: {node: ^18.12.0 || >= 20.0.0, pnpm: ^8.6.11} dev: false From fb3cba21122bc3d4c8157b79db11135621bb5c80 Mon Sep 17 00:00:00 2001 From: Michael Kriese Date: Wed, 13 Dec 2023 10:29:38 +0100 Subject: [PATCH 028/173] feat(datasource/kubernetes-api): add more flux versions (#26268) --- data/kubernetes-api.json5 | 43 +++++++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/data/kubernetes-api.json5 b/data/kubernetes-api.json5 index f84031941bcc94..19aa2e192e6307 100644 --- a/data/kubernetes-api.json5 +++ b/data/kubernetes-api.json5 @@ -110,17 +110,52 @@ // https://kubernetes.io/docs/reference/using-api/deprecation-guide/#v1-27 // https://kubernetes.io/docs/reference/using-api/deprecation-guide/#csistoragecapacity-v127 CSIStorageCapacity: ['storage.k8s.io/v1beta1', 'storage.k8s.io/v1'], - // https://github.com/fluxcd/flux2/releases/tag/v2.0.0 + + // https://fluxcd.io + Alert: [ + 'notification.toolkit.fluxcd.io/v1beta2', + 'notification.toolkit.fluxcd.io/v1beta3', + ], + Bucket: [ + 'source.toolkit.fluxcd.io/v1alpha1', + 'source.toolkit.fluxcd.io/v1beta1', + 'source.toolkit.fluxcd.io/v1beta2', + ], GitRepository: [ + 'source.toolkit.fluxcd.io/v1alpha1', + 'source.toolkit.fluxcd.io/v1beta1', 'source.toolkit.fluxcd.io/v1beta2', 'source.toolkit.fluxcd.io/v1', ], - Kustomization: [ - 'kustomize.toolkit.fluxcd.io/v1beta2', - 'kustomize.toolkit.fluxcd.io/v1', + HelmChart: [ + 'source.toolkit.fluxcd.io/v1alpha1', + 'source.toolkit.fluxcd.io/v1beta1', + ], + HelmRelease: [ + 'helm.toolkit.fluxcd.io/v2beta1', + 'helm.toolkit.fluxcd.io/v2beta2', + ], + HelmRepository: [ + 'source.toolkit.fluxcd.io/v1alpha1', + 'source.toolkit.fluxcd.io/v1beta1', + 'source.toolkit.fluxcd.io/v1beta2', + ], + ImageRepository: ['image.toolkit.fluxcd.io/v1beta2'], + OCIRepository: ['source.toolkit.fluxcd.io/v1beta2'], + Provider: [ + 'notification.toolkit.fluxcd.io/v1beta2', + 'notification.toolkit.fluxcd.io/v1beta3', ], Receiver: [ 'notification.toolkit.fluxcd.io/v1beta2', 'notification.toolkit.fluxcd.io/v1', ], + + // https://fluxcd.io/flux/components/kustomize/kustomizations + // https://kubectl.docs.kubernetes.io/references/kustomize/kustomization + Kustomization: [ + 'kustomize.toolkit.fluxcd.io/v1beta2', + 'kustomize.toolkit.fluxcd.io/v1', + 'kustomize.config.k8s.io/v1beta1', + ], } From 1604f50d94748821ab403197bfc2e118c0bdb40b Mon Sep 17 00:00:00 2001 From: HonkingGoose <34918129+HonkingGoose@users.noreply.github.com> Date: Wed, 13 Dec 2023 12:48:57 +0100 Subject: [PATCH 029/173] docs(gitlab bot security): rewrite (#26270) --- docs/usage/gitlab-bot-security.md | 59 ++++++++++++++++++------------- 1 file changed, 34 insertions(+), 25 deletions(-) diff --git a/docs/usage/gitlab-bot-security.md b/docs/usage/gitlab-bot-security.md index f44ad1bf7a3d02..1fd31351cc129c 100644 --- a/docs/usage/gitlab-bot-security.md +++ b/docs/usage/gitlab-bot-security.md @@ -4,25 +4,33 @@ title: GitLab bot security # GitLab bot security -You should understand GitLab's security model, before deciding to run a "bot" service like Renovate on GitLab, particularly the pipeline credentials. +Make sure you understand GitLab's security model, before you run a "bot" service like Renovate on GitLab, particularly the pipeline credentials. -**Important**: If you have any doubts or concerns about this content that could affect other users, please follow our [Security Policy](https://github.com/renovatebot/renovate/security/policy) and report them confidentially. + +!!! warning + If you have any doubts or concerns about this content that could affect other users, please follow our [Security Policy](https://github.com/renovatebot/renovate/security/policy) and report them confidentially. ## `CI_JOB_TOKEN` permissions -The concept of `CI_JOB_TOKEN` permissions was [overhauled in GitLab release 8.12](https://about.gitlab.com/releases/2016/09/22/gitlab-8-12-released/), jobs are now run with the permissions of the user account which _triggered_ the pipeline. +The concept of `CI_JOB_TOKEN` permissions was [overhauled in GitLab release 8.12](https://about.gitlab.com/releases/2016/09/22/gitlab-8-12-released/), jobs now run with the permissions of the user account which _triggered_ the pipeline. For security reasons the token was limited to read-only permissions and a limited set of API endpoints, but it’s been extended to allow [write access to the GitLab Package Registry](https://docs.gitlab.com/ee/api/index.html#gitlab-ci-job-token). -Any pipeline triggered by a user account thus has permissions to read any repository which that account has access to as well as publish packages to them. +Any pipeline triggered by a user account thus has permissions to: -With the current GitLab CI permissions model, you should avoid committing to any project which you don’t trust completely, because that project could maliciously steal repository data, publish fake releases, or spam releases. +- read any repository which that account has access to +- publish packages to them + +With the current GitLab CI permissions model, you should only commit to a project which you trust completely. +Because that project could maliciously steal repository data, publish fake releases, or spam releases. ## Risks of hosting a Renovate GitLab app/bot/service -The GitLab security model means that the risks of running a _public_ bot service on GitLab are too high, which is why the existing service has been suspended until an alternate security model is ready. +With GitLab's current security model, we find the risks of running a _public_ bot service like Renovate are too high. +Therefore we stopped hosting Renovate on GitLab, and are waiting for a better security model. -It's also important to remember that when accounts are invited into projects or groups on GitLab, acceptance happens automatically (which was a useful feature to leverage for a shared service). +You should remember that when accounts are invited into projects or groups on GitLab, acceptance happens automatically. +This was a useful feature to leverage for a shared service. -If you are running a self-hosted Renovate service, it is advisable to: +If you are running a self-hosted Renovate service, we recommend you: - Run a shared service only within projects which have shared visibility/security within the users, or which have a low risk that a user would try to gain access to a private project they don't otherwise have access to - If running with `autodiscover`, also configure a value for `autodiscoverFilter` so that the bot can't be invited to projects or groups you don't intend @@ -33,33 +41,34 @@ The following research notes may help you to assess the GitLab bot security risk ### Public projects only -If a bot service is run on public projects only, then the risk of private project data being accessed by unauthorized users is zero. -But malicious users can still spoof or spam packages to any other public project they are not a member of, so that rules out this approach for a public hosted service. +If you only run a bot service on _public_ projects, the risk of unauthorized users accessing private project data is zero. +But malicious users can still spoof or spam packages to any other public project they are not a member of, this rules out this approach for a public hosted service. A public-visibility-only bot service should be low risk for most self-hosted GitLab instances. -There is still a small problem that you can't _prevent_ users from inviting the bot into private projects if they are not aware of the risks of doing so. +But you _can't stop users_ from inviting the bot into _private_ projects by accident, which is risky. ### Project Access Tokens -[Project Access Tokens](https://docs.gitlab.com/ee/user/project/settings/project_access_tokens.html) are a recently added feature for GitLab. -The main downsides to their use for a shared bot service are: +[Project Access Tokens](https://docs.gitlab.com/ee/user/project/settings/project_access_tokens.html) (PATs) are a recently added feature for GitLab. +The main downsides to using PATs for a shared bot service are: -- It is not yet possible to [provision them through the API](https://gitlab.com/gitlab-org/gitlab/-/issues/238991), so project maintainers would need to provision a project bot account and then save it to Renovate manually and per-project -- Project Access Tokens are a paid-only feature for gitlab.com, which excludes a large percentage of the public service user base -- At the time of writing, there are still some issues with getting Project Access Tokens to trigger and authenticate CI -- Any service using such tokens would get MRs from a user like `@project_123_bot` which is less intuitive than `@renovate-bot` +- You can not [provision PATs through the API](https://gitlab.com/gitlab-org/gitlab/-/issues/238991), so project maintainers would need to provision a project bot account and then save it to Renovate manually and per-project +- PATs are a paid-only feature for gitlab.com, which prevents users on the free plan from using them +- At the time of writing, there are still some issues with getting PATs to trigger and authenticate CI +- Any service using PATs would get MRs from a user like `@project_123_bot` instead of `@renovate-bot` -The big benefit of Project Access Tokens is their limited scope, users with write access to one project cannot read/write to other projects. +The big benefit of PATs is their limited scope: users with write access to one project cannot read/write to other projects. ### Group Access Tokens Group Access Tokens are still in the planning stage, but may offer a more scalable way to manage a Renovate service. -Tokens could be provisioned into Renovate per-group and permissions/visibility would need to be kept uniform throughout the group to ensure escalation of privileges is not possible. +Tokens could be provisioned into Renovate per-group. +Permissions and visibility _must_ be kept uniform throughout the group to prevent a privilege escalation. -It should be noted though that many GitLab users _do not_ have uniform permissions/visibility throughout groups today, so this is a risk of Group Access Tokens in general. -Even [https://gitlab.com/gitlab-org](https://gitlab.com/gitlab-org) is a good example of how common it is to mix project visibility within a same group. +Many GitLab users _do not_ have uniform permissions and visibility throughout groups today, so this is a risk of Group Access Tokens in general. +The [`gitlab-org` organization on GitLab](https://gitlab.com/gitlab-org) shows how common it is to mix project visibility within a same group. -Similarly with Project Access Tokens, if they are a paid-only feature then it would exclude free users from using such a service. +And the same as with PATs, if Group Access Tokens becomes a paid feature then users on a free plan can't use the feature. ### Skipping CI @@ -77,13 +86,13 @@ Bot services are better if they are provisioned with a "bot identity" so that us ## Recommended migration -Until the hosted app can be reactivated, we recommend users migrate to use self-hosted pipelines to run Renovate. -Please see the [renovate-bot/renovate-runner README on GitLab](https://gitlab.com/renovate-bot/renovate-runner/-/blob/HEAD/README.md) for instructions on how to set this up as easily as possible. +Until we can safely reactivate the hosted app, we recommend users migrate to use self-hosted pipelines to run Renovate. +Read the [renovate-bot/renovate-runner README on GitLab](https://gitlab.com/renovate-bot/renovate-runner/-/blob/HEAD/README.md) to learn how. ## Status of the Renovate app for GitLab We're trying to find a workable design for the GitLab app, so we can enable it safely again. -If you have any ideas, open a [discussion](https://github.com/renovatebot/renovate/discussions) and let us know! +If you have any ideas, please open a [discussion](https://github.com/renovatebot/renovate/discussions) and let us know! GitLab introduced Group Access Tokens & API for paid & self-hosted instances, but a good permission setup/flow is still not possible. Check out [GitLab issue #346298](https://gitlab.com/gitlab-org/gitlab/-/issues/346298). From 78e66c3a44bbd9a86f909efefc41894513eb437a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 13 Dec 2023 12:04:27 +0000 Subject: [PATCH 030/173] build(deps): update dependency @renovatebot/ruby-semver to v3.0.21 (#26271) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index b885a20bda4dcd..16f3fdea400a1f 100644 --- a/package.json +++ b/package.json @@ -166,7 +166,7 @@ "@qnighy/marshal": "0.1.3", "@renovatebot/osv-offline": "1.3.10", "@renovatebot/pep440": "3.0.14", - "@renovatebot/ruby-semver": "3.0.20", + "@renovatebot/ruby-semver": "3.0.21", "@sindresorhus/is": "4.6.0", "@types/ms": "0.7.34", "@types/tmp": "0.2.6", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 063a7a3382aa28..585b03dec6cc77 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -72,8 +72,8 @@ importers: specifier: 3.0.14 version: 3.0.14 '@renovatebot/ruby-semver': - specifier: 3.0.20 - version: 3.0.20 + specifier: 3.0.21 + version: 3.0.21 '@sindresorhus/is': specifier: 4.6.0 version: 4.6.0 @@ -2844,8 +2844,8 @@ packages: engines: {node: ^18.12.0 || >= 20.0.0, pnpm: ^8.6.11} dev: false - /@renovatebot/ruby-semver@3.0.20: - resolution: {integrity: sha512-HOn6SWkSfbMNBPFa/Bqwb30LIoCwlxxYQihL2dqX2n+OPzSXT5ZmmTabFF6Gso65T3dc5g67Tdt57mICxmn3SQ==} + /@renovatebot/ruby-semver@3.0.21: + resolution: {integrity: sha512-Td3WoH5OE4CVyHuKM7c7aSrjPW49prHe6SLrshzdazEEPkjiPDB5/SznSFRImHzD1ox4LXCTi4hfFH1Necjjhg==} engines: {node: ^18.12.0 || >= 20.0.0, pnpm: ^8.6.11} dev: false From f9ae909058bb84487c205166810ae0a33a6f1495 Mon Sep 17 00:00:00 2001 From: rami3l Date: Wed, 13 Dec 2023 23:17:04 +0800 Subject: [PATCH 031/173] fix(cargo): fix handling of `x` and `x.y` versions (#26263) --- lib/modules/versioning/cargo/index.spec.ts | 14 +++++++++++++- lib/modules/versioning/cargo/index.ts | 15 +++++++++------ 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/lib/modules/versioning/cargo/index.spec.ts b/lib/modules/versioning/cargo/index.spec.ts index 7b474f42cd4177..e295365dc4954b 100644 --- a/lib/modules/versioning/cargo/index.spec.ts +++ b/lib/modules/versioning/cargo/index.spec.ts @@ -6,6 +6,14 @@ describe('modules/versioning/cargo/index', () => { ${'4.2.0'} | ${'4.2, >= 3.0, < 5.0.0'} | ${true} ${'4.2.0'} | ${'2.0, >= 3.0, < 5.0.0'} | ${false} ${'4.2.0'} | ${'4.2.0, < 4.2.4'} | ${true} + ${'4.2.0'} | ${'4.1'} | ${true} + ${'4.2.0'} | ${'4'} | ${true} + ${'4.2.0'} | ${'4.3'} | ${false} + ${'4.2.0'} | ${'5'} | ${false} + ${'0.4.2'} | ${'0.4'} | ${true} + ${'0.4.2'} | ${'0'} | ${true} + ${'0.4.2'} | ${'0.3'} | ${false} + ${'0.4.2'} | ${'1'} | ${false} ${'4.2.0'} | ${'4.3.0, 3.0.0'} | ${false} ${'4.2.0'} | ${'> 5.0.0, <= 6.0.0'} | ${false} `( @@ -121,7 +129,11 @@ describe('modules/versioning/cargo/index', () => { ${'5.0'} | ${'bump'} | ${'5.0.0'} | ${'5.0.7'} | ${'5.0'} ${'5.0'} | ${'bump'} | ${'5.0.0'} | ${'5.1.7'} | ${'5.1'} ${'5.0'} | ${'bump'} | ${'5.0.0'} | ${'6.1.7'} | ${'6.1'} - ${'5.0'} | ${'replace'} | ${'5.0.0'} | ${'6.1.7'} | ${'6.1'} + ${'0.5'} | ${'bump'} | ${'0.5.0'} | ${'0.5.1'} | ${'0.5'} + ${'0.5'} | ${'bump'} | ${'0.5.0'} | ${'0.6.1'} | ${'0.6'} + ${'5.0'} | ${'replace'} | ${'5.0.0'} | ${'5.1.7'} | ${'5.0'} + ${'5.0'} | ${'replace'} | ${'5.0.0'} | ${'6.1.7'} | ${'6.0'} + ${'0.5'} | ${'replace'} | ${'0.5.0'} | ${'0.6.1'} | ${'0.6'} ${'=1.0.0'} | ${'replace'} | ${'1.0.0'} | ${'1.1.0'} | ${'=1.1.0'} ${'1.0.*'} | ${'replace'} | ${'1.0.0'} | ${'1.1.0'} | ${'1.1.*'} ${'1.*'} | ${'replace'} | ${'1.0.0'} | ${'2.1.0'} | ${'2.*'} diff --git a/lib/modules/versioning/cargo/index.ts b/lib/modules/versioning/cargo/index.ts index 8a2dfeb447d819..6a0d88f4f38838 100644 --- a/lib/modules/versioning/cargo/index.ts +++ b/lib/modules/versioning/cargo/index.ts @@ -19,11 +19,10 @@ export const supportedRangeStrategies: RangeStrategy[] = [ const isVersion = (input: string): boolean => npm.isVersion(input); function convertToCaret(item: string): string { - // In Cargo, "1.2.3" doesn't mean exactly 1.2.3, it means >= 1.2.3 < 2.0.0 - if (isVersion(item)) { - // NOTE: Partial versions like '1.2' don't get converted to '^1.2' - // because isVersion('1.2') === false - // In cargo and in npm 1.2 is equivalent to 1.2.* so it is correct behavior. + // In Cargo, caret versions are used by default, so "1.2.3" actually means ^1.2.3. + // Similarly, "0.4" actually means ^0.4. + // See: https://doc.rust-lang.org/stable/cargo/reference/specifying-dependencies.html#caret-requirements + if (isVersion(item) || isVersion(item + '.0') || isVersion(item + '.0.0')) { return '^' + item.trim(); } return item.trim(); @@ -122,7 +121,11 @@ function getNewValue({ } // Try to reverse any caret we added if (newCargo.startsWith('^') && !currentValue.startsWith('^')) { - newCargo = newCargo.substring(1); + const withoutCaret = newCargo.substring(1); + // NOTE: We want the number of components in the new version to match the original. + // e.g. "5.0" should be updated to "6.0". + const components = currentValue.split('.').length; + newCargo = withoutCaret.split('.').slice(0, components).join('.'); } return newCargo; } From 74cb4ddc0409584a8d6262ed1d399a4fc7293f68 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 13 Dec 2023 15:28:47 +0000 Subject: [PATCH 032/173] fix(deps): update ghcr.io/containerbase/sidecar docker tag to v9.30.3 (#26279) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- lib/config/options/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/config/options/index.ts b/lib/config/options/index.ts index 5824df5d87c40d..bab96cece2086c 100644 --- a/lib/config/options/index.ts +++ b/lib/config/options/index.ts @@ -380,7 +380,7 @@ const options: RenovateOptions[] = [ description: 'Change this value to override the default Renovate sidecar image.', type: 'string', - default: 'ghcr.io/containerbase/sidecar:9.30.2', + default: 'ghcr.io/containerbase/sidecar:9.30.3', globalOnly: true, }, { From f99352582488d825701ffac67c929c55261e3484 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 13 Dec 2023 19:52:57 +0000 Subject: [PATCH 033/173] build(deps): update dependency graph-data-structure to v3.5.0 (#26282) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 16f3fdea400a1f..cf30e0abde6cfb 100644 --- a/package.json +++ b/package.json @@ -205,7 +205,7 @@ "good-enough-parser": "1.1.23", "google-auth-library": "9.4.1", "got": "11.8.6", - "graph-data-structure": "3.3.0", + "graph-data-structure": "3.5.0", "handlebars": "4.7.8", "ignore": "5.3.0", "ini": "4.1.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 585b03dec6cc77..ddcb439620f413 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -189,8 +189,8 @@ importers: specifier: 11.8.6 version: 11.8.6 graph-data-structure: - specifier: 3.3.0 - version: 3.3.0 + specifier: 3.5.0 + version: 3.5.0 handlebars: specifier: 4.7.8 version: 4.7.8 @@ -6448,8 +6448,8 @@ packages: /graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - /graph-data-structure@3.3.0: - resolution: {integrity: sha512-p5z0GZ3tm85kuB0iXFjLpbL9gNSFeDPPOyINhLQm6mVfHbLaj62LF9uB1tymcsxkHqLWLQSqGA0f/4/OepCdxA==} + /graph-data-structure@3.5.0: + resolution: {integrity: sha512-AAgjRtBZC1acIExgK2otv2LDdcYeZdQFKiEStXRDTyaVs6sUUaGUif05pCczTqAU4ny82NQtM1p5PK7AQEYgRA==} dev: false /grapheme-splitter@1.0.4: From afdca55004e1b3b6d9b4ad561b4bb39d6effc20f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 13 Dec 2023 22:46:53 +0000 Subject: [PATCH 034/173] chore(deps): update github/codeql-action action to v2.22.11 (#26284) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/codeql-analysis.yml | 6 +++--- .github/workflows/scorecard.yml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 5fc59f8e477f53..7cff17d2d599de 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -39,7 +39,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@305f6546310b9203e892c28c1484e82977f4f63d # v2.22.10 + uses: github/codeql-action/init@03e7845b7bfcd5e7fb63d1ae8c61b0e791134fab # v2.22.11 with: languages: javascript @@ -49,7 +49,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@305f6546310b9203e892c28c1484e82977f4f63d # v2.22.10 + uses: github/codeql-action/autobuild@03e7845b7bfcd5e7fb63d1ae8c61b0e791134fab # v2.22.11 # ℹ️ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -63,4 +63,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@305f6546310b9203e892c28c1484e82977f4f63d # v2.22.10 + uses: github/codeql-action/analyze@03e7845b7bfcd5e7fb63d1ae8c61b0e791134fab # v2.22.11 diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index c00a69e5df5290..f1729c17216602 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -50,6 +50,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: 'Upload to code-scanning' - uses: github/codeql-action/upload-sarif@305f6546310b9203e892c28c1484e82977f4f63d # v2.22.10 + uses: github/codeql-action/upload-sarif@03e7845b7bfcd5e7fb63d1ae8c61b0e791134fab # v2.22.11 with: sarif_file: results.sarif From 3aaa3e57e27f112a1f23d99c4580433fe4d8cb19 Mon Sep 17 00:00:00 2001 From: Sergei Zharinov Date: Thu, 14 Dec 2023 04:10:50 -0300 Subject: [PATCH 035/173] feat(http): Support for `Retry-After` header (#25859) Co-authored-by: Rhys Arkins Co-authored-by: HonkingGoose <34918129+HonkingGoose@users.noreply.github.com> Co-authored-by: Michael Kriese Co-authored-by: Sebastian Poxhofer --- docs/usage/configuration-options.md | 20 ++++ lib/config/options/index.ts | 11 ++ lib/types/host-rules.ts | 1 + lib/util/http/index.ts | 17 +-- lib/util/http/retry-after.spec.ts | 162 ++++++++++++++++++++++++++++ lib/util/http/retry-after.ts | 115 ++++++++++++++++++++ lib/util/http/types.ts | 3 +- 7 files changed, 322 insertions(+), 7 deletions(-) create mode 100644 lib/util/http/retry-after.spec.ts create mode 100644 lib/util/http/retry-after.ts diff --git a/docs/usage/configuration-options.md b/docs/usage/configuration-options.md index 34b8621470a5fb..8102ed15bc53b1 100644 --- a/docs/usage/configuration-options.md +++ b/docs/usage/configuration-options.md @@ -1768,6 +1768,26 @@ Example config: } ``` +### maxRetryAfter + +A remote host may return a `4xx` response with a `Retry-After` header value, which indicates that Renovate has been rate-limited. +Renovate may try to contact the host again after waiting a certain time, that's set by the host. +By default, Renovate tries again after the `Retry-After` header value has passed, up to a maximum of 60 seconds. +If the `Retry-After` value is more than 60 seconds, Renovate will abort the request instead of waiting. + +You can configure a different maximum value in seconds using `maxRetryAfter`: + +```json +{ + "hostRules": [ + { + "matchHost": "api.github.com", + "maxRetryAfter": 25 + } + ] +} +``` + ### dnsCache Enable got [dnsCache](https://github.com/sindresorhus/got/blob/v11.5.2/readme.md#dnsCache) support. diff --git a/lib/config/options/index.ts b/lib/config/options/index.ts index bab96cece2086c..c057b68f9b8666 100644 --- a/lib/config/options/index.ts +++ b/lib/config/options/index.ts @@ -2741,6 +2741,17 @@ const options: RenovateOptions[] = [ globalOnly: true, default: [], }, + { + name: 'maxRetryAfter', + description: + 'Maximum retry-after header value to wait for before retrying a failed request.', + type: 'integer', + default: 60, + stage: 'package', + parent: 'hostRules', + cli: false, + env: false, + }, ]; export function getOptions(): RenovateOptions[] { diff --git a/lib/types/host-rules.ts b/lib/types/host-rules.ts index c8b26a1358da58..e29576f4bd655f 100644 --- a/lib/types/host-rules.ts +++ b/lib/types/host-rules.ts @@ -11,6 +11,7 @@ export interface HostRuleSearchResult { enableHttp2?: boolean; concurrentRequestLimit?: number; maxRequestsPerSecond?: number; + maxRetryAfter?: number; dnsCache?: boolean; keepAlive?: boolean; diff --git a/lib/util/http/index.ts b/lib/util/http/index.ts index 7c3164438e9793..c675e378f5692e 100644 --- a/lib/util/http/index.ts +++ b/lib/util/http/index.ts @@ -15,6 +15,7 @@ import { applyAuthorization, removeAuthorization } from './auth'; import { hooks } from './hooks'; import { applyHostRule, findMatchingRule } from './host-rules'; import { getQueue } from './queue'; +import { getRetryAfter, wrapWithRetry } from './retry-after'; import { Throttle, getThrottle } from './throttle'; import type { GotJSONOptions, @@ -130,11 +131,14 @@ export class Http { protected hostType: string, options: HttpOptions = {}, ) { - this.options = merge(options, { context: { hostType } }); - - if (process.env.NODE_ENV === 'test') { - this.options.retry = 0; - } + const retryLimit = process.env.NODE_ENV === 'test' ? 0 : 2; + this.options = merge(options, { + context: { hostType }, + retry: { + limit: retryLimit, + maxRetryAfter: 0, // Don't rely on `got` retry-after handling, just let it fail and then we'll handle it + }, + }); } protected getThrottle(url: string): Throttle | null { @@ -226,7 +230,8 @@ export class Http { ? () => queue.add>(throttledTask) : throttledTask; - resPromise = queuedTask(); + const { maxRetryAfter = 60 } = hostRule; + resPromise = wrapWithRetry(queuedTask, url, getRetryAfter, maxRetryAfter); if (memCacheKey) { memCache.set(memCacheKey, resPromise); diff --git a/lib/util/http/retry-after.spec.ts b/lib/util/http/retry-after.spec.ts new file mode 100644 index 00000000000000..9535cfabb3328d --- /dev/null +++ b/lib/util/http/retry-after.spec.ts @@ -0,0 +1,162 @@ +import { RequestError } from 'got'; +import { getRetryAfter, wrapWithRetry } from './retry-after'; + +function requestError( + response: { + statusCode?: number; + headers?: Record; + } | null = null, +) { + const err = new RequestError('request error', {}, null as never); + if (response) { + (err as any).response = response; + } + return err; +} + +describe('util/http/retry-after', () => { + beforeEach(() => { + jest.useFakeTimers(); + }); + + afterEach(() => { + jest.useRealTimers(); + }); + + describe('wrapWithRetry', () => { + it('works', async () => { + const task = jest.fn(() => Promise.resolve(42)); + const res = await wrapWithRetry(task, 'foobar', () => null, 60); + expect(res).toBe(42); + expect(task).toHaveBeenCalledTimes(1); + }); + + it('throws', async () => { + const task = jest.fn(() => Promise.reject(new Error('error'))); + + await expect( + wrapWithRetry(task, 'http://example.com', () => null, 60), + ).rejects.toThrow('error'); + + expect(task).toHaveBeenCalledTimes(1); + }); + + it('retries', async () => { + const task = jest + .fn() + .mockRejectedValueOnce(new Error('error-1')) + .mockRejectedValueOnce(new Error('error-2')) + .mockResolvedValueOnce(42); + + const p = wrapWithRetry(task, 'http://example.com', () => 1, 60); + await jest.advanceTimersByTimeAsync(2000); + + const res = await p; + expect(res).toBe(42); + expect(task).toHaveBeenCalledTimes(3); + }); + + it('gives up after max retries', async () => { + const task = jest + .fn() + .mockRejectedValueOnce('error-1') + .mockRejectedValueOnce('error-2') + .mockRejectedValueOnce('error-3') + .mockRejectedValue('error-4'); + + const p = wrapWithRetry(task, 'http://example.com', () => 1, 60).catch( + (err) => err, + ); + await jest.advanceTimersByTimeAsync(2000); + + await expect(p).resolves.toBe('error-3'); + expect(task).toHaveBeenCalledTimes(3); + }); + + it('gives up when delay exceeds maxRetryAfter', async () => { + const task = jest.fn().mockRejectedValue('error'); + + const p = wrapWithRetry(task, 'http://example.com', () => 61, 60).catch( + (err) => err, + ); + + await expect(p).resolves.toBe('error'); + expect(task).toHaveBeenCalledTimes(1); + }); + }); + + describe('getRetryAfter', () => { + it('returns null for non-RequestError', () => { + expect(getRetryAfter(new Error())).toBeNull(); + }); + + it('returns null for RequestError without response', () => { + expect(getRetryAfter(requestError())).toBeNull(); + }); + + it('returns null for status other than 429', () => { + const err = new RequestError('request-error', {}, null as never); + (err as any).response = { statusCode: 302 }; + expect(getRetryAfter(requestError({ statusCode: 302 }))).toBeNull(); + }); + + it('returns null missing "retry-after" header', () => { + expect( + getRetryAfter(requestError({ statusCode: 429, headers: {} })), + ).toBeNull(); + }); + + it('returns null for non-integer "retry-after" header', () => { + expect( + getRetryAfter( + requestError({ + statusCode: 429, + headers: { + 'retry-after': 'Wed, 21 Oct 2015 07:28:00 GMT', + }, + }), + ), + ).toBeNull(); + }); + + it('returns delay in seconds from date', () => { + jest.setSystemTime(new Date('2020-01-01T00:00:00Z')); + expect( + getRetryAfter( + requestError({ + statusCode: 429, + headers: { + 'retry-after': 'Wed, 01 Jan 2020 00:00:42 GMT', + }, + }), + ), + ).toBe(42); + }); + + it('returns delay in seconds from number', () => { + expect( + getRetryAfter( + requestError({ + statusCode: 429, + headers: { + 'retry-after': '42', + }, + }), + ), + ).toBe(42); + }); + + it('returns null for invalid header value', () => { + expect( + getRetryAfter( + requestError({ + statusCode: 429, + headers: { + 'retry-after': 'invalid', + }, + }), + ), + ).toBeNull(); + }); + }); +}); diff --git a/lib/util/http/retry-after.ts b/lib/util/http/retry-after.ts new file mode 100644 index 00000000000000..6cde4ae33a1d85 --- /dev/null +++ b/lib/util/http/retry-after.ts @@ -0,0 +1,115 @@ +import { setTimeout } from 'timers/promises'; +import { RequestError } from 'got'; +import { DateTime } from 'luxon'; +import { logger } from '../../logger'; +import { parseUrl } from '../url'; +import type { Task } from './types'; + +const hostDelays = new Map>(); + +const maxRetries = 2; + +/** + * Given a task that returns a promise, retry the task if it fails with a + * 429 Too Many Requests or 403 Forbidden response, using the Retry-After + * header to determine the delay. + * + * For response codes other than 429 or 403, or if the Retry-After header + * is not present or invalid, the task is not retried, throwing the error. + */ +export async function wrapWithRetry( + task: Task, + url: string, + getRetryAfter: (err: unknown) => number | null, + maxRetryAfter: number, +): Promise { + const key = parseUrl(url)?.host ?? url; + + let retries = 0; + for (;;) { + try { + await hostDelays.get(key); + hostDelays.delete(key); + + return await task(); + } catch (err) { + const delaySeconds = getRetryAfter(err); + if (delaySeconds === null) { + throw err; + } + + if (retries === maxRetries) { + logger.debug( + `Retry-After: reached maximum retries (${maxRetries}) for ${url}`, + ); + throw err; + } + + if (delaySeconds > maxRetryAfter) { + logger.debug( + `Retry-After: delay ${delaySeconds} seconds exceeds maxRetryAfter ${maxRetryAfter} seconds for ${url}`, + ); + throw err; + } + + logger.debug( + `Retry-After: will retry ${url} after ${delaySeconds} seconds`, + ); + + const delay = Promise.all([ + hostDelays.get(key), + setTimeout(1000 * delaySeconds), + ]); + hostDelays.set(key, delay); + retries += 1; + } + } +} + +export function getRetryAfter(err: unknown): number | null { + if (!(err instanceof RequestError)) { + return null; + } + + if (!err.response) { + return null; + } + + if (err.response.statusCode < 400 || err.response.statusCode >= 500) { + logger.warn( + { url: err.response.url }, + `Retry-After: unexpected status code ${err.response.statusCode}`, + ); + return null; + } + + const retryAfter = err.response.headers['retry-after']?.trim(); + if (!retryAfter) { + return null; + } + + const date = DateTime.fromHTTP(retryAfter); + if (date.isValid) { + const seconds = Math.floor(date.diffNow('seconds').seconds); + if (seconds < 0) { + logger.debug( + { url: err.response.url, retryAfter }, + 'Retry-After: date in the past', + ); + return null; + } + + return seconds; + } + + const seconds = parseInt(retryAfter, 10); + if (!Number.isNaN(seconds) && seconds > 0) { + return seconds; + } + + logger.debug( + { url: err.response.url, retryAfter }, + 'Retry-After: unsupported format', + ); + return null; +} diff --git a/lib/util/http/types.ts b/lib/util/http/types.ts index 4f576ef17a1788..86b5366ac53b64 100644 --- a/lib/util/http/types.ts +++ b/lib/util/http/types.ts @@ -92,4 +92,5 @@ export interface HttpResponse { authorization?: boolean; } -export type GotTask = () => Promise>; +export type Task = () => Promise; +export type GotTask = Task>; From 4cc34429c3164beacbfed75c2d7df9c3f49ffe55 Mon Sep 17 00:00:00 2001 From: Sebastian Poxhofer Date: Thu, 14 Dec 2023 08:12:58 +0100 Subject: [PATCH 036/173] fix(manager/terraform): missing accuracy for ranges (#26283) --- .../manager/terraform/lockfile/index.spec.ts | 13 +++++++++ .../manager/terraform/lockfile/index.ts | 12 ++++++-- .../manager/terraform/lockfile/util.ts | 28 +++++++++++++++++++ 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/lib/modules/manager/terraform/lockfile/index.spec.ts b/lib/modules/manager/terraform/lockfile/index.spec.ts index fb1eb92b9f3e2b..a49a2dadd1e6de 100644 --- a/lib/modules/manager/terraform/lockfile/index.spec.ts +++ b/lib/modules/manager/terraform/lockfile/index.spec.ts @@ -1117,5 +1117,18 @@ describe('modules/manager/terraform/lockfile/index', () => { ), ).toBe('>= 2.36.0, 2.46.0'); }); + + it('create constraint with full version', () => { + expect( + getNewConstraint( + { + currentValue: '>= 4.0, <4.12', + newValue: '< 4.21', + newVersion: '4.20.0', + }, + '>= 4.0.0, < 4.12.0', + ), + ).toBe('< 4.21.0'); + }); }); }); diff --git a/lib/modules/manager/terraform/lockfile/index.ts b/lib/modules/manager/terraform/lockfile/index.ts index 53c6ae7e3388a5..70f9e8739ee9d4 100644 --- a/lib/modules/manager/terraform/lockfile/index.ts +++ b/lib/modules/manager/terraform/lockfile/index.ts @@ -17,6 +17,7 @@ import { extractLocks, findLockFile, isPinnedVersion, + massageNewValue, readLockFile, writeLockUpdates, } from './util'; @@ -70,8 +71,15 @@ export function getNewConstraint( dep: Upgrade>, oldConstraint: string | undefined, ): string | undefined { - const { currentValue, currentVersion, newValue, newVersion, packageName } = - dep; + const { + currentValue, + currentVersion, + newValue: rawNewValue, + newVersion, + packageName, + } = dep; + + const newValue = massageNewValue(rawNewValue); if (oldConstraint && currentValue && newValue && currentValue === newValue) { logger.debug( diff --git a/lib/modules/manager/terraform/lockfile/util.ts b/lib/modules/manager/terraform/lockfile/util.ts index b3193ec1e0f479..cb3c0079baa335 100644 --- a/lib/modules/manager/terraform/lockfile/util.ts +++ b/lib/modules/manager/terraform/lockfile/util.ts @@ -1,3 +1,4 @@ +import is from '@sindresorhus/is'; import { findLocalSiblingOrParent, readLocalFile } from '../../../../util/fs'; import { newlineRegex, regEx } from '../../../../util/regex'; import { get as getVersioning } from '../../../versioning'; @@ -225,3 +226,30 @@ export function writeLockUpdates( }, }; } + +export function massageNewValue(value: string | undefined): string | undefined { + if (is.nullOrUndefined(value)) { + return value; + } + + const elements = value.split(','); + const massagedElements: string[] = []; + for (const element of elements) { + // these constraints are allowed to miss precision + if (element.includes('~>')) { + massagedElements.push(element); + continue; + } + + const missing0s = 3 - element.split('.').length; + + let massagedElement = element; + + for (let i = 0; i < missing0s; i++) { + massagedElement = `${massagedElement}.0`; + } + massagedElements.push(massagedElement); + } + + return massagedElements.join(','); +} From e9f6edb4ca875d51e8c927749098afe8dbe624ff Mon Sep 17 00:00:00 2001 From: Maxime Brunet Date: Wed, 13 Dec 2023 23:16:13 -0800 Subject: [PATCH 037/173] fix(dashboard): improve note (#26281) --- lib/modules/platform/github/index.ts | 1 + lib/workers/repository/dependency-dashboard.spec.ts | 2 +- lib/workers/repository/package-files.ts | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/modules/platform/github/index.ts b/lib/modules/platform/github/index.ts index bb28ec791fff09..fcc2a2d55cd5b5 100644 --- a/lib/modules/platform/github/index.ts +++ b/lib/modules/platform/github/index.ts @@ -1823,6 +1823,7 @@ export function massageMarkdown(input: string): string { ) .replace(regEx(/]\(https:\/\/github\.com\//g), '](https://togithub.com/') .replace(regEx(/]: https:\/\/github\.com\//g), ']: https://togithub.com/') + .replace('> ℹ **Note**\n> \n', '> [!NOTE]\n') .replace('> ⚠ **Warning**\n> \n', '> [!WARNING]\n') .replace('> ❗ **Important**\n> \n', '> [!IMPORTANT]\n'); return smartTruncate(massagedInput, GitHubMaxPrBodyLen); diff --git a/lib/workers/repository/dependency-dashboard.spec.ts b/lib/workers/repository/dependency-dashboard.spec.ts index 38ae078cd04d17..a0d6ffc8d870cc 100644 --- a/lib/workers/repository/dependency-dashboard.spec.ts +++ b/lib/workers/repository/dependency-dashboard.spec.ts @@ -1036,7 +1036,7 @@ describe('workers/repository/dependency-dashboard', () => { describe('PackageFiles.getDashboardMarkdown()', () => { const note = - '> **Note**\n\n> Detected dependencies section has been truncated\n'; + '> ℹ **Note**\n> \n> Detected dependencies section has been truncated\n\n'; const title = `## Detected dependencies\n\n`; beforeEach(() => { diff --git a/lib/workers/repository/package-files.ts b/lib/workers/repository/package-files.ts index 3dd16047f9d331..73614ef881ea63 100644 --- a/lib/workers/repository/package-files.ts +++ b/lib/workers/repository/package-files.ts @@ -33,7 +33,7 @@ export class PackageFiles { */ static getDashboardMarkdown(maxLength: number, setHeader = true): string { const note = - '> **Note**\n\n> Detected dependencies section has been truncated\n'; + '> ℹ **Note**\n> \n> Detected dependencies section has been truncated\n\n'; const title = `## Detected dependencies\n\n`; // exclude header length from the available space From e1dd622a9b9452dea159c311f5c54d3753f0511a Mon Sep 17 00:00:00 2001 From: joegoldman2 <147369450+joegoldman2@users.noreply.github.com> Date: Thu, 14 Dec 2023 09:17:43 +0200 Subject: [PATCH 038/173] feat(presets): add grpc-dotnet monorepo (#26285) --- lib/config/presets/internal/monorepo.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/config/presets/internal/monorepo.ts b/lib/config/presets/internal/monorepo.ts index 00fda759abf9bb..c47ae0abb504ed 100644 --- a/lib/config/presets/internal/monorepo.ts +++ b/lib/config/presets/internal/monorepo.ts @@ -299,6 +299,7 @@ const repoGroups = { 'https://github.com/dotansimha/graphql-codegen', ], groovy: 'https://github.com/apache/groovy', + 'grpc-dotnet': 'https://github.com/grpc/grpc-dotnet', guava: 'https://github.com/google/guava', Hangfire: 'https://github.com/HangfireIO/Hangfire', 'hickory-dns': 'https://github.com/hickory-dns/hickory-dns', From 9474f9a5d75bed9d2531b4479d4efdb27f858640 Mon Sep 17 00:00:00 2001 From: Michael Kriese Date: Thu, 14 Dec 2023 08:18:12 +0100 Subject: [PATCH 039/173] fix(repo-cache): pass relative paths to fs layer (#26227) --- lib/util/cache/repository/impl/local.spec.ts | 2 +- lib/util/cache/repository/impl/local.ts | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/util/cache/repository/impl/local.spec.ts b/lib/util/cache/repository/impl/local.spec.ts index a30907ec273281..3362f4034ad728 100644 --- a/lib/util/cache/repository/impl/local.spec.ts +++ b/lib/util/cache/repository/impl/local.spec.ts @@ -188,7 +188,7 @@ describe('util/cache/repository/impl/local', () => { `Repository cache type not supported using type "local" instead`, ); expect(fs.outputCacheFile).toHaveBeenCalledWith( - '/tmp/cache/renovate/repository/github/some/repo.json', + 'renovate/repository/github/some/repo.json', JSON.stringify(newCacheRecord), ); }); diff --git a/lib/util/cache/repository/impl/local.ts b/lib/util/cache/repository/impl/local.ts index c2d485b6803a29..530dbabc80243d 100644 --- a/lib/util/cache/repository/impl/local.ts +++ b/lib/util/cache/repository/impl/local.ts @@ -1,5 +1,4 @@ import upath from 'upath'; -import { GlobalConfig } from '../../../../config/global'; import { logger } from '../../../../logger'; import { cachePathExists, outputCacheFile, readCacheFile } from '../../../fs'; import type { RepoCacheRecord } from '../schema'; @@ -30,10 +29,9 @@ export class RepoCacheLocal extends RepoCacheBase { } private getCacheFileName(): string { - const cacheDir = GlobalConfig.get('cacheDir'); - const repoCachePath = '/renovate/repository/'; + const repoCachePath = 'renovate/repository/'; const platform = this.platform; const fileName = `${this.repository}.json`; - return upath.join(cacheDir, repoCachePath, platform, fileName); + return upath.join(repoCachePath, platform, fileName); } } From 9ed6d0fcb26ff6825e74c5598c20e8f7c6d856b6 Mon Sep 17 00:00:00 2001 From: Rhys Arkins Date: Thu, 14 Dec 2023 08:34:42 +0100 Subject: [PATCH 040/173] fix(cargo): get extraEnv for precise updates (#26273) --- lib/modules/manager/cargo/artifacts.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/modules/manager/cargo/artifacts.ts b/lib/modules/manager/cargo/artifacts.ts index 4ca7aabc5f1ca4..7fa9ced9db4f4b 100644 --- a/lib/modules/manager/cargo/artifacts.ts +++ b/lib/modules/manager/cargo/artifacts.ts @@ -59,6 +59,7 @@ async function cargoUpdatePrecise( } const execOptions: ExecOptions = { + extraEnv: { ...getGitEnvironmentVariables(['cargo']) }, docker: {}, toolConstraints: [{ toolName: 'rust', constraint }], }; From a913538d330ccee5c7d6762a9b53a902d74c9c07 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 14 Dec 2023 08:49:19 +0000 Subject: [PATCH 041/173] chore(deps): update ghcr.io/containerbase/devcontainer docker tag to v9.30.4 (#26291) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .devcontainer/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 7c3bbdf9499baf..83a81ac05c6046 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1 +1 @@ -FROM ghcr.io/containerbase/devcontainer:9.30.3 +FROM ghcr.io/containerbase/devcontainer:9.30.4 From eef1eedb45c3b3a1c95bfaa4fab3d8661882a7c7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 14 Dec 2023 08:52:21 +0000 Subject: [PATCH 042/173] chore(deps): update dependency @types/node to v18.19.3 (#26290) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 104 ++++++++++++++++++++++++------------------------- 2 files changed, 53 insertions(+), 53 deletions(-) diff --git a/package.json b/package.json index cf30e0abde6cfb..5100f925f7f850 100644 --- a/package.json +++ b/package.json @@ -295,7 +295,7 @@ "@types/mdast": "3.0.15", "@types/moo": "0.5.9", "@types/nock": "10.0.3", - "@types/node": "18.19.2", + "@types/node": "18.19.3", "@types/parse-link-header": "2.0.3", "@types/prettier": "2.7.3", "@types/semver": "7.5.6", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ddcb439620f413..57370367c81a69 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -449,8 +449,8 @@ importers: specifier: 10.0.3 version: 10.0.3 '@types/node': - specifier: 18.19.2 - version: 18.19.2 + specifier: 18.19.3 + version: 18.19.3 '@types/parse-link-header': specifier: 2.0.3 version: 2.0.3 @@ -546,7 +546,7 @@ importers: version: 8.0.3 jest: specifier: 29.7.0 - version: 29.7.0(@types/node@18.19.2)(ts-node@10.9.1) + version: 29.7.0(@types/node@18.19.3)(ts-node@10.9.1) jest-extended: specifier: 4.0.2 version: 4.0.2(jest@29.7.0) @@ -594,7 +594,7 @@ importers: version: 29.1.1(@babel/core@7.23.5)(@jest/types@29.6.3)(jest@29.7.0)(typescript@5.3.3) ts-node: specifier: 10.9.1 - version: 10.9.1(@swc/core@1.3.100)(@types/node@18.19.2)(typescript@5.3.3) + version: 10.9.1(@swc/core@1.3.100)(@types/node@18.19.3)(typescript@5.3.3) type-fest: specifier: 4.8.3 version: 4.8.3 @@ -2025,7 +2025,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.6.3 - '@types/node': 18.19.2 + '@types/node': 18.19.3 chalk: 4.1.2 jest-message-util: 29.7.0 jest-util: 29.7.0 @@ -2046,14 +2046,14 @@ packages: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 18.19.2 + '@types/node': 18.19.3 ansi-escapes: 4.3.2 chalk: 4.1.2 ci-info: 3.9.0 exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@18.19.2)(ts-node@10.9.1) + jest-config: 29.7.0(@types/node@18.19.3)(ts-node@10.9.1) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -2081,7 +2081,7 @@ packages: dependencies: '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 18.19.2 + '@types/node': 18.19.3 jest-mock: 29.7.0 dev: true @@ -2115,7 +2115,7 @@ packages: dependencies: '@jest/types': 29.6.3 '@sinonjs/fake-timers': 10.3.0 - '@types/node': 18.19.2 + '@types/node': 18.19.3 jest-message-util: 29.7.0 jest-mock: 29.7.0 jest-util: 29.7.0 @@ -2148,7 +2148,7 @@ packages: '@jest/transform': 29.7.0 '@jest/types': 29.6.3 '@jridgewell/trace-mapping': 0.3.20 - '@types/node': 18.19.2 + '@types/node': 18.19.3 chalk: 4.1.2 collect-v8-coverage: 1.0.2 exit: 0.1.2 @@ -2236,7 +2236,7 @@ packages: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 18.19.2 + '@types/node': 18.19.3 '@types/yargs': 17.0.32 chalk: 4.1.2 dev: true @@ -3608,7 +3608,7 @@ packages: /@types/aws4@1.11.6: resolution: {integrity: sha512-5CnVUkHNyLGpD9AnOcK66YyP0qvIh6nhJJoeK8zSl5YKikUcUbdB7SlHevUYVqicgeh6j5AJa1qa/h08dSZHoA==} dependencies: - '@types/node': 18.19.2 + '@types/node': 18.19.3 dev: true /@types/babel__core@7.20.5: @@ -3647,19 +3647,19 @@ packages: /@types/bunyan@1.8.11: resolution: {integrity: sha512-758fRH7umIMk5qt5ELmRMff4mLDlN+xyYzC+dkPTdKwbSkJFvz6xwyScrytPU0QIBbRRwbiE8/BIg8bpajerNQ==} dependencies: - '@types/node': 18.19.2 + '@types/node': 18.19.3 dev: true /@types/bunyan@1.8.9: resolution: {integrity: sha512-ZqS9JGpBxVOvsawzmVt30sP++gSQMTejCkIAQ3VdadOcRE8izTyW66hufvwLeH+YEGP6Js2AW7Gz+RMyvrEbmw==} dependencies: - '@types/node': 18.19.2 + '@types/node': 18.19.3 dev: false /@types/cacache@17.0.2: resolution: {integrity: sha512-IrqHzVX2VRMDQQKa7CtKRnuoCLdRJiLW6hWU+w7i7+AaQ0Ii5bKwJxd5uRK4zBCyrHd3tG6G8zOm2LplxbSfQg==} dependencies: - '@types/node': 18.19.2 + '@types/node': 18.19.3 dev: true /@types/cacheable-request@6.0.3: @@ -3667,7 +3667,7 @@ packages: dependencies: '@types/http-cache-semantics': 4.0.4 '@types/keyv': 3.1.4 - '@types/node': 18.19.2 + '@types/node': 18.19.3 '@types/responselike': 1.0.3 dev: false @@ -3714,7 +3714,7 @@ packages: resolution: {integrity: sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==} dependencies: '@types/jsonfile': 6.1.4 - '@types/node': 18.19.2 + '@types/node': 18.19.3 dev: true /@types/git-url-parse@9.0.3: @@ -3732,7 +3732,7 @@ packages: /@types/graceful-fs@4.1.9: resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} dependencies: - '@types/node': 18.19.2 + '@types/node': 18.19.3 dev: true /@types/http-cache-semantics@4.0.4: @@ -3778,13 +3778,13 @@ packages: /@types/jsonfile@6.1.4: resolution: {integrity: sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==} dependencies: - '@types/node': 18.19.2 + '@types/node': 18.19.3 dev: true /@types/keyv@3.1.4: resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} dependencies: - '@types/node': 18.19.2 + '@types/node': 18.19.3 dev: false /@types/linkify-it@3.0.5: @@ -3817,7 +3817,7 @@ packages: /@types/marshal@0.5.3: resolution: {integrity: sha512-ptxKIirn/lt95Zi/MErrtn/K8VvrByNOAF9gxbIJCxWj9CXAifjAvm/bRMg7WXQjwi1DlbXG6HJ1RzHe6oYEug==} dependencies: - '@types/node': 18.19.2 + '@types/node': 18.19.3 dev: true /@types/mdast@3.0.15: @@ -3848,11 +3848,11 @@ packages: /@types/nock@10.0.3: resolution: {integrity: sha512-OthuN+2FuzfZO3yONJ/QVjKmLEuRagS9TV9lEId+WHL9KhftYG+/2z+pxlr0UgVVXSpVD8woie/3fzQn8ft/Ow==} dependencies: - '@types/node': 18.19.2 + '@types/node': 18.19.3 dev: true - /@types/node@18.19.2: - resolution: {integrity: sha512-6wzfBdbWpe8QykUkXBjtmO3zITA0A3FIjoy+in0Y2K4KrCiRhNYJIdwAPDffZ3G6GnaKaSLSEa9ZuORLfEoiwg==} + /@types/node@18.19.3: + resolution: {integrity: sha512-k5fggr14DwAytoA/t8rPrIz++lXK7/DqckthCmoZOKNsEbJkId4Z//BqgApXBUGrGddrigYa1oqheo/7YmW4rg==} dependencies: undici-types: 5.26.5 @@ -3870,7 +3870,7 @@ packages: /@types/responselike@1.0.3: resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==} dependencies: - '@types/node': 18.19.2 + '@types/node': 18.19.3 dev: false /@types/semver-stable@3.0.2: @@ -3905,7 +3905,7 @@ packages: /@types/tar@6.1.10: resolution: {integrity: sha512-60ZO+W0tRKJ3ggdzJKp75xKVlNogKYMqGvr2bMH/+k3T0BagfYTnbmVDFMJB1BFttz6yRgP5MDGP27eh7brrqw==} dependencies: - '@types/node': 18.19.2 + '@types/node': 18.19.3 minipass: 4.2.8 dev: true @@ -3950,7 +3950,7 @@ packages: resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} requiresBuild: true dependencies: - '@types/node': 18.19.2 + '@types/node': 18.19.3 dev: false optional: true @@ -5076,7 +5076,7 @@ packages: typescript: 5.3.3 dev: true - /create-jest@29.7.0(@types/node@18.19.2)(ts-node@10.9.1): + /create-jest@29.7.0(@types/node@18.19.3)(ts-node@10.9.1): resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -5085,7 +5085,7 @@ packages: chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@18.19.2)(ts-node@10.9.1) + jest-config: 29.7.0(@types/node@18.19.3)(ts-node@10.9.1) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -5722,7 +5722,7 @@ packages: '@typescript-eslint/eslint-plugin': 6.13.2(@typescript-eslint/parser@6.13.2)(eslint@8.55.0)(typescript@5.3.3) '@typescript-eslint/utils': 5.62.0(eslint@8.55.0)(typescript@5.3.3) eslint: 8.55.0 - jest: 29.7.0(@types/node@18.19.2)(ts-node@10.9.1) + jest: 29.7.0(@types/node@18.19.3)(ts-node@10.9.1) transitivePeerDependencies: - supports-color - typescript @@ -7114,7 +7114,7 @@ packages: '@jest/expect': 29.7.0 '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 18.19.2 + '@types/node': 18.19.3 chalk: 4.1.2 co: 4.6.0 dedent: 1.5.1 @@ -7135,7 +7135,7 @@ packages: - supports-color dev: true - /jest-cli@29.7.0(@types/node@18.19.2)(ts-node@10.9.1): + /jest-cli@29.7.0(@types/node@18.19.3)(ts-node@10.9.1): resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -7149,10 +7149,10 @@ packages: '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@18.19.2)(ts-node@10.9.1) + create-jest: 29.7.0(@types/node@18.19.3)(ts-node@10.9.1) exit: 0.1.2 import-local: 3.1.0 - jest-config: 29.7.0(@types/node@18.19.2)(ts-node@10.9.1) + jest-config: 29.7.0(@types/node@18.19.3)(ts-node@10.9.1) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -7163,7 +7163,7 @@ packages: - ts-node dev: true - /jest-config@29.7.0(@types/node@18.19.2)(ts-node@10.9.1): + /jest-config@29.7.0(@types/node@18.19.3)(ts-node@10.9.1): resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: @@ -7178,7 +7178,7 @@ packages: '@babel/core': 7.23.5 '@jest/test-sequencer': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 18.19.2 + '@types/node': 18.19.3 babel-jest: 29.7.0(@babel/core@7.23.5) chalk: 4.1.2 ci-info: 3.9.0 @@ -7198,7 +7198,7 @@ packages: pretty-format: 29.7.0 slash: 3.0.0 strip-json-comments: 3.1.1 - ts-node: 10.9.1(@swc/core@1.3.100)(@types/node@18.19.2)(typescript@5.3.3) + ts-node: 10.9.1(@swc/core@1.3.100)(@types/node@18.19.3)(typescript@5.3.3) transitivePeerDependencies: - babel-plugin-macros - supports-color @@ -7239,7 +7239,7 @@ packages: '@jest/environment': 29.7.0 '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 18.19.2 + '@types/node': 18.19.3 jest-mock: 29.7.0 jest-util: 29.7.0 dev: true @@ -7253,7 +7253,7 @@ packages: jest: optional: true dependencies: - jest: 29.7.0(@types/node@18.19.2)(ts-node@10.9.1) + jest: 29.7.0(@types/node@18.19.3)(ts-node@10.9.1) jest-diff: 29.7.0 jest-get-type: 29.6.3 dev: true @@ -7269,7 +7269,7 @@ packages: dependencies: '@jest/types': 29.6.3 '@types/graceful-fs': 4.1.9 - '@types/node': 18.19.2 + '@types/node': 18.19.3 anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.11 @@ -7331,7 +7331,7 @@ packages: jest: ^24.0.0 || ^25.0.0 || ^26.0.0 || ^27.0.0 || ^28.0.0 || ^29.0.0 typescript: ^3.0.0 || ^4.0.0 || ^5.0.0 dependencies: - jest: 29.7.0(@types/node@18.19.2)(ts-node@10.9.1) + jest: 29.7.0(@types/node@18.19.3)(ts-node@10.9.1) ts-essentials: 7.0.3(typescript@5.3.3) typescript: 5.3.3 dev: true @@ -7341,7 +7341,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.6.3 - '@types/node': 18.19.2 + '@types/node': 18.19.3 jest-util: 29.7.0 dev: true @@ -7396,7 +7396,7 @@ packages: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 18.19.2 + '@types/node': 18.19.3 chalk: 4.1.2 emittery: 0.13.1 graceful-fs: 4.2.11 @@ -7427,7 +7427,7 @@ packages: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 18.19.2 + '@types/node': 18.19.3 chalk: 4.1.2 cjs-module-lexer: 1.2.3 collect-v8-coverage: 1.0.2 @@ -7479,7 +7479,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.6.3 - '@types/node': 18.19.2 + '@types/node': 18.19.3 chalk: 4.1.2 ci-info: 3.9.0 graceful-fs: 4.2.11 @@ -7504,7 +7504,7 @@ packages: dependencies: '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 18.19.2 + '@types/node': 18.19.3 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.13.1 @@ -7516,13 +7516,13 @@ packages: resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@types/node': 18.19.2 + '@types/node': 18.19.3 jest-util: 29.7.0 merge-stream: 2.0.0 supports-color: 8.1.1 dev: true - /jest@29.7.0(@types/node@18.19.2)(ts-node@10.9.1): + /jest@29.7.0(@types/node@18.19.3)(ts-node@10.9.1): resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -7535,7 +7535,7 @@ packages: '@jest/core': 29.7.0(ts-node@10.9.1) '@jest/types': 29.6.3 import-local: 3.1.0 - jest-cli: 29.7.0(@types/node@18.19.2)(ts-node@10.9.1) + jest-cli: 29.7.0(@types/node@18.19.3)(ts-node@10.9.1) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -10153,7 +10153,7 @@ packages: '@jest/types': 29.6.3 bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@18.19.2)(ts-node@10.9.1) + jest: 29.7.0(@types/node@18.19.3)(ts-node@10.9.1) jest-util: 29.7.0 json5: 2.2.3 lodash.memoize: 4.1.2 @@ -10163,7 +10163,7 @@ packages: yargs-parser: 21.1.1 dev: true - /ts-node@10.9.1(@swc/core@1.3.100)(@types/node@18.19.2)(typescript@5.3.3): + /ts-node@10.9.1(@swc/core@1.3.100)(@types/node@18.19.3)(typescript@5.3.3): resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} hasBin: true peerDependencies: @@ -10183,7 +10183,7 @@ packages: '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 18.19.2 + '@types/node': 18.19.3 acorn: 8.11.2 acorn-walk: 8.3.1 arg: 4.1.3 From b0e84976d1472ac9fc22ca27ccb8ea49cc7ee16e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 14 Dec 2023 09:15:31 +0000 Subject: [PATCH 043/173] fix(deps): update ghcr.io/containerbase/sidecar docker tag to v9.30.4 (#26293) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- lib/config/options/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/config/options/index.ts b/lib/config/options/index.ts index c057b68f9b8666..630df161649cb7 100644 --- a/lib/config/options/index.ts +++ b/lib/config/options/index.ts @@ -380,7 +380,7 @@ const options: RenovateOptions[] = [ description: 'Change this value to override the default Renovate sidecar image.', type: 'string', - default: 'ghcr.io/containerbase/sidecar:9.30.3', + default: 'ghcr.io/containerbase/sidecar:9.30.4', globalOnly: true, }, { From 79cddd9405c6a9b975800057e4a00056ea517622 Mon Sep 17 00:00:00 2001 From: Michael Kriese Date: Thu, 14 Dec 2023 13:23:25 +0100 Subject: [PATCH 044/173] feat(nuget): filter registry urls by package source mappings (#26295) --- lib/modules/manager/nuget/extract.ts | 27 ++-- .../manager/nuget/extract/global-manifest.ts | 12 +- lib/modules/manager/nuget/types.ts | 6 + lib/modules/manager/nuget/util.spec.ts | 120 +++++++++++++++++- lib/modules/manager/nuget/util.ts | 61 ++++++++- 5 files changed, 206 insertions(+), 20 deletions(-) diff --git a/lib/modules/manager/nuget/extract.ts b/lib/modules/manager/nuget/extract.ts index 4cd519bf63833e..0ad9632a4fa723 100644 --- a/lib/modules/manager/nuget/extract.ts +++ b/lib/modules/manager/nuget/extract.ts @@ -11,8 +11,8 @@ import type { PackageFileContent, } from '../types'; import { extractMsbuildGlobalManifest } from './extract/global-manifest'; -import type { DotnetToolsManifest } from './types'; -import { findVersion, getConfiguredRegistries } from './util'; +import type { DotnetToolsManifest, NugetPackageDependency } from './types'; +import { applyRegistries, findVersion, getConfiguredRegistries } from './util'; /** * https://docs.microsoft.com/en-us/nuget/concepts/package-versioning @@ -39,8 +39,8 @@ function isXmlElem(node: XmlNode): boolean { return hasKey('name', node); } -function extractDepsFromXml(xmlNode: XmlDocument): PackageDependency[] { - const results: PackageDependency[] = []; +function extractDepsFromXml(xmlNode: XmlDocument): NugetPackageDependency[] { + const results: NugetPackageDependency[] = []; const todo: XmlElement[] = [xmlNode]; while (todo.length) { const child = todo.pop()!; @@ -79,9 +79,6 @@ export async function extractPackageFile( logger.trace(`nuget.extractPackageFile(${packageFile})`); const registries = await getConfiguredRegistries(packageFile); - const registryUrls = registries - ? registries.map((registry) => registry.url) - : undefined; if (packageFile.endsWith('dotnet-tools.json')) { const deps: PackageDependency[] = []; @@ -102,15 +99,14 @@ export async function extractPackageFile( for (const depName of Object.keys(manifest.tools ?? {})) { const tool = manifest.tools[depName]; const currentValue = tool.version; - const dep: PackageDependency = { + const dep: NugetPackageDependency = { depType: 'nuget', depName, currentValue, datasource: NugetDatasource.id, }; - if (registryUrls) { - dep.registryUrls = registryUrls; - } + + applyRegistries(dep, registries); deps.push(dep); } @@ -119,17 +115,16 @@ export async function extractPackageFile( } if (packageFile.endsWith('global.json')) { - return extractMsbuildGlobalManifest(content, packageFile); + return extractMsbuildGlobalManifest(content, packageFile, registries); } let deps: PackageDependency[] = []; let packageFileVersion: string | undefined; try { const parsedXml = new XmlDocument(content); - deps = extractDepsFromXml(parsedXml).map((dep) => ({ - ...dep, - ...(registryUrls && { registryUrls }), - })); + deps = extractDepsFromXml(parsedXml).map((dep) => + applyRegistries(dep, registries), + ); packageFileVersion = findVersion(parsedXml)?.val; } catch (err) { logger.debug({ err, packageFile }, `Failed to parse XML`); diff --git a/lib/modules/manager/nuget/extract/global-manifest.ts b/lib/modules/manager/nuget/extract/global-manifest.ts index 45a61aba1f1e20..45c66a29e0682c 100644 --- a/lib/modules/manager/nuget/extract/global-manifest.ts +++ b/lib/modules/manager/nuget/extract/global-manifest.ts @@ -2,11 +2,17 @@ import { logger } from '../../../../logger'; import { DotnetVersionDatasource } from '../../../datasource/dotnet-version'; import { NugetDatasource } from '../../../datasource/nuget'; import type { PackageDependency, PackageFileContent } from '../../types'; -import type { MsbuildGlobalManifest } from '../types'; +import type { + MsbuildGlobalManifest, + NugetPackageDependency, + Registry, +} from '../types'; +import { applyRegistries } from '../util'; export function extractMsbuildGlobalManifest( content: string, packageFile: string, + registries: Registry[] | undefined, ): PackageFileContent | null { const deps: PackageDependency[] = []; let manifest: MsbuildGlobalManifest; @@ -35,13 +41,15 @@ export function extractMsbuildGlobalManifest( if (manifest['msbuild-sdks']) { for (const depName of Object.keys(manifest['msbuild-sdks'])) { const currentValue = manifest['msbuild-sdks'][depName]; - const dep: PackageDependency = { + const dep: NugetPackageDependency = { depType: 'msbuild-sdk', depName, currentValue, datasource: NugetDatasource.id, }; + applyRegistries(dep, registries); + deps.push(dep); } } diff --git a/lib/modules/manager/nuget/types.ts b/lib/modules/manager/nuget/types.ts index 30b5d63547b1d4..0eef41beaf9885 100644 --- a/lib/modules/manager/nuget/types.ts +++ b/lib/modules/manager/nuget/types.ts @@ -1,3 +1,5 @@ +import type { PackageDependency } from '../types'; + export interface DotnetToolsManifest { readonly version: number; readonly isRoot: boolean; @@ -41,3 +43,7 @@ export interface PackageSourceMap { readonly name: string; readonly patterns: string[]; } + +export interface NugetPackageDependency extends PackageDependency { + depName: string; +} diff --git a/lib/modules/manager/nuget/util.spec.ts b/lib/modules/manager/nuget/util.spec.ts index 80655a1ecd94dc..13097f69016a5f 100644 --- a/lib/modules/manager/nuget/util.spec.ts +++ b/lib/modules/manager/nuget/util.spec.ts @@ -1,8 +1,9 @@ import { codeBlock } from 'common-tags'; import { XmlDocument } from 'xmldoc'; import { fs } from '../../../../test/util'; +import type { Registry } from './types'; import { bumpPackageVersion } from './update'; -import { findVersion, getConfiguredRegistries } from './util'; +import { applyRegistries, findVersion, getConfiguredRegistries } from './util'; jest.mock('../../../util/fs'); @@ -106,4 +107,121 @@ describe('modules/manager/nuget/util', () => { ]); }); }); + + describe('applyRegistries', () => { + it('applies registry to package name via source mapping', () => { + const registries: Registry[] = [ + { + name: 'nuget.org', + url: 'https://api.nuget.org/v3/index.json', + sourceMappedPackagePatterns: ['*'], + }, + { + name: 'contoso.com', + url: 'https://contoso.com/packages/', + sourceMappedPackagePatterns: ['Contoso.*', 'NuGet.Common'], + }, + { + name: 'contoso.test', + url: 'https://contoso.test/packages/', + sourceMappedPackagePatterns: [ + 'Contoso.*', + 'Contoso.Test.*', + 'NuGet.*', + 'NuGet.Common*', + ], + }, + ]; + + expect( + applyRegistries({ depName: 'Newtonsoft.Json' }, registries), + ).toEqual({ + depName: 'Newtonsoft.Json', + registryUrls: ['https://api.nuget.org/v3/index.json'], + }); + + expect( + applyRegistries({ depName: 'Contoso.SomePackage' }, registries), + ).toEqual({ + depName: 'Contoso.SomePackage', + registryUrls: [ + 'https://contoso.com/packages/', + 'https://contoso.test/packages/', + ], + }); + + expect(applyRegistries({ depName: 'NuGet.Some' }, registries)).toEqual({ + depName: 'NuGet.Some', + registryUrls: ['https://contoso.test/packages/'], + }); + + expect( + applyRegistries({ depName: 'Contoso.Test.SomePackage' }, registries), + ).toEqual({ + depName: 'Contoso.Test.SomePackage', + registryUrls: ['https://contoso.test/packages/'], + }); + }); + + it('applies registry to package name case insensitive', () => { + const registries: Registry[] = [ + { + name: 'nuget.org', + url: 'https://api.nuget.org/v3/index.json', + sourceMappedPackagePatterns: ['*'], + }, + { + name: 'contoso.com', + url: 'https://contoso.com/packages/', + sourceMappedPackagePatterns: ['Contoso.*', 'Nuget.common'], + }, + ]; + + expect(applyRegistries({ depName: 'NuGet.Common' }, registries)).toEqual({ + depName: 'NuGet.Common', + registryUrls: ['https://contoso.com/packages/'], + }); + }); + + it('applies all registries to package name', () => { + const registries: Registry[] = [ + { + name: 'nuget.org', + url: 'https://api.nuget.org/v3/index.json', + }, + { + name: 'contoso.com', + url: 'https://contoso.com/packages/', + }, + ]; + + expect( + applyRegistries( + { + depName: 'Newtonsoft.Json', + }, + registries, + ), + ).toEqual({ + depName: 'Newtonsoft.Json', + registryUrls: [ + 'https://api.nuget.org/v3/index.json', + 'https://contoso.com/packages/', + ], + }); + }); + + it('applies nothing', () => { + expect( + applyRegistries( + { + depName: 'Newtonsoft.Json', + }, + undefined, + ), + ).toEqual({ + depName: 'Newtonsoft.Json', + }); + }); + }); }); diff --git a/lib/modules/manager/nuget/util.ts b/lib/modules/manager/nuget/util.ts index 8511c91b07f0d3..54cf05773aaf97 100644 --- a/lib/modules/manager/nuget/util.ts +++ b/lib/modules/manager/nuget/util.ts @@ -2,9 +2,10 @@ import upath from 'upath'; import { XmlDocument, XmlElement } from 'xmldoc'; import { logger } from '../../../logger'; import { findUpLocal, readLocalFile } from '../../../util/fs'; +import { minimatch } from '../../../util/minimatch'; import { regEx } from '../../../util/regex'; import { nugetOrg } from '../../datasource/nuget'; -import type { Registry } from './types'; +import type { NugetPackageDependency, Registry } from './types'; export async function readFileAsXmlDocument( file: string, @@ -122,3 +123,61 @@ export function findVersion(parsedXml: XmlDocument): XmlElement | null { } return null; } + +export function applyRegistries( + dep: NugetPackageDependency, + registries: Registry[] | undefined, +): NugetPackageDependency { + if (registries) { + if (!registries.some((reg) => reg.sourceMappedPackagePatterns)) { + dep.registryUrls = registries.map((reg) => reg.url); + return dep; + } + + const regs = registries.filter((r) => r.sourceMappedPackagePatterns); + const map = new Map( + regs.flatMap((r) => r.sourceMappedPackagePatterns!.map((p) => [p, []])), + ); + const depName = dep.depName; + + for (const reg of regs) { + for (const pattern of reg.sourceMappedPackagePatterns!) { + map.get(pattern)!.push(reg); + } + } + + const urls: string[] = []; + + for (const [pattern, regs] of [...map].sort(sortPatterns)) { + if (minimatch(pattern, { nocase: true }).match(depName)) { + urls.push(...regs.map((r) => r.url)); + break; + } + } + + if (urls.length) { + dep.registryUrls = urls; + } + } + return dep; +} + +/* + * Sorts patterns by specificity: + * 1. Exact match patterns + * 2. Wildcard match patterns + */ +function sortPatterns( + a: [string, Registry[]], + b: [string, Registry[]], +): number { + if (a[0].endsWith('*') && !b[0].endsWith('*')) { + return 1; + } + + if (!a[0].endsWith('*') && b[0].endsWith('*')) { + return -1; + } + + return a[0].localeCompare(b[0]) * -1; +} From 1521e67c0f2263ed72e600442c812e187e0fb29f Mon Sep 17 00:00:00 2001 From: ps-occrp <138824595+ps-occrp@users.noreply.github.com> Date: Thu, 14 Dec 2023 14:14:48 +0100 Subject: [PATCH 045/173] feat(terragrunt): add support for tfr prefix (#26209) Co-authored-by: Michael Kriese --- .../manager/terragrunt/__fixtures__/1.hcl | 39 +++++++++++++++++++ .../manager/terragrunt/extract.spec.ts | 27 +++++++++++++ lib/modules/manager/terragrunt/modules.ts | 14 +++++++ 3 files changed, 80 insertions(+) create mode 100644 lib/modules/manager/terragrunt/__fixtures__/1.hcl diff --git a/lib/modules/manager/terragrunt/__fixtures__/1.hcl b/lib/modules/manager/terragrunt/__fixtures__/1.hcl new file mode 100644 index 00000000000000..61164ff13f4e93 --- /dev/null +++ b/lib/modules/manager/terragrunt/__fixtures__/1.hcl @@ -0,0 +1,39 @@ +#real +terraform { + extra_arguments "common_vars" { + commands = ["plan", "apply"] + + arguments = [ + "-var-file=../../common.tfvars", + "-var-file=../region.tfvars" + ] + } + + before_hook "before_hook" { + commands = ["apply", "plan"] + execute = ["echo", "Running Terraform"] + } + + source = "tfr:///myuser/myrepo/cloud//folder/modules/moduleone?ref=v0.0.9" + + after_hook "after_hook" { + commands = ["apply", "plan"] + execute = ["echo", "Finished running Terraform"] + run_on_error = true + } +} + +#submodule +terraform { + source = "tfr:///terraform-google-modules/kubernetes-engine/google//modules/private-cluster?version=1.2.3" +} + +#bar +terraform { + source = "tfr:///terraform-aws-modules/vpc/aws?version=3.3.0" +} + +#missing third backslash +terraform { + source = "tfr://terraform-aws-modules/vpc/aws?version=3.3.0" +} diff --git a/lib/modules/manager/terragrunt/extract.spec.ts b/lib/modules/manager/terragrunt/extract.spec.ts index 5b7af54845281c..7dfae48e2f8f59 100644 --- a/lib/modules/manager/terragrunt/extract.spec.ts +++ b/lib/modules/manager/terragrunt/extract.spec.ts @@ -7,6 +7,33 @@ describe('modules/manager/terragrunt/extract', () => { expect(extractPackageFile('nothing here')).toBeNull(); }); + it('extracts terragrunt sources using tfr protocol', () => { + const res = extractPackageFile(Fixtures.get('1.hcl')); + expect(res).toEqual({ + deps: [ + { + currentValue: 'v0.0.9', + datasource: 'terraform-module', + depName: 'myuser/myrepo/cloud', + depType: 'terragrunt', + }, + { + currentValue: '1.2.3', + datasource: 'terraform-module', + depName: 'terraform-google-modules/kubernetes-engine/google', + depType: 'terragrunt', + }, + { + currentValue: '3.3.0', + datasource: 'terraform-module', + depName: 'terraform-aws-modules/vpc/aws', + depType: 'terragrunt', + }, + {}, + ], + }); + }); + it('extracts terragrunt sources', () => { const res = extractPackageFile(Fixtures.get('2.hcl')); expect(res).toEqual({ diff --git a/lib/modules/manager/terragrunt/modules.ts b/lib/modules/manager/terragrunt/modules.ts index 56722fe7a12323..2e22f7d3c1bbc8 100644 --- a/lib/modules/manager/terragrunt/modules.ts +++ b/lib/modules/manager/terragrunt/modules.ts @@ -13,6 +13,9 @@ export const githubRefMatchRegex = regEx( export const gitTagsRefMatchRegex = regEx( /(?:git::)?(?(?:http|https|ssh):\/\/(?:.*@)?(?.*.*\/(?.*\/.*)))\?(depth=\d+&)?ref=(?.*?)(&depth=\d+)?$/, ); +export const tfrVersionMatchRegex = regEx( + /tfr:\/\/(?.*?)\/(?[^/]+?)\/(?[^/]+?)\/(?[^/?]+).*\?(?:ref|version)=(?.*?)$/, +); const hostnameMatchRegex = regEx(/^(?([\w|\d]+\.)+[\w|\d]+)/); export function extractTerragruntModule( @@ -35,6 +38,7 @@ export function analyseTerragruntModule( const source = dep.managerData!.source; const githubRefMatch = githubRefMatchRegex.exec(source ?? ''); const gitTagsRefMatch = gitTagsRefMatchRegex.exec(source ?? ''); + const tfrVersionMatch = tfrVersionMatchRegex.exec(source ?? ''); if (githubRefMatch?.groups) { dep.depType = 'github'; @@ -58,6 +62,16 @@ export function analyseTerragruntModule( } dep.currentValue = gitTagsRefMatch.groups.tag; dep.datasource = GitTagsDatasource.id; + } else if (tfrVersionMatch?.groups) { + dep.depType = 'terragrunt'; + dep.depName = + tfrVersionMatch.groups.org + + '/' + + tfrVersionMatch.groups.name + + '/' + + tfrVersionMatch.groups.cloud; + dep.currentValue = tfrVersionMatch.groups.currentValue; + dep.datasource = TerraformModuleDatasource.id; } else if (source) { const moduleParts = source.split('//')[0].split('/'); if (moduleParts[0] === '..') { From 0256334c145090357ecb8e7c42a77aceb0152ee8 Mon Sep 17 00:00:00 2001 From: joegoldman2 <147369450+joegoldman2@users.noreply.github.com> Date: Thu, 14 Dec 2023 15:23:29 +0200 Subject: [PATCH 046/173] feat(presets): add ml-dotnet monorepo (#26289) --- lib/config/presets/internal/monorepo.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/config/presets/internal/monorepo.ts b/lib/config/presets/internal/monorepo.ts index c47ae0abb504ed..6482561da291da 100644 --- a/lib/config/presets/internal/monorepo.ts +++ b/lib/config/presets/internal/monorepo.ts @@ -343,6 +343,7 @@ const repoGroups = { mdx: 'https://github.com/mdx-js/mdx', 'middy-js': 'https://github.com/middyjs/middy', 'mikro-orm': 'https://github.com/mikro-orm/mikro-orm', + 'ml-dotnet': 'https://github.com/dotnet/machinelearning', mockito: 'https://github.com/mockito/mockito', 'mongo-csharp-driver': 'https://github.com/mongodb/mongo-csharp-driver', mstest: 'https://github.com/microsoft/testfx', From f05d693dd5ce5e84b6347b90ec75b1701b9da665 Mon Sep 17 00:00:00 2001 From: joegoldman2 <147369450+joegoldman2@users.noreply.github.com> Date: Thu, 14 Dec 2023 15:23:53 +0200 Subject: [PATCH 047/173] feat(presets): add openiddict monorepo (#26288) --- lib/config/presets/internal/monorepo.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/config/presets/internal/monorepo.ts b/lib/config/presets/internal/monorepo.ts index 6482561da291da..719ffe697b0e30 100644 --- a/lib/config/presets/internal/monorepo.ts +++ b/lib/config/presets/internal/monorepo.ts @@ -376,6 +376,7 @@ const repoGroups = { 'https://github.com/nuxt/nuxt', ], okhttp: 'https://github.com/square/okhttp', + openiddict: 'https://github.com/openiddict/openiddict-core', 'opentelemetry-dotnet': 'https://github.com/open-telemetry/opentelemetry-dotnet', 'opentelemetry-erlang': From 907932e544058b21252e62bb613d7cfa7f3af067 Mon Sep 17 00:00:00 2001 From: joegoldman2 <147369450+joegoldman2@users.noreply.github.com> Date: Thu, 14 Dec 2023 15:24:15 +0200 Subject: [PATCH 048/173] feat(presets): add playwright-dotnet monorepo (#26287) --- lib/config/presets/internal/monorepo.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/config/presets/internal/monorepo.ts b/lib/config/presets/internal/monorepo.ts index 719ffe697b0e30..a86f87f632073e 100644 --- a/lib/config/presets/internal/monorepo.ts +++ b/lib/config/presets/internal/monorepo.ts @@ -393,7 +393,8 @@ const repoGroups = { 'https://github.com/pixijs/pixi.js', // old repo 'https://github.com/pixijs/pixijs', ], - playwright: 'https://github.com/Microsoft/playwright', + playwright: 'https://github.com/microsoft/playwright', + 'playwright-dotnet': 'https://github.com/microsoft/playwright-dotnet', pnpjs: 'https://github.com/pnp/pnpjs', pollyjs: 'https://github.com/Netflix/pollyjs', pouchdb: 'https://github.com/pouchdb/pouchdb', From eea63ff779e5f273c0298cfc35cb9a1b1414d705 Mon Sep 17 00:00:00 2001 From: Valen Varangu-Booth Date: Thu, 14 Dec 2023 10:45:54 -0500 Subject: [PATCH 049/173] feat(onboarding): search parent groups for presets (#25856) Co-authored-by: Rhys Arkins Co-authored-by: Michael Kriese --- docs/usage/config-presets.md | 11 ++-- .../onboarding/branch/config.spec.ts | 52 +++++++++++++++- .../repository/onboarding/branch/config.ts | 59 +++++++++++-------- 3 files changed, 88 insertions(+), 34 deletions(-) diff --git a/docs/usage/config-presets.md b/docs/usage/config-presets.md index 89ccd6fc4cfdf0..54dad726f10e56 100644 --- a/docs/usage/config-presets.md +++ b/docs/usage/config-presets.md @@ -217,13 +217,12 @@ Create a [discussion](https://github.com/renovatebot/renovate/discussions) to pr The maintainers can also help improve the preset, and let you know where to put it in the code. If you are proposing a "monorepo" preset addition then it's OK to raise a PR directly as that can be more efficient than a GitHub Discussion. -## Organization level presets +## Group/Organization level presets -Whenever repository onboarding happens, Renovate checks if the current user/group/org has a default config to extend. -It looks for: - -- A repository called `renovate-config` under the same user/group/org with a `default.json` file or -- A repository named like `.{{platform}}` (e.g. `.github`) under the same user/group/org with `renovate-config.json` +Whenever repository onboarding happens, Renovate checks for a a default config to extend. +Renovate will check for a repository called `renovate-config` with a `default.json` file in the parent user/group/org of the repository. +On platforms that support nested groups (e.g. GitLab), Renovate will check for this repository at each level of grouping, from nearest to furthest, and use the first one it finds. +On all platforms, it will then look for a repository named like `.{{platform}}` (e.g. `.github`) with a `renovate-config.json`, under the same top-level user/group/org. If found, that repository's preset will be suggested as the sole extended preset, and any existing `onboardingConfig` config will be ignored/overridden. For example the result may be: diff --git a/lib/workers/repository/onboarding/branch/config.spec.ts b/lib/workers/repository/onboarding/branch/config.spec.ts index c1b0f4df4b266c..88d9ed41719932 100644 --- a/lib/workers/repository/onboarding/branch/config.spec.ts +++ b/lib/workers/repository/onboarding/branch/config.spec.ts @@ -45,7 +45,7 @@ describe('workers/repository/onboarding/branch/config', () => { }); describe('getOnboardingConfig', () => { - it('handles finding an organization preset', async () => { + it('handles finding a preset in the same group level', async () => { mockedPresets.getPreset.mockResolvedValueOnce({ enabled: true }); const onboardingConfig = await getOnboardingConfig(config); expect(mockedPresets.getPreset).toHaveBeenCalledTimes(1); @@ -68,7 +68,55 @@ describe('workers/repository/onboarding/branch/config', () => { }); }); - it('handles not finding an organization preset', async () => { + it('handles finding a preset in the same group', async () => { + config.repository = 'org/group/repo'; + mockedPresets.getPreset.mockImplementation(({ repo }) => { + if (repo === 'org/group/renovate-config') { + return Promise.resolve({ enabled: true }); + } + return Promise.reject(new Error(PRESET_DEP_NOT_FOUND)); + }); + const onboardingConfig = await getOnboardingConfig(config); + expect(mockedPresets.getPreset).toHaveBeenCalledTimes(1); + expect(onboardingConfig).toEqual({ + $schema: 'https://docs.renovatebot.com/renovate-schema.json', + extends: ['local>org/group/renovate-config'], + }); + }); + + it('handles finding a preset in a parent group', async () => { + config.repository = 'org/group/repo'; + mockedPresets.getPreset.mockImplementation(({ repo }) => { + if (repo === 'org/renovate-config') { + return Promise.resolve({ enabled: true }); + } + return Promise.reject(new Error(PRESET_DEP_NOT_FOUND)); + }); + const onboardingConfig = await getOnboardingConfig(config); + expect(mockedPresets.getPreset).toHaveBeenCalledTimes(2); + expect(onboardingConfig).toEqual({ + $schema: 'https://docs.renovatebot.com/renovate-schema.json', + extends: ['local>org/renovate-config'], + }); + }); + + it('handles falling back to finding a organization preset', async () => { + config.repository = 'org/group/repo'; + mockedPresets.getPreset.mockImplementation(({ repo }) => { + if (repo === 'org/.github') { + return Promise.resolve({ enabled: true }); + } + return Promise.reject(new Error(PRESET_DEP_NOT_FOUND)); + }); + const onboardingConfig = await getOnboardingConfig(config); + expect(mockedPresets.getPreset).toHaveBeenCalledTimes(3); + expect(onboardingConfig).toEqual({ + $schema: 'https://docs.renovatebot.com/renovate-schema.json', + extends: ['local>org/.github:renovate-config'], + }); + }); + + it('handles not finding any preset', async () => { mockedPresets.getPreset.mockRejectedValue( new Error(PRESET_DEP_NOT_FOUND), ); diff --git a/lib/workers/repository/onboarding/branch/config.ts b/lib/workers/repository/onboarding/branch/config.ts index 78ba923b45b01d..5096f42ea9bc48 100644 --- a/lib/workers/repository/onboarding/branch/config.ts +++ b/lib/workers/repository/onboarding/branch/config.ts @@ -14,34 +14,43 @@ async function getOnboardingConfig( ): Promise { let onboardingConfig = clone(config.onboardingConfig); - let orgPreset: string | undefined; + let foundPreset: string | undefined; - logger.debug( - 'Checking if this org/owner has a default Renovate preset which can be used.', - ); + logger.debug('Checking for a default Renovate preset which can be used.'); // TODO #22198 - const orgName = config.repository!.split('/')[0]; + const repoPathParts = config.repository!.split('/'); - // Check for org/renovate-config - try { - const repo = `${orgName}/renovate-config`; - const orgPresetName = `local>${repo}`; - logger.debug(`Checking for preset: ${orgPresetName}`); - if (await getPreset({ repo })) { - orgPreset = orgPresetName; - } - } catch (err) { - if ( - err.message !== PRESET_DEP_NOT_FOUND && - !err.message.startsWith('Unsupported platform') - ) { - logger.warn({ err }, 'Unknown error fetching default owner preset'); + for ( + let index = repoPathParts.length - 1; + index >= 1 && !foundPreset; + index-- + ) { + const groupName = repoPathParts.slice(0, index).join('/'); + + // Check for group/renovate-config + try { + const repo = `${groupName}/renovate-config`; + const preset = `local>${repo}`; + logger.debug(`Checking for preset: ${preset}`); + if (await getPreset({ repo })) { + foundPreset = preset; + } + } catch (err) { + if ( + err.message !== PRESET_DEP_NOT_FOUND && + !err.message.startsWith('Unsupported platform') + ) { + logger.warn({ err }, 'Unknown error fetching default owner preset'); + } } } - if (!orgPreset) { + if (!foundPreset) { // Check for org/.{{platform}} + + const orgName = repoPathParts[0]; + // TODO: types (#22198) const platform = GlobalConfig.get('platform')!; try { @@ -56,7 +65,7 @@ async function getOnboardingConfig( presetName, }) ) { - orgPreset = orgPresetName; + foundPreset = orgPresetName; } } catch (err) { if ( @@ -68,13 +77,11 @@ async function getOnboardingConfig( } } - if (orgPreset) { - logger.debug( - `Found org preset ${orgPreset} - using it in onboarding config`, - ); + if (foundPreset) { + logger.debug(`Found preset ${foundPreset} - using it in onboarding config`); onboardingConfig = { $schema: 'https://docs.renovatebot.com/renovate-schema.json', - extends: [orgPreset], + extends: [foundPreset], }; } else { // Organization preset did not exist From 35c0e26e164186e943ecd6e3c255584e289004f7 Mon Sep 17 00:00:00 2001 From: Rhys Arkins Date: Thu, 14 Dec 2023 16:46:39 +0100 Subject: [PATCH 050/173] fix(replacements): default replacementName to packageName (#26296) --- .../repository/process/lookup/utils.spec.ts | 36 +++++++++++++++++++ .../repository/process/lookup/utils.ts | 11 +++--- 2 files changed, 43 insertions(+), 4 deletions(-) create mode 100644 lib/workers/repository/process/lookup/utils.spec.ts diff --git a/lib/workers/repository/process/lookup/utils.spec.ts b/lib/workers/repository/process/lookup/utils.spec.ts new file mode 100644 index 00000000000000..99033286d3e001 --- /dev/null +++ b/lib/workers/repository/process/lookup/utils.spec.ts @@ -0,0 +1,36 @@ +import type { LookupUpdateConfig } from './types'; +import { determineNewReplacementName } from './utils'; + +const lookupConfig: LookupUpdateConfig = { + datasource: 'npm', + packageName: 'b', + currentValue: '1.0.0', + versioning: 'semver', + rangeStrategy: 'replace', +}; + +describe('workers/repository/process/lookup/utils', () => { + describe('determineNewReplacementName()', () => { + it('returns the replacement name if defined', () => { + expect( + determineNewReplacementName({ + ...lookupConfig, + replacementName: 'foo', + }), + ).toBe('foo'); + }); + + it('returns the replacement name template if defined', () => { + expect( + determineNewReplacementName({ + ...lookupConfig, + replacementNameTemplate: 'foo', + }), + ).toBe('foo'); + }); + + it('returns the package name if defined', () => { + expect(determineNewReplacementName(lookupConfig)).toBe('b'); + }); + }); +}); diff --git a/lib/workers/repository/process/lookup/utils.ts b/lib/workers/repository/process/lookup/utils.ts index 3a63e363e40f2d..9e12201bb3cbfa 100644 --- a/lib/workers/repository/process/lookup/utils.ts +++ b/lib/workers/repository/process/lookup/utils.ts @@ -38,10 +38,13 @@ export function isReplacementRulesConfigured( export function determineNewReplacementName( config: LookupUpdateConfig, ): string { - return ( - config.replacementName ?? - template.compile(config.replacementNameTemplate!, config, true) - ); + if (config.replacementName) { + return config.replacementName; + } + if (config.replacementNameTemplate) { + return template.compile(config.replacementNameTemplate, config, true); + } + return config.packageName; } export function determineNewReplacementValue( From 376fefd159fea88cf0a8a5a148a54229793a0201 Mon Sep 17 00:00:00 2001 From: Rhys Arkins Date: Thu, 14 Dec 2023 16:47:31 +0100 Subject: [PATCH 051/173] fix(onboarding): fix semantic ignored onboarding PRs (#26297) --- .../repository/onboarding/branch/check.ts | 23 +++++++++++++------ lib/workers/repository/onboarding/common.ts | 4 ++++ lib/workers/repository/onboarding/pr/index.ts | 10 ++++---- 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/lib/workers/repository/onboarding/branch/check.ts b/lib/workers/repository/onboarding/branch/check.ts index 8351c36934c1c9..c3773f789b9dbb 100644 --- a/lib/workers/repository/onboarding/branch/check.ts +++ b/lib/workers/repository/onboarding/branch/check.ts @@ -11,6 +11,7 @@ import { scm } from '../../../../modules/platform/scm'; import { getCache } from '../../../../util/cache/repository'; import { readLocalFile } from '../../../../util/fs'; import { getBranchCommit } from '../../../../util/git'; +import { getSemanticCommitPrTitle } from '../common'; async function findFile(fileName: string): Promise { logger.debug(`findFile(${fileName})`); @@ -41,13 +42,21 @@ async function packageJsonConfigExists(): Promise { return false; } -function closedPrExists(config: RenovateConfig): Promise { - return platform.findPr({ - branchName: config.onboardingBranch!, - prTitle: config.onboardingPrTitle, - state: '!open', - targetBranch: config.baseBranch, - }); +async function closedPrExists(config: RenovateConfig): Promise { + return ( + (await platform.findPr({ + branchName: config.onboardingBranch!, + prTitle: config.onboardingPrTitle, + state: '!open', + targetBranch: config.baseBranch, + })) ?? + (await platform.findPr({ + branchName: config.onboardingBranch!, + prTitle: getSemanticCommitPrTitle(config), + state: '!open', + targetBranch: config.baseBranch, + })) + ); } export async function isOnboarded(config: RenovateConfig): Promise { diff --git a/lib/workers/repository/onboarding/common.ts b/lib/workers/repository/onboarding/common.ts index f4a03a98892a49..03fdc7b95c242e 100644 --- a/lib/workers/repository/onboarding/common.ts +++ b/lib/workers/repository/onboarding/common.ts @@ -3,6 +3,10 @@ import type { RenovateConfig } from '../../../config/types'; import { logger } from '../../../logger'; import * as memCache from '../../../util/cache/memory'; +export function getSemanticCommitPrTitle(config: RenovateConfig): string { + return `${config.semanticCommitType ?? 'chore'}: ${config.onboardingPrTitle}`; +} + export function defaultConfigFile(config: RenovateConfig): string { return configFileNames.includes(config.onboardingConfigFileName!) ? config.onboardingConfigFileName! diff --git a/lib/workers/repository/onboarding/pr/index.ts b/lib/workers/repository/onboarding/pr/index.ts index adfddab3ea9288..5ce7fb3bbe3122 100644 --- a/lib/workers/repository/onboarding/pr/index.ts +++ b/lib/workers/repository/onboarding/pr/index.ts @@ -21,7 +21,11 @@ import { getPlatformPrOptions } from '../../update/pr'; import { prepareLabels } from '../../update/pr/labels'; import { addParticipants } from '../../update/pr/participants'; import { isOnboardingBranchConflicted } from '../branch/onboarding-branch-cache'; -import { OnboardingState, defaultConfigFile } from '../common'; +import { + OnboardingState, + defaultConfigFile, + getSemanticCommitPrTitle, +} from '../common'; import { getBaseBranchDesc } from './base-branch'; import { getConfigDesc } from './config-description'; import { getPrList } from './pr-list'; @@ -175,9 +179,7 @@ If you need any further assistance then you can also [request help here](${ // TODO #22198 const prTitle = config.semanticCommits === 'enabled' - ? `${config.semanticCommitType ?? 'chore'}: ${ - config.onboardingPrTitle - }` + ? getSemanticCommitPrTitle(config) : config.onboardingPrTitle!; const pr = await platform.createPr({ sourceBranch: config.onboardingBranch!, From 3ed295cf94b1c8d1dace5ce6a901f3668922ebab Mon Sep 17 00:00:00 2001 From: RahulGautamSingh Date: Thu, 14 Dec 2023 22:05:50 +0545 Subject: [PATCH 052/173] feat(config): custom status checks (#26047) Co-authored-by: HonkingGoose <34918129+HonkingGoose@users.noreply.github.com> Co-authored-by: Rhys Arkins --- docs/usage/configuration-options.md | 17 ++++ lib/config/options/index.ts | 13 +++ lib/config/types.ts | 10 ++ lib/config/validation.spec.ts | 24 +++++ lib/config/validation.ts | 36 +++++++- .../repository/reconfigure/index.spec.ts | 46 +++++++++- lib/workers/repository/reconfigure/index.ts | 85 ++++++++++------- .../update/branch/artifacts.spec.ts | 45 ++++++++- .../repository/update/branch/artifacts.ts | 9 +- .../update/branch/status-checks.spec.ts | 92 ++++++++++++++++++- .../repository/update/branch/status-checks.ts | 19 +++- 11 files changed, 350 insertions(+), 46 deletions(-) diff --git a/docs/usage/configuration-options.md b/docs/usage/configuration-options.md index 8102ed15bc53b1..d225073659b490 100644 --- a/docs/usage/configuration-options.md +++ b/docs/usage/configuration-options.md @@ -3584,6 +3584,23 @@ Configure this to `true` if you wish to get one PR for every separate major vers e.g. if you are on webpack@v1 currently then default behavior is a PR for upgrading to webpack@v3 and not for webpack@v2. If this setting is true then you would get one PR for webpack@v2 and one for webpack@v3. +## statusCheckNames + +You can customize the name/context of status checks that Renovate adds to commits/branches/PRs. + +This option enables you to modify any existing status checks name/context, but adding new status checks this way is _not_ supported. +Setting the value to `null` or an empty string, effectively disables or skips that status check. +This option is mergeable, which means you only have to specify the status checks that you want to modify. + +```json title="Example of overriding status check strings" +{ + "statusCheckNames": { + "minimumReleaseAge": "custom/stability-days", + "mergeConfidence": "custom/merge-confidence-level" + } +} +``` + ## stopUpdatingLabel This feature only works on supported platforms, check the table above. diff --git a/lib/config/options/index.ts b/lib/config/options/index.ts index 630df161649cb7..bff4368287f67b 100644 --- a/lib/config/options/index.ts +++ b/lib/config/options/index.ts @@ -170,6 +170,19 @@ const options: RenovateOptions[] = [ type: 'string', }, }, + { + name: 'statusCheckNames', + description: 'Custom strings to use as status check names.', + type: 'object', + mergeable: true, + advancedUse: true, + default: { + artifactError: 'renovate/artifacts', + configValidation: 'renovate/config-validation', + mergeConfidence: 'renovate/merge-confidence', + minimumReleaseAge: 'renovate/stability-days', + }, + }, { name: 'extends', description: 'Configuration presets to use or extend.', diff --git a/lib/config/types.ts b/lib/config/types.ts index 950fe4ea2b761d..777f27b3aa0a00 100644 --- a/lib/config/types.ts +++ b/lib/config/types.ts @@ -190,6 +190,14 @@ export type RenovateRepository = export type UseBaseBranchConfigType = 'merge' | 'none'; export type ConstraintsFilter = 'strict' | 'none'; +export const allowedStatusCheckStrings = [ + 'minimumReleaseAge', + 'mergeConfidence', + 'configValidation', + 'artifactError', +] as const; +export type StatusCheckKey = (typeof allowedStatusCheckStrings)[number]; + // TODO: Proper typings export interface RenovateConfig extends LegacyAdminConfig, @@ -261,6 +269,8 @@ export interface RenovateConfig checkedBranches?: string[]; customizeDashboard?: Record; + + statusCheckNames?: Record; } const CustomDatasourceFormats = ['json', 'plain', 'yaml', 'html'] as const; diff --git a/lib/config/validation.spec.ts b/lib/config/validation.spec.ts index fb74dd9431ce1b..744d0e46cbba1a 100644 --- a/lib/config/validation.spec.ts +++ b/lib/config/validation.spec.ts @@ -144,6 +144,30 @@ describe('config/validation', () => { ]); }); + it('validates invalid statusCheckNames', async () => { + const config = { + statusCheckNames: { + randomKey: '', + mergeConfidence: 10, + configValidation: '', + artifactError: null, + }, + }; + // @ts-expect-error invalid options + const { errors } = await configValidation.validateConfig(config); + expect(errors).toMatchObject([ + { + message: + 'Invalid `statusCheckNames.mergeConfidence` configuration: status check is not a string.', + }, + { + message: + 'Invalid `statusCheckNames.statusCheckNames.randomKey` configuration: key is not allowed.', + }, + ]); + expect(errors).toHaveLength(2); + }); + it('catches invalid customDatasources record type', async () => { const config = { customDatasources: { diff --git a/lib/config/validation.ts b/lib/config/validation.ts index d83a0694cedf68..dbcae32e7c91be 100644 --- a/lib/config/validation.ts +++ b/lib/config/validation.ts @@ -16,11 +16,13 @@ import { import { migrateConfig } from './migration'; import { getOptions } from './options'; import { resolveConfigPresets } from './presets'; -import type { - RenovateConfig, - RenovateOptions, - ValidationMessage, - ValidationResult, +import { + type RenovateConfig, + type RenovateOptions, + type StatusCheckKey, + type ValidationMessage, + type ValidationResult, + allowedStatusCheckStrings, } from './types'; import * as managerValidator from './validation-helpers/managers'; @@ -563,6 +565,30 @@ export async function validateConfig( message: `Invalid \`${currentPath}.${key}.${res}\` configuration: value is not a string`, }); } + } else if (key === 'statusCheckNames') { + for (const [statusCheckKey, statusCheckValue] of Object.entries( + val, + )) { + if ( + !allowedStatusCheckStrings.includes( + statusCheckKey as StatusCheckKey, + ) + ) { + errors.push({ + topic: 'Configuration Error', + message: `Invalid \`${currentPath}.${key}.${statusCheckKey}\` configuration: key is not allowed.`, + }); + } + if ( + !(is.string(statusCheckValue) || is.null_(statusCheckValue)) + ) { + errors.push({ + topic: 'Configuration Error', + message: `Invalid \`${currentPath}.${statusCheckKey}\` configuration: status check is not a string.`, + }); + continue; + } + } } else if (key === 'customDatasources') { const allowedKeys = [ 'description', diff --git a/lib/workers/repository/reconfigure/index.spec.ts b/lib/workers/repository/reconfigure/index.spec.ts index e149dc808a8670..f7c97269ef01ef 100644 --- a/lib/workers/repository/reconfigure/index.spec.ts +++ b/lib/workers/repository/reconfigure/index.spec.ts @@ -4,6 +4,7 @@ import { fs, git, mocked, + partial, platform, scm, } from '../../../../test/util'; @@ -26,6 +27,9 @@ describe('workers/repository/reconfigure/index', () => { const config: RenovateConfig = { branchPrefix: 'prefix/', baseBranch: 'base', + statusCheckNames: partial({ + configValidation: 'renovate/config-validation', + }), }; beforeEach(() => { @@ -151,6 +155,46 @@ describe('workers/repository/reconfigure/index', () => { }); }); + it('skips adding status check if statusCheckNames.configValidation is null', async () => { + cache.getCache.mockReturnValueOnce({ + reconfigureBranchCache: { + reconfigureBranchSha: 'new-sha', + isConfigValid: false, + }, + }); + + await validateReconfigureBranch({ + ...config, + statusCheckNames: partial({ + configValidation: null, + }), + }); + expect(logger.debug).toHaveBeenCalledWith( + 'Status check is null or an empty string, skipping status check addition.', + ); + expect(platform.setBranchStatus).not.toHaveBeenCalled(); + }); + + it('skips adding status check if statusCheckNames.configValidation is empty string', async () => { + cache.getCache.mockReturnValueOnce({ + reconfigureBranchCache: { + reconfigureBranchSha: 'new-sha', + isConfigValid: false, + }, + }); + + await validateReconfigureBranch({ + ...config, + statusCheckNames: partial({ + configValidation: '', + }), + }); + expect(logger.debug).toHaveBeenCalledWith( + 'Status check is null or an empty string, skipping status check addition.', + ); + expect(platform.setBranchStatus).not.toHaveBeenCalled(); + }); + it('skips validation if cache is valid', async () => { cache.getCache.mockReturnValueOnce({ reconfigureBranchCache: { @@ -174,7 +218,7 @@ describe('workers/repository/reconfigure/index', () => { platform.getBranchStatusCheck.mockResolvedValueOnce('green'); await validateReconfigureBranch(config); expect(logger.debug).toHaveBeenCalledWith( - 'Skipping validation check as status check already exists', + 'Skipping validation check because status check already exists.', ); }); diff --git a/lib/workers/repository/reconfigure/index.ts b/lib/workers/repository/reconfigure/index.ts index e8e4f69c2fa8e8..79a7e9f71f842c 100644 --- a/lib/workers/repository/reconfigure/index.ts +++ b/lib/workers/repository/reconfigure/index.ts @@ -6,6 +6,7 @@ import { logger } from '../../../logger'; import { platform } from '../../../modules/platform'; import { ensureComment } from '../../../modules/platform/comment'; import { scm } from '../../../modules/platform/scm'; +import type { BranchStatus } from '../../../types'; import { getCache } from '../../../util/cache/repository'; import { readLocalFile } from '../../../util/fs'; import { getBranchCommit } from '../../../util/git'; @@ -16,6 +17,25 @@ import { setReconfigureBranchCache, } from './reconfigure-cache'; +async function setBranchStatus( + branchName: string, + description: string, + state: BranchStatus, + context?: string | null, +): Promise { + if (!is.nonEmptyString(context)) { + // already logged this case when validating the status check + return; + } + + await platform.setBranchStatus({ + branchName, + context, + description, + state, + }); +} + export function getReconfigureBranchName(prefix: string): string { return `${prefix}reconfigure`; } @@ -23,7 +43,7 @@ export async function validateReconfigureBranch( config: RenovateConfig, ): Promise { logger.debug('validateReconfigureBranch()'); - const context = `renovate/config-validation`; + const context = config.statusCheckNames?.configValidation; const branchName = getReconfigureBranchName(config.branchPrefix!); const branchExists = await scm.branchExists(branchName); @@ -48,14 +68,23 @@ export async function validateReconfigureBranch( return; } - const validationStatus = await platform.getBranchStatusCheck( - branchName, - 'renovate/config-validation', - ); - // if old status check is present skip validation - if (is.nonEmptyString(validationStatus)) { - logger.debug('Skipping validation check as status check already exists'); - return; + if (context) { + const validationStatus = await platform.getBranchStatusCheck( + branchName, + context, + ); + + // if old status check is present skip validation + if (is.nonEmptyString(validationStatus)) { + logger.debug( + 'Skipping validation check because status check already exists.', + ); + return; + } + } else { + logger.debug( + 'Status check is null or an empty string, skipping status check addition.', + ); } try { @@ -70,12 +99,12 @@ export async function validateReconfigureBranch( if (!is.nonEmptyString(configFileName)) { logger.warn('No config file found in reconfigure branch'); - await platform.setBranchStatus({ + await setBranchStatus( branchName, + 'Validation Failed - No config file found', + 'red', context, - description: 'Validation Failed - No config file found', - state: 'red', - }); + ); setReconfigureBranchCache(branchSha, false); await scm.checkoutBranch(config.defaultBranch!); return; @@ -90,12 +119,12 @@ export async function validateReconfigureBranch( if (!is.nonEmptyString(configFileRaw)) { logger.warn('Empty or invalid config file'); - await platform.setBranchStatus({ + await setBranchStatus( branchName, + 'Validation Failed - Empty/Invalid config file', + 'red', context, - description: 'Validation Failed - Empty/Invalid config file', - state: 'red', - }); + ); setReconfigureBranchCache(branchSha, false); await scm.checkoutBranch(config.baseBranch!); return; @@ -110,12 +139,12 @@ export async function validateReconfigureBranch( } } catch (err) { logger.error({ err }, 'Error while parsing config file'); - await platform.setBranchStatus({ + await setBranchStatus( branchName, + 'Validation Failed - Unparsable config file', + 'red', context, - description: 'Validation Failed - Unparsable config file', - state: 'red', - }); + ); setReconfigureBranchCache(branchSha, false); await scm.checkoutBranch(config.baseBranch!); return; @@ -150,24 +179,14 @@ export async function validateReconfigureBranch( content: body, }); } - await platform.setBranchStatus({ - branchName, - context, - description: 'Validation Failed', - state: 'red', - }); + await setBranchStatus(branchName, 'Validation Failed', 'red', context); setReconfigureBranchCache(branchSha, false); await scm.checkoutBranch(config.baseBranch!); return; } // passing check - await platform.setBranchStatus({ - branchName, - context, - description: 'Validation Successful', - state: 'green', - }); + await setBranchStatus(branchName, 'Validation Successful', 'green', context); setReconfigureBranchCache(branchSha, true); await scm.checkoutBranch(config.baseBranch!); diff --git a/lib/workers/repository/update/branch/artifacts.spec.ts b/lib/workers/repository/update/branch/artifacts.spec.ts index dd0a3215580f40..db588a04843445 100644 --- a/lib/workers/repository/update/branch/artifacts.spec.ts +++ b/lib/workers/repository/update/branch/artifacts.spec.ts @@ -1,5 +1,6 @@ -import { platform } from '../../../../../test/util'; +import { RenovateConfig, partial, platform } from '../../../../../test/util'; import { GlobalConfig } from '../../../../config/global'; +import { logger } from '../../../../logger'; import type { BranchConfig } from '../../../types'; import { setArtifactErrorStatus } from './artifacts'; @@ -14,6 +15,9 @@ describe('workers/repository/update/branch/artifacts', () => { branchName: 'renovate/pin', upgrades: [], artifactErrors: [{ lockFile: 'some' }], + statusCheckNames: partial({ + artifactError: 'renovate/artifact', + }), } satisfies BranchConfig; }); @@ -30,15 +34,50 @@ describe('workers/repository/update/branch/artifacts', () => { expect(platform.setBranchStatus).not.toHaveBeenCalled(); }); + it('skips status if statusCheckNames.artifactError is null', async () => { + await setArtifactErrorStatus({ + ...config, + statusCheckNames: partial({ + artifactError: null, + }), + }); + expect(logger.debug).toHaveBeenCalledWith( + 'Status check is null or an empty string, skipping status check addition.', + ); + expect(platform.setBranchStatus).not.toHaveBeenCalled(); + }); + + it('skips status if statusCheckNames.artifactError is empty string', async () => { + await setArtifactErrorStatus({ + ...config, + statusCheckNames: partial({ + artifactError: '', + }), + }); + expect(logger.debug).toHaveBeenCalledWith( + 'Status check is null or an empty string, skipping status check addition.', + ); + expect(platform.setBranchStatus).not.toHaveBeenCalled(); + }); + + it('skips status if statusCheckNames is undefined', async () => { + await setArtifactErrorStatus({ + ...config, + statusCheckNames: undefined, + }); + expect(logger.debug).toHaveBeenCalledWith( + 'Status check is null or an empty string, skipping status check addition.', + ); + expect(platform.setBranchStatus).not.toHaveBeenCalled(); + }); + it('skips status (dry-run)', async () => { GlobalConfig.set({ dryRun: 'full' }); - platform.getBranchStatusCheck.mockResolvedValueOnce(null); await setArtifactErrorStatus(config); expect(platform.setBranchStatus).not.toHaveBeenCalled(); }); it('skips status (no errors)', async () => { - platform.getBranchStatusCheck.mockResolvedValueOnce(null); config.artifactErrors = []; await setArtifactErrorStatus(config); expect(platform.setBranchStatus).not.toHaveBeenCalled(); diff --git a/lib/workers/repository/update/branch/artifacts.ts b/lib/workers/repository/update/branch/artifacts.ts index 0d395e4e770fdb..0fb8d87def1e7d 100644 --- a/lib/workers/repository/update/branch/artifacts.ts +++ b/lib/workers/repository/update/branch/artifacts.ts @@ -11,7 +11,14 @@ export async function setArtifactErrorStatus( return; } - const context = `renovate/artifacts`; + const context = config.statusCheckNames?.artifactError; + if (!context) { + logger.debug( + 'Status check is null or an empty string, skipping status check addition.', + ); + return; + } + const description = 'Artifact file update failure'; const state = 'red'; const existingState = await platform.getBranchStatusCheck( diff --git a/lib/workers/repository/update/branch/status-checks.spec.ts b/lib/workers/repository/update/branch/status-checks.spec.ts index 05dc5740d4a4a9..ff6c8f21e12705 100644 --- a/lib/workers/repository/update/branch/status-checks.spec.ts +++ b/lib/workers/repository/update/branch/status-checks.spec.ts @@ -1,4 +1,5 @@ -import { partial, platform } from '../../../../../test/util'; +import { RenovateConfig, partial, platform } from '../../../../../test/util'; +import { logger } from '../../../../logger'; import { ConfidenceConfig, StabilityConfig, @@ -14,6 +15,9 @@ describe('workers/repository/update/branch/status-checks', () => { beforeEach(() => { config = partial({ branchName: 'renovate/some-branch', + statusCheckNames: partial({ + minimumReleaseAge: 'renovate/stability-days', + }), }); }); @@ -45,6 +49,46 @@ describe('workers/repository/update/branch/status-checks', () => { expect(platform.getBranchStatusCheck).toHaveBeenCalledTimes(1); expect(platform.setBranchStatus).toHaveBeenCalledTimes(0); }); + + it('skips status if statusCheckNames.minimumReleaseAge is null', async () => { + config.stabilityStatus = 'green'; + await setStability({ + ...config, + statusCheckNames: partial({ + minimumReleaseAge: null, + }), + }); + expect(logger.debug).toHaveBeenCalledWith( + 'Status check is null or an empty string, skipping status check addition.', + ); + expect(platform.setBranchStatus).not.toHaveBeenCalled(); + }); + + it('skips status if statusCheckNames.minimumReleaseAge is empty string', async () => { + config.stabilityStatus = 'green'; + await setStability({ + ...config, + statusCheckNames: partial({ + minimumReleaseAge: '', + }), + }); + expect(logger.debug).toHaveBeenCalledWith( + 'Status check is null or an empty string, skipping status check addition.', + ); + expect(platform.setBranchStatus).not.toHaveBeenCalled(); + }); + + it('skips status if statusCheckNames is undefined', async () => { + config.stabilityStatus = 'green'; + await setStability({ + ...config, + statusCheckNames: undefined as never, + }); + expect(logger.debug).toHaveBeenCalledWith( + 'Status check is null or an empty string, skipping status check addition.', + ); + expect(platform.setBranchStatus).not.toHaveBeenCalled(); + }); }); describe('setConfidence', () => { @@ -53,6 +97,9 @@ describe('workers/repository/update/branch/status-checks', () => { beforeEach(() => { config = { branchName: 'renovate/some-branch', + statusCheckNames: partial({ + mergeConfidence: 'renovate/merge-confidence', + }), }; }); @@ -85,6 +132,49 @@ describe('workers/repository/update/branch/status-checks', () => { expect(platform.getBranchStatusCheck).toHaveBeenCalledTimes(1); expect(platform.setBranchStatus).toHaveBeenCalledTimes(0); }); + + it('skips status if statusCheckNames.mergeConfidence is null', async () => { + config.minimumConfidence = 'high'; + config.confidenceStatus = 'green'; + await setConfidence({ + ...config, + statusCheckNames: partial({ + mergeConfidence: null, + }), + }); + expect(logger.debug).toHaveBeenCalledWith( + 'Status check is null or an empty string, skipping status check addition.', + ); + expect(platform.setBranchStatus).not.toHaveBeenCalled(); + }); + + it('skips status if statusCheckNames.mergeConfidence is empty string', async () => { + config.minimumConfidence = 'high'; + config.confidenceStatus = 'green'; + await setConfidence({ + ...config, + statusCheckNames: partial({ + mergeConfidence: '', + }), + }); + expect(logger.debug).toHaveBeenCalledWith( + 'Status check is null or an empty string, skipping status check addition.', + ); + expect(platform.setBranchStatus).not.toHaveBeenCalled(); + }); + + it('skips status if statusCheckNames is undefined', async () => { + config.minimumConfidence = 'high'; + config.confidenceStatus = 'green'; + await setConfidence({ + ...config, + statusCheckNames: undefined as never, + }); + expect(logger.debug).toHaveBeenCalledWith( + 'Status check is null or an empty string, skipping status check addition.', + ); + expect(platform.setBranchStatus).not.toHaveBeenCalled(); + }); }); describe('getBranchStatus', () => { diff --git a/lib/workers/repository/update/branch/status-checks.ts b/lib/workers/repository/update/branch/status-checks.ts index ecb0167dc2d9d6..e162818bef8317 100644 --- a/lib/workers/repository/update/branch/status-checks.ts +++ b/lib/workers/repository/update/branch/status-checks.ts @@ -62,7 +62,15 @@ export async function setStability(config: StabilityConfig): Promise { if (!config.stabilityStatus) { return; } - const context = `renovate/stability-days`; + + const context = config.statusCheckNames?.minimumReleaseAge; + if (!context) { + logger.debug( + 'Status check is null or an empty string, skipping status check addition.', + ); + return; + } + const description = config.stabilityStatus === 'green' ? 'Updates have met minimum release age requirement' @@ -90,7 +98,14 @@ export async function setConfidence(config: ConfidenceConfig): Promise { ) { return; } - const context = `renovate/merge-confidence`; + const context = config.statusCheckNames?.mergeConfidence; + if (!context) { + logger.debug( + 'Status check is null or an empty string, skipping status check addition.', + ); + return; + } + const description = config.confidenceStatus === 'green' ? 'Updates have met Merge Confidence requirement' From d0db10e291b96fad62311173ae479ad48b257feb Mon Sep 17 00:00:00 2001 From: joegoldman2 <147369450+joegoldman2@users.noreply.github.com> Date: Thu, 14 Dec 2023 18:24:31 +0200 Subject: [PATCH 053/173] feat(presets): add opentelemetry-dotnet-contrib monorepo (#26298) --- lib/config/presets/internal/monorepo.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/config/presets/internal/monorepo.ts b/lib/config/presets/internal/monorepo.ts index a86f87f632073e..2ac4e34fd4fec1 100644 --- a/lib/config/presets/internal/monorepo.ts +++ b/lib/config/presets/internal/monorepo.ts @@ -379,6 +379,8 @@ const repoGroups = { openiddict: 'https://github.com/openiddict/openiddict-core', 'opentelemetry-dotnet': 'https://github.com/open-telemetry/opentelemetry-dotnet', + 'opentelemetry-dotnet-contrib': + 'https://github.com/open-telemetry/opentelemetry-dotnet-contrib', 'opentelemetry-erlang': 'https://github.com/open-telemetry/opentelemetry-erlang', 'opentelemetry-erlang-contrib': From 92cb4148d4559ef56e2c470a25386b1964960c86 Mon Sep 17 00:00:00 2001 From: Sergei Zharinov Date: Thu, 14 Dec 2023 17:26:13 -0300 Subject: [PATCH 054/173] refactor(bitbucket): Use `URLSearchParams` for PR list url construction (#26301) --- lib/modules/platform/bitbucket/index.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/modules/platform/bitbucket/index.ts b/lib/modules/platform/bitbucket/index.ts index 9f30b6e2aef8ff..aa8773aceacb8c 100644 --- a/lib/modules/platform/bitbucket/index.ts +++ b/lib/modules/platform/bitbucket/index.ts @@ -275,11 +275,15 @@ export async function getPrList(): Promise { logger.debug('getPrList()'); if (!config.prList) { logger.debug('Retrieving PR list'); - let url = `/2.0/repositories/${config.repository}/pullrequests?`; - url += utils.prStates.all.map((state) => 'state=' + state).join('&'); + const querySearchParams = new URL.URLSearchParams(); + for (const state of utils.prStates.all) { + querySearchParams.append('state', state); + } if (renovateUserUuid && !config.ignorePrAuthor) { - url += `&q=author.uuid="${renovateUserUuid}"`; + querySearchParams.append('q', `author.uuid="${renovateUserUuid}"`); } + const query = querySearchParams.toString(); + const url = `/2.0/repositories/${config.repository}/pullrequests?${query}`; const prs = ( await bitbucketHttp.getJson>(url, { paginate: true, From 6febbeb322b30a35e614a382a30041758d0d2126 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 14 Dec 2023 20:40:50 +0000 Subject: [PATCH 055/173] build(deps): update dependency @opentelemetry/instrumentation-bunyan to v0.34.0 (#26303) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 5100f925f7f850..ebf357828be020 100644 --- a/package.json +++ b/package.json @@ -157,7 +157,7 @@ "@opentelemetry/context-async-hooks": "1.18.1", "@opentelemetry/exporter-trace-otlp-http": "0.45.1", "@opentelemetry/instrumentation": "0.45.1", - "@opentelemetry/instrumentation-bunyan": "0.33.0", + "@opentelemetry/instrumentation-bunyan": "0.34.0", "@opentelemetry/instrumentation-http": "0.45.1", "@opentelemetry/resources": "1.18.1", "@opentelemetry/sdk-trace-base": "1.18.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 57370367c81a69..a3f6e12878e415 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -45,8 +45,8 @@ importers: specifier: 0.45.1 version: 0.45.1(@opentelemetry/api@1.7.0) '@opentelemetry/instrumentation-bunyan': - specifier: 0.33.0 - version: 0.33.0(@opentelemetry/api@1.7.0) + specifier: 0.34.0 + version: 0.34.0(@opentelemetry/api@1.7.0) '@opentelemetry/instrumentation-http': specifier: 0.45.1 version: 0.45.1(@opentelemetry/api@1.7.0) @@ -2514,13 +2514,14 @@ packages: '@opentelemetry/sdk-trace-base': 1.18.1(@opentelemetry/api@1.7.0) dev: false - /@opentelemetry/instrumentation-bunyan@0.33.0(@opentelemetry/api@1.7.0): - resolution: {integrity: sha512-i3xfmhajtOEuFO+9yMU/wJiH0tY4VtIlbJKGIKVHFOsoNqPQpG7iUQP01p0FRoje+UB+ZUvs4hU7fCZzwtnC1g==} + /@opentelemetry/instrumentation-bunyan@0.34.0(@opentelemetry/api@1.7.0): + resolution: {integrity: sha512-UjuvggGrclyn6avTcMAdqLyrrTV26ufB73vPBPlEmA3a2dtYCS07zW82Kacxi5emZDpmHIk6zQE18DqCb/xfpA==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': ^1.3.0 dependencies: '@opentelemetry/api': 1.7.0 + '@opentelemetry/api-logs': 0.45.1 '@opentelemetry/instrumentation': 0.45.1(@opentelemetry/api@1.7.0) '@types/bunyan': 1.8.9 transitivePeerDependencies: From bfa16e2e7df60b46c1308fc87e416a88a633b76a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Korczak?= Date: Fri, 15 Dec 2023 08:07:09 +0100 Subject: [PATCH 056/173] feat(presets): add panda-css monorepo (#26306) --- lib/config/presets/internal/monorepo.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/config/presets/internal/monorepo.ts b/lib/config/presets/internal/monorepo.ts index 2ac4e34fd4fec1..8bec5d9d05274c 100644 --- a/lib/config/presets/internal/monorepo.ts +++ b/lib/config/presets/internal/monorepo.ts @@ -388,6 +388,7 @@ const repoGroups = { 'opentelemetry-go': 'https://github.com/open-telemetry/opentelemetry-go', 'opentelemetry-js': 'https://github.com/open-telemetry/opentelemetry-js', orleans: 'https://github.com/dotnet/orleans', + 'panda-css': 'https://github.com/chakra-ui/panda', parcel: 'https://github.com/parcel-bundler/parcel', 'percy-cli': 'https://github.com/percy/cli', picassojs: 'https://github.com/qlik-oss/picasso.js', From 6884d83a0573ebd40210cf0717c1814afd68a649 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Korczak?= Date: Fri, 15 Dec 2023 08:07:27 +0100 Subject: [PATCH 057/173] feat(presets): add zag-js monorepo (#26305) --- lib/config/presets/internal/monorepo.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/config/presets/internal/monorepo.ts b/lib/config/presets/internal/monorepo.ts index 8bec5d9d05274c..87dc2011257032 100644 --- a/lib/config/presets/internal/monorepo.ts +++ b/lib/config/presets/internal/monorepo.ts @@ -493,6 +493,7 @@ const repoGroups = { 'https://github.com/xunit/xunit.analyzers', ], yarn: 'https://github.com/yarnpkg/berry', + 'zag-js': 'https://github.com/chakra-ui/zag', 'zxing-net': 'https://github.com/micjahn/ZXing.Net', }; From 6a3e74e8ec36128e38777d79ee8c24fc1a569b78 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 15 Dec 2023 11:28:39 +0100 Subject: [PATCH 058/173] fix(deps): update ghcr.io/containerbase/sidecar docker tag to v9.30.5 (#26313) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- lib/config/options/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/config/options/index.ts b/lib/config/options/index.ts index bff4368287f67b..be64a6ce0e3b76 100644 --- a/lib/config/options/index.ts +++ b/lib/config/options/index.ts @@ -393,7 +393,7 @@ const options: RenovateOptions[] = [ description: 'Change this value to override the default Renovate sidecar image.', type: 'string', - default: 'ghcr.io/containerbase/sidecar:9.30.4', + default: 'ghcr.io/containerbase/sidecar:9.30.5', globalOnly: true, }, { From b181efb83f955c5898bb0d15507aa8b13c8cad99 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 15 Dec 2023 12:03:58 +0000 Subject: [PATCH 059/173] chore(deps): update ghcr.io/containerbase/devcontainer docker tag to v9.30.5 (#26316) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .devcontainer/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 83a81ac05c6046..d42c95a1bd3fee 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1 +1 @@ -FROM ghcr.io/containerbase/devcontainer:9.30.4 +FROM ghcr.io/containerbase/devcontainer:9.30.5 From e2b97aecea88a1a52f5ce43084d370cdfecef0d5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 15 Dec 2023 12:23:15 +0000 Subject: [PATCH 060/173] chore(deps): update dependency ts-node to v10.9.2 (#26317) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 44 ++++++++++++++++++++++---------------------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/package.json b/package.json index ebf357828be020..ee70f5313d478c 100644 --- a/package.json +++ b/package.json @@ -343,7 +343,7 @@ "tar": "6.2.0", "tmp-promise": "3.0.3", "ts-jest": "29.1.1", - "ts-node": "10.9.1", + "ts-node": "10.9.2", "type-fest": "4.8.3", "typescript": "5.3.3", "unified": "9.2.2" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a3f6e12878e415..dea4ff9cf37e51 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -546,7 +546,7 @@ importers: version: 8.0.3 jest: specifier: 29.7.0 - version: 29.7.0(@types/node@18.19.3)(ts-node@10.9.1) + version: 29.7.0(@types/node@18.19.3)(ts-node@10.9.2) jest-extended: specifier: 4.0.2 version: 4.0.2(jest@29.7.0) @@ -593,8 +593,8 @@ importers: specifier: 29.1.1 version: 29.1.1(@babel/core@7.23.5)(@jest/types@29.6.3)(jest@29.7.0)(typescript@5.3.3) ts-node: - specifier: 10.9.1 - version: 10.9.1(@swc/core@1.3.100)(@types/node@18.19.3)(typescript@5.3.3) + specifier: 10.9.2 + version: 10.9.2(@swc/core@1.3.100)(@types/node@18.19.3)(typescript@5.3.3) type-fest: specifier: 4.8.3 version: 4.8.3 @@ -2032,7 +2032,7 @@ packages: slash: 3.0.0 dev: true - /@jest/core@29.7.0(ts-node@10.9.1): + /@jest/core@29.7.0(ts-node@10.9.2): resolution: {integrity: sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: @@ -2053,7 +2053,7 @@ packages: exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@18.19.3)(ts-node@10.9.1) + jest-config: 29.7.0(@types/node@18.19.3)(ts-node@10.9.2) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -5077,7 +5077,7 @@ packages: typescript: 5.3.3 dev: true - /create-jest@29.7.0(@types/node@18.19.3)(ts-node@10.9.1): + /create-jest@29.7.0(@types/node@18.19.3)(ts-node@10.9.2): resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -5086,7 +5086,7 @@ packages: chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@18.19.3)(ts-node@10.9.1) + jest-config: 29.7.0(@types/node@18.19.3)(ts-node@10.9.2) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -5723,7 +5723,7 @@ packages: '@typescript-eslint/eslint-plugin': 6.13.2(@typescript-eslint/parser@6.13.2)(eslint@8.55.0)(typescript@5.3.3) '@typescript-eslint/utils': 5.62.0(eslint@8.55.0)(typescript@5.3.3) eslint: 8.55.0 - jest: 29.7.0(@types/node@18.19.3)(ts-node@10.9.1) + jest: 29.7.0(@types/node@18.19.3)(ts-node@10.9.2) transitivePeerDependencies: - supports-color - typescript @@ -7136,7 +7136,7 @@ packages: - supports-color dev: true - /jest-cli@29.7.0(@types/node@18.19.3)(ts-node@10.9.1): + /jest-cli@29.7.0(@types/node@18.19.3)(ts-node@10.9.2): resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -7146,14 +7146,14 @@ packages: node-notifier: optional: true dependencies: - '@jest/core': 29.7.0(ts-node@10.9.1) + '@jest/core': 29.7.0(ts-node@10.9.2) '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@18.19.3)(ts-node@10.9.1) + create-jest: 29.7.0(@types/node@18.19.3)(ts-node@10.9.2) exit: 0.1.2 import-local: 3.1.0 - jest-config: 29.7.0(@types/node@18.19.3)(ts-node@10.9.1) + jest-config: 29.7.0(@types/node@18.19.3)(ts-node@10.9.2) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -7164,7 +7164,7 @@ packages: - ts-node dev: true - /jest-config@29.7.0(@types/node@18.19.3)(ts-node@10.9.1): + /jest-config@29.7.0(@types/node@18.19.3)(ts-node@10.9.2): resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: @@ -7199,7 +7199,7 @@ packages: pretty-format: 29.7.0 slash: 3.0.0 strip-json-comments: 3.1.1 - ts-node: 10.9.1(@swc/core@1.3.100)(@types/node@18.19.3)(typescript@5.3.3) + ts-node: 10.9.2(@swc/core@1.3.100)(@types/node@18.19.3)(typescript@5.3.3) transitivePeerDependencies: - babel-plugin-macros - supports-color @@ -7254,7 +7254,7 @@ packages: jest: optional: true dependencies: - jest: 29.7.0(@types/node@18.19.3)(ts-node@10.9.1) + jest: 29.7.0(@types/node@18.19.3)(ts-node@10.9.2) jest-diff: 29.7.0 jest-get-type: 29.6.3 dev: true @@ -7332,7 +7332,7 @@ packages: jest: ^24.0.0 || ^25.0.0 || ^26.0.0 || ^27.0.0 || ^28.0.0 || ^29.0.0 typescript: ^3.0.0 || ^4.0.0 || ^5.0.0 dependencies: - jest: 29.7.0(@types/node@18.19.3)(ts-node@10.9.1) + jest: 29.7.0(@types/node@18.19.3)(ts-node@10.9.2) ts-essentials: 7.0.3(typescript@5.3.3) typescript: 5.3.3 dev: true @@ -7523,7 +7523,7 @@ packages: supports-color: 8.1.1 dev: true - /jest@29.7.0(@types/node@18.19.3)(ts-node@10.9.1): + /jest@29.7.0(@types/node@18.19.3)(ts-node@10.9.2): resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -7533,10 +7533,10 @@ packages: node-notifier: optional: true dependencies: - '@jest/core': 29.7.0(ts-node@10.9.1) + '@jest/core': 29.7.0(ts-node@10.9.2) '@jest/types': 29.6.3 import-local: 3.1.0 - jest-cli: 29.7.0(@types/node@18.19.3)(ts-node@10.9.1) + jest-cli: 29.7.0(@types/node@18.19.3)(ts-node@10.9.2) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -10154,7 +10154,7 @@ packages: '@jest/types': 29.6.3 bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@18.19.3)(ts-node@10.9.1) + jest: 29.7.0(@types/node@18.19.3)(ts-node@10.9.2) jest-util: 29.7.0 json5: 2.2.3 lodash.memoize: 4.1.2 @@ -10164,8 +10164,8 @@ packages: yargs-parser: 21.1.1 dev: true - /ts-node@10.9.1(@swc/core@1.3.100)(@types/node@18.19.3)(typescript@5.3.3): - resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} + /ts-node@10.9.2(@swc/core@1.3.100)(@types/node@18.19.3)(typescript@5.3.3): + resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} hasBin: true peerDependencies: '@swc/core': '>=1.2.50' From 014d32c8e41f11e9d3510e309916d6a019924007 Mon Sep 17 00:00:00 2001 From: Robert Munteanu Date: Fri, 15 Dec 2023 16:28:24 +0100 Subject: [PATCH 061/173] feat(presets): add json-smart-v2 monorepo (#26322) --- lib/config/presets/internal/monorepo.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/config/presets/internal/monorepo.ts b/lib/config/presets/internal/monorepo.ts index 87dc2011257032..92d971222e7dc2 100644 --- a/lib/config/presets/internal/monorepo.ts +++ b/lib/config/presets/internal/monorepo.ts @@ -316,6 +316,7 @@ const repoGroups = { 'https://github.com/jestjs/jest', ], jna: 'https://github.com/java-native-access/jna', + 'json-smart-v2': 'https://github.com/netplex/json-smart-v2', jsplumb: 'https://github.com/jsplumb/jsplumb', junit5: 'https://github.com/junit-team/junit5', kotlin: 'https://github.com/JetBrains/kotlin', From 5b8dd8e0aadb3e5eabb6ea562c8763521e4c72d9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 15 Dec 2023 19:54:48 +0000 Subject: [PATCH 062/173] chore(deps): update devcontainers/ci action to v0.3.1900000339 (#26327) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/devcontainer.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/devcontainer.yml b/.github/workflows/devcontainer.yml index 77f35cee730547..e71f5b0cdb0a6f 100644 --- a/.github/workflows/devcontainer.yml +++ b/.github/workflows/devcontainer.yml @@ -21,6 +21,6 @@ jobs: uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Build and run dev container task - uses: devcontainers/ci@c3e31cc561800ac318ed000e22ffc6713c93d009 # v0.3.1900000338 + uses: devcontainers/ci@3d462823359c481c587cb7426f39775f24257115 # v0.3.1900000339 with: runCmd: pnpm build From 0d12eb9761b97a46ef4ee771c9b92dcb8ffc50e4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 16 Dec 2023 00:30:00 +0000 Subject: [PATCH 063/173] chore(deps): update pnpm to v8.12.0 (#26330) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ee70f5313d478c..b57bef38f8e4f4 100644 --- a/package.json +++ b/package.json @@ -348,7 +348,7 @@ "typescript": "5.3.3", "unified": "9.2.2" }, - "packageManager": "pnpm@8.11.0", + "packageManager": "pnpm@8.12.0", "files": [ "dist", "renovate-schema.json" From ad2f62c14e0503e63b70e0edf303c780bff834fa Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 16 Dec 2023 00:42:18 +0000 Subject: [PATCH 064/173] chore(deps): update pnpm to v8.12.1 (#26331) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b57bef38f8e4f4..db56adabde7d91 100644 --- a/package.json +++ b/package.json @@ -348,7 +348,7 @@ "typescript": "5.3.3", "unified": "9.2.2" }, - "packageManager": "pnpm@8.12.0", + "packageManager": "pnpm@8.12.1", "files": [ "dist", "renovate-schema.json" From 97abffb8c3e828ec909595b6de7b3c3e0323340e Mon Sep 17 00:00:00 2001 From: Erwan Finot Date: Sat, 16 Dec 2023 06:15:17 +0100 Subject: [PATCH 065/173] fix(manager/git-submodules): Fix branch detection for special branch value `.` (#26329) --- lib/modules/manager/git-submodules/extract.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/modules/manager/git-submodules/extract.ts b/lib/modules/manager/git-submodules/extract.ts index 6e0ac14ec4b9f8..64cc0806cd0679 100644 --- a/lib/modules/manager/git-submodules/extract.ts +++ b/lib/modules/manager/git-submodules/extract.ts @@ -70,7 +70,7 @@ async function getBranch( ).trim(); return branchFromConfig === '.' - ? (await git.branch(['--show-current'])).current.trim() + ? (await git.branch(['--list'])).current.trim() : branchFromConfig || (await getDefaultBranch(subModuleUrl)).trim(); } From 33b7600e9801ec7f46e4ad2018da76ebf5e3171b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 16 Dec 2023 15:59:53 +0000 Subject: [PATCH 066/173] fix(deps): update ghcr.io/containerbase/sidecar docker tag to v9.30.6 (#26335) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- lib/config/options/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/config/options/index.ts b/lib/config/options/index.ts index be64a6ce0e3b76..2aa388e3f230c3 100644 --- a/lib/config/options/index.ts +++ b/lib/config/options/index.ts @@ -393,7 +393,7 @@ const options: RenovateOptions[] = [ description: 'Change this value to override the default Renovate sidecar image.', type: 'string', - default: 'ghcr.io/containerbase/sidecar:9.30.5', + default: 'ghcr.io/containerbase/sidecar:9.30.6', globalOnly: true, }, { From b528b8c2d6806a0ac26c70f251b9476a5c24a666 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 16 Dec 2023 15:59:55 +0000 Subject: [PATCH 067/173] chore(deps): update ghcr.io/containerbase/devcontainer docker tag to v9.30.6 (#26334) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .devcontainer/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index d42c95a1bd3fee..7490a0f2687871 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1 +1 @@ -FROM ghcr.io/containerbase/devcontainer:9.30.5 +FROM ghcr.io/containerbase/devcontainer:9.30.6 From e80b882156b386276c48542e96701bb0df3a95e3 Mon Sep 17 00:00:00 2001 From: Sergei Zharinov Date: Sat, 16 Dec 2023 15:08:13 -0300 Subject: [PATCH 068/173] feat(bitbucket): Server-side filtering of PR list response (#26336) --- lib/modules/platform/bitbucket/index.spec.ts | 17 +++++++++-------- lib/modules/platform/bitbucket/index.ts | 3 ++- lib/modules/platform/bitbucket/types.ts | 2 +- lib/modules/platform/bitbucket/utils.ts | 15 +++++++++++++++ 4 files changed, 27 insertions(+), 10 deletions(-) diff --git a/lib/modules/platform/bitbucket/index.spec.ts b/lib/modules/platform/bitbucket/index.spec.ts index 8a6695384d53ef..8e5318b180de1b 100644 --- a/lib/modules/platform/bitbucket/index.spec.ts +++ b/lib/modules/platform/bitbucket/index.spec.ts @@ -3,6 +3,7 @@ import type { logger as _logger } from '../../../logger'; import type * as _git from '../../../util/git'; import { setBaseUrl } from '../../../util/http/bitbucket'; import type { Platform, PlatformResult, RepoParams } from '../types'; +import { prFieldsFilter } from './utils'; jest.mock('../../../util/git'); jest.mock('../../../util/host-rules'); @@ -235,7 +236,7 @@ describe('modules/platform/bitbucket/index', () => { const scope = await initRepoMock(); scope .get( - '/2.0/repositories/some/repo/pullrequests?state=OPEN&state=MERGED&state=DECLINED&state=SUPERSEDED&pagelen=50', + `/2.0/repositories/some/repo/pullrequests?state=OPEN&state=MERGED&state=DECLINED&state=SUPERSEDED&fields=${prFieldsFilter}&pagelen=50`, ) .reply(200, { values: [pr] }) .get('/2.0/repositories/some/repo/pullrequests/5') @@ -248,7 +249,7 @@ describe('modules/platform/bitbucket/index', () => { const scope = await initRepoMock(); scope .get( - '/2.0/repositories/some/repo/pullrequests?state=OPEN&state=MERGED&state=DECLINED&state=SUPERSEDED&pagelen=50', + `/2.0/repositories/some/repo/pullrequests?state=OPEN&state=MERGED&state=DECLINED&state=SUPERSEDED&fields=${prFieldsFilter}&pagelen=50`, ) .reply(200, { values: [pr] }); @@ -753,7 +754,7 @@ describe('modules/platform/bitbucket/index', () => { await initRepoMock(undefined, null, scope); scope .get( - '/2.0/repositories/some/repo/pullrequests?state=OPEN&state=MERGED&state=DECLINED&state=SUPERSEDED&q=author.uuid="12345"&pagelen=50', + `/2.0/repositories/some/repo/pullrequests?state=OPEN&state=MERGED&state=DECLINED&state=SUPERSEDED&q=author.uuid="12345"&fields=${prFieldsFilter}&pagelen=50`, ) .reply(200, { values: [ @@ -779,7 +780,7 @@ describe('modules/platform/bitbucket/index', () => { const scope = await initRepoMock(); scope .get( - '/2.0/repositories/some/repo/pullrequests?state=OPEN&state=MERGED&state=DECLINED&state=SUPERSEDED&pagelen=50', + `/2.0/repositories/some/repo/pullrequests?state=OPEN&state=MERGED&state=DECLINED&state=SUPERSEDED&fields=${prFieldsFilter}&pagelen=50`, ) .reply(200, { values: [pr] }); expect( @@ -805,7 +806,7 @@ describe('modules/platform/bitbucket/index', () => { const scope = await initRepoMock(); scope .get( - '/2.0/repositories/some/repo/pullrequests?state=OPEN&state=MERGED&state=DECLINED&state=SUPERSEDED&pagelen=50', + `/2.0/repositories/some/repo/pullrequests?state=OPEN&state=MERGED&state=DECLINED&state=SUPERSEDED&fields=${prFieldsFilter}&pagelen=50`, ) .reply(200, { values: [ @@ -843,7 +844,7 @@ describe('modules/platform/bitbucket/index', () => { const scope = await initRepoMock({}, { is_private: true }); scope .get( - '/2.0/repositories/some/repo/pullrequests?state=OPEN&state=MERGED&state=DECLINED&state=SUPERSEDED&pagelen=50', + `/2.0/repositories/some/repo/pullrequests?state=OPEN&state=MERGED&state=DECLINED&state=SUPERSEDED&fields=${prFieldsFilter}&pagelen=50`, ) .reply(200, { values: [ @@ -883,7 +884,7 @@ describe('modules/platform/bitbucket/index', () => { const scope = await initRepoMock({}, { is_private: false }); scope .get( - '/2.0/repositories/some/repo/pullrequests?state=OPEN&state=MERGED&state=DECLINED&state=SUPERSEDED&pagelen=50', + `/2.0/repositories/some/repo/pullrequests?state=OPEN&state=MERGED&state=DECLINED&state=SUPERSEDED&fields=${prFieldsFilter}&pagelen=50`, ) .reply(200, { values: [ @@ -927,7 +928,7 @@ describe('modules/platform/bitbucket/index', () => { const scope = await initRepoMock({}, { is_private: false }); scope .get( - '/2.0/repositories/some/repo/pullrequests?state=OPEN&state=MERGED&state=DECLINED&state=SUPERSEDED&pagelen=50', + `/2.0/repositories/some/repo/pullrequests?state=OPEN&state=MERGED&state=DECLINED&state=SUPERSEDED&fields=${prFieldsFilter}&pagelen=50`, ) .reply(200, { values: [ diff --git a/lib/modules/platform/bitbucket/index.ts b/lib/modules/platform/bitbucket/index.ts index aa8773aceacb8c..ad94a1e098be90 100644 --- a/lib/modules/platform/bitbucket/index.ts +++ b/lib/modules/platform/bitbucket/index.ts @@ -44,7 +44,7 @@ import type { RepoInfoBody, } from './types'; import * as utils from './utils'; -import { mergeBodyTransformer } from './utils'; +import { mergeBodyTransformer, prFieldsFilter } from './utils'; export const id = 'bitbucket'; @@ -282,6 +282,7 @@ export async function getPrList(): Promise { if (renovateUserUuid && !config.ignorePrAuthor) { querySearchParams.append('q', `author.uuid="${renovateUserUuid}"`); } + querySearchParams.append('fields', prFieldsFilter); const query = querySearchParams.toString(); const url = `/2.0/repositories/${config.repository}/pullrequests?${query}`; const prs = ( diff --git a/lib/modules/platform/bitbucket/types.ts b/lib/modules/platform/bitbucket/types.ts index 2bd692ca6b2680..56bc4f82717cb1 100644 --- a/lib/modules/platform/bitbucket/types.ts +++ b/lib/modules/platform/bitbucket/types.ts @@ -89,7 +89,7 @@ export interface PrResponse { name: string; }; }; - reviewers: Array; + reviewers: Account[]; created_on: string; } diff --git a/lib/modules/platform/bitbucket/utils.ts b/lib/modules/platform/bitbucket/utils.ts index 06d72dacd31b23..4d9ee1e87967d3 100644 --- a/lib/modules/platform/bitbucket/utils.ts +++ b/lib/modules/platform/bitbucket/utils.ts @@ -72,3 +72,18 @@ export function prInfo(pr: PrResponse): Pr { createdAt: pr.created_on, }; } + +export const prFieldsFilter = [ + 'values.id', + 'values.title', + 'values.state', + 'values.links.commits.href', + 'values.summary.raw', + 'values.source.branch.name', + 'values.destination.branch.name', + 'values.reviewers.display_name', + 'values.reviewers.uuid', + 'values.reviewers.nickname', + 'values.reviewers.account_status', + 'values.created_on', +].join(','); From c7eaf60eb6aa00a74e06952a3ebc812a2ce47d3b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 17 Dec 2023 06:39:21 +0100 Subject: [PATCH 069/173] fix(data): automatic update of static data (#26339) --- data/debian-distro-info.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/debian-distro-info.json b/data/debian-distro-info.json index 0df090a94b72a0..a650201981946e 100644 --- a/data/debian-distro-info.json +++ b/data/debian-distro-info.json @@ -39,7 +39,7 @@ "series": "potato", "created": "1999-03-09", "release": "2000-08-15", - "eol": "2003-07-30" + "eol": "2003-06-30" }, "v3": { "codename": "Woody", From 24f8f0dd88e2da291b3686934e1e820f9d56d770 Mon Sep 17 00:00:00 2001 From: Johannes Feichtner <343448+Churro@users.noreply.github.com> Date: Sun, 17 Dec 2023 06:45:33 +0100 Subject: [PATCH 070/173] feat(manager/poetry): add support for explicit sources (#26337) --- .../poetry/__snapshots__/extract.spec.ts.snap | 10 +- lib/modules/manager/poetry/extract.spec.ts | 117 ++++-- lib/modules/manager/poetry/schema.spec.ts | 360 ++++++++++++++++++ lib/modules/manager/poetry/schema.ts | 107 +++++- 4 files changed, 542 insertions(+), 52 deletions(-) create mode 100644 lib/modules/manager/poetry/schema.spec.ts diff --git a/lib/modules/manager/poetry/__snapshots__/extract.spec.ts.snap b/lib/modules/manager/poetry/__snapshots__/extract.spec.ts.snap index fb65b2995258b2..23cdcb538c841e 100644 --- a/lib/modules/manager/poetry/__snapshots__/extract.spec.ts.snap +++ b/lib/modules/manager/poetry/__snapshots__/extract.spec.ts.snap @@ -358,6 +358,7 @@ exports[`modules/manager/poetry/extract extractPackageFile() extracts multiple d "depType": "dependencies", "managerData": { "nestedVersion": true, + "sourceName": undefined, }, "versioning": "poetry", }, @@ -368,6 +369,7 @@ exports[`modules/manager/poetry/extract extractPackageFile() extracts multiple d "depType": "dependencies", "managerData": { "nestedVersion": true, + "sourceName": undefined, }, "versioning": "poetry", }, @@ -542,14 +544,6 @@ exports[`modules/manager/poetry/extract extractPackageFile() extracts multiple d ] `; -exports[`modules/manager/poetry/extract extractPackageFile() extracts registries 1`] = ` -[ - "https://foo.bar/simple/", - "https://bar.baz/+simple/", - "https://pypi.org/pypi/", -] -`; - exports[`modules/manager/poetry/extract extractPackageFile() handles multiple constraint dependencies 1`] = ` { "deps": [ diff --git a/lib/modules/manager/poetry/extract.spec.ts b/lib/modules/manager/poetry/extract.spec.ts index b0796d40434e59..13c11daa9045eb 100644 --- a/lib/modules/manager/poetry/extract.spec.ts +++ b/lib/modules/manager/poetry/extract.spec.ts @@ -78,29 +78,6 @@ describe('modules/manager/poetry/extract', () => { expect(res?.deps).toHaveLength(3); }); - it('extracts registries', async () => { - const res = await extractPackageFile(pyproject6toml, filename); - expect(res?.registryUrls).toMatchSnapshot(); - expect(res?.registryUrls).toHaveLength(3); - }); - - it('can parse empty registries', async () => { - const res = await extractPackageFile(pyproject7toml, filename); - expect(res?.registryUrls).toBeUndefined(); - }); - - it('can parse missing registries', async () => { - const res = await extractPackageFile(pyproject1toml, filename); - expect(res?.registryUrls).toBeUndefined(); - }); - - it('dedupes registries', async () => { - const res = await extractPackageFile(pyproject8toml, filename); - expect(res).toMatchObject({ - registryUrls: ['https://pypi.org/pypi/', 'https://bar.baz/+simple/'], - }); - }); - it('extracts mixed versioning types', async () => { const res = await extractPackageFile(pyproject9toml, filename); expect(res).toMatchSnapshot({ @@ -305,5 +282,99 @@ describe('modules/manager/poetry/extract', () => { registryUrls: null, }); }); + + describe('registry URLs', () => { + it('can parse empty registries', async () => { + const res = await extractPackageFile(pyproject7toml, filename); + expect(res?.registryUrls).toBeUndefined(); + }); + + it('can parse missing registries', async () => { + const res = await extractPackageFile(pyproject1toml, filename); + expect(res?.registryUrls).toBeUndefined(); + }); + + it('extracts registries', async () => { + const res = await extractPackageFile(pyproject6toml, filename); + expect(res?.registryUrls).toMatchObject([ + 'https://foo.bar/simple/', + 'https://bar.baz/+simple/', + 'https://pypi.org/pypi/', + ]); + }); + + it('dedupes registries', async () => { + const res = await extractPackageFile(pyproject8toml, filename); + expect(res?.registryUrls).toMatchObject([ + 'https://pypi.org/pypi/', + 'https://bar.baz/+simple/', + ]); + }); + + it('source with priority="default" and implicit PyPI priority="primary"', async () => { + const content = codeBlock` + [tool.poetry.dependencies] + python = "^3.11" + + [[tool.poetry.source]] + name = "foo" + url = "https://foo.bar/simple/" + priority = "default" + + [[tool.poetry.source]] + name = "PyPI" + `; + const res = await extractPackageFile(content, filename); + expect(res?.registryUrls).toMatchObject([ + 'https://foo.bar/simple/', + 'https://pypi.org/pypi/', + ]); + }); + + it('source with implicit priority and PyPI with priority="explicit"', async () => { + const content = codeBlock` + [tool.poetry.dependencies] + python = "^3.11" + + [[tool.poetry.source]] + name = "foo" + url = "https://foo.bar/simple/" + + [[tool.poetry.source]] + name = "PyPI" + priority = "explicit" + `; + const res = await extractPackageFile(content, filename); + expect(res?.registryUrls).toMatchObject(['https://foo.bar/simple/']); + }); + + it('supports dependencies with explicit source', async () => { + const content = codeBlock` + [tool.poetry.dependencies] + attrs = "^23.1.0" + typer = { version = "^0.9.0", source = "pypi" } + requests-cache = { version = "^1.1.0", source = "artifactory" } + + [[tool.poetry.source]] + name = "artifactory" + url = "https://example.com" + priority = "explicit" + `; + const res = await extractPackageFile(content, filename); + expect(res?.deps).toMatchObject([ + { depName: 'attrs', currentValue: '^23.1.0' }, + { + depName: 'typer', + currentValue: '^0.9.0', + registryUrls: ['https://pypi.org/pypi/'], + }, + { + depName: 'requests-cache', + currentValue: '^1.1.0', + registryUrls: ['https://example.com'], + }, + ]); + }); + }); }); }); diff --git a/lib/modules/manager/poetry/schema.spec.ts b/lib/modules/manager/poetry/schema.spec.ts new file mode 100644 index 00000000000000..4da5b1e6e99367 --- /dev/null +++ b/lib/modules/manager/poetry/schema.spec.ts @@ -0,0 +1,360 @@ +import { PoetrySources } from './schema'; + +describe('modules/manager/poetry/schema', () => { + describe('PoetrySources', () => { + it('parses default values', () => { + expect(PoetrySources.parse([])).toBeEmptyArray(); + expect(PoetrySources.parse([null])).toBeEmptyArray(); + }); + + it('parses unordered sources', () => { + expect( + PoetrySources.parse([ + { name: 'missing-url' }, + { name: 'missing-priority', url: 'https://some-source.com' }, + { + name: 'foo-Secondary', + priority: 'secondary', + url: 'https://some-vcs.com/secondary', + }, + { name: 'PyPI', priority: 'primary' }, + { + name: 'foo-Primary', + priority: 'primary', + url: 'https://some-vcs.com/primary', + }, + { + name: 'foo-Default', + priority: 'default', + url: 'https://some-vcs.com/default', + }, + { + name: 'foo-Explicit', + priority: 'explicit', + url: 'https://some-vcs.com/explicit', + }, + { + name: 'foo-Supplemental', + priority: 'supplemental', + url: 'https://some-vcs.com/supplemental', + }, + ]), + ).toEqual([ + { + name: 'foo-default', + priority: 'default', + url: 'https://some-vcs.com/default', + }, + { + name: 'missing-priority', + priority: 'primary', + url: 'https://some-source.com', + }, + { + name: 'pypi', + priority: 'primary', + url: 'https://pypi.org/pypi/', + }, + { + name: 'foo-primary', + priority: 'primary', + url: 'https://some-vcs.com/primary', + }, + { + name: 'foo-secondary', + priority: 'secondary', + url: 'https://some-vcs.com/secondary', + }, + { + name: 'foo-supplemental', + priority: 'supplemental', + url: 'https://some-vcs.com/supplemental', + }, + { + name: 'foo-explicit', + priority: 'explicit', + url: 'https://some-vcs.com/explicit', + }, + ]); + }); + + it('implicit use of PyPI source', () => { + expect( + PoetrySources.parse([ + { + name: 'foo-Supplemental', + priority: 'supplemental', + url: 'https://some-vcs.com/supplemental', + }, + ]), + ).toEqual([ + { + name: 'pypi', + priority: 'default', + url: 'https://pypi.org/pypi/', + }, + { + name: 'foo-supplemental', + priority: 'supplemental', + url: 'https://some-vcs.com/supplemental', + }, + ]); + + expect( + PoetrySources.parse([ + { + name: 'foo-Primary', + priority: 'primary', + url: 'https://some-vcs.com/primary', + }, + ]), + ).toEqual([ + { + name: 'foo-primary', + priority: 'primary', + url: 'https://some-vcs.com/primary', + }, + { + name: 'pypi', + priority: 'secondary', + url: 'https://pypi.org/pypi/', + }, + ]); + }); + + it('source with priority="default"', () => { + expect( + PoetrySources.parse([ + { + name: 'foo', + priority: 'default', + url: 'https://foo.bar/simple/', + }, + ]), + ).toEqual([ + { + name: 'foo', + priority: 'default', + url: 'https://foo.bar/simple/', + }, + ]); + }); + + it('PyPI source with priority="default"', () => { + expect( + PoetrySources.parse([ + { + name: 'PyPI', + priority: 'default', + }, + ]), + ).toEqual([ + { + name: 'pypi', + priority: 'default', + url: 'https://pypi.org/pypi/', + }, + ]); + }); + + it('source with priority="primary"', () => { + expect( + PoetrySources.parse([ + { + name: 'foo', + priority: 'primary', + url: 'https://foo.bar/simple/', + }, + ]), + ).toEqual([ + { + name: 'foo', + priority: 'primary', + url: 'https://foo.bar/simple/', + }, + { + name: 'pypi', + priority: 'secondary', + url: 'https://pypi.org/pypi/', + }, + ]); + }); + + it('source with implicit priority="primary"', () => { + expect( + PoetrySources.parse([ + { + name: 'foo', + url: 'https://foo.bar/simple/', + }, + ]), + ).toEqual([ + { + name: 'foo', + priority: 'primary', + url: 'https://foo.bar/simple/', + }, + { + name: 'pypi', + priority: 'secondary', + url: 'https://pypi.org/pypi/', + }, + ]); + }); + + it('sources with priority="secondary"', () => { + expect( + PoetrySources.parse([ + { + name: 'foo', + priority: 'secondary', + url: 'https://foo.bar/simple/', + }, + { + name: 'bar', + priority: 'secondary', + url: 'https://bar.baz/simple/', + }, + ]), + ).toEqual([ + { + name: 'pypi', + priority: 'default', + url: 'https://pypi.org/pypi/', + }, + { + name: 'foo', + priority: 'secondary', + url: 'https://foo.bar/simple/', + }, + { + name: 'bar', + priority: 'secondary', + url: 'https://bar.baz/simple/', + }, + ]); + }); + + it('unordered sources and implicit PyPI priority="primary"', () => { + expect( + PoetrySources.parse([ + { + name: 'foo', + priority: 'secondary', + url: 'https://foo.bar/simple/', + }, + { + name: 'bar', + url: 'https://bar.baz/simple/', + }, + { + name: 'PyPI', + }, + { + name: 'baz', + url: 'https://baz.bar/simple/', + }, + ]), + ).toEqual([ + { + name: 'bar', + priority: 'primary', + url: 'https://bar.baz/simple/', + }, + { + name: 'pypi', + priority: 'primary', + url: 'https://pypi.org/pypi/', + }, + { + name: 'baz', + priority: 'primary', + url: 'https://baz.bar/simple/', + }, + { + name: 'foo', + priority: 'secondary', + url: 'https://foo.bar/simple/', + }, + ]); + }); + + it('unordered sources with implicit PyPI priority="secondary"', () => { + expect( + PoetrySources.parse([ + { + name: 'foo', + priority: 'secondary', + url: 'https://foo.bar/simple/', + }, + { + name: 'bar', + url: 'https://bar.baz/simple/', + }, + ]), + ).toEqual([ + { + name: 'bar', + priority: 'primary', + url: 'https://bar.baz/simple/', + }, + { + name: 'foo', + priority: 'secondary', + url: 'https://foo.bar/simple/', + }, + { + name: 'pypi', + priority: 'secondary', + url: 'https://pypi.org/pypi/', + }, + ]); + }); + + it('source with priority="supplemental"', () => { + expect( + PoetrySources.parse([ + { + name: 'supplemental', + priority: 'supplemental', + url: 'https://supplemental.com/simple/', + }, + ]), + ).toEqual([ + { + name: 'pypi', + priority: 'default', + url: 'https://pypi.org/pypi/', + }, + { + name: 'supplemental', + priority: 'supplemental', + url: 'https://supplemental.com/simple/', + }, + ]); + }); + + it('source with priority="explicit"', () => { + expect( + PoetrySources.parse([ + { + name: 'explicit', + priority: 'explicit', + url: 'https://explicit.com/simple/', + }, + ]), + ).toEqual([ + { + name: 'pypi', + priority: 'default', + url: 'https://pypi.org/pypi/', + }, + { + name: 'explicit', + priority: 'explicit', + url: 'https://explicit.com/simple/', + }, + ]); + }); + }); +}); diff --git a/lib/modules/manager/poetry/schema.ts b/lib/modules/manager/poetry/schema.ts index afe3f8ec6db36d..527c54a2b17783 100644 --- a/lib/modules/manager/poetry/schema.ts +++ b/lib/modules/manager/poetry/schema.ts @@ -1,4 +1,5 @@ import { ZodEffects, ZodType, ZodTypeDef, z } from 'zod'; +import { logger } from '../../../logger'; import { parseGitUrl } from '../../../util/git/url'; import { regEx } from '../../../util/regex'; import { LooseArray, LooseRecord, Toml } from '../../../util/schema-utils'; @@ -71,15 +72,15 @@ const PoetryGitDependency = z const PoetryPypiDependency = z.union([ z - .object({ version: z.string().optional() }) - .transform(({ version: currentValue }): PackageDependency => { + .object({ version: z.string().optional(), source: z.string().optional() }) + .transform(({ version: currentValue, source }): PackageDependency => { if (!currentValue) { return { datasource: PypiDatasource.id }; } return { datasource: PypiDatasource.id, - managerData: { nestedVersion: true }, + managerData: { nestedVersion: true, sourceName: source?.toLowerCase() }, currentValue, }; }), @@ -178,6 +179,70 @@ export const PoetryGroupDependencies = LooseRecord( return deps; }); +const PoetrySourceOrder = [ + 'default', + 'primary', + 'secondary', + 'supplemental', + 'explicit', +] as const; + +export const PoetrySource = z.object({ + name: z.string().toLowerCase(), + url: z.string().optional(), + priority: z.enum(PoetrySourceOrder).default('primary'), +}); +export type PoetrySource = z.infer; + +export const PoetrySources = LooseArray(PoetrySource, { + onError: ({ error: err }) => { + logger.debug({ err }, 'Poetry: error parsing sources array'); + }, +}) + .transform((sources) => { + const pypiUrl = process.env.PIP_INDEX_URL ?? 'https://pypi.org/pypi/'; + const result: PoetrySource[] = []; + + let overridesPyPi = false; + let hasDefaultSource = false; + let hasPrimarySource = false; + for (const source of sources) { + if (source.name === 'pypi') { + source.url = pypiUrl; + overridesPyPi = true; + } + + if (!source.url) { + continue; + } + + if (source.priority === 'default') { + hasDefaultSource = true; + } else if (source.priority === 'primary') { + hasPrimarySource = true; + } + + result.push(source); + } + + if (sources.length && !hasDefaultSource && !overridesPyPi) { + result.push({ + name: 'pypi', + priority: hasPrimarySource ? 'secondary' : 'default', + url: pypiUrl, + }); + } + + result.sort( + (a, b) => + PoetrySourceOrder.indexOf(a.priority) - + PoetrySourceOrder.indexOf(b.priority), + ); + + return result; + }) + .catch([]); + export const PoetrySectionSchema = z .object({ dependencies: withDepType(PoetryDependencies, 'dependencies').optional(), @@ -187,21 +252,7 @@ export const PoetrySectionSchema = z ).optional(), extras: withDepType(PoetryDependencies, 'extras').optional(), group: PoetryGroupDependencies.optional(), - source: LooseArray( - z - .object({ - url: z.string(), - }) - .transform(({ url }) => url), - ) - .refine((urls) => urls.length > 0) - .transform((urls) => [ - ...urls, - process.env.PIP_INDEX_URL ?? 'https://pypi.org/pypi/', - ]) - .transform((urls) => uniq(urls)) - .optional() - .catch(undefined), + source: PoetrySources, }) .transform( ({ @@ -209,7 +260,7 @@ export const PoetrySectionSchema = z 'dev-dependencies': devDependencies = [], extras: extraDependencies = [], group: groupDependencies = [], - source: registryUrls, + source: sourceUrls, }) => { const deps: PackageDependency[] = [ ...dependencies, @@ -220,8 +271,22 @@ export const PoetrySectionSchema = z const res: PackageFileContent = { deps }; - if (registryUrls) { - res.registryUrls = registryUrls; + if (sourceUrls.length) { + for (const dep of res.deps) { + if (dep.managerData?.sourceName) { + const sourceUrl = sourceUrls.find( + ({ name }) => name === dep.managerData?.sourceName, + ); + if (sourceUrl?.url) { + dep.registryUrls = [sourceUrl.url]; + } + } + } + + const sourceUrlsFiltered = sourceUrls.filter( + ({ priority }) => priority !== 'explicit', + ); + res.registryUrls = uniq(sourceUrlsFiltered.map(({ url }) => url!)); } return res; From d74fa61bee2368f52a7364448c7cbc1c4de93bd8 Mon Sep 17 00:00:00 2001 From: RahulGautamSingh Date: Sun, 17 Dec 2023 11:31:47 +0545 Subject: [PATCH 071/173] fix(versioning/loose): sort numeric parts numerically (#26341) --- lib/modules/versioning/loose/index.spec.ts | 2 ++ lib/modules/versioning/loose/index.ts | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/modules/versioning/loose/index.spec.ts b/lib/modules/versioning/loose/index.spec.ts index 81b94d57946742..9d19c2f903b8a0 100644 --- a/lib/modules/versioning/loose/index.spec.ts +++ b/lib/modules/versioning/loose/index.spec.ts @@ -53,6 +53,7 @@ describe('modules/versioning/loose/index', () => { a | b | expected ${'2.4.0'} | ${'2.4'} | ${true} ${'2.4.2'} | ${'2.4.1'} | ${true} + ${'2.4.100'} | ${'2.4.99'} | ${true} ${'2.4.beta'} | ${'2.4.alpha'} | ${true} ${'1.9'} | ${'2'} | ${false} ${'1.9'} | ${'1.9.1'} | ${false} @@ -63,6 +64,7 @@ describe('modules/versioning/loose/index', () => { ${'2024-07-21T11-33-05.abc123'} | ${'2023-06-21T11-33-05.abc123'} | ${true} ${'2023-07-21T11-33-05.abc123'} | ${'2023-07-21T11-33-04.abc123'} | ${true} ${'2023-07-21-113305-abc123'} | ${'2023-07-21-113304-abc123'} | ${true} + ${'1.1.5-100'} | ${'1.1.5-99'} | ${true} `('isGreaterThan("$a", "$b") === $expected', ({ a, b, expected }) => { expect(loose.isGreaterThan(a, b)).toBe(expected); }); diff --git a/lib/modules/versioning/loose/index.ts b/lib/modules/versioning/loose/index.ts index 2bc1f5e9ce0cdc..dc5ac03f359039 100644 --- a/lib/modules/versioning/loose/index.ts +++ b/lib/modules/versioning/loose/index.ts @@ -52,7 +52,9 @@ class LooseVersioningApi extends GenericVersioningApi { } if (parsed1.suffix && parsed2.suffix) { - return parsed1.suffix.localeCompare(parsed2.suffix); + return parsed1.suffix.localeCompare(parsed2.suffix, undefined, { + numeric: true, + }); } if (parsed1.suffix) { From 47c4ecc274d3b377074f32ea73f02af2f377a107 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 18 Dec 2023 00:07:26 +0000 Subject: [PATCH 072/173] docs: update references to renovate/renovate to v37.102.0 (#26343) 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 b02875b26906db..e1afe89394b991 100644 --- a/docs/usage/docker.md +++ b/docs/usage/docker.md @@ -383,7 +383,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:37.89.6 +FROM renovate/renovate:37.102.0 # Include the "Docker tip" which you can find here https://cloud.google.com/sdk/docs/install # under "Installation" for "Debian/Ubuntu" RUN ... From abd2561224be78b5d3a8f3de40aff7f7cda1566d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 18 Dec 2023 00:11:03 +0000 Subject: [PATCH 073/173] chore(deps): lock file maintenance (#26344) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- pnpm-lock.yaml | 278 ++++++++++++++++++++++++------------------------- 1 file changed, 139 insertions(+), 139 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dea4ff9cf37e51..6dee738fa6ebfc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -591,7 +591,7 @@ importers: version: 3.0.3 ts-jest: specifier: 29.1.1 - version: 29.1.1(@babel/core@7.23.5)(@jest/types@29.6.3)(jest@29.7.0)(typescript@5.3.3) + version: 29.1.1(@babel/core@7.23.6)(@jest/types@29.6.3)(jest@29.7.0)(typescript@5.3.3) ts-node: specifier: 10.9.2 version: 10.9.2(@swc/core@1.3.100)(@types/node@18.19.3)(typescript@5.3.3) @@ -1574,20 +1574,20 @@ packages: engines: {node: '>=6.9.0'} dev: true - /@babel/core@7.23.5: - resolution: {integrity: sha512-Cwc2XjUrG4ilcfOw4wBAK+enbdgwAcAJCfGUItPBKR7Mjw4aEfAFYrLxeRp4jWgtNIKn3n2AlBOfwwafl+42/g==} + /@babel/core@7.23.6: + resolution: {integrity: sha512-FxpRyGjrMJXh7X3wGLGhNDCRiwpWEF74sKjTLDJSG5Kyvow3QZaG0Adbqzi9ZrVjTWpsX+2cxWXD71NMg93kdw==} engines: {node: '>=6.9.0'} dependencies: '@ampproject/remapping': 2.2.1 '@babel/code-frame': 7.23.5 - '@babel/generator': 7.23.5 - '@babel/helper-compilation-targets': 7.22.15 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.5) - '@babel/helpers': 7.23.5 - '@babel/parser': 7.23.5 + '@babel/generator': 7.23.6 + '@babel/helper-compilation-targets': 7.23.6 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.6) + '@babel/helpers': 7.23.6 + '@babel/parser': 7.23.6 '@babel/template': 7.22.15 - '@babel/traverse': 7.23.5 - '@babel/types': 7.23.5 + '@babel/traverse': 7.23.6 + '@babel/types': 7.23.6 convert-source-map: 2.0.0 debug: 4.3.4 gensync: 1.0.0-beta.2 @@ -1597,18 +1597,18 @@ packages: - supports-color dev: true - /@babel/generator@7.23.5: - resolution: {integrity: sha512-BPssCHrBD+0YrxviOa3QzpqwhNIXKEtOa2jQrm4FlmkC2apYgRnQcmPWiGZDlGxiNtltnUFolMe8497Esry+jA==} + /@babel/generator@7.23.6: + resolution: {integrity: sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.23.5 + '@babel/types': 7.23.6 '@jridgewell/gen-mapping': 0.3.3 '@jridgewell/trace-mapping': 0.3.20 jsesc: 2.5.2 dev: true - /@babel/helper-compilation-targets@7.22.15: - resolution: {integrity: sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==} + /@babel/helper-compilation-targets@7.23.6: + resolution: {integrity: sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==} engines: {node: '>=6.9.0'} dependencies: '@babel/compat-data': 7.23.5 @@ -1628,30 +1628,30 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/template': 7.22.15 - '@babel/types': 7.23.5 + '@babel/types': 7.23.6 dev: true /@babel/helper-hoist-variables@7.22.5: resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.23.5 + '@babel/types': 7.23.6 dev: true /@babel/helper-module-imports@7.22.15: resolution: {integrity: sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.23.5 + '@babel/types': 7.23.6 dev: true - /@babel/helper-module-transforms@7.23.3(@babel/core@7.23.5): + /@babel/helper-module-transforms@7.23.3(@babel/core@7.23.6): resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.23.5 + '@babel/core': 7.23.6 '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-module-imports': 7.22.15 '@babel/helper-simple-access': 7.22.5 @@ -1668,14 +1668,14 @@ packages: resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.23.5 + '@babel/types': 7.23.6 dev: true /@babel/helper-split-export-declaration@7.22.6: resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.23.5 + '@babel/types': 7.23.6 dev: true /@babel/helper-string-parser@7.23.4: @@ -1692,13 +1692,13 @@ packages: engines: {node: '>=6.9.0'} dev: true - /@babel/helpers@7.23.5: - resolution: {integrity: sha512-oO7us8FzTEsG3U6ag9MfdF1iA/7Z6dz+MtFhifZk8C8o453rGJFFWUP1t+ULM9TUIAzC9uxXEiXjOiVMyd7QPg==} + /@babel/helpers@7.23.6: + resolution: {integrity: sha512-wCfsbN4nBidDRhpDhvcKlzHWCTlgJYUUdSJfzXb2NuBssDSIjc3xcb+znA7l+zYsFljAcGM0aFkN40cR3lXiGA==} engines: {node: '>=6.9.0'} dependencies: '@babel/template': 7.22.15 - '@babel/traverse': 7.23.5 - '@babel/types': 7.23.5 + '@babel/traverse': 7.23.6 + '@babel/types': 7.23.6 transitivePeerDependencies: - supports-color dev: true @@ -1711,149 +1711,149 @@ packages: chalk: 2.4.2 js-tokens: 4.0.0 - /@babel/parser@7.23.5: - resolution: {integrity: sha512-hOOqoiNXrmGdFbhgCzu6GiURxUgM27Xwd/aPuu8RfHEZPBzL1Z54okAHAQjXfcQNwvrlkAmAp4SlRTZ45vlthQ==} + /@babel/parser@7.23.6: + resolution: {integrity: sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==} engines: {node: '>=6.0.0'} hasBin: true dependencies: - '@babel/types': 7.23.5 + '@babel/types': 7.23.6 dev: true - /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.23.5): + /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.23.6): resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.5 + '@babel/core': 7.23.6 '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.23.5): + /@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.23.6): resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.5 + '@babel/core': 7.23.6 '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.23.5): + /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.23.6): resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.5 + '@babel/core': 7.23.6 '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.23.5): + /@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.23.6): resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.5 + '@babel/core': 7.23.6 '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.23.5): + /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.23.6): resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.5 + '@babel/core': 7.23.6 '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-jsx@7.23.3(@babel/core@7.23.5): + /@babel/plugin-syntax-jsx@7.23.3(@babel/core@7.23.6): resolution: {integrity: sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.5 + '@babel/core': 7.23.6 '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.23.5): + /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.23.6): resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.5 + '@babel/core': 7.23.6 '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.23.5): + /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.23.6): resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.5 + '@babel/core': 7.23.6 '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.23.5): + /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.23.6): resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.5 + '@babel/core': 7.23.6 '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.23.5): + /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.23.6): resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.5 + '@babel/core': 7.23.6 '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.23.5): + /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.23.6): resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.5 + '@babel/core': 7.23.6 '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.23.5): + /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.23.6): resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.5 + '@babel/core': 7.23.6 '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.23.5): + /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.23.6): resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.5 + '@babel/core': 7.23.6 '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-typescript@7.23.3(@babel/core@7.23.5): + /@babel/plugin-syntax-typescript@7.23.3(@babel/core@7.23.6): resolution: {integrity: sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.5 + '@babel/core': 7.23.6 '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/runtime-corejs3@7.23.5: - resolution: {integrity: sha512-7+ziVclejQTLYhXl+Oi1f6gTGD1XDCeLa4R472TNGQxb08zbEJ0OdNoh5Piz+57Ltmui6xR88BXR4gS3/Toslw==} + /@babel/runtime-corejs3@7.23.6: + resolution: {integrity: sha512-Djs/ZTAnpyj0nyg7p1J6oiE/tZ9G2stqAFlLGZynrW+F3k2w2jGK2mLOBxzYIOcZYA89+c3d3wXKpYLcpwcU6w==} engines: {node: '>=6.9.0'} dependencies: core-js-pure: 3.34.0 - regenerator-runtime: 0.14.0 + regenerator-runtime: 0.14.1 dev: false /@babel/template@7.22.15: @@ -1861,30 +1861,30 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/code-frame': 7.23.5 - '@babel/parser': 7.23.5 - '@babel/types': 7.23.5 + '@babel/parser': 7.23.6 + '@babel/types': 7.23.6 dev: true - /@babel/traverse@7.23.5: - resolution: {integrity: sha512-czx7Xy5a6sapWWRx61m1Ke1Ra4vczu1mCTtJam5zRTBOonfdJ+S/B6HYmGYu3fJtr8GGET3si6IhgWVBhJ/m8w==} + /@babel/traverse@7.23.6: + resolution: {integrity: sha512-czastdK1e8YByZqezMPFiZ8ahwVMh/ESl9vPgvgdB9AmFMGP5jfpFax74AQgl5zj4XHzqeYAg2l8PuUeRS1MgQ==} engines: {node: '>=6.9.0'} dependencies: '@babel/code-frame': 7.23.5 - '@babel/generator': 7.23.5 + '@babel/generator': 7.23.6 '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-function-name': 7.23.0 '@babel/helper-hoist-variables': 7.22.5 '@babel/helper-split-export-declaration': 7.22.6 - '@babel/parser': 7.23.5 - '@babel/types': 7.23.5 + '@babel/parser': 7.23.6 + '@babel/types': 7.23.6 debug: 4.3.4 globals: 11.12.0 transitivePeerDependencies: - supports-color dev: true - /@babel/types@7.23.5: - resolution: {integrity: sha512-ON5kSOJwVO6xXVRTvOI0eOnWe7VdUcIpsovGo9U/Br4Ie4UVFQTboO2cYnDhAGU6Fp+UxSiT+pMft0SMHfuq6w==} + /@babel/types@7.23.6: + resolution: {integrity: sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==} engines: {node: '>=6.9.0'} dependencies: '@babel/helper-string-parser': 7.23.4 @@ -2210,7 +2210,7 @@ packages: resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@babel/core': 7.23.5 + '@babel/core': 7.23.6 '@jest/types': 29.6.3 '@jridgewell/trace-mapping': 0.3.20 babel-plugin-istanbul: 6.1.1 @@ -2768,7 +2768,7 @@ packages: /@qnighy/marshal@0.1.3: resolution: {integrity: sha512-uaDZTJYtD2UgQTGemmgWeth+e2WapZm+GkAq8UU8AJ55PKRFaf1GkH7X/uzA+Ygu8iInzIlM2FGyCUnruyMKMg==} dependencies: - '@babel/runtime-corejs3': 7.23.5 + '@babel/runtime-corejs3': 7.23.6 dev: false /@redis/bloom@1.2.0(@redis/client@1.5.12): @@ -2823,7 +2823,7 @@ packages: /@renovatebot/osv-offline-db@1.4.0: resolution: {integrity: sha512-VqR66WlewMLnDOVmnEAHIFZuATG46LwvNu6ZPjH0sEaH6bCqNxfJ6kBMFEiJOWWjGOxI1u2F+nr1vtdixC9UwA==} dependencies: - '@seald-io/nedb': 4.0.2 + '@seald-io/nedb': 4.0.3 dev: false /@renovatebot/osv-offline@1.3.10: @@ -2854,8 +2854,8 @@ packages: resolution: {integrity: sha512-qv3jnwoakeax2razYaMsGI/luWdliBLHTdC6jU55hQt1hcFqzauH/HsBollQ7IR4ySTtYhT+xyHoijpA16C+tA==} dev: false - /@seald-io/nedb@4.0.2: - resolution: {integrity: sha512-gJ91fT1sgh2cLXYVcTSh7khZ8LdemI8+SojCdpZ5wy+DUQ4fSrEwGqOwbdV49NDs2BBO6GeBpSb8CnhG2IW1rw==} + /@seald-io/nedb@4.0.3: + resolution: {integrity: sha512-ik4rn0Ks8q1VEzhe6qFh9/MBrw77ym1OZxF2mBS6/H8cr4lpNhCvF8FqB901Oft1CSP50LL0ay4QQCU3xqn+Ew==} dependencies: '@seald-io/binary-search-tree': 1.0.3 localforage: 1.10.0 @@ -2926,7 +2926,7 @@ packages: https-proxy-agent: 7.0.2 issue-parser: 6.0.0 lodash-es: 4.17.21 - mime: 4.0.0 + mime: 4.0.1 p-filter: 3.0.0 semantic-release: 22.0.12(typescript@5.3.3) url-join: 5.0.0 @@ -3615,30 +3615,30 @@ packages: /@types/babel__core@7.20.5: resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} dependencies: - '@babel/parser': 7.23.5 - '@babel/types': 7.23.5 - '@types/babel__generator': 7.6.7 + '@babel/parser': 7.23.6 + '@babel/types': 7.23.6 + '@types/babel__generator': 7.6.8 '@types/babel__template': 7.4.4 '@types/babel__traverse': 7.20.4 dev: true - /@types/babel__generator@7.6.7: - resolution: {integrity: sha512-6Sfsq+EaaLrw4RmdFWE9Onp63TOUue71AWb4Gpa6JxzgTYtimbM086WnYTy2U67AofR++QKCo08ZP6pwx8YFHQ==} + /@types/babel__generator@7.6.8: + resolution: {integrity: sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==} dependencies: - '@babel/types': 7.23.5 + '@babel/types': 7.23.6 dev: true /@types/babel__template@7.4.4: resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} dependencies: - '@babel/parser': 7.23.5 - '@babel/types': 7.23.5 + '@babel/parser': 7.23.6 + '@babel/types': 7.23.6 dev: true /@types/babel__traverse@7.20.4: resolution: {integrity: sha512-mSM/iKUk5fDDrEV/e83qY+Cr3I1+Q3qqTuEn++HAWYjEa1+NxZr6CNrcJGf2ZTnq4HoFGC3zaTPZTobCzCFukA==} dependencies: - '@babel/types': 7.23.5 + '@babel/types': 7.23.6 dev: true /@types/breejs__later@4.1.5: @@ -4533,17 +4533,17 @@ packages: typed-rest-client: 1.8.11 dev: false - /babel-jest@29.7.0(@babel/core@7.23.5): + /babel-jest@29.7.0(@babel/core@7.23.6): resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: '@babel/core': ^7.8.0 dependencies: - '@babel/core': 7.23.5 + '@babel/core': 7.23.6 '@jest/transform': 29.7.0 '@types/babel__core': 7.20.5 babel-plugin-istanbul: 6.1.1 - babel-preset-jest: 29.6.3(@babel/core@7.23.5) + babel-preset-jest: 29.6.3(@babel/core@7.23.6) chalk: 4.1.2 graceful-fs: 4.2.11 slash: 3.0.0 @@ -4569,40 +4569,40 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@babel/template': 7.22.15 - '@babel/types': 7.23.5 + '@babel/types': 7.23.6 '@types/babel__core': 7.20.5 '@types/babel__traverse': 7.20.4 dev: true - /babel-preset-current-node-syntax@1.0.1(@babel/core@7.23.5): + /babel-preset-current-node-syntax@1.0.1(@babel/core@7.23.6): resolution: {integrity: sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.23.5 - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.23.5) - '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.23.5) - '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.23.5) - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.23.5) - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.23.5) - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.23.5) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.23.5) - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.23.5) - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.23.5) - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.23.5) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.5) - '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.23.5) - dev: true - - /babel-preset-jest@29.6.3(@babel/core@7.23.5): + '@babel/core': 7.23.6 + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.23.6) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.23.6) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.23.6) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.23.6) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.23.6) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.23.6) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.23.6) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.23.6) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.23.6) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.23.6) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.6) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.23.6) + dev: true + + /babel-preset-jest@29.6.3(@babel/core@7.23.6): resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.23.5 + '@babel/core': 7.23.6 babel-plugin-jest-hoist: 29.6.3 - babel-preset-current-node-syntax: 1.0.1(@babel/core@7.23.5) + babel-preset-current-node-syntax: 1.0.1(@babel/core@7.23.6) dev: true /backslash@0.2.0: @@ -4668,8 +4668,8 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true dependencies: - caniuse-lite: 1.0.30001568 - electron-to-chromium: 1.4.609 + caniuse-lite: 1.0.30001570 + electron-to-chromium: 1.4.614 node-releases: 2.0.14 update-browserslist-db: 1.0.13(browserslist@4.22.2) dev: true @@ -4795,8 +4795,8 @@ packages: engines: {node: '>=10'} dev: true - /caniuse-lite@1.0.30001568: - resolution: {integrity: sha512-vSUkH84HontZJ88MiNrOau1EBrCqEQYgkC5gIySiDlpsm8sGVrhU7Kx4V6h0tnqaHzIHZv08HlJIwPbL4XL9+A==} + /caniuse-lite@1.0.30001570: + resolution: {integrity: sha512-+3e0ASu4sw1SWaoCtvPeyXp+5PsjigkSt8OXZbF9StH5pQWbxEjLAZE3n8Aup5udop1uRiKA7a4utUk/uoSpUw==} dev: true /cardinal@2.1.1: @@ -5375,8 +5375,8 @@ packages: semver: 7.5.4 dev: false - /electron-to-chromium@1.4.609: - resolution: {integrity: sha512-ihiCP7PJmjoGNuLpl7TjNA8pCQWu09vGyjlPYw1Rqww4gvNuCcmvl+44G+2QyJ6S2K4o+wbTS++Xz0YN8Q9ERw==} + /electron-to-chromium@1.4.614: + resolution: {integrity: sha512-X4ze/9Sc3QWs6h92yerwqv7aB/uU8vCjZcrMjA8N9R1pjMFRe44dLsck5FzLilOYvcXuDn93B+bpGYyufc70gQ==} dev: true /email-addresses@5.0.0: @@ -5691,7 +5691,7 @@ packages: object.groupby: 1.0.1 object.values: 1.1.7 semver: 6.3.1 - tsconfig-paths: 3.14.2 + tsconfig-paths: 3.15.0 transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack @@ -7011,7 +7011,7 @@ packages: resolution: {integrity: sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==} engines: {node: '>=8'} dependencies: - '@babel/core': 7.23.5 + '@babel/core': 7.23.6 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.2 semver: 6.3.1 @@ -7023,8 +7023,8 @@ packages: resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} engines: {node: '>=8'} dependencies: - '@babel/core': 7.23.5 - '@babel/parser': 7.23.5 + '@babel/core': 7.23.6 + '@babel/parser': 7.23.6 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.2 semver: 6.3.1 @@ -7036,8 +7036,8 @@ packages: resolution: {integrity: sha512-EAMEJBsYuyyztxMxW3g7ugGPkrZsV57v0Hmv3mm1uQsmB+QnZuepg731CRaIgeUVSdmsTngOkSnauNF8p7FIhA==} engines: {node: '>=10'} dependencies: - '@babel/core': 7.23.5 - '@babel/parser': 7.23.5 + '@babel/core': 7.23.6 + '@babel/parser': 7.23.6 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.2 semver: 7.5.4 @@ -7176,11 +7176,11 @@ packages: ts-node: optional: true dependencies: - '@babel/core': 7.23.5 + '@babel/core': 7.23.6 '@jest/test-sequencer': 29.7.0 '@jest/types': 29.6.3 '@types/node': 18.19.3 - babel-jest: 29.7.0(@babel/core@7.23.5) + babel-jest: 29.7.0(@babel/core@7.23.6) chalk: 4.1.2 ci-info: 3.9.0 deepmerge: 4.3.1 @@ -7451,15 +7451,15 @@ packages: resolution: {integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@babel/core': 7.23.5 - '@babel/generator': 7.23.5 - '@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.23.5) - '@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.23.5) - '@babel/types': 7.23.5 + '@babel/core': 7.23.6 + '@babel/generator': 7.23.6 + '@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.23.6) + '@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.23.6) + '@babel/types': 7.23.6 '@jest/expect-utils': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - babel-preset-current-node-syntax: 1.0.1(@babel/core@7.23.5) + babel-preset-current-node-syntax: 1.0.1(@babel/core@7.23.6) chalk: 4.1.2 expect: 29.7.0 graceful-fs: 4.2.11 @@ -7935,11 +7935,11 @@ packages: markdownlint-micromark: 0.1.7 dev: true - /marked-terminal@6.1.0(marked@9.1.6): - resolution: {integrity: sha512-QaCSF6NV82oo6K0szEnmc65ooDeW0T/Adcyf0fcW+Hto2GT1VADFg8dn1zaeHqzj65fqDH1hMNChGNRaC/lbkA==} + /marked-terminal@6.2.0(marked@9.1.6): + resolution: {integrity: sha512-ubWhwcBFHnXsjYNsu+Wndpg0zhY4CahSpPlA70PlO0rR9r2sZpkyU+rkCsOWH+KMEkx847UpALON+HWgxowFtw==} engines: {node: '>=16.0.0'} peerDependencies: - marked: '>=1 <11' + marked: '>=1 <12' dependencies: ansi-escapes: 6.2.0 cardinal: 2.1.1 @@ -8087,8 +8087,8 @@ packages: braces: 3.0.2 picomatch: 2.3.1 - /mime@4.0.0: - resolution: {integrity: sha512-pzhgdeqU5pJ9t5WK9m4RT4GgGWqYJylxUf62Yb9datXRwdcw5MjiD1BYI5evF8AgTXN9gtKX3CFLvCUL5fAhEA==} + /mime@4.0.1: + resolution: {integrity: sha512-5lZ5tyrIfliMXzFtkYyekWbtRXObT9OWa8IwQ5uxTBDHucNNwniRqo0yInflj+iYi5CBa6qxadGzGarDfuEOxA==} engines: {node: '>=16'} hasBin: true dev: true @@ -9233,8 +9233,8 @@ packages: '@redis/time-series': 1.0.5(@redis/client@1.5.12) dev: false - /regenerator-runtime@0.14.0: - resolution: {integrity: sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==} + /regenerator-runtime@0.14.1: + resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} dev: false /regexp.prototype.flags@1.5.1: @@ -9487,7 +9487,7 @@ packages: import-from-esm: 1.3.3 lodash-es: 4.17.21 marked: 9.1.6 - marked-terminal: 6.1.0(marked@9.1.6) + marked-terminal: 6.2.0(marked@9.1.6) micromatch: 4.0.5 p-each-series: 3.0.0 p-reduce: 3.0.0 @@ -10129,7 +10129,7 @@ packages: typescript: 5.3.3 dev: true - /ts-jest@29.1.1(@babel/core@7.23.5)(@jest/types@29.6.3)(jest@29.7.0)(typescript@5.3.3): + /ts-jest@29.1.1(@babel/core@7.23.6)(@jest/types@29.6.3)(jest@29.7.0)(typescript@5.3.3): resolution: {integrity: sha512-D6xjnnbP17cC85nliwGiL+tpoKN0StpgE0TeOjXQTU6MVCfsB4v7aW05CgQ/1OywGb0x/oy9hHFnN+sczTiRaA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -10150,7 +10150,7 @@ packages: esbuild: optional: true dependencies: - '@babel/core': 7.23.5 + '@babel/core': 7.23.6 '@jest/types': 29.6.3 bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 @@ -10196,8 +10196,8 @@ packages: yn: 3.1.1 dev: true - /tsconfig-paths@3.14.2: - resolution: {integrity: sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==} + /tsconfig-paths@3.15.0: + resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} dependencies: '@types/json5': 0.0.29 json5: 1.0.2 From f23c92e5b28d91d3f22de2f5d21a45e69d50c666 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 18 Dec 2023 03:35:25 +0000 Subject: [PATCH 074/173] chore(deps): lock file maintenance (#26347) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> From 886eb5ccd53bca9eac690e0fb1e0c9a14929ce41 Mon Sep 17 00:00:00 2001 From: Sebastian Poxhofer Date: Mon, 18 Dec 2023 09:37:34 +0100 Subject: [PATCH 075/173] ci(workflows/scorecard): revert #26284 for scorecard to fix upload (#26348) --- .github/workflows/scorecard.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index f1729c17216602..c00a69e5df5290 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -50,6 +50,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: 'Upload to code-scanning' - uses: github/codeql-action/upload-sarif@03e7845b7bfcd5e7fb63d1ae8c61b0e791134fab # v2.22.11 + uses: github/codeql-action/upload-sarif@305f6546310b9203e892c28c1484e82977f4f63d # v2.22.10 with: sarif_file: results.sarif From 6824f7470a0f07621406a0b3e648df3aa47719d2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 18 Dec 2023 13:03:27 +0000 Subject: [PATCH 076/173] chore(deps): update actions/setup-node action to v4.0.1 (#26354) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/actions/setup-node/action.yml | 2 +- .github/workflows/build.yml | 2 +- .github/workflows/release-npm.yml | 2 +- .github/workflows/update-data.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/actions/setup-node/action.yml b/.github/actions/setup-node/action.yml index 28ad2e1b14dd04..ca92594ff0fcdf 100644 --- a/.github/actions/setup-node/action.yml +++ b/.github/actions/setup-node/action.yml @@ -52,7 +52,7 @@ runs: run: corepack enable - name: Setup Node - uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 + uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1 with: node-version: ${{ inputs.node-version }} cache: ${{ env.CACHE_HIT != 'true' && 'pnpm' || '' }} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5c036f6b76743c..fc2cdd3076fb87 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -511,7 +511,7 @@ jobs: uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Setup Node.js - uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 + uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1 with: node-version: ${{ env.NODE_VERSION }} diff --git a/.github/workflows/release-npm.yml b/.github/workflows/release-npm.yml index 8ce17cbb547ca5..675102e557102c 100644 --- a/.github/workflows/release-npm.yml +++ b/.github/workflows/release-npm.yml @@ -48,7 +48,7 @@ jobs: run: corepack enable - name: Set up Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 + uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1 with: node-version: ${{ env.NODE_VERSION }} cache: pnpm diff --git a/.github/workflows/update-data.yml b/.github/workflows/update-data.yml index 6fa631fbfb56ba..42e31279da666e 100644 --- a/.github/workflows/update-data.yml +++ b/.github/workflows/update-data.yml @@ -24,7 +24,7 @@ jobs: run: corepack enable - name: Set up Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 + uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1 with: node-version: ${{ env.NODE_VERSION }} cache: pnpm From 3c0792569df6b0dc955895d597b8315f5a855e62 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 18 Dec 2023 13:06:51 +0000 Subject: [PATCH 077/173] build(deps): update dependency @renovatebot/pep440 to v3.0.15 (#26353) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index db56adabde7d91..2b319d671884ae 100644 --- a/package.json +++ b/package.json @@ -165,7 +165,7 @@ "@opentelemetry/semantic-conventions": "1.18.1", "@qnighy/marshal": "0.1.3", "@renovatebot/osv-offline": "1.3.10", - "@renovatebot/pep440": "3.0.14", + "@renovatebot/pep440": "3.0.15", "@renovatebot/ruby-semver": "3.0.21", "@sindresorhus/is": "4.6.0", "@types/ms": "0.7.34", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6dee738fa6ebfc..1d93bb68367e00 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -69,8 +69,8 @@ importers: specifier: 1.3.10 version: 1.3.10 '@renovatebot/pep440': - specifier: 3.0.14 - version: 3.0.14 + specifier: 3.0.15 + version: 3.0.15 '@renovatebot/ruby-semver': specifier: 3.0.21 version: 3.0.21 @@ -2840,8 +2840,8 @@ packages: - encoding dev: false - /@renovatebot/pep440@3.0.14: - resolution: {integrity: sha512-ijhB6zyR20xUyhKR9zOy+9wBBAUD6D+LiBjbVMjMTF+8rEfPMA2mTGh+EJ0t44h8ysV41iKNzC0dQmYjxSw9BA==} + /@renovatebot/pep440@3.0.15: + resolution: {integrity: sha512-BrAe7puI22QHA9LKgSG9vpbi5s3sGH6DiHrASNl9iyPHzsbtjB+xtnIhVSvb1s9uaxoBgLr6TczxfI5dwxde8A==} engines: {node: ^18.12.0 || >= 20.0.0, pnpm: ^8.6.11} dev: false From 71d59355b95a9415d587695ebd96b041a8be5736 Mon Sep 17 00:00:00 2001 From: HonkingGoose <34918129+HonkingGoose@users.noreply.github.com> Date: Mon, 18 Dec 2023 16:22:41 +0100 Subject: [PATCH 078/173] docs(versioning): small style fixes (#26352) --- docs/usage/modules/versioning.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/usage/modules/versioning.md b/docs/usage/modules/versioning.md index 75832b13604b1a..eab2373bcb1b40 100644 --- a/docs/usage/modules/versioning.md +++ b/docs/usage/modules/versioning.md @@ -6,24 +6,25 @@ title: Versioning Once Managers have extracted dependencies, and Datasources have located available versions, then Renovate will use a "Versioning" scheme to perform sorting and filtering of results. The "versioning" is different for each package manager, because different package managers use different versioning schemes. -For example, `npm` uses`1.0.0-beta.1` and `pip` uses `1.0.0b1`. +For example, `npm` uses `1.0.0-beta.1` while `pip` uses `1.0.0b1`. ## Why you might need to manually configure versioning Renovate interprets versions correctly out-of-the-box most of the time. -It's impossible to automatically detect **all** versioning schemes, so sometimes you need to tell the bot what versioning scheme it should use. +But Renovate can't automatically detect **all** versioning schemes. +So sometimes you need to tell the bot what versioning scheme it should use. -You can manually configure/override the `versioning` value for a particular dependency. +You can manually configure or override the `versioning` value for a particular dependency. You generally won't need to override the defaults for ecosystems which enforce a strict version scheme like `npm`. -Configuring or overriding the default `versioning` can be particularly helpful for ecosystems like Docker/Kubernetes/Helm, where versioning is barely a "convention". +Configuring or overriding the default `versioning` can be extra helpful for ecosystems like Docker, Kubernetes or Helm, where versioning is barely a "convention". ## General concepts behind overriding versioning -- Although you can reconfigure versioning per-manager or per-datasource, it's unlikely that such a broad change would ever be needed +- Although you can reconfigure versioning per-manager or per-datasource, you probably don't need such a broad change - More commonly you would need to configure `versioning` for individual packages or potentially package patterns - The best way to do this is with `packageRules`, with a combination of `matchManagers`, `matchDatasources`, `matchPackageNames` and `matchPackagePatterns`. - Avoid configuring `versioning` in a rule that also uses `matchUpdateTypes`, as the update types aren't known at the time the `versioning` is applied. + Avoid configuring `versioning` in a rule that also uses `matchUpdateTypes`, as the update types aren't known at the time the `versioning` is applied ## Examples of versioning overrides From f9cb9b158e435cf7c1d1032b6e829b1463b31135 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 18 Dec 2023 18:19:11 +0000 Subject: [PATCH 079/173] chore(deps): update linters to v6.14.0 (#26358) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 4 +- pnpm-lock.yaml | 106 ++++++++++++++++++++++++------------------------- 2 files changed, 55 insertions(+), 55 deletions(-) diff --git a/package.json b/package.json index 2b319d671884ae..36ce030c459d12 100644 --- a/package.json +++ b/package.json @@ -306,8 +306,8 @@ "@types/url-join": "4.0.3", "@types/validate-npm-package-name": "4.0.2", "@types/xmldoc": "1.1.9", - "@typescript-eslint/eslint-plugin": "6.13.2", - "@typescript-eslint/parser": "6.13.2", + "@typescript-eslint/eslint-plugin": "6.14.0", + "@typescript-eslint/parser": "6.14.0", "aws-sdk-client-mock": "3.0.0", "callsite": "1.0.0", "common-tags": "1.8.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1d93bb68367e00..169cb17e59a31d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -482,11 +482,11 @@ importers: specifier: 1.1.9 version: 1.1.9 '@typescript-eslint/eslint-plugin': - specifier: 6.13.2 - version: 6.13.2(@typescript-eslint/parser@6.13.2)(eslint@8.55.0)(typescript@5.3.3) + specifier: 6.14.0 + version: 6.14.0(@typescript-eslint/parser@6.14.0)(eslint@8.55.0)(typescript@5.3.3) '@typescript-eslint/parser': - specifier: 6.13.2 - version: 6.13.2(eslint@8.55.0)(typescript@5.3.3) + specifier: 6.14.0 + version: 6.14.0(eslint@8.55.0)(typescript@5.3.3) aws-sdk-client-mock: specifier: 3.0.0 version: 3.0.0 @@ -516,13 +516,13 @@ importers: version: 1.4.3 eslint-import-resolver-typescript: specifier: 3.6.1 - version: 3.6.1(@typescript-eslint/parser@6.13.2)(eslint-plugin-import@2.29.0)(eslint@8.55.0) + version: 3.6.1(@typescript-eslint/parser@6.14.0)(eslint-plugin-import@2.29.0)(eslint@8.55.0) eslint-plugin-import: specifier: 2.29.0 - version: 2.29.0(@typescript-eslint/parser@6.13.2)(eslint-import-resolver-typescript@3.6.1)(eslint@8.55.0) + version: 2.29.0(@typescript-eslint/parser@6.14.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.55.0) eslint-plugin-jest: specifier: 27.6.0 - version: 27.6.0(@typescript-eslint/eslint-plugin@6.13.2)(eslint@8.55.0)(jest@29.7.0)(typescript@5.3.3) + version: 27.6.0(@typescript-eslint/eslint-plugin@6.14.0)(eslint@8.55.0)(jest@29.7.0)(typescript@5.3.3) eslint-plugin-jest-formatting: specifier: 3.1.0 version: 3.1.0(eslint@8.55.0) @@ -3955,8 +3955,8 @@ packages: dev: false optional: true - /@typescript-eslint/eslint-plugin@6.13.2(@typescript-eslint/parser@6.13.2)(eslint@8.55.0)(typescript@5.3.3): - resolution: {integrity: sha512-3+9OGAWHhk4O1LlcwLBONbdXsAhLjyCFogJY/cWy2lxdVJ2JrcTF2pTGMaLl2AE7U1l31n8Py4a8bx5DLf/0dQ==} + /@typescript-eslint/eslint-plugin@6.14.0(@typescript-eslint/parser@6.14.0)(eslint@8.55.0)(typescript@5.3.3): + resolution: {integrity: sha512-1ZJBykBCXaSHG94vMMKmiHoL0MhNHKSVlcHVYZNw+BKxufhqQVTOawNpwwI1P5nIFZ/4jLVop0mcY6mJJDFNaw==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha @@ -3967,11 +3967,11 @@ packages: optional: true dependencies: '@eslint-community/regexpp': 4.10.0 - '@typescript-eslint/parser': 6.13.2(eslint@8.55.0)(typescript@5.3.3) - '@typescript-eslint/scope-manager': 6.13.2 - '@typescript-eslint/type-utils': 6.13.2(eslint@8.55.0)(typescript@5.3.3) - '@typescript-eslint/utils': 6.13.2(eslint@8.55.0)(typescript@5.3.3) - '@typescript-eslint/visitor-keys': 6.13.2 + '@typescript-eslint/parser': 6.14.0(eslint@8.55.0)(typescript@5.3.3) + '@typescript-eslint/scope-manager': 6.14.0 + '@typescript-eslint/type-utils': 6.14.0(eslint@8.55.0)(typescript@5.3.3) + '@typescript-eslint/utils': 6.14.0(eslint@8.55.0)(typescript@5.3.3) + '@typescript-eslint/visitor-keys': 6.14.0 debug: 4.3.4 eslint: 8.55.0 graphemer: 1.4.0 @@ -3997,8 +3997,8 @@ packages: - typescript dev: true - /@typescript-eslint/parser@6.13.2(eslint@8.55.0)(typescript@5.3.3): - resolution: {integrity: sha512-MUkcC+7Wt/QOGeVlM8aGGJZy1XV5YKjTpq9jK6r6/iLsGXhBVaGP5N0UYvFsu9BFlSpwY9kMretzdBH01rkRXg==} + /@typescript-eslint/parser@6.14.0(eslint@8.55.0)(typescript@5.3.3): + resolution: {integrity: sha512-QjToC14CKacd4Pa7JK4GeB/vHmWFJckec49FR4hmIRf97+KXole0T97xxu9IFiPxVQ1DBWrQ5wreLwAGwWAVQA==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 @@ -4007,10 +4007,10 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/scope-manager': 6.13.2 - '@typescript-eslint/types': 6.13.2 - '@typescript-eslint/typescript-estree': 6.13.2(typescript@5.3.3) - '@typescript-eslint/visitor-keys': 6.13.2 + '@typescript-eslint/scope-manager': 6.14.0 + '@typescript-eslint/types': 6.14.0 + '@typescript-eslint/typescript-estree': 6.14.0(typescript@5.3.3) + '@typescript-eslint/visitor-keys': 6.14.0 debug: 4.3.4 eslint: 8.55.0 typescript: 5.3.3 @@ -4026,16 +4026,16 @@ packages: '@typescript-eslint/visitor-keys': 5.62.0 dev: true - /@typescript-eslint/scope-manager@6.13.2: - resolution: {integrity: sha512-CXQA0xo7z6x13FeDYCgBkjWzNqzBn8RXaE3QVQVIUm74fWJLkJkaHmHdKStrxQllGh6Q4eUGyNpMe0b1hMkXFA==} + /@typescript-eslint/scope-manager@6.14.0: + resolution: {integrity: sha512-VT7CFWHbZipPncAZtuALr9y3EuzY1b1t1AEkIq2bTXUPKw+pHoXflGNG5L+Gv6nKul1cz1VH8fz16IThIU0tdg==} engines: {node: ^16.0.0 || >=18.0.0} dependencies: - '@typescript-eslint/types': 6.13.2 - '@typescript-eslint/visitor-keys': 6.13.2 + '@typescript-eslint/types': 6.14.0 + '@typescript-eslint/visitor-keys': 6.14.0 dev: true - /@typescript-eslint/type-utils@6.13.2(eslint@8.55.0)(typescript@5.3.3): - resolution: {integrity: sha512-Qr6ssS1GFongzH2qfnWKkAQmMUyZSyOr0W54nZNU1MDfo+U4Mv3XveeLZzadc/yq8iYhQZHYT+eoXJqnACM1tw==} + /@typescript-eslint/type-utils@6.14.0(eslint@8.55.0)(typescript@5.3.3): + resolution: {integrity: sha512-x6OC9Q7HfYKqjnuNu5a7kffIYs3No30isapRBJl1iCHLitD8O0lFbRcVGiOcuyN837fqXzPZ1NS10maQzZMKqw==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 @@ -4044,8 +4044,8 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 6.13.2(typescript@5.3.3) - '@typescript-eslint/utils': 6.13.2(eslint@8.55.0)(typescript@5.3.3) + '@typescript-eslint/typescript-estree': 6.14.0(typescript@5.3.3) + '@typescript-eslint/utils': 6.14.0(eslint@8.55.0)(typescript@5.3.3) debug: 4.3.4 eslint: 8.55.0 ts-api-utils: 1.0.3(typescript@5.3.3) @@ -4059,8 +4059,8 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /@typescript-eslint/types@6.13.2: - resolution: {integrity: sha512-7sxbQ+EMRubQc3wTfTsycgYpSujyVbI1xw+3UMRUcrhSy+pN09y/lWzeKDbvhoqcRbHdc+APLs/PWYi/cisLPg==} + /@typescript-eslint/types@6.14.0: + resolution: {integrity: sha512-uty9H2K4Xs8E47z3SnXEPRNDfsis8JO27amp2GNCnzGETEW3yTqEIVg5+AI7U276oGF/tw6ZA+UesxeQ104ceA==} engines: {node: ^16.0.0 || >=18.0.0} dev: true @@ -4085,8 +4085,8 @@ packages: - supports-color dev: true - /@typescript-eslint/typescript-estree@6.13.2(typescript@5.3.3): - resolution: {integrity: sha512-SuD8YLQv6WHnOEtKv8D6HZUzOub855cfPnPMKvdM/Bh1plv1f7Q/0iFUDLKKlxHcEstQnaUU4QZskgQq74t+3w==} + /@typescript-eslint/typescript-estree@6.14.0(typescript@5.3.3): + resolution: {integrity: sha512-yPkaLwK0yH2mZKFE/bXkPAkkFgOv15GJAUzgUVonAbv0Hr4PK/N2yaA/4XQbTZQdygiDkpt5DkxPELqHguNvyw==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: typescript: '*' @@ -4094,8 +4094,8 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/types': 6.13.2 - '@typescript-eslint/visitor-keys': 6.13.2 + '@typescript-eslint/types': 6.14.0 + '@typescript-eslint/visitor-keys': 6.14.0 debug: 4.3.4 globby: 11.1.0 is-glob: 4.0.3 @@ -4126,8 +4126,8 @@ packages: - typescript dev: true - /@typescript-eslint/utils@6.13.2(eslint@8.55.0)(typescript@5.3.3): - resolution: {integrity: sha512-b9Ptq4eAZUym4idijCRzl61oPCwwREcfDI8xGk751Vhzig5fFZR9CyzDz4Sp/nxSLBYxUPyh4QdIDqWykFhNmQ==} + /@typescript-eslint/utils@6.14.0(eslint@8.55.0)(typescript@5.3.3): + resolution: {integrity: sha512-XwRTnbvRr7Ey9a1NT6jqdKX8y/atWG+8fAIu3z73HSP8h06i3r/ClMhmaF/RGWGW1tHJEwij1uEg2GbEmPYvYg==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 @@ -4135,9 +4135,9 @@ packages: '@eslint-community/eslint-utils': 4.4.0(eslint@8.55.0) '@types/json-schema': 7.0.15 '@types/semver': 7.5.6 - '@typescript-eslint/scope-manager': 6.13.2 - '@typescript-eslint/types': 6.13.2 - '@typescript-eslint/typescript-estree': 6.13.2(typescript@5.3.3) + '@typescript-eslint/scope-manager': 6.14.0 + '@typescript-eslint/types': 6.14.0 + '@typescript-eslint/typescript-estree': 6.14.0(typescript@5.3.3) eslint: 8.55.0 semver: 7.5.4 transitivePeerDependencies: @@ -4153,11 +4153,11 @@ packages: eslint-visitor-keys: 3.4.3 dev: true - /@typescript-eslint/visitor-keys@6.13.2: - resolution: {integrity: sha512-OGznFs0eAQXJsp+xSd6k/O1UbFi/K/L7WjqeRoFE7vadjAF9y0uppXhYNQNEqygjou782maGClOoZwPqF0Drlw==} + /@typescript-eslint/visitor-keys@6.14.0: + resolution: {integrity: sha512-fB5cw6GRhJUz03MrROVuj5Zm/Q+XWlVdIsFj+Zb1Hvqouc8t+XP2H5y53QYU/MGtd2dPg6/vJJlhoX3xc2ehfw==} engines: {node: ^16.0.0 || >=18.0.0} dependencies: - '@typescript-eslint/types': 6.13.2 + '@typescript-eslint/types': 6.14.0 eslint-visitor-keys: 3.4.3 dev: true @@ -5610,7 +5610,7 @@ packages: - supports-color dev: true - /eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.13.2)(eslint-plugin-import@2.29.0)(eslint@8.55.0): + /eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.14.0)(eslint-plugin-import@2.29.0)(eslint@8.55.0): resolution: {integrity: sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: @@ -5620,8 +5620,8 @@ packages: debug: 4.3.4 enhanced-resolve: 5.15.0 eslint: 8.55.0 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.13.2)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.55.0) - eslint-plugin-import: 2.29.0(@typescript-eslint/parser@6.13.2)(eslint-import-resolver-typescript@3.6.1)(eslint@8.55.0) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.14.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.55.0) + eslint-plugin-import: 2.29.0(@typescript-eslint/parser@6.14.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.55.0) fast-glob: 3.3.2 get-tsconfig: 4.7.2 is-core-module: 2.13.1 @@ -5633,7 +5633,7 @@ packages: - supports-color dev: true - /eslint-module-utils@2.8.0(@typescript-eslint/parser@6.13.2)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.55.0): + /eslint-module-utils@2.8.0(@typescript-eslint/parser@6.14.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.55.0): resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} engines: {node: '>=4'} peerDependencies: @@ -5654,16 +5654,16 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 6.13.2(eslint@8.55.0)(typescript@5.3.3) + '@typescript-eslint/parser': 6.14.0(eslint@8.55.0)(typescript@5.3.3) debug: 3.2.7 eslint: 8.55.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.13.2)(eslint-plugin-import@2.29.0)(eslint@8.55.0) + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.14.0)(eslint-plugin-import@2.29.0)(eslint@8.55.0) transitivePeerDependencies: - supports-color dev: true - /eslint-plugin-import@2.29.0(@typescript-eslint/parser@6.13.2)(eslint-import-resolver-typescript@3.6.1)(eslint@8.55.0): + /eslint-plugin-import@2.29.0(@typescript-eslint/parser@6.14.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.55.0): resolution: {integrity: sha512-QPOO5NO6Odv5lpoTkddtutccQjysJuFxoPS7fAHO+9m9udNHvTCPSAMW9zGAYj8lAIdr40I8yPCdUYrncXtrwg==} engines: {node: '>=4'} peerDependencies: @@ -5673,7 +5673,7 @@ packages: '@typescript-eslint/parser': optional: true dependencies: - '@typescript-eslint/parser': 6.13.2(eslint@8.55.0)(typescript@5.3.3) + '@typescript-eslint/parser': 6.14.0(eslint@8.55.0)(typescript@5.3.3) array-includes: 3.1.7 array.prototype.findlastindex: 1.2.3 array.prototype.flat: 1.3.2 @@ -5682,7 +5682,7 @@ packages: doctrine: 2.1.0 eslint: 8.55.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.13.2)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.55.0) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.14.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.55.0) hasown: 2.0.0 is-core-module: 2.13.1 is-glob: 4.0.3 @@ -5707,7 +5707,7 @@ packages: eslint: 8.55.0 dev: true - /eslint-plugin-jest@27.6.0(@typescript-eslint/eslint-plugin@6.13.2)(eslint@8.55.0)(jest@29.7.0)(typescript@5.3.3): + /eslint-plugin-jest@27.6.0(@typescript-eslint/eslint-plugin@6.14.0)(eslint@8.55.0)(jest@29.7.0)(typescript@5.3.3): resolution: {integrity: sha512-MTlusnnDMChbElsszJvrwD1dN3x6nZl//s4JD23BxB6MgR66TZlL064su24xEIS3VACfAoHV1vgyMgPw8nkdng==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: @@ -5720,7 +5720,7 @@ packages: jest: optional: true dependencies: - '@typescript-eslint/eslint-plugin': 6.13.2(@typescript-eslint/parser@6.13.2)(eslint@8.55.0)(typescript@5.3.3) + '@typescript-eslint/eslint-plugin': 6.14.0(@typescript-eslint/parser@6.14.0)(eslint@8.55.0)(typescript@5.3.3) '@typescript-eslint/utils': 5.62.0(eslint@8.55.0)(typescript@5.3.3) eslint: 8.55.0 jest: 29.7.0(@types/node@18.19.3)(ts-node@10.9.2) From 8cd7f2212e6a384bca722cdc4c0acb5766962ab6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 18 Dec 2023 18:36:40 +0000 Subject: [PATCH 080/173] chore(deps): update linters (#26359) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 10 +-- pnpm-lock.yaml | 194 ++++++++++++++++++++++++------------------------- 2 files changed, 102 insertions(+), 102 deletions(-) diff --git a/package.json b/package.json index 36ce030c459d12..58d0092a903788 100644 --- a/package.json +++ b/package.json @@ -278,7 +278,7 @@ "@types/common-tags": "1.8.4", "@types/conventional-commits-detector": "1.0.2", "@types/diff": "5.0.9", - "@types/eslint": "8.44.8", + "@types/eslint": "8.44.9", "@types/fs-extra": "11.0.4", "@types/git-url-parse": "9.0.3", "@types/github-url-from-git": "1.5.3", @@ -306,19 +306,19 @@ "@types/url-join": "4.0.3", "@types/validate-npm-package-name": "4.0.2", "@types/xmldoc": "1.1.9", - "@typescript-eslint/eslint-plugin": "6.14.0", - "@typescript-eslint/parser": "6.14.0", + "@typescript-eslint/eslint-plugin": "6.15.0", + "@typescript-eslint/parser": "6.15.0", "aws-sdk-client-mock": "3.0.0", "callsite": "1.0.0", "common-tags": "1.8.2", "conventional-changelog-conventionalcommits": "7.0.2", "diff": "5.1.0", "emojibase-data": "15.3.0", - "eslint": "8.55.0", + "eslint": "8.56.0", "eslint-config-prettier": "9.1.0", "eslint-formatter-gha": "1.4.3", "eslint-import-resolver-typescript": "3.6.1", - "eslint-plugin-import": "2.29.0", + "eslint-plugin-import": "2.29.1", "eslint-plugin-jest": "27.6.0", "eslint-plugin-jest-formatting": "3.1.0", "eslint-plugin-promise": "6.1.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 169cb17e59a31d..41af45f681b344 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -398,8 +398,8 @@ importers: specifier: 5.0.9 version: 5.0.9 '@types/eslint': - specifier: 8.44.8 - version: 8.44.8 + specifier: 8.44.9 + version: 8.44.9 '@types/fs-extra': specifier: 11.0.4 version: 11.0.4 @@ -482,11 +482,11 @@ importers: specifier: 1.1.9 version: 1.1.9 '@typescript-eslint/eslint-plugin': - specifier: 6.14.0 - version: 6.14.0(@typescript-eslint/parser@6.14.0)(eslint@8.55.0)(typescript@5.3.3) + specifier: 6.15.0 + version: 6.15.0(@typescript-eslint/parser@6.15.0)(eslint@8.56.0)(typescript@5.3.3) '@typescript-eslint/parser': - specifier: 6.14.0 - version: 6.14.0(eslint@8.55.0)(typescript@5.3.3) + specifier: 6.15.0 + version: 6.15.0(eslint@8.56.0)(typescript@5.3.3) aws-sdk-client-mock: specifier: 3.0.0 version: 3.0.0 @@ -506,32 +506,32 @@ importers: specifier: 15.3.0 version: 15.3.0(emojibase@15.3.0) eslint: - specifier: 8.55.0 - version: 8.55.0 + specifier: 8.56.0 + version: 8.56.0 eslint-config-prettier: specifier: 9.1.0 - version: 9.1.0(eslint@8.55.0) + version: 9.1.0(eslint@8.56.0) eslint-formatter-gha: specifier: 1.4.3 version: 1.4.3 eslint-import-resolver-typescript: specifier: 3.6.1 - version: 3.6.1(@typescript-eslint/parser@6.14.0)(eslint-plugin-import@2.29.0)(eslint@8.55.0) + version: 3.6.1(@typescript-eslint/parser@6.15.0)(eslint-plugin-import@2.29.1)(eslint@8.56.0) eslint-plugin-import: - specifier: 2.29.0 - version: 2.29.0(@typescript-eslint/parser@6.14.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.55.0) + specifier: 2.29.1 + version: 2.29.1(@typescript-eslint/parser@6.15.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0) eslint-plugin-jest: specifier: 27.6.0 - version: 27.6.0(@typescript-eslint/eslint-plugin@6.14.0)(eslint@8.55.0)(jest@29.7.0)(typescript@5.3.3) + version: 27.6.0(@typescript-eslint/eslint-plugin@6.15.0)(eslint@8.56.0)(jest@29.7.0)(typescript@5.3.3) eslint-plugin-jest-formatting: specifier: 3.1.0 - version: 3.1.0(eslint@8.55.0) + version: 3.1.0(eslint@8.56.0) eslint-plugin-promise: specifier: 6.1.1 - version: 6.1.1(eslint@8.55.0) + version: 6.1.1(eslint@8.56.0) eslint-plugin-typescript-enum: specifier: 2.1.0 - version: 2.1.0(eslint@8.55.0)(typescript@5.3.3) + version: 2.1.0(eslint@8.56.0)(typescript@5.3.3) expect: specifier: 29.7.0 version: 29.7.0 @@ -1921,13 +1921,13 @@ packages: '@jridgewell/trace-mapping': 0.3.9 dev: true - /@eslint-community/eslint-utils@4.4.0(eslint@8.55.0): + /@eslint-community/eslint-utils@4.4.0(eslint@8.56.0): resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 dependencies: - eslint: 8.55.0 + eslint: 8.56.0 eslint-visitor-keys: 3.4.3 dev: true @@ -1953,8 +1953,8 @@ packages: - supports-color dev: true - /@eslint/js@8.55.0: - resolution: {integrity: sha512-qQfo2mxH5yVom1kacMtZZJFVdW+E70mqHMJvVg6WTLo+VBuQJ4TojZlfWBjK0ve5BdEeNAVxOsl/nvNMpJOaJA==} + /@eslint/js@8.56.0: + resolution: {integrity: sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true @@ -3700,8 +3700,8 @@ packages: resolution: {integrity: sha512-TB/6hBkYQJxsZHSqyeuO1Jt0AB/bW6G7rHt9g7lML7SOF6lbgcHvw/Lr+69iqN0qxgXLhWKScAon73JNnptuDw==} dev: false - /@types/eslint@8.44.8: - resolution: {integrity: sha512-4K8GavROwhrYl2QXDXm0Rv9epkA8GBFu0EI+XrrnnuCl7u8CWBRusX7fXJfanhZTDWSAL24gDI/UqXyUM0Injw==} + /@types/eslint@8.44.9: + resolution: {integrity: sha512-6yBxcvwnnYoYT1Uk2d+jvIfsuP4mb2EdIxFnrPABj5a/838qe5bGkNLFOiipX4ULQ7XVQvTxOh7jO+BTAiqsEw==} dependencies: '@types/estree': 1.0.5 '@types/json-schema': 7.0.15 @@ -3955,8 +3955,8 @@ packages: dev: false optional: true - /@typescript-eslint/eslint-plugin@6.14.0(@typescript-eslint/parser@6.14.0)(eslint@8.55.0)(typescript@5.3.3): - resolution: {integrity: sha512-1ZJBykBCXaSHG94vMMKmiHoL0MhNHKSVlcHVYZNw+BKxufhqQVTOawNpwwI1P5nIFZ/4jLVop0mcY6mJJDFNaw==} + /@typescript-eslint/eslint-plugin@6.15.0(@typescript-eslint/parser@6.15.0)(eslint@8.56.0)(typescript@5.3.3): + resolution: {integrity: sha512-j5qoikQqPccq9QoBAupOP+CBu8BaJ8BLjaXSioDISeTZkVO3ig7oSIKh3H+rEpee7xCXtWwSB4KIL5l6hWZzpg==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha @@ -3967,13 +3967,13 @@ packages: optional: true dependencies: '@eslint-community/regexpp': 4.10.0 - '@typescript-eslint/parser': 6.14.0(eslint@8.55.0)(typescript@5.3.3) - '@typescript-eslint/scope-manager': 6.14.0 - '@typescript-eslint/type-utils': 6.14.0(eslint@8.55.0)(typescript@5.3.3) - '@typescript-eslint/utils': 6.14.0(eslint@8.55.0)(typescript@5.3.3) - '@typescript-eslint/visitor-keys': 6.14.0 + '@typescript-eslint/parser': 6.15.0(eslint@8.56.0)(typescript@5.3.3) + '@typescript-eslint/scope-manager': 6.15.0 + '@typescript-eslint/type-utils': 6.15.0(eslint@8.56.0)(typescript@5.3.3) + '@typescript-eslint/utils': 6.15.0(eslint@8.56.0)(typescript@5.3.3) + '@typescript-eslint/visitor-keys': 6.15.0 debug: 4.3.4 - eslint: 8.55.0 + eslint: 8.56.0 graphemer: 1.4.0 ignore: 5.3.0 natural-compare: 1.4.0 @@ -3984,21 +3984,21 @@ packages: - supports-color dev: true - /@typescript-eslint/experimental-utils@5.62.0(eslint@8.55.0)(typescript@5.3.3): + /@typescript-eslint/experimental-utils@5.62.0(eslint@8.56.0)(typescript@5.3.3): resolution: {integrity: sha512-RTXpeB3eMkpoclG3ZHft6vG/Z30azNHuqY6wKPBHlVMZFuEvrtlEDe8gMqDb+SO+9hjC/pLekeSCryf9vMZlCw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: - '@typescript-eslint/utils': 5.62.0(eslint@8.55.0)(typescript@5.3.3) - eslint: 8.55.0 + '@typescript-eslint/utils': 5.62.0(eslint@8.56.0)(typescript@5.3.3) + eslint: 8.56.0 transitivePeerDependencies: - supports-color - typescript dev: true - /@typescript-eslint/parser@6.14.0(eslint@8.55.0)(typescript@5.3.3): - resolution: {integrity: sha512-QjToC14CKacd4Pa7JK4GeB/vHmWFJckec49FR4hmIRf97+KXole0T97xxu9IFiPxVQ1DBWrQ5wreLwAGwWAVQA==} + /@typescript-eslint/parser@6.15.0(eslint@8.56.0)(typescript@5.3.3): + resolution: {integrity: sha512-MkgKNnsjC6QwcMdlNAel24jjkEO/0hQaMDLqP4S9zq5HBAUJNQB6y+3DwLjX7b3l2b37eNAxMPLwb3/kh8VKdA==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 @@ -4007,12 +4007,12 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/scope-manager': 6.14.0 - '@typescript-eslint/types': 6.14.0 - '@typescript-eslint/typescript-estree': 6.14.0(typescript@5.3.3) - '@typescript-eslint/visitor-keys': 6.14.0 + '@typescript-eslint/scope-manager': 6.15.0 + '@typescript-eslint/types': 6.15.0 + '@typescript-eslint/typescript-estree': 6.15.0(typescript@5.3.3) + '@typescript-eslint/visitor-keys': 6.15.0 debug: 4.3.4 - eslint: 8.55.0 + eslint: 8.56.0 typescript: 5.3.3 transitivePeerDependencies: - supports-color @@ -4026,16 +4026,16 @@ packages: '@typescript-eslint/visitor-keys': 5.62.0 dev: true - /@typescript-eslint/scope-manager@6.14.0: - resolution: {integrity: sha512-VT7CFWHbZipPncAZtuALr9y3EuzY1b1t1AEkIq2bTXUPKw+pHoXflGNG5L+Gv6nKul1cz1VH8fz16IThIU0tdg==} + /@typescript-eslint/scope-manager@6.15.0: + resolution: {integrity: sha512-+BdvxYBltqrmgCNu4Li+fGDIkW9n//NrruzG9X1vBzaNK+ExVXPoGB71kneaVw/Jp+4rH/vaMAGC6JfMbHstVg==} engines: {node: ^16.0.0 || >=18.0.0} dependencies: - '@typescript-eslint/types': 6.14.0 - '@typescript-eslint/visitor-keys': 6.14.0 + '@typescript-eslint/types': 6.15.0 + '@typescript-eslint/visitor-keys': 6.15.0 dev: true - /@typescript-eslint/type-utils@6.14.0(eslint@8.55.0)(typescript@5.3.3): - resolution: {integrity: sha512-x6OC9Q7HfYKqjnuNu5a7kffIYs3No30isapRBJl1iCHLitD8O0lFbRcVGiOcuyN837fqXzPZ1NS10maQzZMKqw==} + /@typescript-eslint/type-utils@6.15.0(eslint@8.56.0)(typescript@5.3.3): + resolution: {integrity: sha512-CnmHKTfX6450Bo49hPg2OkIm/D/TVYV7jO1MCfPYGwf6x3GO0VU8YMO5AYMn+u3X05lRRxA4fWCz87GFQV6yVQ==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 @@ -4044,10 +4044,10 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 6.14.0(typescript@5.3.3) - '@typescript-eslint/utils': 6.14.0(eslint@8.55.0)(typescript@5.3.3) + '@typescript-eslint/typescript-estree': 6.15.0(typescript@5.3.3) + '@typescript-eslint/utils': 6.15.0(eslint@8.56.0)(typescript@5.3.3) debug: 4.3.4 - eslint: 8.55.0 + eslint: 8.56.0 ts-api-utils: 1.0.3(typescript@5.3.3) typescript: 5.3.3 transitivePeerDependencies: @@ -4059,8 +4059,8 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /@typescript-eslint/types@6.14.0: - resolution: {integrity: sha512-uty9H2K4Xs8E47z3SnXEPRNDfsis8JO27amp2GNCnzGETEW3yTqEIVg5+AI7U276oGF/tw6ZA+UesxeQ104ceA==} + /@typescript-eslint/types@6.15.0: + resolution: {integrity: sha512-yXjbt//E4T/ee8Ia1b5mGlbNj9fB9lJP4jqLbZualwpP2BCQ5is6BcWwxpIsY4XKAhmdv3hrW92GdtJbatC6dQ==} engines: {node: ^16.0.0 || >=18.0.0} dev: true @@ -4085,8 +4085,8 @@ packages: - supports-color dev: true - /@typescript-eslint/typescript-estree@6.14.0(typescript@5.3.3): - resolution: {integrity: sha512-yPkaLwK0yH2mZKFE/bXkPAkkFgOv15GJAUzgUVonAbv0Hr4PK/N2yaA/4XQbTZQdygiDkpt5DkxPELqHguNvyw==} + /@typescript-eslint/typescript-estree@6.15.0(typescript@5.3.3): + resolution: {integrity: sha512-7mVZJN7Hd15OmGuWrp2T9UvqR2Ecg+1j/Bp1jXUEY2GZKV6FXlOIoqVDmLpBiEiq3katvj/2n2mR0SDwtloCew==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: typescript: '*' @@ -4094,8 +4094,8 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/types': 6.14.0 - '@typescript-eslint/visitor-keys': 6.14.0 + '@typescript-eslint/types': 6.15.0 + '@typescript-eslint/visitor-keys': 6.15.0 debug: 4.3.4 globby: 11.1.0 is-glob: 4.0.3 @@ -4106,19 +4106,19 @@ packages: - supports-color dev: true - /@typescript-eslint/utils@5.62.0(eslint@8.55.0)(typescript@5.3.3): + /@typescript-eslint/utils@5.62.0(eslint@8.56.0)(typescript@5.3.3): resolution: {integrity: sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.55.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@8.56.0) '@types/json-schema': 7.0.15 '@types/semver': 7.5.6 '@typescript-eslint/scope-manager': 5.62.0 '@typescript-eslint/types': 5.62.0 '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.3.3) - eslint: 8.55.0 + eslint: 8.56.0 eslint-scope: 5.1.1 semver: 7.5.4 transitivePeerDependencies: @@ -4126,19 +4126,19 @@ packages: - typescript dev: true - /@typescript-eslint/utils@6.14.0(eslint@8.55.0)(typescript@5.3.3): - resolution: {integrity: sha512-XwRTnbvRr7Ey9a1NT6jqdKX8y/atWG+8fAIu3z73HSP8h06i3r/ClMhmaF/RGWGW1tHJEwij1uEg2GbEmPYvYg==} + /@typescript-eslint/utils@6.15.0(eslint@8.56.0)(typescript@5.3.3): + resolution: {integrity: sha512-eF82p0Wrrlt8fQSRL0bGXzK5nWPRV2dYQZdajcfzOD9+cQz9O7ugifrJxclB+xVOvWvagXfqS4Es7vpLP4augw==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.55.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@8.56.0) '@types/json-schema': 7.0.15 '@types/semver': 7.5.6 - '@typescript-eslint/scope-manager': 6.14.0 - '@typescript-eslint/types': 6.14.0 - '@typescript-eslint/typescript-estree': 6.14.0(typescript@5.3.3) - eslint: 8.55.0 + '@typescript-eslint/scope-manager': 6.15.0 + '@typescript-eslint/types': 6.15.0 + '@typescript-eslint/typescript-estree': 6.15.0(typescript@5.3.3) + eslint: 8.56.0 semver: 7.5.4 transitivePeerDependencies: - supports-color @@ -4153,11 +4153,11 @@ packages: eslint-visitor-keys: 3.4.3 dev: true - /@typescript-eslint/visitor-keys@6.14.0: - resolution: {integrity: sha512-fB5cw6GRhJUz03MrROVuj5Zm/Q+XWlVdIsFj+Zb1Hvqouc8t+XP2H5y53QYU/MGtd2dPg6/vJJlhoX3xc2ehfw==} + /@typescript-eslint/visitor-keys@6.15.0: + resolution: {integrity: sha512-1zvtdC1a9h5Tb5jU9x3ADNXO9yjP8rXlaoChu0DQX40vf5ACVpYIVIZhIMZ6d5sDXH7vq4dsZBT1fEGj8D2n2w==} engines: {node: ^16.0.0 || >=18.0.0} dependencies: - '@typescript-eslint/types': 6.14.0 + '@typescript-eslint/types': 6.15.0 eslint-visitor-keys: 3.4.3 dev: true @@ -5569,13 +5569,13 @@ packages: engines: {node: '>=12'} dev: true - /eslint-config-prettier@9.1.0(eslint@8.55.0): + /eslint-config-prettier@9.1.0(eslint@8.56.0): resolution: {integrity: sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==} hasBin: true peerDependencies: eslint: '>=7.0.0' dependencies: - eslint: 8.55.0 + eslint: 8.56.0 dev: true /eslint-formatter-gha@1.4.3: @@ -5610,7 +5610,7 @@ packages: - supports-color dev: true - /eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.14.0)(eslint-plugin-import@2.29.0)(eslint@8.55.0): + /eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.15.0)(eslint-plugin-import@2.29.1)(eslint@8.56.0): resolution: {integrity: sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: @@ -5619,9 +5619,9 @@ packages: dependencies: debug: 4.3.4 enhanced-resolve: 5.15.0 - eslint: 8.55.0 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.14.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.55.0) - eslint-plugin-import: 2.29.0(@typescript-eslint/parser@6.14.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.55.0) + eslint: 8.56.0 + eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.15.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.15.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0) fast-glob: 3.3.2 get-tsconfig: 4.7.2 is-core-module: 2.13.1 @@ -5633,7 +5633,7 @@ packages: - supports-color dev: true - /eslint-module-utils@2.8.0(@typescript-eslint/parser@6.14.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.55.0): + /eslint-module-utils@2.8.0(@typescript-eslint/parser@6.15.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0): resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} engines: {node: '>=4'} peerDependencies: @@ -5654,17 +5654,17 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 6.14.0(eslint@8.55.0)(typescript@5.3.3) + '@typescript-eslint/parser': 6.15.0(eslint@8.56.0)(typescript@5.3.3) debug: 3.2.7 - eslint: 8.55.0 + eslint: 8.56.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.14.0)(eslint-plugin-import@2.29.0)(eslint@8.55.0) + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.15.0)(eslint-plugin-import@2.29.1)(eslint@8.56.0) transitivePeerDependencies: - supports-color dev: true - /eslint-plugin-import@2.29.0(@typescript-eslint/parser@6.14.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.55.0): - resolution: {integrity: sha512-QPOO5NO6Odv5lpoTkddtutccQjysJuFxoPS7fAHO+9m9udNHvTCPSAMW9zGAYj8lAIdr40I8yPCdUYrncXtrwg==} + /eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.15.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0): + resolution: {integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==} engines: {node: '>=4'} peerDependencies: '@typescript-eslint/parser': '*' @@ -5673,16 +5673,16 @@ packages: '@typescript-eslint/parser': optional: true dependencies: - '@typescript-eslint/parser': 6.14.0(eslint@8.55.0)(typescript@5.3.3) + '@typescript-eslint/parser': 6.15.0(eslint@8.56.0)(typescript@5.3.3) array-includes: 3.1.7 array.prototype.findlastindex: 1.2.3 array.prototype.flat: 1.3.2 array.prototype.flatmap: 1.3.2 debug: 3.2.7 doctrine: 2.1.0 - eslint: 8.55.0 + eslint: 8.56.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.14.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.55.0) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.15.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0) hasown: 2.0.0 is-core-module: 2.13.1 is-glob: 4.0.3 @@ -5698,16 +5698,16 @@ packages: - supports-color dev: true - /eslint-plugin-jest-formatting@3.1.0(eslint@8.55.0): + /eslint-plugin-jest-formatting@3.1.0(eslint@8.56.0): resolution: {integrity: sha512-XyysraZ1JSgGbLSDxjj5HzKKh0glgWf+7CkqxbTqb7zEhW7X2WHo5SBQ8cGhnszKN+2Lj3/oevBlHNbHezoc/A==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: '>=0.8.0' dependencies: - eslint: 8.55.0 + eslint: 8.56.0 dev: true - /eslint-plugin-jest@27.6.0(@typescript-eslint/eslint-plugin@6.14.0)(eslint@8.55.0)(jest@29.7.0)(typescript@5.3.3): + /eslint-plugin-jest@27.6.0(@typescript-eslint/eslint-plugin@6.15.0)(eslint@8.56.0)(jest@29.7.0)(typescript@5.3.3): resolution: {integrity: sha512-MTlusnnDMChbElsszJvrwD1dN3x6nZl//s4JD23BxB6MgR66TZlL064su24xEIS3VACfAoHV1vgyMgPw8nkdng==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: @@ -5720,28 +5720,28 @@ packages: jest: optional: true dependencies: - '@typescript-eslint/eslint-plugin': 6.14.0(@typescript-eslint/parser@6.14.0)(eslint@8.55.0)(typescript@5.3.3) - '@typescript-eslint/utils': 5.62.0(eslint@8.55.0)(typescript@5.3.3) - eslint: 8.55.0 + '@typescript-eslint/eslint-plugin': 6.15.0(@typescript-eslint/parser@6.15.0)(eslint@8.56.0)(typescript@5.3.3) + '@typescript-eslint/utils': 5.62.0(eslint@8.56.0)(typescript@5.3.3) + eslint: 8.56.0 jest: 29.7.0(@types/node@18.19.3)(ts-node@10.9.2) transitivePeerDependencies: - supports-color - typescript dev: true - /eslint-plugin-promise@6.1.1(eslint@8.55.0): + /eslint-plugin-promise@6.1.1(eslint@8.56.0): resolution: {integrity: sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 dependencies: - eslint: 8.55.0 + eslint: 8.56.0 dev: true - /eslint-plugin-typescript-enum@2.1.0(eslint@8.55.0)(typescript@5.3.3): + /eslint-plugin-typescript-enum@2.1.0(eslint@8.56.0)(typescript@5.3.3): resolution: {integrity: sha512-n6RO89KJ2V2nHVAdIq1q3IBeYZSNZjBreqXOzpjmsBtw+NNhSTTSQXqwO00VYOce9Gy8cr2cDEYpj0Km+Ij90Q==} dependencies: - '@typescript-eslint/experimental-utils': 5.62.0(eslint@8.55.0)(typescript@5.3.3) + '@typescript-eslint/experimental-utils': 5.62.0(eslint@8.56.0)(typescript@5.3.3) transitivePeerDependencies: - eslint - supports-color @@ -5768,15 +5768,15 @@ packages: resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - /eslint@8.55.0: - resolution: {integrity: sha512-iyUUAM0PCKj5QpwGfmCAG9XXbZCWsqP/eWAWrG/W0umvjuLRBECwSFdt+rCntju0xEH7teIABPwXpahftIaTdA==} + /eslint@8.56.0: + resolution: {integrity: sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} hasBin: true dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.55.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@8.56.0) '@eslint-community/regexpp': 4.10.0 '@eslint/eslintrc': 2.1.4 - '@eslint/js': 8.55.0 + '@eslint/js': 8.56.0 '@humanwhocodes/config-array': 0.11.13 '@humanwhocodes/module-importer': 1.0.1 '@nodelib/fs.walk': 1.2.8 From 8885fbfbc1584bb77b6e230855fcae3e5f8d3631 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 19 Dec 2023 04:01:20 +0000 Subject: [PATCH 081/173] build(deps): update dependency @renovatebot/pep440 to v3.0.16 (#26365) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 58d0092a903788..bcb709dfdc562a 100644 --- a/package.json +++ b/package.json @@ -165,7 +165,7 @@ "@opentelemetry/semantic-conventions": "1.18.1", "@qnighy/marshal": "0.1.3", "@renovatebot/osv-offline": "1.3.10", - "@renovatebot/pep440": "3.0.15", + "@renovatebot/pep440": "3.0.16", "@renovatebot/ruby-semver": "3.0.21", "@sindresorhus/is": "4.6.0", "@types/ms": "0.7.34", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 41af45f681b344..1e69aa787e7efb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -69,8 +69,8 @@ importers: specifier: 1.3.10 version: 1.3.10 '@renovatebot/pep440': - specifier: 3.0.15 - version: 3.0.15 + specifier: 3.0.16 + version: 3.0.16 '@renovatebot/ruby-semver': specifier: 3.0.21 version: 3.0.21 @@ -2840,8 +2840,8 @@ packages: - encoding dev: false - /@renovatebot/pep440@3.0.15: - resolution: {integrity: sha512-BrAe7puI22QHA9LKgSG9vpbi5s3sGH6DiHrASNl9iyPHzsbtjB+xtnIhVSvb1s9uaxoBgLr6TczxfI5dwxde8A==} + /@renovatebot/pep440@3.0.16: + resolution: {integrity: sha512-lx0tfTmZRUbEbb1eGI+2CSnFKJ/mXE5l27cQY49TzsIiuc9HRbB2XeMSmyV6tXWm9GTZZZ5oeJqiwn8M7NSxxg==} engines: {node: ^18.12.0 || >= 20.0.0, pnpm: ^8.6.11} dev: false From 0df540e17c4266d7a6b2fc2018d665d3e7b5c003 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 19 Dec 2023 06:17:35 +0000 Subject: [PATCH 082/173] build(deps): update dependency @renovatebot/pep440 to v3.0.17 (#26366) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index bcb709dfdc562a..aae4571c0c1042 100644 --- a/package.json +++ b/package.json @@ -165,7 +165,7 @@ "@opentelemetry/semantic-conventions": "1.18.1", "@qnighy/marshal": "0.1.3", "@renovatebot/osv-offline": "1.3.10", - "@renovatebot/pep440": "3.0.16", + "@renovatebot/pep440": "3.0.17", "@renovatebot/ruby-semver": "3.0.21", "@sindresorhus/is": "4.6.0", "@types/ms": "0.7.34", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1e69aa787e7efb..90f5eed970d84e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -69,8 +69,8 @@ importers: specifier: 1.3.10 version: 1.3.10 '@renovatebot/pep440': - specifier: 3.0.16 - version: 3.0.16 + specifier: 3.0.17 + version: 3.0.17 '@renovatebot/ruby-semver': specifier: 3.0.21 version: 3.0.21 @@ -2840,8 +2840,8 @@ packages: - encoding dev: false - /@renovatebot/pep440@3.0.16: - resolution: {integrity: sha512-lx0tfTmZRUbEbb1eGI+2CSnFKJ/mXE5l27cQY49TzsIiuc9HRbB2XeMSmyV6tXWm9GTZZZ5oeJqiwn8M7NSxxg==} + /@renovatebot/pep440@3.0.17: + resolution: {integrity: sha512-pmXfRIoai7Ba4RcRqw9sEEo/fWPVKNPPHSQgSCvMGnfKKmn0rgyQBZAB1XeXEgb6h4dwMJkvU0p7rWgTSmXXNw==} engines: {node: ^18.12.0 || >= 20.0.0, pnpm: ^8.6.11} dev: false From 62e433f0758945a8428ebc15eb4a9dc5f52e28be Mon Sep 17 00:00:00 2001 From: Nabeel Saabna <48175656+nabeelsaabna@users.noreply.github.com> Date: Tue, 19 Dec 2023 10:49:29 +0200 Subject: [PATCH 083/173] feat(merge-confidence): add Golang support (#26369) --- lib/config/presets/internal/merge-confidence.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/config/presets/internal/merge-confidence.ts b/lib/config/presets/internal/merge-confidence.ts index e238f30197e483..abde81e4398f2a 100644 --- a/lib/config/presets/internal/merge-confidence.ts +++ b/lib/config/presets/internal/merge-confidence.ts @@ -12,6 +12,7 @@ export const presets: Record = { 'packagist', 'pypi', 'rubygems', + 'go', ], matchUpdateTypes: ['patch', 'minor', 'major'], prBodyColumns: [ @@ -37,6 +38,7 @@ export const presets: Record = { 'packagist', 'pypi', 'rubygems', + 'go', ], matchUpdateTypes: ['patch', 'minor', 'major'], prBodyColumns: ['Package', 'Change', 'Age', 'Confidence'], From fa04884a37b6faeb2d91c54eae7ec7f21a4649e1 Mon Sep 17 00:00:00 2001 From: Johannes Feichtner <343448+Churro@users.noreply.github.com> Date: Tue, 19 Dec 2023 09:50:34 +0100 Subject: [PATCH 084/173] feat(manager/pep621): add support for `bumpVersion` option (#26361) Co-authored-by: Rhys Arkins --- docs/usage/configuration-options.md | 2 +- lib/modules/manager/pep621/extract.spec.ts | 12 +++++ lib/modules/manager/pep621/extract.ts | 4 +- lib/modules/manager/pep621/index.ts | 1 + lib/modules/manager/pep621/schema.ts | 1 + lib/modules/manager/pep621/update.spec.ts | 51 ++++++++++++++++++++++ lib/modules/manager/pep621/update.ts | 48 ++++++++++++++++++++ 7 files changed, 117 insertions(+), 2 deletions(-) create mode 100644 lib/modules/manager/pep621/update.spec.ts create mode 100644 lib/modules/manager/pep621/update.ts diff --git a/docs/usage/configuration-options.md b/docs/usage/configuration-options.md index d225073659b490..40f9e3bcc821c4 100644 --- a/docs/usage/configuration-options.md +++ b/docs/usage/configuration-options.md @@ -410,7 +410,7 @@ This is an advance field and it's recommend you seek a config review before appl ## bumpVersion -Currently this setting supports `helmv3`, `npm`, `nuget`, `maven` and `sbt` only, so raise a feature request if you have a use for it with other package managers. +Currently this setting supports `helmv3`, `npm`, `nuget`, `maven`, `pep621` and `sbt` only, so raise a feature request if you have a use for it with other package managers. Its purpose is if you want Renovate to update the `version` field within your package file any time it updates dependencies within. Usually this is for automatic release purposes, so that you don't need to add another step after Renovate before you can release a new version. diff --git a/lib/modules/manager/pep621/extract.spec.ts b/lib/modules/manager/pep621/extract.spec.ts index 31b6edbb20d580..63aa8bcbdd11ff 100644 --- a/lib/modules/manager/pep621/extract.spec.ts +++ b/lib/modules/manager/pep621/extract.spec.ts @@ -311,5 +311,17 @@ describe('modules/manager/pep621/extract', () => { }, ]); }); + + it('should extract project version', () => { + const content = codeBlock` + [project] + name = "test" + version = "0.0.2" + dependencies = [ "requests==2.30.0" ] + `; + + const res = extractPackageFile(content, 'pyproject.toml'); + expect(res?.packageFileVersion).toBe('0.0.2'); + }); }); }); diff --git a/lib/modules/manager/pep621/extract.ts b/lib/modules/manager/pep621/extract.ts index f5c5a607f64574..d1f8e4accf7bf2 100644 --- a/lib/modules/manager/pep621/extract.ts +++ b/lib/modules/manager/pep621/extract.ts @@ -26,6 +26,8 @@ export function extractPackageFile( if (is.nullOrUndefined(def)) { return null; } + + const packageFileVersion = def.project?.version; const pythonConstraint = def.project?.['requires-python']; const extractedConstraints = is.nonEmptyString(pythonConstraint) ? { extractedConstraints: { python: pythonConstraint } } @@ -49,6 +51,6 @@ export function extractPackageFile( } return processedDeps.length - ? { ...extractedConstraints, deps: processedDeps } + ? { ...extractedConstraints, deps: processedDeps, packageFileVersion } : null; } diff --git a/lib/modules/manager/pep621/index.ts b/lib/modules/manager/pep621/index.ts index 1b4326edb1d24b..d71206781f7f95 100644 --- a/lib/modules/manager/pep621/index.ts +++ b/lib/modules/manager/pep621/index.ts @@ -1,5 +1,6 @@ import type { Category } from '../../../constants'; import { PypiDatasource } from '../../datasource/pypi'; +export { bumpPackageVersion } from './update'; export { extractPackageFile } from './extract'; export { updateArtifacts } from './artifacts'; diff --git a/lib/modules/manager/pep621/schema.ts b/lib/modules/manager/pep621/schema.ts index dbf9e1f4f2345b..880336adb38dc5 100644 --- a/lib/modules/manager/pep621/schema.ts +++ b/lib/modules/manager/pep621/schema.ts @@ -10,6 +10,7 @@ const DependencyRecordSchema = z export const PyProjectSchema = z.object({ project: z .object({ + version: z.string().optional().catch(undefined), 'requires-python': z.string().optional(), dependencies: DependencyListSchema, 'optional-dependencies': DependencyRecordSchema, diff --git a/lib/modules/manager/pep621/update.spec.ts b/lib/modules/manager/pep621/update.spec.ts new file mode 100644 index 00000000000000..5b33267b330dc6 --- /dev/null +++ b/lib/modules/manager/pep621/update.spec.ts @@ -0,0 +1,51 @@ +import { codeBlock } from 'common-tags'; +import * as projectUpdater from '.'; + +describe('modules/manager/pep621/update', () => { + describe('bumpPackageVersion()', () => { + const content = codeBlock` + [project] + name = "test" + version = "0.0.2" + description = "test" + `; + + it('increments', () => { + const { bumpedContent } = projectUpdater.bumpPackageVersion( + content, + '0.0.2', + 'patch', + ); + const expected = content.replace('0.0.2', '0.0.3'); + expect(bumpedContent).toEqual(expected); + }); + + it('no ops', () => { + const { bumpedContent } = projectUpdater.bumpPackageVersion( + content, + '0.0.1', + 'patch', + ); + expect(bumpedContent).toEqual(content); + }); + + it('updates', () => { + const { bumpedContent } = projectUpdater.bumpPackageVersion( + content, + '0.0.1', + 'minor', + ); + const expected = content.replace('0.0.2', '0.1.0'); + expect(bumpedContent).toEqual(expected); + }); + + it('returns content if bumping errors', () => { + const { bumpedContent } = projectUpdater.bumpPackageVersion( + content, + '0.0.2', + true as any, + ); + expect(bumpedContent).toEqual(content); + }); + }); +}); diff --git a/lib/modules/manager/pep621/update.ts b/lib/modules/manager/pep621/update.ts new file mode 100644 index 00000000000000..d19bb143ed717f --- /dev/null +++ b/lib/modules/manager/pep621/update.ts @@ -0,0 +1,48 @@ +import { inc } from '@renovatebot/pep440'; +import type { ReleaseType } from 'semver'; +import { logger } from '../../../logger'; +import { regEx } from '../../../util/regex'; +import type { BumpPackageVersionResult } from '../types'; + +export function bumpPackageVersion( + content: string, + currentValue: string, + bumpVersion: ReleaseType, +): BumpPackageVersionResult { + logger.debug( + { bumpVersion, currentValue }, + 'Checking if we should bump pyproject.toml version', + ); + + let bumpedContent = content; + try { + const newProjectVersion = inc(currentValue, bumpVersion); + if (!newProjectVersion) { + throw new Error('pep440 inc failed'); + } + + logger.debug(`newProjectVersion: ${newProjectVersion}`); + bumpedContent = content.replace( + regEx(`^(?version[ \\t]*=[ \\t]*['"])[^'"]*`, 'm'), + `$${newProjectVersion}`, + ); + + if (bumpedContent === content) { + logger.debug('Version was already bumped'); + } else { + logger.debug('Bumped pyproject.toml version'); + } + } catch (err) { + logger.warn( + { + content, + currentValue, + bumpVersion, + manager: 'pep621', + }, + 'Failed to bumpVersion', + ); + } + + return { bumpedContent }; +} From 4b6867a7ecc88d8efb24122a67a10b9d9ce3ce80 Mon Sep 17 00:00:00 2001 From: HonkingGoose <34918129+HonkingGoose@users.noreply.github.com> Date: Tue, 19 Dec 2023 09:51:16 +0100 Subject: [PATCH 085/173] docs: create Renovate and changelogs page (#25982) Co-authored-by: Rhys Arkins --- docs/usage/key-concepts/.pages | 1 + docs/usage/key-concepts/changelogs.md | 109 ++++++++++++++++++++++++++ 2 files changed, 110 insertions(+) create mode 100644 docs/usage/key-concepts/changelogs.md diff --git a/docs/usage/key-concepts/.pages b/docs/usage/key-concepts/.pages index b6ede935c13f2f..de7f425d363c95 100644 --- a/docs/usage/key-concepts/.pages +++ b/docs/usage/key-concepts/.pages @@ -4,3 +4,4 @@ nav: - 'Pull Requests': 'pull-requests.md' - 'Renovate Scheduling': 'scheduling.md' - 'Automerge': 'automerge.md' + - 'Renovate and changelogs': 'changelogs.md' diff --git a/docs/usage/key-concepts/changelogs.md b/docs/usage/key-concepts/changelogs.md new file mode 100644 index 00000000000000..8af4280e864286 --- /dev/null +++ b/docs/usage/key-concepts/changelogs.md @@ -0,0 +1,109 @@ +--- +title: Renovate and changelogs +description: Learn how Renovate fetches changelogs +--- + +This page explains how Renovate fetches changelogs, when it can display them, and more. + +## How Renovate detects changelogs + +Renovate detects and populates changelogs by: + +1. Identifying a source URL from the datasource response for a package, and saving that internally as `sourceUrl` if found +1. Checking if Renovate's internal [_manual_ metadata](https://github.com/renovatebot/renovate/blob/main/lib/modules/datasource/metadata-manual.ts) for the package includes a source URL +1. Looking up the source URL, if it resides on a supported platform (e.g. GitHub) +1. Checking for both "Releases" metadata in the repository and any commonly known "changelog" file names +1. Filtering the found releases to only include those versions being updated by the current PR +1. Formatting and embedding the results into the PR body + +## Changelogs for private packages + +For private packages, the algorithm is mostly the same as described above, with the additional considerations: + +- Renovate must be able to access the private package in the first place +- The private registry must include the source URL in its response +- Renovate must be able to detect and authenticate with whatever private repository corresponds to the source URL + +For more details, see [Private packages, looking up changelogs](../getting-started/private-packages.md#looking-up-changelogs). + +## Relevant configuration options + +### [`fetchChangelogs`](../configuration-options.md#fetchchangelogs) + +Set to `off` if changelog fetching is causing a problem. + +Set to `branch` if you have an advanced use case where you're embedding changelogs in the Git commit itself, we don't recommend this due to its potential size. + +### [`customChangelogUrl`](../configuration-options.md#customchangelogurl) + +This doesn't help with _fetching_ the changelogs, but if you configure it then Renovate will include a link to this URL in the PR body, so users can click through to read the changelog. + +## Platforms that Renovate can fetch changelogs from + +See the list of platforms in the [`fetchChangelogs` config option docs](../configuration-options.md#fetchchangelogs). + +### Running Renovate on a non-GitHub platform + +Most Open Source packages are hosted on github.com, which means most changelogs are hosted there too. +Fetching changelogs from github.com requires a GitHub token because GitHub blocks unauthenticated GraphQL API use. + +This means that if you run Renovate on self-hosted GitHub Enterprise Server, or any non-GitHub platform which Renovate supports, then you need to configure a github.com Personal Access Token in Renovate in order to fetch changelogs. + +Read [Running Renovate, GitHub.com token for changelogs](../getting-started/running.md#githubcom-token-for-changelogs) to learn more. + +## Troubleshooting missing changelogs + +Follow these steps to find out why Renovate does not find a changelog: + +1. The datasource for this package does not support sourceUrls. + - If the registry fundamentally does not provide this data, then the only possibility is for it to be manually populated through PRs to Renovate's source code + - If the registry provides source URLs in its response but Renovate does not understand the required fields, then raise a feature request with examples, or better yet a Pull Request to implement support for the source URL parsing/mapping yourself + - Sometimes self-hosted versions of registries don't include the full metadata compared to what the public registries do +1. The package was published without source URL information being included. + - For example, occasionally `npm` packages don't have `repository` fields included + - For example, Docker images regularly do not have the required `LABEL` entry +1. Renovate cannot access the source repository + - This is typically a concern for private repositories only + - Check if the token Renovate uses has access rights to the repository you need it to access +1. Renovate cannot detect the file names or release name convention within the repository + - In this case an enhancement to Renovate might be needed to better detect the releases/formats, assuming the package/repository has a reasonable convention to follow + +If none of this helps, search the Renovate issues and discussions to see if this is a known problem. + +## Advice for package maintainers + +This section is for package maintainers that want to make sure Renovate can see their changelogs. + +There isn't much information to add other than what's already written above. + +Make sure that you have the required source URL in your package metadata, not just in your repository but also in the final data which the registry returns. +For example, we have seen cases where the `repository` field in npm's `package.json` is populated correctly in the repository, but stripped out as part of the publishing process. + +### Let Renovate understand your versioning and changelogs + +In general, Renovate can understand your versions and changelogs best when you: + +- Use SemVer versioning, so `major.minor.patch` +- Use the [`semantic-release` bot](https://github.com/semantic-release/semantic-release) to automate the release process + +Try to avoid things like: + +- Stripping out the trailing `.0` unnecessarily (e.g. having a package `3.1.0` on a registry but using only `3.1` in your changelogs) +- Using "Release names" in a way which makes the actual version hard to discern (e.g. instead of `3.0.0` you title your release notes `Big news! v3 is here` + +### npm package maintainers + +As maintainer, make sure the `package.json` has a filled in `repository` field, read the [npm Docs, configuring npm `repository` field](https://docs.npmjs.com/cli/v10/configuring-npm/package-json#repository) to learn more. +If your repository uses the monorepo pattern make sure _each_ `package.json` file has a `repository` field. + +### maven package maintainers + +Read [`maven` datasource, making your changelogs fetchable](https://docs.renovatebot.com/modules/datasource/maven/#making-your-changelogs-fetchable). + +### Docker image maintainers + +Read the [Docker datasource](https://docs.renovatebot.com/modules/datasource/docker/) docs. + +### Nuget package maintainers + +See [Renovate issue #14128 about using NuGet's changelogs](https://github.com/renovatebot/renovate/issues/14128). From ef2278e0eaa949b8694a96e1c8608f3c67fd4f60 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 19 Dec 2023 08:59:36 +0000 Subject: [PATCH 086/173] build(deps): update dependency @renovatebot/ruby-semver to v3.0.22 (#26371) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index aae4571c0c1042..805b931c1431d2 100644 --- a/package.json +++ b/package.json @@ -166,7 +166,7 @@ "@qnighy/marshal": "0.1.3", "@renovatebot/osv-offline": "1.3.10", "@renovatebot/pep440": "3.0.17", - "@renovatebot/ruby-semver": "3.0.21", + "@renovatebot/ruby-semver": "3.0.22", "@sindresorhus/is": "4.6.0", "@types/ms": "0.7.34", "@types/tmp": "0.2.6", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 90f5eed970d84e..8477134a30d6ce 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -72,8 +72,8 @@ importers: specifier: 3.0.17 version: 3.0.17 '@renovatebot/ruby-semver': - specifier: 3.0.21 - version: 3.0.21 + specifier: 3.0.22 + version: 3.0.22 '@sindresorhus/is': specifier: 4.6.0 version: 4.6.0 @@ -2845,8 +2845,8 @@ packages: engines: {node: ^18.12.0 || >= 20.0.0, pnpm: ^8.6.11} dev: false - /@renovatebot/ruby-semver@3.0.21: - resolution: {integrity: sha512-Td3WoH5OE4CVyHuKM7c7aSrjPW49prHe6SLrshzdazEEPkjiPDB5/SznSFRImHzD1ox4LXCTi4hfFH1Necjjhg==} + /@renovatebot/ruby-semver@3.0.22: + resolution: {integrity: sha512-ErJPEznhUJv5S6xOnZz2keH1i+xl5icsaZQFrxELu1iY12NK8jTPZ7TwyfwCz/nGpwVtNbVTfVng0hDaNlCiZA==} engines: {node: ^18.12.0 || >= 20.0.0, pnpm: ^8.6.11} dev: false From 5c810a1e512cc4f0b599ebf928025cd51d5d4e5e Mon Sep 17 00:00:00 2001 From: Rhys Arkins Date: Tue, 19 Dec 2023 11:31:28 +0100 Subject: [PATCH 087/173] docs: clarify automerge retry --- docs/usage/known-limitations.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/usage/known-limitations.md b/docs/usage/known-limitations.md index 0ea36edb92a2ad..5912b1556964e8 100644 --- a/docs/usage/known-limitations.md +++ b/docs/usage/known-limitations.md @@ -30,7 +30,8 @@ This makes it likely that Renovate bot checks your repository at least once duri ## Automerge limitations -- Renovate automerges at most one branch per run +- Renovate automerges at most one branch/PR per run +- If an automerge happened, the repository run will be restarted at most once. The second run can also potentially automerge, so it may appear as like two automerges in one run. - Renovate will only automerge a branch when it is up-to-date with the target branch - Renovate may not be able to automerge as many branches as you expect, especially if your base branch is receiving regular commits at the same time From 7cd5ab8e63ae99edf86085e04e307d433b721100 Mon Sep 17 00:00:00 2001 From: RahulGautamSingh Date: Tue, 19 Dec 2023 17:56:40 +0545 Subject: [PATCH 088/173] feat(datasource/nuget): extract latest tag (#26351) --- .../nuget/__snapshots__/index.spec.ts.snap | 12 ++++++++++++ lib/modules/datasource/nuget/index.spec.ts | 16 +++++++++++++++- lib/modules/datasource/nuget/v2.ts | 1 + 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/lib/modules/datasource/nuget/__snapshots__/index.spec.ts.snap b/lib/modules/datasource/nuget/__snapshots__/index.spec.ts.snap index bdbf086ec83c9a..bdce30f14a4718 100644 --- a/lib/modules/datasource/nuget/__snapshots__/index.spec.ts.snap +++ b/lib/modules/datasource/nuget/__snapshots__/index.spec.ts.snap @@ -11,6 +11,9 @@ exports[`modules/datasource/nuget/index getReleases handles paginated results (v "version": "2.0.0", }, ], + "tags": { + "latest": "2.0.0", + }, } `; @@ -200,6 +203,9 @@ exports[`modules/datasource/nuget/index getReleases processes real data (v2) 1`] }, ], "sourceUrl": "https://nunit.org/", + "tags": { + "latest": "3.12.0", + }, } `; @@ -1692,6 +1698,9 @@ exports[`modules/datasource/nuget/index getReleases processes real data with no }, ], "sourceUrl": "https://nunit.org", + "tags": { + "latest": "3.11.0", + }, } `; @@ -1829,6 +1838,9 @@ exports[`modules/datasource/nuget/index getReleases processes real data without "version": "3.11.0", }, ], + "tags": { + "latest": "3.11.0", + }, } `; diff --git a/lib/modules/datasource/nuget/index.spec.ts b/lib/modules/datasource/nuget/index.spec.ts index 6dc521ac76322a..db7bbaa7b52d61 100644 --- a/lib/modules/datasource/nuget/index.spec.ts +++ b/lib/modules/datasource/nuget/index.spec.ts @@ -585,7 +585,7 @@ describe('modules/datasource/nuget/index', () => { expect(res?.sourceUrl).toBeDefined(); }); - it('processes real data no relase (v2)', async () => { + it('processes real data no release (v2)', async () => { httpMock .scope('https://www.nuget.org') .get( @@ -627,6 +627,20 @@ describe('modules/datasource/nuget/index', () => { expect(res).toMatchSnapshot(); }); + it('extracts latest tag (v2)', async () => { + httpMock + .scope('https://www.nuget.org') + .get( + '/api/v2/FindPackagesById()?id=%27nunit%27&$select=Version,IsLatestVersion,ProjectUrl,Published', + ) + .reply(200, pkgListV2NoGitHubProjectUrl); + const res = await getPkgReleases({ + ...configV2, + }); + expect(res).not.toBeNull(); + expect(res?.tags?.latest).toBe('3.11.0'); + }); + it('handles paginated results (v2)', async () => { httpMock .scope('https://www.nuget.org') diff --git a/lib/modules/datasource/nuget/v2.ts b/lib/modules/datasource/nuget/v2.ts index 79c19161a1ab8b..71629f90f8c436 100644 --- a/lib/modules/datasource/nuget/v2.ts +++ b/lib/modules/datasource/nuget/v2.ts @@ -40,6 +40,7 @@ export async function getReleases( try { const pkgIsLatestVersion = getPkgProp(pkgInfo, 'IsLatestVersion'); if (pkgIsLatestVersion === 'true') { + dep['tags'] = { latest: removeBuildMeta(`${version}`) }; const projectUrl = getPkgProp(pkgInfo, 'ProjectUrl'); if (projectUrl) { dep.sourceUrl = massageUrl(projectUrl); From 3998339cf499ba625c94e437c998fb2f12a6a8b7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 19 Dec 2023 12:25:47 +0000 Subject: [PATCH 089/173] fix(deps): update ghcr.io/containerbase/sidecar docker tag to v9.30.7 (#26375) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- lib/config/options/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/config/options/index.ts b/lib/config/options/index.ts index 2aa388e3f230c3..851c33730a896d 100644 --- a/lib/config/options/index.ts +++ b/lib/config/options/index.ts @@ -393,7 +393,7 @@ const options: RenovateOptions[] = [ description: 'Change this value to override the default Renovate sidecar image.', type: 'string', - default: 'ghcr.io/containerbase/sidecar:9.30.6', + default: 'ghcr.io/containerbase/sidecar:9.30.7', globalOnly: true, }, { From dc614d0b3a630f1465a78563383fb91ca81409b7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 19 Dec 2023 12:26:15 +0000 Subject: [PATCH 090/173] chore(deps): update ghcr.io/containerbase/devcontainer docker tag to v9.30.7 (#26374) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .devcontainer/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 7490a0f2687871..3d5b6776c91c37 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1 +1 @@ -FROM ghcr.io/containerbase/devcontainer:9.30.6 +FROM ghcr.io/containerbase/devcontainer:9.30.7 From d2536a7cc2cc4af967b1bf6c04af061fe2aedcca Mon Sep 17 00:00:00 2001 From: Johannes Feichtner <343448+Churro@users.noreply.github.com> Date: Tue, 19 Dec 2023 20:11:04 +0100 Subject: [PATCH 091/173] feat(manager/poetry): add support for `bumpVersion` option (#26377) --- docs/usage/configuration-options.md | 1 + .../poetry/__snapshots__/extract.spec.ts.snap | 4 ++++ lib/modules/manager/poetry/index.ts | 1 + lib/modules/manager/poetry/schema.spec.ts | 13 ++++++++++++- lib/modules/manager/poetry/schema.ts | 4 +++- 5 files changed, 21 insertions(+), 2 deletions(-) diff --git a/docs/usage/configuration-options.md b/docs/usage/configuration-options.md index 40f9e3bcc821c4..f93316f3c55efb 100644 --- a/docs/usage/configuration-options.md +++ b/docs/usage/configuration-options.md @@ -411,6 +411,7 @@ This is an advance field and it's recommend you seek a config review before appl ## bumpVersion Currently this setting supports `helmv3`, `npm`, `nuget`, `maven`, `pep621` and `sbt` only, so raise a feature request if you have a use for it with other package managers. +Currently this setting supports `helmv3`, `npm`, `nuget`, `maven`, `pep621`, `poetry` and `sbt` only, so raise a feature request if you have a use for it with other package managers. Its purpose is if you want Renovate to update the `version` field within your package file any time it updates dependencies within. Usually this is for automatic release purposes, so that you don't need to add another step after Renovate before you can release a new version. diff --git a/lib/modules/manager/poetry/__snapshots__/extract.spec.ts.snap b/lib/modules/manager/poetry/__snapshots__/extract.spec.ts.snap index 23cdcb538c841e..81b6571687665d 100644 --- a/lib/modules/manager/poetry/__snapshots__/extract.spec.ts.snap +++ b/lib/modules/manager/poetry/__snapshots__/extract.spec.ts.snap @@ -345,6 +345,7 @@ exports[`modules/manager/poetry/extract extractPackageFile() extracts mixed vers }, ], "extractedConstraints": {}, + "packageFileVersion": "0.1.0", } `; @@ -427,6 +428,7 @@ exports[`modules/manager/poetry/extract extractPackageFile() extracts multiple d }, ], "extractedConstraints": {}, + "packageFileVersion": "0.1.0", } `; @@ -555,6 +557,7 @@ exports[`modules/manager/poetry/extract extractPackageFile() handles multiple co }, ], "extractedConstraints": {}, + "packageFileVersion": "0.1.0", } `; @@ -589,5 +592,6 @@ exports[`modules/manager/poetry/extract extractPackageFile() resolves lockedVers "extractedConstraints": { "python": "^3.9", }, + "packageFileVersion": undefined, } `; diff --git a/lib/modules/manager/poetry/index.ts b/lib/modules/manager/poetry/index.ts index ba5cdee9a8e951..0b69f3415625bf 100644 --- a/lib/modules/manager/poetry/index.ts +++ b/lib/modules/manager/poetry/index.ts @@ -3,6 +3,7 @@ import { GithubReleasesDatasource } from '../../datasource/github-releases'; import { GithubTagsDatasource } from '../../datasource/github-tags'; import { PypiDatasource } from '../../datasource/pypi'; +export { bumpPackageVersion } from '../pep621/update'; export { extractPackageFile } from './extract'; export { updateArtifacts } from './artifacts'; export { updateLockedDependency } from './update-locked'; diff --git a/lib/modules/manager/poetry/schema.spec.ts b/lib/modules/manager/poetry/schema.spec.ts index 4da5b1e6e99367..373aa68d44c8cb 100644 --- a/lib/modules/manager/poetry/schema.spec.ts +++ b/lib/modules/manager/poetry/schema.spec.ts @@ -1,6 +1,17 @@ -import { PoetrySources } from './schema'; +import { PoetrySectionSchema, PoetrySources } from './schema'; describe('modules/manager/poetry/schema', () => { + it('parses project version', () => { + expect( + PoetrySectionSchema.parse({ version: '1.2.3' }).packageFileVersion, + ).toBe('1.2.3'); + + expect( + PoetrySectionSchema.parse({ version: { some: 'value' } }) + .packageFileVersion, + ).toBeUndefined(); + }); + describe('PoetrySources', () => { it('parses default values', () => { expect(PoetrySources.parse([])).toBeEmptyArray(); diff --git a/lib/modules/manager/poetry/schema.ts b/lib/modules/manager/poetry/schema.ts index 527c54a2b17783..460ddee33812ff 100644 --- a/lib/modules/manager/poetry/schema.ts +++ b/lib/modules/manager/poetry/schema.ts @@ -245,6 +245,7 @@ export const PoetrySources = LooseArray(PoetrySource, { export const PoetrySectionSchema = z .object({ + version: z.string().optional().catch(undefined), dependencies: withDepType(PoetryDependencies, 'dependencies').optional(), 'dev-dependencies': withDepType( PoetryDependencies, @@ -256,6 +257,7 @@ export const PoetrySectionSchema = z }) .transform( ({ + version, dependencies = [], 'dev-dependencies': devDependencies = [], extras: extraDependencies = [], @@ -269,7 +271,7 @@ export const PoetrySectionSchema = z ...groupDependencies, ]; - const res: PackageFileContent = { deps }; + const res: PackageFileContent = { deps, packageFileVersion: version }; if (sourceUrls.length) { for (const dep of res.deps) { From 2e30d3a04fa5312c3d6a0f849c05432ca69266d3 Mon Sep 17 00:00:00 2001 From: azro352 <35503478+azro352@users.noreply.github.com> Date: Wed, 20 Dec 2023 19:20:38 +0100 Subject: [PATCH 092/173] docs: How Renovate Works overview - Basic (#25108) Co-authored-by: HonkingGoose <34918129+HonkingGoose@users.noreply.github.com> Co-authored-by: Anne Stellingwerf Co-authored-by: Rhys Arkins --- docs/usage/key-concepts/.pages | 1 + docs/usage/key-concepts/how-renovate-works.md | 113 ++++++++++++++++++ 2 files changed, 114 insertions(+) create mode 100644 docs/usage/key-concepts/how-renovate-works.md diff --git a/docs/usage/key-concepts/.pages b/docs/usage/key-concepts/.pages index de7f425d363c95..37704ea70abd4a 100644 --- a/docs/usage/key-concepts/.pages +++ b/docs/usage/key-concepts/.pages @@ -1,4 +1,5 @@ nav: + - 'How Renovate works': 'how-renovate-works.md' - 'Presets': 'presets.md' - 'Dependency Dashboard': 'dashboard.md' - 'Pull Requests': 'pull-requests.md' diff --git a/docs/usage/key-concepts/how-renovate-works.md b/docs/usage/key-concepts/how-renovate-works.md new file mode 100644 index 00000000000000..bed2d0e12a0b62 --- /dev/null +++ b/docs/usage/key-concepts/how-renovate-works.md @@ -0,0 +1,113 @@ +--- +title: How Renovate works +description: Learn how Renovate works +--- + +# Introduction + +Renovate usually performs these steps: + +- Cloning the repository +- Scanning package files to extract dependencies +- Looking up registries to check for updates +- Applying any grouping rules defined +- Pushing branches and raising Pull Requests + +Because Renovate must support a lot of dependency naming and versioning conventions, it has modules for each known convention. +You can contribute your own modules, if you want. + +## Modules + +Renovate's modules are: + +- [datasource](../modules/datasource/index.md) +- [manager](../modules/manager/index.md) +- [platform](../modules/platform/index.md) +- [versioning](../modules/versioning.md) + +Renovate uses these modules in order: + +1. The platform module interacts with the source control platform and clones the repository +1. The manager module looks for files based on their name and extracts the dependencies (each dependency has a datasource) +1. The datasource module looks up versions of the dependency +1. The versioning module validates and sorts the returned versions + +For example: + +1. The `gitlabci` manager finds a dependency: `python:3.10-alpine` which has the `docker` datasource +2. The `docker` datasource looks for versions and finds: `[python:3.9,python:3.9-alpine,python:3.10,python:3.10-alpine,python:3.11,python:3.11-alpine]` +3. The `docker` versioning returns `python:3.11-alpine`, because that version is compatible with `python:3.10-alpine` + +# Workflow + +Here's an overview of the workflow: + +```mermaid +flowchart TB + subgraph INITIALIZATION + direction TB + MC[Merge configurations \n most important to least: \n cli > env > file > default] + MC --> IP[Initialize platform] + IP --> AD[Query the platform for repositories] + AD --> NFIL[Narrow the list with filters] + end + + subgraph REPOSITORY + direction TB + FER{{For each repository}} + + subgraph EXTRACTD[EXTRACT DEPENDENCIES] + direction TB + CLBRANCH[Extract base branches] + CLBRANCH --> VULN[Check for vulnerabilities] + VULN --> CC{{For each manager}} + CC -->|manager A| CD["..."] + CC -->|manager B| CCF["match files"] + CCF --> CFEF{{For each file}} + CFEF -->|file 1| CCD1[Extract dependency] + CFEF -->|file 2| CCD2[...] + end + + subgraph LOOKUP[LOOK UP UPDATES] + direction TB + UC{{For each manager}} + UC -->|manager A| UD["..."] + UC -->|manager B| UFEF{{For each file}} + UFEF -->|file 1| FED{{For each dependency}} + UFEF -->|file 2| FED2[...] + FED -->|dep 1| D1[...] + D1 -..-> CU + FED -->|dep 2| D2[use datasource to \n fetch versions] + D2 --> J[use versioning to find \n next valid update] + FED2 -...-> CU + UD -....-> CU + J --> CU[Look up updates] + end + + subgraph WRITEU[WRITE UPDATES] + direction TB + FEU{{For each update}} + FEU --> AUCOND[Check if branch needed: \n existing/rebase/concurrent amount] + AUCOND --> AU[Create branch\nApply update\nCreate PR] + end + + subgraph FINALIZE[FINALIZE] + direction TB + CM[Check for config migration] + CM --> CSB[Clean stale branches] + + end + + FER --> IRPO[Initialize repository] + + IRPO --> EXTRACTD + EXTRACTD --> LOOKUP + + LOOKUP --> WRITEU + + WRITEU --> FINALIZE + + end + + INITIALIZATION --> REPOSITORY +``` From 075a96c00aa53ede32576e924fe81b040789fc14 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 20 Dec 2023 22:50:26 +0000 Subject: [PATCH 093/173] build(deps): update dependency @renovatebot/osv-offline to v1.3.11 (#26389) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index 805b931c1431d2..838e22adc616e3 100644 --- a/package.json +++ b/package.json @@ -164,7 +164,7 @@ "@opentelemetry/sdk-trace-node": "1.18.1", "@opentelemetry/semantic-conventions": "1.18.1", "@qnighy/marshal": "0.1.3", - "@renovatebot/osv-offline": "1.3.10", + "@renovatebot/osv-offline": "1.3.11", "@renovatebot/pep440": "3.0.17", "@renovatebot/ruby-semver": "3.0.22", "@sindresorhus/is": "4.6.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8477134a30d6ce..0f000c279d7def 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -66,8 +66,8 @@ importers: specifier: 0.1.3 version: 0.1.3 '@renovatebot/osv-offline': - specifier: 1.3.10 - version: 1.3.10 + specifier: 1.3.11 + version: 1.3.11 '@renovatebot/pep440': specifier: 3.0.17 version: 3.0.17 @@ -2820,17 +2820,17 @@ packages: '@redis/client': 1.5.12 dev: false - /@renovatebot/osv-offline-db@1.4.0: - resolution: {integrity: sha512-VqR66WlewMLnDOVmnEAHIFZuATG46LwvNu6ZPjH0sEaH6bCqNxfJ6kBMFEiJOWWjGOxI1u2F+nr1vtdixC9UwA==} + /@renovatebot/osv-offline-db@1.4.1: + resolution: {integrity: sha512-njYO9GQ87wU4Q+lWoQkk+jMWoLaBadc8mcPoYhHNnUwaeX7lOOZkQwNSWV+KWjx1pi5WpGUM592kAinvMH8maA==} dependencies: '@seald-io/nedb': 4.0.3 dev: false - /@renovatebot/osv-offline@1.3.10: - resolution: {integrity: sha512-Bj1Xb3HQlFQ6/E0tGNd0BM3LODg3LrVBJrWPdJWj4GdebO0N3OlqXZo2bE1tvVzeqjSdkXMn0mrtomyQSYwbgg==} + /@renovatebot/osv-offline@1.3.11: + resolution: {integrity: sha512-ax3vyY3l+AltdOwo+IUHBIJbeWmgWLL1plr7eMVxUacN5/0vo5b/lWutHcGtkxK1MtAxhOsSB+qrp7H9biR2YA==} dependencies: '@octokit/rest': 20.0.2 - '@renovatebot/osv-offline-db': 1.4.0 + '@renovatebot/osv-offline-db': 1.4.1 adm-zip: 0.5.10 fs-extra: 11.2.0 got: 11.8.6 From 308b7501c925430ffbc0ad3d8b5af80d2d75fb5b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 21 Dec 2023 12:42:13 +0000 Subject: [PATCH 094/173] fix(deps): update ghcr.io/containerbase/sidecar docker tag to v9.30.8 (#26395) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- lib/config/options/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/config/options/index.ts b/lib/config/options/index.ts index 851c33730a896d..6858ef0dc25da9 100644 --- a/lib/config/options/index.ts +++ b/lib/config/options/index.ts @@ -393,7 +393,7 @@ const options: RenovateOptions[] = [ description: 'Change this value to override the default Renovate sidecar image.', type: 'string', - default: 'ghcr.io/containerbase/sidecar:9.30.7', + default: 'ghcr.io/containerbase/sidecar:9.30.8', globalOnly: true, }, { From d53e9ecaf62ac56072b8ae44909cbc51556cfa2f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 21 Dec 2023 12:45:00 +0000 Subject: [PATCH 095/173] build(deps): update opentelemetry-js monorepo (#26396) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 16 ++--- pnpm-lock.yaml | 187 +++++++++++++++++++++++++++++-------------------- 2 files changed, 118 insertions(+), 85 deletions(-) diff --git a/package.json b/package.json index 838e22adc616e3..216e4f4f11d967 100644 --- a/package.json +++ b/package.json @@ -154,15 +154,15 @@ "@breejs/later": "4.2.0", "@cdktf/hcl2json": "0.19.2", "@opentelemetry/api": "1.7.0", - "@opentelemetry/context-async-hooks": "1.18.1", - "@opentelemetry/exporter-trace-otlp-http": "0.45.1", - "@opentelemetry/instrumentation": "0.45.1", + "@opentelemetry/context-async-hooks": "1.19.0", + "@opentelemetry/exporter-trace-otlp-http": "0.46.0", + "@opentelemetry/instrumentation": "0.46.0", "@opentelemetry/instrumentation-bunyan": "0.34.0", - "@opentelemetry/instrumentation-http": "0.45.1", - "@opentelemetry/resources": "1.18.1", - "@opentelemetry/sdk-trace-base": "1.18.1", - "@opentelemetry/sdk-trace-node": "1.18.1", - "@opentelemetry/semantic-conventions": "1.18.1", + "@opentelemetry/instrumentation-http": "0.46.0", + "@opentelemetry/resources": "1.19.0", + "@opentelemetry/sdk-trace-base": "1.19.0", + "@opentelemetry/sdk-trace-node": "1.19.0", + "@opentelemetry/semantic-conventions": "1.19.0", "@qnighy/marshal": "0.1.3", "@renovatebot/osv-offline": "1.3.11", "@renovatebot/pep440": "3.0.17", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0f000c279d7def..187fc03b696d91 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -36,32 +36,32 @@ importers: specifier: 1.7.0 version: 1.7.0 '@opentelemetry/context-async-hooks': - specifier: 1.18.1 - version: 1.18.1(@opentelemetry/api@1.7.0) + specifier: 1.19.0 + version: 1.19.0(@opentelemetry/api@1.7.0) '@opentelemetry/exporter-trace-otlp-http': - specifier: 0.45.1 - version: 0.45.1(@opentelemetry/api@1.7.0) + specifier: 0.46.0 + version: 0.46.0(@opentelemetry/api@1.7.0) '@opentelemetry/instrumentation': - specifier: 0.45.1 - version: 0.45.1(@opentelemetry/api@1.7.0) + specifier: 0.46.0 + version: 0.46.0(@opentelemetry/api@1.7.0) '@opentelemetry/instrumentation-bunyan': specifier: 0.34.0 version: 0.34.0(@opentelemetry/api@1.7.0) '@opentelemetry/instrumentation-http': - specifier: 0.45.1 - version: 0.45.1(@opentelemetry/api@1.7.0) + specifier: 0.46.0 + version: 0.46.0(@opentelemetry/api@1.7.0) '@opentelemetry/resources': - specifier: 1.18.1 - version: 1.18.1(@opentelemetry/api@1.7.0) + specifier: 1.19.0 + version: 1.19.0(@opentelemetry/api@1.7.0) '@opentelemetry/sdk-trace-base': - specifier: 1.18.1 - version: 1.18.1(@opentelemetry/api@1.7.0) + specifier: 1.19.0 + version: 1.19.0(@opentelemetry/api@1.7.0) '@opentelemetry/sdk-trace-node': - specifier: 1.18.1 - version: 1.18.1(@opentelemetry/api@1.7.0) + specifier: 1.19.0 + version: 1.19.0(@opentelemetry/api@1.7.0) '@opentelemetry/semantic-conventions': - specifier: 1.18.1 - version: 1.18.1 + specifier: 1.19.0 + version: 1.19.0 '@qnighy/marshal': specifier: 0.1.3 version: 0.1.3 @@ -2476,13 +2476,20 @@ packages: '@opentelemetry/api': 1.7.0 dev: false + /@opentelemetry/api-logs@0.46.0: + resolution: {integrity: sha512-+9BcqfiEDGPXEIo+o3tso/aqGM5dGbGwAkGVp3FPpZ8GlkK1YlaKRd9gMVyPaeRATwvO5wYGGnCsAc/sMMM9Qw==} + engines: {node: '>=14'} + dependencies: + '@opentelemetry/api': 1.7.0 + dev: false + /@opentelemetry/api@1.7.0: resolution: {integrity: sha512-AdY5wvN0P2vXBi3b29hxZgSFvdhdxPB9+f0B6s//P9Q8nibRWeA3cHm8UmLpio9ABigkVHJ5NMPk+Mz8VCCyrw==} engines: {node: '>=8.0.0'} dev: false - /@opentelemetry/context-async-hooks@1.18.1(@opentelemetry/api@1.7.0): - resolution: {integrity: sha512-HHfJR32NH2x0b69CACCwH8m1dpNALoCTtpgmIWMNkeMGNUeKT48d4AX4xsF4uIRuUoRTbTgtSBRvS+cF97qwCQ==} + /@opentelemetry/context-async-hooks@1.19.0(@opentelemetry/api@1.7.0): + resolution: {integrity: sha512-0i1ECOc9daKK3rjUgDDXf0GDD5XfCou5lXnt2DALIc2qKoruPPcesobNKE54laSVUWnC3jX26RzuOa31g0V32A==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.8.0' @@ -2490,28 +2497,28 @@ packages: '@opentelemetry/api': 1.7.0 dev: false - /@opentelemetry/core@1.18.1(@opentelemetry/api@1.7.0): - resolution: {integrity: sha512-kvnUqezHMhsQvdsnhnqTNfAJs3ox/isB0SVrM1dhVFw7SsB7TstuVa6fgWnN2GdPyilIFLUvvbTZoVRmx6eiRg==} + /@opentelemetry/core@1.19.0(@opentelemetry/api@1.7.0): + resolution: {integrity: sha512-w42AukJh3TP8R0IZZOVJVM/kMWu8g+lm4LzT70WtuKqhwq7KVhcDzZZuZinWZa6TtQCl7Smt2wolEYzpHabOgw==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.8.0' dependencies: '@opentelemetry/api': 1.7.0 - '@opentelemetry/semantic-conventions': 1.18.1 + '@opentelemetry/semantic-conventions': 1.19.0 dev: false - /@opentelemetry/exporter-trace-otlp-http@0.45.1(@opentelemetry/api@1.7.0): - resolution: {integrity: sha512-a6CGqSG66n5R1mghzLMzyzn3iGap1b0v+0PjKFjfYuwLtpHQBxh2PHxItu+m2mXSwnM4R0GJlk9oUW5sQkCE0w==} + /@opentelemetry/exporter-trace-otlp-http@0.46.0(@opentelemetry/api@1.7.0): + resolution: {integrity: sha512-vZ2pYOB+qrQ+jnKPY6Gnd58y1k/Ti//Ny6/XsSX7/jED0X77crtSVgC6N5UA0JiGJOh6QB2KE9gaH99010XHzg==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': ^1.0.0 dependencies: '@opentelemetry/api': 1.7.0 - '@opentelemetry/core': 1.18.1(@opentelemetry/api@1.7.0) - '@opentelemetry/otlp-exporter-base': 0.45.1(@opentelemetry/api@1.7.0) - '@opentelemetry/otlp-transformer': 0.45.1(@opentelemetry/api@1.7.0) - '@opentelemetry/resources': 1.18.1(@opentelemetry/api@1.7.0) - '@opentelemetry/sdk-trace-base': 1.18.1(@opentelemetry/api@1.7.0) + '@opentelemetry/core': 1.19.0(@opentelemetry/api@1.7.0) + '@opentelemetry/otlp-exporter-base': 0.46.0(@opentelemetry/api@1.7.0) + '@opentelemetry/otlp-transformer': 0.46.0(@opentelemetry/api@1.7.0) + '@opentelemetry/resources': 1.19.0(@opentelemetry/api@1.7.0) + '@opentelemetry/sdk-trace-base': 1.19.0(@opentelemetry/api@1.7.0) dev: false /@opentelemetry/instrumentation-bunyan@0.34.0(@opentelemetry/api@1.7.0): @@ -2528,16 +2535,16 @@ packages: - supports-color dev: false - /@opentelemetry/instrumentation-http@0.45.1(@opentelemetry/api@1.7.0): - resolution: {integrity: sha512-ph7kv38Lipg/ggvoNJrwc3RCceLnTkVZwRbE5iu6w7fGsMjjc9jwlSmaOXKxUJjIimil2hL1qBm8xg2lmOVwxg==} + /@opentelemetry/instrumentation-http@0.46.0(@opentelemetry/api@1.7.0): + resolution: {integrity: sha512-t5cxgqfV9AcxVP00/OL1ggkOSZM57VXDpvlWaOidYyyfLKcUJ9e2fGbNwoVsGFboRDeH0iFo7gLA3EEvX13wCA==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': ^1.3.0 dependencies: '@opentelemetry/api': 1.7.0 - '@opentelemetry/core': 1.18.1(@opentelemetry/api@1.7.0) - '@opentelemetry/instrumentation': 0.45.1(@opentelemetry/api@1.7.0) - '@opentelemetry/semantic-conventions': 1.18.1 + '@opentelemetry/core': 1.19.0(@opentelemetry/api@1.7.0) + '@opentelemetry/instrumentation': 0.46.0(@opentelemetry/api@1.7.0) + '@opentelemetry/semantic-conventions': 1.19.0 semver: 7.5.4 transitivePeerDependencies: - supports-color @@ -2559,116 +2566,132 @@ packages: - supports-color dev: false - /@opentelemetry/otlp-exporter-base@0.45.1(@opentelemetry/api@1.7.0): - resolution: {integrity: sha512-Jvd6x8EwWGKEPWF4tkP4LpTPXiIkkafMNMvMJUfJd5DyNAftL1vAz+48jmi3URL2LMPkGryrvWPz8Tdu917gQw==} + /@opentelemetry/instrumentation@0.46.0(@opentelemetry/api@1.7.0): + resolution: {integrity: sha512-a9TijXZZbk0vI5TGLZl+0kxyFfrXHhX6Svtz7Pp2/VBlCSKrazuULEyoJQrOknJyFWNMEmbbJgOciHCCpQcisw==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + dependencies: + '@opentelemetry/api': 1.7.0 + '@types/shimmer': 1.0.5 + import-in-the-middle: 1.7.1 + require-in-the-middle: 7.2.0 + semver: 7.5.4 + shimmer: 1.2.1 + transitivePeerDependencies: + - supports-color + dev: false + + /@opentelemetry/otlp-exporter-base@0.46.0(@opentelemetry/api@1.7.0): + resolution: {integrity: sha512-hfkh7cG17l77ZSLRAogz19SIJzr0KeC7xv5PDyTFbHFpwwoxV/bEViO49CqUFH6ckXB63NrltASP9R7po+ahTQ==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': ^1.0.0 dependencies: '@opentelemetry/api': 1.7.0 - '@opentelemetry/core': 1.18.1(@opentelemetry/api@1.7.0) + '@opentelemetry/core': 1.19.0(@opentelemetry/api@1.7.0) dev: false - /@opentelemetry/otlp-transformer@0.45.1(@opentelemetry/api@1.7.0): - resolution: {integrity: sha512-FhIHgfC0b0XtoBrS5ISfva939yWffNl47ypXR8I7Ru+dunlySpmf2TLocKHYLHGcWiuoeSNO5O4dZCmSKOtpXw==} + /@opentelemetry/otlp-transformer@0.46.0(@opentelemetry/api@1.7.0): + resolution: {integrity: sha512-Fj9hZwr6xuqgsaERn667Uf6kuDG884puWhyrai2Jen2Fq+bGf4/5BzEJp/8xvty0VSU4EfXOto/ys3KpSz2UHg==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': '>=1.3.0 <1.8.0' dependencies: '@opentelemetry/api': 1.7.0 - '@opentelemetry/api-logs': 0.45.1 - '@opentelemetry/core': 1.18.1(@opentelemetry/api@1.7.0) - '@opentelemetry/resources': 1.18.1(@opentelemetry/api@1.7.0) - '@opentelemetry/sdk-logs': 0.45.1(@opentelemetry/api-logs@0.45.1)(@opentelemetry/api@1.7.0) - '@opentelemetry/sdk-metrics': 1.18.1(@opentelemetry/api@1.7.0) - '@opentelemetry/sdk-trace-base': 1.18.1(@opentelemetry/api@1.7.0) + '@opentelemetry/api-logs': 0.46.0 + '@opentelemetry/core': 1.19.0(@opentelemetry/api@1.7.0) + '@opentelemetry/resources': 1.19.0(@opentelemetry/api@1.7.0) + '@opentelemetry/sdk-logs': 0.46.0(@opentelemetry/api-logs@0.46.0)(@opentelemetry/api@1.7.0) + '@opentelemetry/sdk-metrics': 1.19.0(@opentelemetry/api@1.7.0) + '@opentelemetry/sdk-trace-base': 1.19.0(@opentelemetry/api@1.7.0) dev: false - /@opentelemetry/propagator-b3@1.18.1(@opentelemetry/api@1.7.0): - resolution: {integrity: sha512-oSTUOsnt31JDx5SoEy27B5jE1/tiPvvE46w7CDKj0R5oZhCCfYH2bbSGa7NOOyDXDNqQDkgqU1DIV/xOd3f8pw==} + /@opentelemetry/propagator-b3@1.19.0(@opentelemetry/api@1.7.0): + resolution: {integrity: sha512-v7y5IBOKBm0vP3yf0DHzlw4L2gL6tZ0KeeMTaxfO5IuomMffDbrGWcvYFp0Dt4LdZctTSK523rVLBB9FBHBciQ==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.8.0' dependencies: '@opentelemetry/api': 1.7.0 - '@opentelemetry/core': 1.18.1(@opentelemetry/api@1.7.0) + '@opentelemetry/core': 1.19.0(@opentelemetry/api@1.7.0) dev: false - /@opentelemetry/propagator-jaeger@1.18.1(@opentelemetry/api@1.7.0): - resolution: {integrity: sha512-Kh4M1Qewv0Tbmts6D8LgNzx99IjdE18LCmY/utMkgVyU7Bg31Yuj+X6ZyoIRKPcD2EV4rVkuRI16WVMRuGbhWA==} + /@opentelemetry/propagator-jaeger@1.19.0(@opentelemetry/api@1.7.0): + resolution: {integrity: sha512-dedkOoTzKg+nYoLWCMp0Im+wo+XkTRW6aXhi8VQRtMW/9SNJGOllCJSu8llToLxMDF0+6zu7OCrKkevAof2tew==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.8.0' dependencies: '@opentelemetry/api': 1.7.0 - '@opentelemetry/core': 1.18.1(@opentelemetry/api@1.7.0) + '@opentelemetry/core': 1.19.0(@opentelemetry/api@1.7.0) dev: false - /@opentelemetry/resources@1.18.1(@opentelemetry/api@1.7.0): - resolution: {integrity: sha512-JjbcQLYMttXcIabflLRuaw5oof5gToYV9fuXbcsoOeQ0BlbwUn6DAZi++PNsSz2jjPeASfDls10iaO/8BRIPRA==} + /@opentelemetry/resources@1.19.0(@opentelemetry/api@1.7.0): + resolution: {integrity: sha512-RgxvKuuMOf7nctOeOvpDjt2BpZvZGr9Y0vf7eGtY5XYZPkh2p7e2qub1S2IArdBMf9kEbz0SfycqCviOu9isqg==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.8.0' dependencies: '@opentelemetry/api': 1.7.0 - '@opentelemetry/core': 1.18.1(@opentelemetry/api@1.7.0) - '@opentelemetry/semantic-conventions': 1.18.1 + '@opentelemetry/core': 1.19.0(@opentelemetry/api@1.7.0) + '@opentelemetry/semantic-conventions': 1.19.0 dev: false - /@opentelemetry/sdk-logs@0.45.1(@opentelemetry/api-logs@0.45.1)(@opentelemetry/api@1.7.0): - resolution: {integrity: sha512-z0RRgW4LeKEKnhXS4F/HnqB6+7gsy63YK47F4XAJYHs4s1KKg8XnQ2RkbuL31i/a9nXkylttYtvsT50CGr487g==} + /@opentelemetry/sdk-logs@0.46.0(@opentelemetry/api-logs@0.46.0)(@opentelemetry/api@1.7.0): + resolution: {integrity: sha512-Knlyk4+G72uEzNh6GRN1Fhmrj+/rkATI5/lOrevN7zRDLgp4kfyZBGGoWk7w+qQjlYvwhIIdPVxlIcipivdZIg==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': '>=1.4.0 <1.8.0' '@opentelemetry/api-logs': '>=0.39.1' dependencies: '@opentelemetry/api': 1.7.0 - '@opentelemetry/api-logs': 0.45.1 - '@opentelemetry/core': 1.18.1(@opentelemetry/api@1.7.0) - '@opentelemetry/resources': 1.18.1(@opentelemetry/api@1.7.0) + '@opentelemetry/api-logs': 0.46.0 + '@opentelemetry/core': 1.19.0(@opentelemetry/api@1.7.0) + '@opentelemetry/resources': 1.19.0(@opentelemetry/api@1.7.0) dev: false - /@opentelemetry/sdk-metrics@1.18.1(@opentelemetry/api@1.7.0): - resolution: {integrity: sha512-TEFgeNFhdULBYiCoHbz31Y4PDsfjjxRp8Wmdp6ybLQZPqMNEb+dRq+XN8Xw3ivIgTaf9gYsomgV5ensX99RuEQ==} + /@opentelemetry/sdk-metrics@1.19.0(@opentelemetry/api@1.7.0): + resolution: {integrity: sha512-FiMii40zr0Fmys4F1i8gmuCvbinBnBsDeGBr4FQemOf0iPCLytYQm5AZJ/nn4xSc71IgKBQwTFQRAGJI7JvZ4Q==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': '>=1.3.0 <1.8.0' dependencies: '@opentelemetry/api': 1.7.0 - '@opentelemetry/core': 1.18.1(@opentelemetry/api@1.7.0) - '@opentelemetry/resources': 1.18.1(@opentelemetry/api@1.7.0) + '@opentelemetry/core': 1.19.0(@opentelemetry/api@1.7.0) + '@opentelemetry/resources': 1.19.0(@opentelemetry/api@1.7.0) lodash.merge: 4.6.2 dev: false - /@opentelemetry/sdk-trace-base@1.18.1(@opentelemetry/api@1.7.0): - resolution: {integrity: sha512-tRHfDxN5dO+nop78EWJpzZwHsN1ewrZRVVwo03VJa3JQZxToRDH29/+MB24+yoa+IArerdr7INFJiX/iN4gjqg==} + /@opentelemetry/sdk-trace-base@1.19.0(@opentelemetry/api@1.7.0): + resolution: {integrity: sha512-+IRvUm+huJn2KqfFW3yW/cjvRwJ8Q7FzYHoUNx5Fr0Lws0LxjMJG1uVB8HDpLwm7mg5XXH2M5MF+0jj5cM8BpQ==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.8.0' dependencies: '@opentelemetry/api': 1.7.0 - '@opentelemetry/core': 1.18.1(@opentelemetry/api@1.7.0) - '@opentelemetry/resources': 1.18.1(@opentelemetry/api@1.7.0) - '@opentelemetry/semantic-conventions': 1.18.1 + '@opentelemetry/core': 1.19.0(@opentelemetry/api@1.7.0) + '@opentelemetry/resources': 1.19.0(@opentelemetry/api@1.7.0) + '@opentelemetry/semantic-conventions': 1.19.0 dev: false - /@opentelemetry/sdk-trace-node@1.18.1(@opentelemetry/api@1.7.0): - resolution: {integrity: sha512-ML0l9TNlfLoplLF1F8lb95NGKgdm6OezDS3Ymqav9sYxMd5bnH2LZVzd4xEF+ov5vpZJOGdWxJMs2nC9no7+xA==} + /@opentelemetry/sdk-trace-node@1.19.0(@opentelemetry/api@1.7.0): + resolution: {integrity: sha512-TCiEq/cUjM15RFqBRwWomTVbOqzndWL4ILa7ZCu0zbjU1/XY6AgHkgrgAc7vGP6TjRqH4Xryuglol8tcIfbBUQ==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.8.0' dependencies: '@opentelemetry/api': 1.7.0 - '@opentelemetry/context-async-hooks': 1.18.1(@opentelemetry/api@1.7.0) - '@opentelemetry/core': 1.18.1(@opentelemetry/api@1.7.0) - '@opentelemetry/propagator-b3': 1.18.1(@opentelemetry/api@1.7.0) - '@opentelemetry/propagator-jaeger': 1.18.1(@opentelemetry/api@1.7.0) - '@opentelemetry/sdk-trace-base': 1.18.1(@opentelemetry/api@1.7.0) + '@opentelemetry/context-async-hooks': 1.19.0(@opentelemetry/api@1.7.0) + '@opentelemetry/core': 1.19.0(@opentelemetry/api@1.7.0) + '@opentelemetry/propagator-b3': 1.19.0(@opentelemetry/api@1.7.0) + '@opentelemetry/propagator-jaeger': 1.19.0(@opentelemetry/api@1.7.0) + '@opentelemetry/sdk-trace-base': 1.19.0(@opentelemetry/api@1.7.0) semver: 7.5.4 dev: false - /@opentelemetry/semantic-conventions@1.18.1: - resolution: {integrity: sha512-+NLGHr6VZwcgE/2lw8zDIufOCGnzsA5CbQIMleXZTrgkBd0TanCX+MiDYJ1TOS4KL/Tqk0nFRxawnaYr6pkZkA==} + /@opentelemetry/semantic-conventions@1.19.0: + resolution: {integrity: sha512-14jRpC8f5c0gPSwoZ7SbEJni1PqI+AhAE8m1bMz6v+RPM4OlP1PT2UHBJj5Qh/ALLPjhVU/aZUK3YyjTUqqQVg==} engines: {node: '>=14'} dev: false @@ -6671,6 +6694,15 @@ packages: module-details-from-path: 1.0.3 dev: false + /import-in-the-middle@1.7.1: + resolution: {integrity: sha512-1LrZPDtW+atAxH42S6288qyDFNQ2YCty+2mxEPRtfazH6Z5QwkaBSTS2ods7hnVJioF6rkRfNoA6A/MstpFXLg==} + dependencies: + acorn: 8.11.2 + acorn-import-assertions: 1.9.0(acorn@8.11.2) + cjs-module-lexer: 1.2.3 + module-details-from-path: 1.0.3 + dev: false + /import-local@3.1.0: resolution: {integrity: sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==} engines: {node: '>=8'} @@ -10640,6 +10672,7 @@ packages: /wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + requiresBuild: true /write-file-atomic@3.0.3: resolution: {integrity: sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==} From 285a67707069c405b3db8db6fd76f698b222af46 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 21 Dec 2023 15:59:21 +0000 Subject: [PATCH 096/173] chore(deps): update ghcr.io/containerbase/devcontainer docker tag to v9.30.9 (#26402) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .devcontainer/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 3d5b6776c91c37..9c12781223a183 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1 +1 @@ -FROM ghcr.io/containerbase/devcontainer:9.30.7 +FROM ghcr.io/containerbase/devcontainer:9.30.9 From e52f456b7ef7e6dcb2a26b0b9b604905e6192aeb Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 21 Dec 2023 16:00:15 +0000 Subject: [PATCH 097/173] chore(deps): update dependency @types/traverse to v0.6.36 (#26401) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 216e4f4f11d967..dde1996deb0cf8 100644 --- a/package.json +++ b/package.json @@ -302,7 +302,7 @@ "@types/semver-stable": "3.0.2", "@types/semver-utils": "1.1.3", "@types/tar": "6.1.10", - "@types/traverse": "0.6.35", + "@types/traverse": "0.6.36", "@types/url-join": "4.0.3", "@types/validate-npm-package-name": "4.0.2", "@types/xmldoc": "1.1.9", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 187fc03b696d91..2d4e7468755426 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -470,8 +470,8 @@ importers: specifier: 6.1.10 version: 6.1.10 '@types/traverse': - specifier: 0.6.35 - version: 0.6.35 + specifier: 0.6.36 + version: 0.6.36 '@types/url-join': specifier: 4.0.3 version: 4.0.3 @@ -3937,8 +3937,8 @@ packages: resolution: {integrity: sha512-chhaNf2oKHlRkDGt+tiKE2Z5aJ6qalm7Z9rlLdBwmOiAAf09YQvvoLXjWK4HWPF1xU/fqvMgfNfpVoBscA/tKA==} dev: false - /@types/traverse@0.6.35: - resolution: {integrity: sha512-ZZBG4X4CTVqKLpPvDtqxyCO7VsVAfOsvbJAdbM90uYrXRv27fAjbV8eVUtdBLivC6x6Gcx6n6Kvjbai3IX1rWw==} + /@types/traverse@0.6.36: + resolution: {integrity: sha512-0ko4fZgKQf2J/2FvDJHua9KZ19zJkfI5FxG1ZeEUhezEwuq6UL+4T0IxcBfmHilBeAj7OSUTwrm/lPnh8EB1/Q==} dev: true /@types/treeify@1.0.3: From 8b24dded4172b9da7f7c6a26dea7eb5caf2318d7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 21 Dec 2023 16:19:37 +0000 Subject: [PATCH 098/173] build(deps): update dependency traverse to v0.6.8 (#26403) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index dde1996deb0cf8..c3b84a91bab0f0 100644 --- a/package.json +++ b/package.json @@ -243,7 +243,7 @@ "slugify": "1.6.6", "source-map-support": "0.5.21", "toml-eslint-parser": "0.9.3", - "traverse": "0.6.7", + "traverse": "0.6.8", "tslib": "2.6.2", "upath": "2.0.1", "url-join": "4.0.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2d4e7468755426..7bc7334439e61d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -303,8 +303,8 @@ importers: specifier: 0.9.3 version: 0.9.3 traverse: - specifier: 0.6.7 - version: 0.6.7 + specifier: 0.6.8 + version: 0.6.8 tslib: specifier: 2.6.2 version: 2.6.2 @@ -6285,7 +6285,7 @@ packages: split2: 1.0.0 stream-combiner2: 1.1.1 through2: 2.0.5 - traverse: 0.6.7 + traverse: 0.6.8 dev: true /git-raw-commits@2.0.11: @@ -10128,8 +10128,9 @@ packages: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} dev: false - /traverse@0.6.7: - resolution: {integrity: sha512-/y956gpUo9ZNCb99YjxG7OaslxZWHfCHAUUfshwqOXmxUIvqLjVO581BT+gM59+QV9tFe6/CGG53tsA1Y7RSdg==} + /traverse@0.6.8: + resolution: {integrity: sha512-aXJDbk6SnumuaZSANd21XAo15ucCDE38H4fkqiGsc3MhCK+wOlZvLP9cB/TvpHT0mOyWgC4Z8EwRlzqYSUzdsA==} + engines: {node: '>= 0.4'} /treeify@1.1.0: resolution: {integrity: sha512-1m4RA7xVAJrSGrrXGs0L3YTwyvBs2S8PbRHaLZAkFw7JR8oIFwYtysxlBZhYIa7xSyiYJKZ3iGrrk55cGA3i9A==} From 6b4d5fcdbb0502c71ebe9fc9f63e6ed987e6fe3c Mon Sep 17 00:00:00 2001 From: RahulGautamSingh Date: Thu, 21 Dec 2023 23:41:41 +0545 Subject: [PATCH 099/173] feat(datasource/hex): extract deprecated versions (#26392) --- .../datasource/hex/__fixtures__/certifi.json | 7 ++++++- .../hex/__snapshots__/index.spec.ts.snap | 2 ++ lib/modules/datasource/hex/index.spec.ts | 13 +++++++++++++ lib/modules/datasource/hex/schema.ts | 14 ++++++++++++++ 4 files changed, 35 insertions(+), 1 deletion(-) diff --git a/lib/modules/datasource/hex/__fixtures__/certifi.json b/lib/modules/datasource/hex/__fixtures__/certifi.json index ae3248783ea01a..4d52475d6f5c38 100644 --- a/lib/modules/datasource/hex/__fixtures__/certifi.json +++ b/lib/modules/datasource/hex/__fixtures__/certifi.json @@ -148,7 +148,12 @@ } ], "repository": "hexpm", - "retirements": {}, + "retirements": { + "0.1.1": { + "message": "Used for testing", + "reason": "Not really retired" + } +}, "updated_at": "2020-03-04T14:54:16.279054Z", "url": "https://hex.pm/api/packages/certifi" } diff --git a/lib/modules/datasource/hex/__snapshots__/index.spec.ts.snap b/lib/modules/datasource/hex/__snapshots__/index.spec.ts.snap index f1dba45a9e7558..4067953c19a138 100644 --- a/lib/modules/datasource/hex/__snapshots__/index.spec.ts.snap +++ b/lib/modules/datasource/hex/__snapshots__/index.spec.ts.snap @@ -6,6 +6,7 @@ exports[`modules/datasource/hex/index getReleases process public repo without au "registryUrl": "https://hex.pm/", "releases": [ { + "isDeprecated": true, "releaseTimestamp": "2015-09-10T13:58:55.620Z", "version": "0.1.1", }, @@ -112,6 +113,7 @@ exports[`modules/datasource/hex/index getReleases processes real data 1`] = ` "registryUrl": "https://hex.pm/", "releases": [ { + "isDeprecated": true, "releaseTimestamp": "2015-09-10T13:58:55.620Z", "version": "0.1.1", }, diff --git a/lib/modules/datasource/hex/index.spec.ts b/lib/modules/datasource/hex/index.spec.ts index 70556645629f5e..cf9cbb9b565b5e 100644 --- a/lib/modules/datasource/hex/index.spec.ts +++ b/lib/modules/datasource/hex/index.spec.ts @@ -131,6 +131,19 @@ describe('modules/datasource/hex/index', () => { expect(res).toBeDefined(); }); + it('extracts depreceated info', async () => { + httpMock + .scope(baseUrl) + .get('/packages/certifi') + .reply(200, certifiResponse); + hostRules.find.mockReturnValueOnce({}); + const res = await getPkgReleases({ + datasource, + packageName: 'certifi', + }); + expect(res?.releases.some((rel) => rel.isDeprecated)).toBeTrue(); + }); + it('processes a private repo with auth', async () => { httpMock .scope(baseUrl, { diff --git a/lib/modules/datasource/hex/schema.ts b/lib/modules/datasource/hex/schema.ts index b1015ae664d065..fea85b0919da78 100644 --- a/lib/modules/datasource/hex/schema.ts +++ b/lib/modules/datasource/hex/schema.ts @@ -1,3 +1,4 @@ +import is from '@sindresorhus/is'; import { z } from 'zod'; import { LooseArray } from '../../../util/schema-utils'; import type { Release, ReleaseResult } from '../types'; @@ -19,6 +20,15 @@ export const HexRelease = z inserted_at: z.string().optional(), }), ).refine((releases) => releases.length > 0, 'No releases found'), + retirements: z + .record( + z.string(), + z.object({ + message: z.string(), + reason: z.string(), + }), + ) + .optional(), }) .transform((hexResponse): ReleaseResult => { const releases: Release[] = hexResponse.releases.map( @@ -29,6 +39,10 @@ export const HexRelease = z release.releaseTimestamp = releaseTimestamp; } + if (is.plainObject(hexResponse.retirements?.[version])) { + release.isDeprecated = true; + } + return release; }, ); From 9bbd16a85b64e2e3fbd65514df7ce21bce7644f6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 21 Dec 2023 18:06:18 +0000 Subject: [PATCH 100/173] fix(deps): update ghcr.io/containerbase/sidecar docker tag to v9.30.9 (#26407) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- lib/config/options/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/config/options/index.ts b/lib/config/options/index.ts index 6858ef0dc25da9..06319babafae1f 100644 --- a/lib/config/options/index.ts +++ b/lib/config/options/index.ts @@ -393,7 +393,7 @@ const options: RenovateOptions[] = [ description: 'Change this value to override the default Renovate sidecar image.', type: 'string', - default: 'ghcr.io/containerbase/sidecar:9.30.8', + default: 'ghcr.io/containerbase/sidecar:9.30.9', globalOnly: true, }, { From 5d95ece27110bf1208feb3f2e30dab692d10471f Mon Sep 17 00:00:00 2001 From: Okean <76069640+Tinyblargon@users.noreply.github.com> Date: Thu, 21 Dec 2023 20:26:37 +0100 Subject: [PATCH 101/173] feat(manager/ansible-galaxy): support `.ansible.yaml` double extension (#26390) --- lib/modules/manager/ansible-galaxy/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/modules/manager/ansible-galaxy/index.ts b/lib/modules/manager/ansible-galaxy/index.ts index 5b468378b37828..85e0d274ca0cd7 100644 --- a/lib/modules/manager/ansible-galaxy/index.ts +++ b/lib/modules/manager/ansible-galaxy/index.ts @@ -8,7 +8,7 @@ export { extractPackageFile } from './extract'; export const categories: Category[] = ['ansible', 'iac']; export const defaultConfig = { - fileMatch: ['(^|/)requirements\\.ya?ml$', '(^|/)galaxy\\.ya?ml$'], + fileMatch: ['(^|/)(galaxy|requirements)(\\.ansible)?\\.ya?ml$'], }; export const supportedDatasources = [ From 063fc2bea0c8ccafd78dd57e507bb1804328da01 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 22 Dec 2023 19:24:26 +0000 Subject: [PATCH 102/173] chore(deps): update github/codeql-action action to v2.22.12 (#26416) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/codeql-analysis.yml | 6 +++--- .github/workflows/scorecard.yml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 7cff17d2d599de..2eb7aa6b8f547f 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -39,7 +39,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@03e7845b7bfcd5e7fb63d1ae8c61b0e791134fab # v2.22.11 + uses: github/codeql-action/init@1500a131381b66de0c52ac28abb13cd79f4b7ecc # v2.22.12 with: languages: javascript @@ -49,7 +49,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@03e7845b7bfcd5e7fb63d1ae8c61b0e791134fab # v2.22.11 + uses: github/codeql-action/autobuild@1500a131381b66de0c52ac28abb13cd79f4b7ecc # v2.22.12 # ℹ️ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -63,4 +63,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@03e7845b7bfcd5e7fb63d1ae8c61b0e791134fab # v2.22.11 + uses: github/codeql-action/analyze@1500a131381b66de0c52ac28abb13cd79f4b7ecc # v2.22.12 diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index c00a69e5df5290..4a2a2a0b6b1325 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -50,6 +50,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: 'Upload to code-scanning' - uses: github/codeql-action/upload-sarif@305f6546310b9203e892c28c1484e82977f4f63d # v2.22.10 + uses: github/codeql-action/upload-sarif@1500a131381b66de0c52ac28abb13cd79f4b7ecc # v2.22.12 with: sarif_file: results.sarif From 0b80cb3ec800371df3523f8bf3f5419f7aac8782 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 25 Dec 2023 03:11:32 +0000 Subject: [PATCH 103/173] docs: update references to renovate/renovate to v37.107.0 (#26421) 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 e1afe89394b991..958a4d00370a1d 100644 --- a/docs/usage/docker.md +++ b/docs/usage/docker.md @@ -383,7 +383,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:37.102.0 +FROM renovate/renovate:37.107.0 # Include the "Docker tip" which you can find here https://cloud.google.com/sdk/docs/install # under "Installation" for "Debian/Ubuntu" RUN ... From fc454513c46e338d65f97396bddfa0e9d10e7305 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 25 Dec 2023 03:13:26 +0000 Subject: [PATCH 104/173] chore(deps): lock file maintenance (#26422) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- pnpm-lock.yaml | 64 ++++++++++++++++++-------------------------------- 1 file changed, 23 insertions(+), 41 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7bc7334439e61d..0736eda9c65591 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2313,7 +2313,7 @@ packages: engines: {node: '>= 8'} dependencies: '@nodelib/fs.scandir': 2.1.5 - fastq: 1.15.0 + fastq: 1.16.0 /@npmcli/agent@2.2.0: resolution: {integrity: sha512-2yThA1Es98orMkpSLVqlDZAMPK3jHJhifP2gnNUdk1754uZ8yI5c+ulCoVG+WlntQA6MzhrURMXjSd9Z7dJ2/Q==} @@ -2930,8 +2930,8 @@ packages: - supports-color dev: true - /@semantic-release/github@9.2.5(semantic-release@22.0.12): - resolution: {integrity: sha512-XWumFEOHiWllekymZjeVgkQCJ4YnD8020ZspAHYIIBNX8O4d/1ldeU5iNXu6NGkKlOCokyXh13KwVP0UEMm5kw==} + /@semantic-release/github@9.2.6(semantic-release@22.0.12): + resolution: {integrity: sha512-shi+Lrf6exeNZF+sBhK+P011LSbhmIAoUEgEY6SsxF8irJ+J2stwI5jkyDQ+4gzYyDImzV6LCKdYB9FXnQRWKA==} engines: {node: '>=18'} peerDependencies: semantic-release: '>=20.1.0' @@ -2950,7 +2950,7 @@ packages: issue-parser: 6.0.0 lodash-es: 4.17.21 mime: 4.0.1 - p-filter: 3.0.0 + p-filter: 4.0.0 semantic-release: 22.0.12(typescript@5.3.3) url-join: 5.0.0 transitivePeerDependencies: @@ -4333,14 +4333,6 @@ packages: clean-stack: 2.2.0 indent-string: 4.0.0 - /aggregate-error@4.0.1: - resolution: {integrity: sha512-0poP0T7el6Vq3rstR8Mn4V/IQrpBLO6POkUSrN7RhyY+GF/InCFShQzsQ39T25gkHhLgSLByyAz+Kjb+c2L98w==} - engines: {node: '>=12'} - dependencies: - clean-stack: 4.2.0 - indent-string: 5.0.0 - dev: true - /aggregate-error@5.0.0: resolution: {integrity: sha512-gOsf2YwSlleG6IjRYG2A7k0HmBMEo6qVNk9Bp/EaLgAJT5ngH6PXbqa4ItvnEwCm/velL5jAnQgsHsWnjhGmvw==} engines: {node: '>=18'} @@ -4691,8 +4683,8 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true dependencies: - caniuse-lite: 1.0.30001570 - electron-to-chromium: 1.4.614 + caniuse-lite: 1.0.30001571 + electron-to-chromium: 1.4.616 node-releases: 2.0.14 update-browserslist-db: 1.0.13(browserslist@4.22.2) dev: true @@ -4818,8 +4810,8 @@ packages: engines: {node: '>=10'} dev: true - /caniuse-lite@1.0.30001570: - resolution: {integrity: sha512-+3e0ASu4sw1SWaoCtvPeyXp+5PsjigkSt8OXZbF9StH5pQWbxEjLAZE3n8Aup5udop1uRiKA7a4utUk/uoSpUw==} + /caniuse-lite@1.0.30001571: + resolution: {integrity: sha512-tYq/6MoXhdezDLFZuCO/TKboTzuQ/xR5cFdgXPfDtM7/kchBO3b4VWghE/OAi/DV7tTdhmLjZiZBZi1fA/GheQ==} dev: true /cardinal@2.1.1: @@ -4898,13 +4890,6 @@ packages: resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} engines: {node: '>=6'} - /clean-stack@4.2.0: - resolution: {integrity: sha512-LYv6XPxoyODi36Dp976riBtSY27VmFo+MKqEU9QCCWyTrdEPDog+RWA7xQWHi6Vbp61j5c4cdzzX1NidnwtUWg==} - engines: {node: '>=12'} - dependencies: - escape-string-regexp: 5.0.0 - dev: true - /clean-stack@5.2.0: resolution: {integrity: sha512-TyUIUJgdFnCISzG5zu3291TAsE77ddchd0bepon1VVQrKLGKFED4iXFEDQ24mIPdPBbyE16PK3F8MYE1CmcBEQ==} engines: {node: '>=14.16'} @@ -5398,8 +5383,8 @@ packages: semver: 7.5.4 dev: false - /electron-to-chromium@1.4.614: - resolution: {integrity: sha512-X4ze/9Sc3QWs6h92yerwqv7aB/uU8vCjZcrMjA8N9R1pjMFRe44dLsck5FzLilOYvcXuDn93B+bpGYyufc70gQ==} + /electron-to-chromium@1.4.616: + resolution: {integrity: sha512-1n7zWYh8eS0L9Uy+GskE0lkBUNK83cXTVJI0pU3mGprFsbfSdAc15VTFbo+A+Bq4pwstmL30AVcEU3Fo463lNg==} dev: true /email-addresses@5.0.0: @@ -5909,7 +5894,7 @@ packages: human-signals: 5.0.0 is-stream: 3.0.0 merge-stream: 2.0.0 - npm-run-path: 5.1.0 + npm-run-path: 5.2.0 onetime: 6.0.0 signal-exit: 4.1.0 strip-final-newline: 3.0.0 @@ -5998,8 +5983,8 @@ packages: strnum: 1.0.5 dev: false - /fastq@1.15.0: - resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} + /fastq@1.16.0: + resolution: {integrity: sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==} dependencies: reusify: 1.0.4 @@ -8501,8 +8486,8 @@ packages: path-key: 3.1.1 dev: true - /npm-run-path@5.1.0: - resolution: {integrity: sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==} + /npm-run-path@5.2.0: + resolution: {integrity: sha512-W4/tgAXFqFA0iL7fk0+uQ3g7wkL8xJmx3XdK0VGb4cHW//eZTtKGvFBBoRKVTpY7n6ze4NL9ly7rgXcHufqXKg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} dependencies: path-key: 4.0.0 @@ -8734,11 +8719,11 @@ packages: p-map: 2.1.0 dev: false - /p-filter@3.0.0: - resolution: {integrity: sha512-QtoWLjXAW++uTX67HZQz1dbTpqBfiidsB6VtQUC9iR85S120+s0T5sO6s+B5MLzFcZkrEd/DGMmCjR+f2Qpxwg==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + /p-filter@4.0.0: + resolution: {integrity: sha512-3gxOrNadcyxj+YKFyRmRIEuCMGayNNJoXL7Zf1dqfdfoDsVB190bHfFfhqfcNEDFLfQP1q2uir2cBgIqnIT+cQ==} + engines: {node: '>=18'} dependencies: - p-map: 5.5.0 + p-map: 7.0.0 dev: true /p-finally@1.0.0: @@ -8808,11 +8793,9 @@ packages: aggregate-error: 3.1.0 dev: false - /p-map@5.5.0: - resolution: {integrity: sha512-VFqfGDHlx87K66yZrNdI4YGtD70IRyd+zSvgks6mzHPRNkoKy+9EKP4SFC77/vTTQYmRmti7dvqC+m5jBrBAcg==} - engines: {node: '>=12'} - dependencies: - aggregate-error: 4.0.1 + /p-map@7.0.0: + resolution: {integrity: sha512-EZl03dLKv3RypkrjlevZoNwQMSy4bAblWcR18zhonktnN4fUs3asFQKSe0awn982omGxamvbejqQKQYDJYHCEg==} + engines: {node: '>=18'} dev: true /p-queue@6.6.2: @@ -9502,7 +9485,7 @@ packages: dependencies: '@semantic-release/commit-analyzer': 11.1.0(semantic-release@22.0.12) '@semantic-release/error': 4.0.0 - '@semantic-release/github': 9.2.5(semantic-release@22.0.12) + '@semantic-release/github': 9.2.6(semantic-release@22.0.12) '@semantic-release/npm': 11.0.2(semantic-release@22.0.12) '@semantic-release/release-notes-generator': 12.1.0(semantic-release@22.0.12) aggregate-error: 5.0.0 @@ -10673,7 +10656,6 @@ packages: /wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - requiresBuild: true /write-file-atomic@3.0.3: resolution: {integrity: sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==} From f1242b7aabaa86aa010356d6fcf3cc03d7a2610a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 25 Dec 2023 07:20:15 +0000 Subject: [PATCH 105/173] chore(deps): update dependency @swc/core to v1.3.101 (#26423) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 81 ++++++++++++++++++++++++++++---------------------- 2 files changed, 47 insertions(+), 36 deletions(-) diff --git a/package.json b/package.json index c3b84a91bab0f0..c22aebccc771cf 100644 --- a/package.json +++ b/package.json @@ -266,7 +266,7 @@ "@openpgp/web-stream-tools": "0.0.14", "@renovate/eslint-plugin": "file:tools/eslint", "@semantic-release/exec": "6.0.3", - "@swc/core": "1.3.100", + "@swc/core": "1.3.101", "@types/auth-header": "1.0.6", "@types/aws4": "1.11.6", "@types/breejs__later": "4.1.5", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0736eda9c65591..079f3499dc001f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -362,8 +362,8 @@ importers: specifier: 6.0.3 version: 6.0.3(semantic-release@22.0.12) '@swc/core': - specifier: 1.3.100 - version: 1.3.100 + specifier: 1.3.101 + version: 1.3.101 '@types/auth-header': specifier: 1.0.6 version: 1.0.6 @@ -594,7 +594,7 @@ importers: version: 29.1.1(@babel/core@7.23.6)(@jest/types@29.6.3)(jest@29.7.0)(typescript@5.3.3) ts-node: specifier: 10.9.2 - version: 10.9.2(@swc/core@1.3.100)(@types/node@18.19.3)(typescript@5.3.3) + version: 10.9.2(@swc/core@1.3.101)(@types/node@18.19.3)(typescript@5.3.3) type-fest: specifier: 4.8.3 version: 4.8.3 @@ -3434,8 +3434,8 @@ packages: tslib: 2.6.2 dev: false - /@swc/core-darwin-arm64@1.3.100: - resolution: {integrity: sha512-XVWFsKe6ei+SsDbwmsuRkYck1SXRpO60Hioa4hoLwR8fxbA9eVp6enZtMxzVVMBi8ej5seZ4HZQeAWepbukiBw==} + /@swc/core-darwin-arm64@1.3.101: + resolution: {integrity: sha512-mNFK+uHNPRXSnfTOG34zJOeMl2waM4hF4a2NY7dkMXrPqw9CoJn4MwTXJcyMiSz1/BnNjjTCHF3Yhj0jPxmkzQ==} engines: {node: '>=10'} cpu: [arm64] os: [darwin] @@ -3443,8 +3443,8 @@ packages: dev: true optional: true - /@swc/core-darwin-x64@1.3.100: - resolution: {integrity: sha512-KF/MXrnH1nakm1wbt4XV8FS7kvqD9TGmVxeJ0U4bbvxXMvzeYUurzg3AJUTXYmXDhH/VXOYJE5N5RkwZZPs5iA==} + /@swc/core-darwin-x64@1.3.101: + resolution: {integrity: sha512-B085j8XOx73Fg15KsHvzYWG262bRweGr3JooO1aW5ec5pYbz5Ew9VS5JKYS03w2UBSxf2maWdbPz2UFAxg0whw==} engines: {node: '>=10'} cpu: [x64] os: [darwin] @@ -3452,8 +3452,17 @@ packages: dev: true optional: true - /@swc/core-linux-arm64-gnu@1.3.100: - resolution: {integrity: sha512-p8hikNnAEJrw5vHCtKiFT4hdlQxk1V7vqPmvUDgL/qe2menQDK/i12tbz7/3BEQ4UqUPnvwpmVn2d19RdEMNxw==} + /@swc/core-linux-arm-gnueabihf@1.3.101: + resolution: {integrity: sha512-9xLKRb6zSzRGPqdz52Hy5GuB1lSjmLqa0lST6MTFads3apmx4Vgs8Y5NuGhx/h2I8QM4jXdLbpqQlifpzTlSSw==} + engines: {node: '>=10'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@swc/core-linux-arm64-gnu@1.3.101: + resolution: {integrity: sha512-oE+r1lo7g/vs96Weh2R5l971dt+ZLuhaUX+n3BfDdPxNHfObXgKMjO7E+QS5RbGjv/AwiPCxQmbdCp/xN5ICJA==} engines: {node: '>=10'} cpu: [arm64] os: [linux] @@ -3461,8 +3470,8 @@ packages: dev: true optional: true - /@swc/core-linux-arm64-musl@1.3.100: - resolution: {integrity: sha512-BWx/0EeY89WC4q3AaIaBSGfQxkYxIlS3mX19dwy2FWJs/O+fMvF9oLk/CyJPOZzbp+1DjGeeoGFuDYpiNO91JA==} + /@swc/core-linux-arm64-musl@1.3.101: + resolution: {integrity: sha512-OGjYG3H4BMOTnJWJyBIovCez6KiHF30zMIu4+lGJTCrxRI2fAjGLml3PEXj8tC3FMcud7U2WUn6TdG0/te2k6g==} engines: {node: '>=10'} cpu: [arm64] os: [linux] @@ -3470,8 +3479,8 @@ packages: dev: true optional: true - /@swc/core-linux-x64-gnu@1.3.100: - resolution: {integrity: sha512-XUdGu3dxAkjsahLYnm8WijPfKebo+jHgHphDxaW0ovI6sTdmEGFDew7QzKZRlbYL2jRkUuuKuDGvD6lO5frmhA==} + /@swc/core-linux-x64-gnu@1.3.101: + resolution: {integrity: sha512-/kBMcoF12PRO/lwa8Z7w4YyiKDcXQEiLvM+S3G9EvkoKYGgkkz4Q6PSNhF5rwg/E3+Hq5/9D2R+6nrkF287ihg==} engines: {node: '>=10'} cpu: [x64] os: [linux] @@ -3479,8 +3488,8 @@ packages: dev: true optional: true - /@swc/core-linux-x64-musl@1.3.100: - resolution: {integrity: sha512-PhoXKf+f0OaNW/GCuXjJ0/KfK9EJX7z2gko+7nVnEA0p3aaPtbP6cq1Ubbl6CMoPL+Ci3gZ7nYumDqXNc3CtLQ==} + /@swc/core-linux-x64-musl@1.3.101: + resolution: {integrity: sha512-kDN8lm4Eew0u1p+h1l3JzoeGgZPQ05qDE0czngnjmfpsH2sOZxVj1hdiCwS5lArpy7ktaLu5JdRnx70MkUzhXw==} engines: {node: '>=10'} cpu: [x64] os: [linux] @@ -3488,8 +3497,8 @@ packages: dev: true optional: true - /@swc/core-win32-arm64-msvc@1.3.100: - resolution: {integrity: sha512-PwLADZN6F9cXn4Jw52FeP/MCLVHm8vwouZZSOoOScDtihjY495SSjdPnlosMaRSR4wJQssGwiD/4MbpgQPqbAw==} + /@swc/core-win32-arm64-msvc@1.3.101: + resolution: {integrity: sha512-9Wn8TTLWwJKw63K/S+jjrZb9yoJfJwCE2RV5vPCCWmlMf3U1AXj5XuWOLUX+Rp2sGKau7wZKsvywhheWm+qndQ==} engines: {node: '>=10'} cpu: [arm64] os: [win32] @@ -3497,8 +3506,8 @@ packages: dev: true optional: true - /@swc/core-win32-ia32-msvc@1.3.100: - resolution: {integrity: sha512-0f6nicKSLlDKlyPRl2JEmkpBV4aeDfRQg6n8mPqgL7bliZIcDahG0ej+HxgNjZfS3e0yjDxsNRa6sAqWU2Z60A==} + /@swc/core-win32-ia32-msvc@1.3.101: + resolution: {integrity: sha512-onO5KvICRVlu2xmr4//V2je9O2XgS1SGKpbX206KmmjcJhXN5EYLSxW9qgg+kgV5mip+sKTHTAu7IkzkAtElYA==} engines: {node: '>=10'} cpu: [ia32] os: [win32] @@ -3506,8 +3515,8 @@ packages: dev: true optional: true - /@swc/core-win32-x64-msvc@1.3.100: - resolution: {integrity: sha512-b7J0rPoMkRTa3XyUGt8PwCaIBuYWsL2DqbirrQKRESzgCvif5iNpqaM6kjIjI/5y5q1Ycv564CB51YDpiS8EtQ==} + /@swc/core-win32-x64-msvc@1.3.101: + resolution: {integrity: sha512-T3GeJtNQV00YmiVw/88/nxJ/H43CJvFnpvBHCVn17xbahiVUOPOduh3rc9LgAkKiNt/aV8vU3OJR+6PhfMR7UQ==} engines: {node: '>=10'} cpu: [x64] os: [win32] @@ -3515,8 +3524,8 @@ packages: dev: true optional: true - /@swc/core@1.3.100: - resolution: {integrity: sha512-7dKgTyxJjlrMwFZYb1auj3Xq0D8ZBe+5oeIgfMlRU05doXZypYJe0LAk0yjj3WdbwYzpF+T1PLxwTWizI0pckw==} + /@swc/core@1.3.101: + resolution: {integrity: sha512-w5aQ9qYsd/IYmXADAnkXPGDMTqkQalIi+kfFf/MHRKTpaOL7DHjMXwPp/n8hJ0qNjRvchzmPtOqtPBiER50d8A==} engines: {node: '>=10'} requiresBuild: true peerDependencies: @@ -3528,15 +3537,16 @@ packages: '@swc/counter': 0.1.2 '@swc/types': 0.1.5 optionalDependencies: - '@swc/core-darwin-arm64': 1.3.100 - '@swc/core-darwin-x64': 1.3.100 - '@swc/core-linux-arm64-gnu': 1.3.100 - '@swc/core-linux-arm64-musl': 1.3.100 - '@swc/core-linux-x64-gnu': 1.3.100 - '@swc/core-linux-x64-musl': 1.3.100 - '@swc/core-win32-arm64-msvc': 1.3.100 - '@swc/core-win32-ia32-msvc': 1.3.100 - '@swc/core-win32-x64-msvc': 1.3.100 + '@swc/core-darwin-arm64': 1.3.101 + '@swc/core-darwin-x64': 1.3.101 + '@swc/core-linux-arm-gnueabihf': 1.3.101 + '@swc/core-linux-arm64-gnu': 1.3.101 + '@swc/core-linux-arm64-musl': 1.3.101 + '@swc/core-linux-x64-gnu': 1.3.101 + '@swc/core-linux-x64-musl': 1.3.101 + '@swc/core-win32-arm64-msvc': 1.3.101 + '@swc/core-win32-ia32-msvc': 1.3.101 + '@swc/core-win32-x64-msvc': 1.3.101 dev: true /@swc/counter@0.1.2: @@ -7216,7 +7226,7 @@ packages: pretty-format: 29.7.0 slash: 3.0.0 strip-json-comments: 3.1.1 - ts-node: 10.9.2(@swc/core@1.3.100)(@types/node@18.19.3)(typescript@5.3.3) + ts-node: 10.9.2(@swc/core@1.3.101)(@types/node@18.19.3)(typescript@5.3.3) transitivePeerDependencies: - babel-plugin-macros - supports-color @@ -10180,7 +10190,7 @@ packages: yargs-parser: 21.1.1 dev: true - /ts-node@10.9.2(@swc/core@1.3.100)(@types/node@18.19.3)(typescript@5.3.3): + /ts-node@10.9.2(@swc/core@1.3.101)(@types/node@18.19.3)(typescript@5.3.3): resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} hasBin: true peerDependencies: @@ -10195,7 +10205,7 @@ packages: optional: true dependencies: '@cspotcode/source-map-support': 0.8.1 - '@swc/core': 1.3.100 + '@swc/core': 1.3.101 '@tsconfig/node10': 1.0.9 '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 @@ -10656,6 +10666,7 @@ packages: /wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + requiresBuild: true /write-file-atomic@3.0.3: resolution: {integrity: sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==} From 6bcb0301c6142ea43b1a80941ea5c269138ab87b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 25 Dec 2023 14:43:20 +0100 Subject: [PATCH 106/173] chore(deps): update github/codeql-action action to v3 (#26418) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/codeql-analysis.yml | 6 +++--- .github/workflows/scorecard.yml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 2eb7aa6b8f547f..e2389c9409962d 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -39,7 +39,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@1500a131381b66de0c52ac28abb13cd79f4b7ecc # v2.22.12 + uses: github/codeql-action/init@012739e5082ff0c22ca6d6ab32e07c36df03c4a4 # v3.22.12 with: languages: javascript @@ -49,7 +49,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@1500a131381b66de0c52ac28abb13cd79f4b7ecc # v2.22.12 + uses: github/codeql-action/autobuild@012739e5082ff0c22ca6d6ab32e07c36df03c4a4 # v3.22.12 # ℹ️ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -63,4 +63,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@1500a131381b66de0c52ac28abb13cd79f4b7ecc # v2.22.12 + uses: github/codeql-action/analyze@012739e5082ff0c22ca6d6ab32e07c36df03c4a4 # v3.22.12 diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 4a2a2a0b6b1325..50fd61b3941c16 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -50,6 +50,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: 'Upload to code-scanning' - uses: github/codeql-action/upload-sarif@1500a131381b66de0c52ac28abb13cd79f4b7ecc # v2.22.12 + uses: github/codeql-action/upload-sarif@012739e5082ff0c22ca6d6ab32e07c36df03c4a4 # v3.22.12 with: sarif_file: results.sarif From 7c87f2f9c40f54242ada25e8ce7c4092c50119ae Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 25 Dec 2023 22:17:23 +0000 Subject: [PATCH 107/173] build(deps): update dependency redis to v4.6.12 (#26425) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 44 ++++++++++++++++++++++---------------------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/package.json b/package.json index c22aebccc771cf..639b38e81b0c47 100644 --- a/package.json +++ b/package.json @@ -231,7 +231,7 @@ "p-throttle": "4.1.1", "parse-link-header": "2.0.0", "prettier": "3.1.1", - "redis": "4.6.11", + "redis": "4.6.12", "remark": "13.0.0", "remark-github": "10.1.0", "safe-stable-stringify": "2.4.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 079f3499dc001f..b130cc8357697d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -267,8 +267,8 @@ importers: specifier: 3.1.1 version: 3.1.1 redis: - specifier: 4.6.11 - version: 4.6.11 + specifier: 4.6.12 + version: 4.6.12 remark: specifier: 13.0.0 version: 13.0.0 @@ -2794,16 +2794,16 @@ packages: '@babel/runtime-corejs3': 7.23.6 dev: false - /@redis/bloom@1.2.0(@redis/client@1.5.12): + /@redis/bloom@1.2.0(@redis/client@1.5.13): resolution: {integrity: sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==} peerDependencies: '@redis/client': ^1.0.0 dependencies: - '@redis/client': 1.5.12 + '@redis/client': 1.5.13 dev: false - /@redis/client@1.5.12: - resolution: {integrity: sha512-/ZjE18HRzMd80eXIIUIPcH81UoZpwulbo8FmbElrjPqH0QC0SeIKu1BOU49bO5trM5g895kAjhvalt5h77q+4A==} + /@redis/client@1.5.13: + resolution: {integrity: sha512-epkUM9D0Sdmt93/8Ozk43PNjLi36RZzG+d/T1Gdu5AI8jvghonTeLYV69WVWdilvFo+PYxbP0TZ0saMvr6nscQ==} engines: {node: '>=14'} dependencies: cluster-key-slot: 1.1.2 @@ -2811,36 +2811,36 @@ packages: yallist: 4.0.0 dev: false - /@redis/graph@1.1.1(@redis/client@1.5.12): + /@redis/graph@1.1.1(@redis/client@1.5.13): resolution: {integrity: sha512-FEMTcTHZozZciLRl6GiiIB4zGm5z5F3F6a6FZCyrfxdKOhFlGkiAqlexWMBzCi4DcRoyiOsuLfW+cjlGWyExOw==} peerDependencies: '@redis/client': ^1.0.0 dependencies: - '@redis/client': 1.5.12 + '@redis/client': 1.5.13 dev: false - /@redis/json@1.0.6(@redis/client@1.5.12): + /@redis/json@1.0.6(@redis/client@1.5.13): resolution: {integrity: sha512-rcZO3bfQbm2zPRpqo82XbW8zg4G/w4W3tI7X8Mqleq9goQjAGLL7q/1n1ZX4dXEAmORVZ4s1+uKLaUOg7LrUhw==} peerDependencies: '@redis/client': ^1.0.0 dependencies: - '@redis/client': 1.5.12 + '@redis/client': 1.5.13 dev: false - /@redis/search@1.1.6(@redis/client@1.5.12): + /@redis/search@1.1.6(@redis/client@1.5.13): resolution: {integrity: sha512-mZXCxbTYKBQ3M2lZnEddwEAks0Kc7nauire8q20oA0oA/LoA+E/b5Y5KZn232ztPb1FkIGqo12vh3Lf+Vw5iTw==} peerDependencies: '@redis/client': ^1.0.0 dependencies: - '@redis/client': 1.5.12 + '@redis/client': 1.5.13 dev: false - /@redis/time-series@1.0.5(@redis/client@1.5.12): + /@redis/time-series@1.0.5(@redis/client@1.5.13): resolution: {integrity: sha512-IFjIgTusQym2B5IZJG3XKr5llka7ey84fw/NOYqESP5WUfQs9zz1ww/9+qoz4ka/S6KcGBodzlCeZ5UImKbscg==} peerDependencies: '@redis/client': ^1.0.0 dependencies: - '@redis/client': 1.5.12 + '@redis/client': 1.5.13 dev: false /@renovatebot/osv-offline-db@1.4.1: @@ -9247,15 +9247,15 @@ packages: esprima: 4.0.1 dev: true - /redis@4.6.11: - resolution: {integrity: sha512-kg1Lt4NZLYkAjPOj/WcyIGWfZfnyfKo1Wg9YKVSlzhFwxpFIl3LYI8BWy1Ab963LLDsTz2+OwdsesHKljB3WMQ==} + /redis@4.6.12: + resolution: {integrity: sha512-41Xuuko6P4uH4VPe5nE3BqXHB7a9lkFL0J29AlxKaIfD6eWO8VO/5PDF9ad2oS+mswMsfFxaM5DlE3tnXT+P8Q==} dependencies: - '@redis/bloom': 1.2.0(@redis/client@1.5.12) - '@redis/client': 1.5.12 - '@redis/graph': 1.1.1(@redis/client@1.5.12) - '@redis/json': 1.0.6(@redis/client@1.5.12) - '@redis/search': 1.1.6(@redis/client@1.5.12) - '@redis/time-series': 1.0.5(@redis/client@1.5.12) + '@redis/bloom': 1.2.0(@redis/client@1.5.13) + '@redis/client': 1.5.13 + '@redis/graph': 1.1.1(@redis/client@1.5.13) + '@redis/json': 1.0.6(@redis/client@1.5.13) + '@redis/search': 1.1.6(@redis/client@1.5.13) + '@redis/time-series': 1.0.5(@redis/client@1.5.13) dev: false /regenerator-runtime@0.14.1: From 9581ca15da4162aaaeeb1dd2372ad10606d07e4b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 26 Dec 2023 16:34:30 +0000 Subject: [PATCH 108/173] chore(deps): update pnpm to v8.13.0 (#26428) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 639b38e81b0c47..214a45a7c3407e 100644 --- a/package.json +++ b/package.json @@ -348,7 +348,7 @@ "typescript": "5.3.3", "unified": "9.2.2" }, - "packageManager": "pnpm@8.12.1", + "packageManager": "pnpm@8.13.0", "files": [ "dist", "renovate-schema.json" From b8a28e0309def1ede5e723dbb460fde52e520892 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 26 Dec 2023 16:44:31 +0000 Subject: [PATCH 109/173] chore(deps): update pnpm to v8.13.1 (#26430) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 214a45a7c3407e..516945440ebe6a 100644 --- a/package.json +++ b/package.json @@ -348,7 +348,7 @@ "typescript": "5.3.3", "unified": "9.2.2" }, - "packageManager": "pnpm@8.13.0", + "packageManager": "pnpm@8.13.1", "files": [ "dist", "renovate-schema.json" From 109883fd76ea55185d07b7f9f47825c27a19e436 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 27 Dec 2023 05:09:48 +0000 Subject: [PATCH 110/173] chore(deps): update dependency @types/eslint to v8.56.0 (#26433) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 516945440ebe6a..29d6f3c09ebed2 100644 --- a/package.json +++ b/package.json @@ -278,7 +278,7 @@ "@types/common-tags": "1.8.4", "@types/conventional-commits-detector": "1.0.2", "@types/diff": "5.0.9", - "@types/eslint": "8.44.9", + "@types/eslint": "8.56.0", "@types/fs-extra": "11.0.4", "@types/git-url-parse": "9.0.3", "@types/github-url-from-git": "1.5.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b130cc8357697d..e2556c11f41e6e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -398,8 +398,8 @@ importers: specifier: 5.0.9 version: 5.0.9 '@types/eslint': - specifier: 8.44.9 - version: 8.44.9 + specifier: 8.56.0 + version: 8.56.0 '@types/fs-extra': specifier: 11.0.4 version: 11.0.4 @@ -3733,8 +3733,8 @@ packages: resolution: {integrity: sha512-TB/6hBkYQJxsZHSqyeuO1Jt0AB/bW6G7rHt9g7lML7SOF6lbgcHvw/Lr+69iqN0qxgXLhWKScAon73JNnptuDw==} dev: false - /@types/eslint@8.44.9: - resolution: {integrity: sha512-6yBxcvwnnYoYT1Uk2d+jvIfsuP4mb2EdIxFnrPABj5a/838qe5bGkNLFOiipX4ULQ7XVQvTxOh7jO+BTAiqsEw==} + /@types/eslint@8.56.0: + resolution: {integrity: sha512-FlsN0p4FhuYRjIxpbdXovvHQhtlG05O1GG/RNWvdAxTboR438IOTwmrY/vLA+Xfgg06BTkP045M3vpFwTMv1dg==} dependencies: '@types/estree': 1.0.5 '@types/json-schema': 7.0.15 From 0f01e8aaf92eaf3eeaeffaea379e8df170613b6f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 27 Dec 2023 05:29:15 +0000 Subject: [PATCH 111/173] chore(deps): update linters to v6.16.0 (#26434) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 4 +- pnpm-lock.yaml | 107 +++++++++++++++++++++++++------------------------ 2 files changed, 56 insertions(+), 55 deletions(-) diff --git a/package.json b/package.json index 29d6f3c09ebed2..7977ec473cc803 100644 --- a/package.json +++ b/package.json @@ -306,8 +306,8 @@ "@types/url-join": "4.0.3", "@types/validate-npm-package-name": "4.0.2", "@types/xmldoc": "1.1.9", - "@typescript-eslint/eslint-plugin": "6.15.0", - "@typescript-eslint/parser": "6.15.0", + "@typescript-eslint/eslint-plugin": "6.16.0", + "@typescript-eslint/parser": "6.16.0", "aws-sdk-client-mock": "3.0.0", "callsite": "1.0.0", "common-tags": "1.8.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e2556c11f41e6e..4dc154501e13e2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -482,11 +482,11 @@ importers: specifier: 1.1.9 version: 1.1.9 '@typescript-eslint/eslint-plugin': - specifier: 6.15.0 - version: 6.15.0(@typescript-eslint/parser@6.15.0)(eslint@8.56.0)(typescript@5.3.3) + specifier: 6.16.0 + version: 6.16.0(@typescript-eslint/parser@6.16.0)(eslint@8.56.0)(typescript@5.3.3) '@typescript-eslint/parser': - specifier: 6.15.0 - version: 6.15.0(eslint@8.56.0)(typescript@5.3.3) + specifier: 6.16.0 + version: 6.16.0(eslint@8.56.0)(typescript@5.3.3) aws-sdk-client-mock: specifier: 3.0.0 version: 3.0.0 @@ -516,13 +516,13 @@ importers: version: 1.4.3 eslint-import-resolver-typescript: specifier: 3.6.1 - version: 3.6.1(@typescript-eslint/parser@6.15.0)(eslint-plugin-import@2.29.1)(eslint@8.56.0) + version: 3.6.1(@typescript-eslint/parser@6.16.0)(eslint-plugin-import@2.29.1)(eslint@8.56.0) eslint-plugin-import: specifier: 2.29.1 - version: 2.29.1(@typescript-eslint/parser@6.15.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0) + version: 2.29.1(@typescript-eslint/parser@6.16.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0) eslint-plugin-jest: specifier: 27.6.0 - version: 27.6.0(@typescript-eslint/eslint-plugin@6.15.0)(eslint@8.56.0)(jest@29.7.0)(typescript@5.3.3) + version: 27.6.0(@typescript-eslint/eslint-plugin@6.16.0)(eslint@8.56.0)(jest@29.7.0)(typescript@5.3.3) eslint-plugin-jest-formatting: specifier: 3.1.0 version: 3.1.0(eslint@8.56.0) @@ -3988,8 +3988,8 @@ packages: dev: false optional: true - /@typescript-eslint/eslint-plugin@6.15.0(@typescript-eslint/parser@6.15.0)(eslint@8.56.0)(typescript@5.3.3): - resolution: {integrity: sha512-j5qoikQqPccq9QoBAupOP+CBu8BaJ8BLjaXSioDISeTZkVO3ig7oSIKh3H+rEpee7xCXtWwSB4KIL5l6hWZzpg==} + /@typescript-eslint/eslint-plugin@6.16.0(@typescript-eslint/parser@6.16.0)(eslint@8.56.0)(typescript@5.3.3): + resolution: {integrity: sha512-O5f7Kv5o4dLWQtPX4ywPPa+v9G+1q1x8mz0Kr0pXUtKsevo+gIJHLkGc8RxaZWtP8RrhwhSNIWThnW42K9/0rQ==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha @@ -4000,11 +4000,11 @@ packages: optional: true dependencies: '@eslint-community/regexpp': 4.10.0 - '@typescript-eslint/parser': 6.15.0(eslint@8.56.0)(typescript@5.3.3) - '@typescript-eslint/scope-manager': 6.15.0 - '@typescript-eslint/type-utils': 6.15.0(eslint@8.56.0)(typescript@5.3.3) - '@typescript-eslint/utils': 6.15.0(eslint@8.56.0)(typescript@5.3.3) - '@typescript-eslint/visitor-keys': 6.15.0 + '@typescript-eslint/parser': 6.16.0(eslint@8.56.0)(typescript@5.3.3) + '@typescript-eslint/scope-manager': 6.16.0 + '@typescript-eslint/type-utils': 6.16.0(eslint@8.56.0)(typescript@5.3.3) + '@typescript-eslint/utils': 6.16.0(eslint@8.56.0)(typescript@5.3.3) + '@typescript-eslint/visitor-keys': 6.16.0 debug: 4.3.4 eslint: 8.56.0 graphemer: 1.4.0 @@ -4030,8 +4030,8 @@ packages: - typescript dev: true - /@typescript-eslint/parser@6.15.0(eslint@8.56.0)(typescript@5.3.3): - resolution: {integrity: sha512-MkgKNnsjC6QwcMdlNAel24jjkEO/0hQaMDLqP4S9zq5HBAUJNQB6y+3DwLjX7b3l2b37eNAxMPLwb3/kh8VKdA==} + /@typescript-eslint/parser@6.16.0(eslint@8.56.0)(typescript@5.3.3): + resolution: {integrity: sha512-H2GM3eUo12HpKZU9njig3DF5zJ58ja6ahj1GoHEHOgQvYxzoFJJEvC1MQ7T2l9Ha+69ZSOn7RTxOdpC/y3ikMw==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 @@ -4040,10 +4040,10 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/scope-manager': 6.15.0 - '@typescript-eslint/types': 6.15.0 - '@typescript-eslint/typescript-estree': 6.15.0(typescript@5.3.3) - '@typescript-eslint/visitor-keys': 6.15.0 + '@typescript-eslint/scope-manager': 6.16.0 + '@typescript-eslint/types': 6.16.0 + '@typescript-eslint/typescript-estree': 6.16.0(typescript@5.3.3) + '@typescript-eslint/visitor-keys': 6.16.0 debug: 4.3.4 eslint: 8.56.0 typescript: 5.3.3 @@ -4059,16 +4059,16 @@ packages: '@typescript-eslint/visitor-keys': 5.62.0 dev: true - /@typescript-eslint/scope-manager@6.15.0: - resolution: {integrity: sha512-+BdvxYBltqrmgCNu4Li+fGDIkW9n//NrruzG9X1vBzaNK+ExVXPoGB71kneaVw/Jp+4rH/vaMAGC6JfMbHstVg==} + /@typescript-eslint/scope-manager@6.16.0: + resolution: {integrity: sha512-0N7Y9DSPdaBQ3sqSCwlrm9zJwkpOuc6HYm7LpzLAPqBL7dmzAUimr4M29dMkOP/tEwvOCC/Cxo//yOfJD3HUiw==} engines: {node: ^16.0.0 || >=18.0.0} dependencies: - '@typescript-eslint/types': 6.15.0 - '@typescript-eslint/visitor-keys': 6.15.0 + '@typescript-eslint/types': 6.16.0 + '@typescript-eslint/visitor-keys': 6.16.0 dev: true - /@typescript-eslint/type-utils@6.15.0(eslint@8.56.0)(typescript@5.3.3): - resolution: {integrity: sha512-CnmHKTfX6450Bo49hPg2OkIm/D/TVYV7jO1MCfPYGwf6x3GO0VU8YMO5AYMn+u3X05lRRxA4fWCz87GFQV6yVQ==} + /@typescript-eslint/type-utils@6.16.0(eslint@8.56.0)(typescript@5.3.3): + resolution: {integrity: sha512-ThmrEOcARmOnoyQfYkHw/DX2SEYBalVECmoldVuH6qagKROp/jMnfXpAU/pAIWub9c4YTxga+XwgAkoA0pxfmg==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 @@ -4077,8 +4077,8 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 6.15.0(typescript@5.3.3) - '@typescript-eslint/utils': 6.15.0(eslint@8.56.0)(typescript@5.3.3) + '@typescript-eslint/typescript-estree': 6.16.0(typescript@5.3.3) + '@typescript-eslint/utils': 6.16.0(eslint@8.56.0)(typescript@5.3.3) debug: 4.3.4 eslint: 8.56.0 ts-api-utils: 1.0.3(typescript@5.3.3) @@ -4092,8 +4092,8 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /@typescript-eslint/types@6.15.0: - resolution: {integrity: sha512-yXjbt//E4T/ee8Ia1b5mGlbNj9fB9lJP4jqLbZualwpP2BCQ5is6BcWwxpIsY4XKAhmdv3hrW92GdtJbatC6dQ==} + /@typescript-eslint/types@6.16.0: + resolution: {integrity: sha512-hvDFpLEvTJoHutVl87+MG/c5C8I6LOgEx05zExTSJDEVU7hhR3jhV8M5zuggbdFCw98+HhZWPHZeKS97kS3JoQ==} engines: {node: ^16.0.0 || >=18.0.0} dev: true @@ -4118,8 +4118,8 @@ packages: - supports-color dev: true - /@typescript-eslint/typescript-estree@6.15.0(typescript@5.3.3): - resolution: {integrity: sha512-7mVZJN7Hd15OmGuWrp2T9UvqR2Ecg+1j/Bp1jXUEY2GZKV6FXlOIoqVDmLpBiEiq3katvj/2n2mR0SDwtloCew==} + /@typescript-eslint/typescript-estree@6.16.0(typescript@5.3.3): + resolution: {integrity: sha512-VTWZuixh/vr7nih6CfrdpmFNLEnoVBF1skfjdyGnNwXOH1SLeHItGdZDHhhAIzd3ACazyY2Fg76zuzOVTaknGA==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: typescript: '*' @@ -4127,11 +4127,12 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/types': 6.15.0 - '@typescript-eslint/visitor-keys': 6.15.0 + '@typescript-eslint/types': 6.16.0 + '@typescript-eslint/visitor-keys': 6.16.0 debug: 4.3.4 globby: 11.1.0 is-glob: 4.0.3 + minimatch: 9.0.3 semver: 7.5.4 ts-api-utils: 1.0.3(typescript@5.3.3) typescript: 5.3.3 @@ -4159,8 +4160,8 @@ packages: - typescript dev: true - /@typescript-eslint/utils@6.15.0(eslint@8.56.0)(typescript@5.3.3): - resolution: {integrity: sha512-eF82p0Wrrlt8fQSRL0bGXzK5nWPRV2dYQZdajcfzOD9+cQz9O7ugifrJxclB+xVOvWvagXfqS4Es7vpLP4augw==} + /@typescript-eslint/utils@6.16.0(eslint@8.56.0)(typescript@5.3.3): + resolution: {integrity: sha512-T83QPKrBm6n//q9mv7oiSvy/Xq/7Hyw9SzSEhMHJwznEmQayfBM87+oAlkNAMEO7/MjIwKyOHgBJbxB0s7gx2A==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 @@ -4168,9 +4169,9 @@ packages: '@eslint-community/eslint-utils': 4.4.0(eslint@8.56.0) '@types/json-schema': 7.0.15 '@types/semver': 7.5.6 - '@typescript-eslint/scope-manager': 6.15.0 - '@typescript-eslint/types': 6.15.0 - '@typescript-eslint/typescript-estree': 6.15.0(typescript@5.3.3) + '@typescript-eslint/scope-manager': 6.16.0 + '@typescript-eslint/types': 6.16.0 + '@typescript-eslint/typescript-estree': 6.16.0(typescript@5.3.3) eslint: 8.56.0 semver: 7.5.4 transitivePeerDependencies: @@ -4186,11 +4187,11 @@ packages: eslint-visitor-keys: 3.4.3 dev: true - /@typescript-eslint/visitor-keys@6.15.0: - resolution: {integrity: sha512-1zvtdC1a9h5Tb5jU9x3ADNXO9yjP8rXlaoChu0DQX40vf5ACVpYIVIZhIMZ6d5sDXH7vq4dsZBT1fEGj8D2n2w==} + /@typescript-eslint/visitor-keys@6.16.0: + resolution: {integrity: sha512-QSFQLruk7fhs91a/Ep/LqRdbJCZ1Rq03rqBdKT5Ky17Sz8zRLUksqIe9DW0pKtg/Z35/ztbLQ6qpOCN6rOC11A==} engines: {node: ^16.0.0 || >=18.0.0} dependencies: - '@typescript-eslint/types': 6.15.0 + '@typescript-eslint/types': 6.16.0 eslint-visitor-keys: 3.4.3 dev: true @@ -5628,7 +5629,7 @@ packages: - supports-color dev: true - /eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.15.0)(eslint-plugin-import@2.29.1)(eslint@8.56.0): + /eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.16.0)(eslint-plugin-import@2.29.1)(eslint@8.56.0): resolution: {integrity: sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: @@ -5638,8 +5639,8 @@ packages: debug: 4.3.4 enhanced-resolve: 5.15.0 eslint: 8.56.0 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.15.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.15.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.16.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.16.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0) fast-glob: 3.3.2 get-tsconfig: 4.7.2 is-core-module: 2.13.1 @@ -5651,7 +5652,7 @@ packages: - supports-color dev: true - /eslint-module-utils@2.8.0(@typescript-eslint/parser@6.15.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0): + /eslint-module-utils@2.8.0(@typescript-eslint/parser@6.16.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0): resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} engines: {node: '>=4'} peerDependencies: @@ -5672,16 +5673,16 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 6.15.0(eslint@8.56.0)(typescript@5.3.3) + '@typescript-eslint/parser': 6.16.0(eslint@8.56.0)(typescript@5.3.3) debug: 3.2.7 eslint: 8.56.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.15.0)(eslint-plugin-import@2.29.1)(eslint@8.56.0) + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.16.0)(eslint-plugin-import@2.29.1)(eslint@8.56.0) transitivePeerDependencies: - supports-color dev: true - /eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.15.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0): + /eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.16.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0): resolution: {integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==} engines: {node: '>=4'} peerDependencies: @@ -5691,7 +5692,7 @@ packages: '@typescript-eslint/parser': optional: true dependencies: - '@typescript-eslint/parser': 6.15.0(eslint@8.56.0)(typescript@5.3.3) + '@typescript-eslint/parser': 6.16.0(eslint@8.56.0)(typescript@5.3.3) array-includes: 3.1.7 array.prototype.findlastindex: 1.2.3 array.prototype.flat: 1.3.2 @@ -5700,7 +5701,7 @@ packages: doctrine: 2.1.0 eslint: 8.56.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.15.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.16.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0) hasown: 2.0.0 is-core-module: 2.13.1 is-glob: 4.0.3 @@ -5725,7 +5726,7 @@ packages: eslint: 8.56.0 dev: true - /eslint-plugin-jest@27.6.0(@typescript-eslint/eslint-plugin@6.15.0)(eslint@8.56.0)(jest@29.7.0)(typescript@5.3.3): + /eslint-plugin-jest@27.6.0(@typescript-eslint/eslint-plugin@6.16.0)(eslint@8.56.0)(jest@29.7.0)(typescript@5.3.3): resolution: {integrity: sha512-MTlusnnDMChbElsszJvrwD1dN3x6nZl//s4JD23BxB6MgR66TZlL064su24xEIS3VACfAoHV1vgyMgPw8nkdng==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: @@ -5738,7 +5739,7 @@ packages: jest: optional: true dependencies: - '@typescript-eslint/eslint-plugin': 6.15.0(@typescript-eslint/parser@6.15.0)(eslint@8.56.0)(typescript@5.3.3) + '@typescript-eslint/eslint-plugin': 6.16.0(@typescript-eslint/parser@6.16.0)(eslint@8.56.0)(typescript@5.3.3) '@typescript-eslint/utils': 5.62.0(eslint@8.56.0)(typescript@5.3.3) eslint: 8.56.0 jest: 29.7.0(@types/node@18.19.3)(ts-node@10.9.2) From 84270beec4c42d483a9d949553dcfa18898d21d0 Mon Sep 17 00:00:00 2001 From: Gabriel-Ladzaretti <97394622+Gabriel-Ladzaretti@users.noreply.github.com> Date: Wed, 27 Dec 2023 10:03:30 +0200 Subject: [PATCH 112/173] fix(matchConfidence): align supported datasources list with internal preset (#26420) Co-authored-by: Michael Kriese --- docs/usage/merge-confidence.md | 1 + docs/usage/self-hosted-experimental.md | 5 ++ .../presets/internal/merge-confidence.ts | 30 ++++---- lib/util/merge-confidence/index.spec.ts | 72 ++++++++++++++++++- lib/util/merge-confidence/index.ts | 43 ++++++++++- 5 files changed, 127 insertions(+), 24 deletions(-) diff --git a/docs/usage/merge-confidence.md b/docs/usage/merge-confidence.md index 76e361aa616b1c..01a24c4633abbb 100644 --- a/docs/usage/merge-confidence.md +++ b/docs/usage/merge-confidence.md @@ -29,6 +29,7 @@ Renovate will show Merge Confidence badges for these languages: | Language | Datasource | | ---------- | ----------- | +| Golang | `go` | | JavaScript | `npm` | | Java | `maven` | | Python | `pypi` | diff --git a/docs/usage/self-hosted-experimental.md b/docs/usage/self-hosted-experimental.md index 45d7c8fffc7003..01a2993e414873 100644 --- a/docs/usage/self-hosted-experimental.md +++ b/docs/usage/self-hosted-experimental.md @@ -126,6 +126,11 @@ Skip initializing `RE2` for regular expressions and instead use Node-native `Reg If set, Renovate will query this API for Merge Confidence data. This feature is in private beta. +## `RENOVATE_X_MERGE_CONFIDENCE_SUPPORTED_DATASOURCES` + +If set, Renovate will query the merge-confidence JSON API only for datasources that are part of this list. +The expected value for this environment variable is a JSON array of strings. + ## `RENOVATE_X_PLATFORM_VERSION` If set, Renovate will use this string as GitLab server version instead of checking via the GitLab API. diff --git a/lib/config/presets/internal/merge-confidence.ts b/lib/config/presets/internal/merge-confidence.ts index abde81e4398f2a..f2e900c8bf621b 100644 --- a/lib/config/presets/internal/merge-confidence.ts +++ b/lib/config/presets/internal/merge-confidence.ts @@ -1,19 +1,21 @@ import type { Preset } from '../types'; +export const supportedDatasources = [ + 'go', + 'maven', + 'npm', + 'nuget', + 'packagist', + 'pypi', + 'rubygems', +]; + export const presets: Record = { 'all-badges': { description: 'Show all Merge Confidence badges for pull requests.', packageRules: [ { - matchDatasources: [ - 'maven', - 'npm', - 'nuget', - 'packagist', - 'pypi', - 'rubygems', - 'go', - ], + matchDatasources: supportedDatasources, matchUpdateTypes: ['patch', 'minor', 'major'], prBodyColumns: [ 'Package', @@ -31,15 +33,7 @@ export const presets: Record = { 'Show only the Age and Confidence Merge Confidence badges for pull requests.', packageRules: [ { - matchDatasources: [ - 'maven', - 'npm', - 'nuget', - 'packagist', - 'pypi', - 'rubygems', - 'go', - ], + matchDatasources: supportedDatasources, matchUpdateTypes: ['patch', 'minor', 'major'], prBodyColumns: ['Package', 'Change', 'Age', 'Confidence'], }, diff --git a/lib/util/merge-confidence/index.spec.ts b/lib/util/merge-confidence/index.spec.ts index a347fd0170f306..6c9e379abe23cc 100644 --- a/lib/util/merge-confidence/index.spec.ts +++ b/lib/util/merge-confidence/index.spec.ts @@ -9,6 +9,7 @@ import { initConfig, initMergeConfidence, isActiveConfidenceLevel, + parseSupportedDatasourceString, resetConfig, satisfiesConfidenceLevel, } from '.'; @@ -296,8 +297,11 @@ describe('util/merge-confidence/index', () => { }); describe('initMergeConfidence()', () => { - it('using default base url if none is set', async () => { + beforeEach(() => { resetConfig(); + }); + + it('using default base url if none is set', async () => { delete process.env.RENOVATE_X_MERGE_CONFIDENCE_API_BASE_URL; httpMock .scope(defaultApiBaseUrl) @@ -309,12 +313,22 @@ describe('util/merge-confidence/index', () => { 'using default merge confidence API base URL', ); expect(logger.debug).toHaveBeenCalledWith( + { + supportedDatasources: [ + 'go', + 'maven', + 'npm', + 'nuget', + 'packagist', + 'pypi', + 'rubygems', + ], + }, 'merge confidence API - successfully authenticated', ); }); it('warns and then resolves if base url is invalid', async () => { - resetConfig(); process.env.RENOVATE_X_MERGE_CONFIDENCE_API_BASE_URL = 'invalid-url.com'; httpMock @@ -328,12 +342,12 @@ describe('util/merge-confidence/index', () => { 'invalid merge confidence API base URL found in environment variables - using default value instead', ); expect(logger.debug).toHaveBeenCalledWith( + expect.anything(), 'merge confidence API - successfully authenticated', ); }); it('resolves if no token', async () => { - resetConfig(); hostRules.clear(); await expect(initMergeConfidence()).toResolve(); @@ -347,6 +361,7 @@ describe('util/merge-confidence/index', () => { await expect(initMergeConfidence()).toResolve(); expect(logger.debug).toHaveBeenCalledWith( + expect.anything(), 'merge confidence API - successfully authenticated', ); }); @@ -389,6 +404,57 @@ describe('util/merge-confidence/index', () => { 'merge confidence API request failed - aborting run', ); }); + + describe('parseSupportedDatasourceList()', () => { + type ParseSupportedDatasourceTestCase = { + name: string; + datasourceListString: string | undefined; + expected: string[] | undefined; + }; + + afterEach(() => { + delete process.env.RENOVATE_X_MERGE_CONFIDENCE_SUPPORTED_DATASOURCES; + }); + + it.each([ + { + name: 'it should do nothing when the input is undefined', + datasourceListString: undefined, + expected: undefined, + }, + { + name: 'it should successfully parse the given datasource list', + datasourceListString: `["go","npm"]`, + expected: ['go', 'npm'], + }, + { + name: 'it should gracefully handle invalid json', + datasourceListString: `{`, + expected: undefined, + }, + { + name: 'it should discard non-array JSON input', + datasourceListString: `{}`, + expected: undefined, + }, + { + name: 'it should discard non-string array JSON input', + datasourceListString: `[1,2]`, + expected: undefined, + }, + ])( + `$name`, + ({ + datasourceListString, + expected, + }: ParseSupportedDatasourceTestCase) => { + process.env.RENOVATE_X_MERGE_CONFIDENCE_SUPPORTED_DATASOURCES = + datasourceListString; + + expect(parseSupportedDatasourceString()).toStrictEqual(expected); + }, + ); + }); }); }); }); diff --git a/lib/util/merge-confidence/index.ts b/lib/util/merge-confidence/index.ts index e903d32cab0f4b..95386836a04a36 100644 --- a/lib/util/merge-confidence/index.ts +++ b/lib/util/merge-confidence/index.ts @@ -1,8 +1,10 @@ import is from '@sindresorhus/is'; +import { supportedDatasources as presetSupportedDatasources } from '../../config/presets/internal/merge-confidence'; import type { UpdateType } from '../../config/types'; import { logger } from '../../logger'; import { ExternalHostError } from '../../types/errors/external-host-error'; import * as packageCache from '../cache/package'; +import { parseJson } from '../common'; import * as hostRules from '../host-rules'; import { Http } from '../http'; import { MERGE_CONFIDENCE } from './common'; @@ -12,8 +14,7 @@ const hostType = 'merge-confidence'; const http = new Http(hostType); let token: string | undefined; let apiBaseUrl: string | undefined; - -const supportedDatasources = ['npm', 'maven', 'pypi']; +let supportedDatasources: string[] = []; export const confidenceLevels: Record = { low: -1, @@ -25,14 +26,47 @@ export const confidenceLevels: Record = { export function initConfig(): void { apiBaseUrl = getApiBaseUrl(); token = getApiToken(); + supportedDatasources = + parseSupportedDatasourceString() ?? presetSupportedDatasources; + if (!is.nullOrUndefined(token)) { logger.debug(`Merge confidence token found for ${apiBaseUrl}`); } } +export function parseSupportedDatasourceString(): string[] | undefined { + const supportedDatasourceString = + process.env.RENOVATE_X_MERGE_CONFIDENCE_SUPPORTED_DATASOURCES; + + if (!is.string(supportedDatasourceString)) { + return undefined; + } + + let parsedDatasourceList: unknown; + try { + parsedDatasourceList = parseJson(supportedDatasourceString, '.json5'); + } catch (err) { + logger.error( + { supportedDatasourceString, err }, + 'Failed to parse supported datasources list; Invalid JSON format', + ); + } + + if (!is.array(parsedDatasourceList, is.string)) { + logger.warn( + { parsedDatasourceList }, + `Expected a string array but got ${typeof parsedDatasourceList}`, + ); + return undefined; + } + + return parsedDatasourceList; +} + export function resetConfig(): void { token = undefined; apiBaseUrl = undefined; + supportedDatasources = []; } export function isMergeConfidence(value: string): value is MergeConfidence { @@ -190,7 +224,10 @@ export async function initMergeConfidence(): Promise { apiErrorHandler(err); } - logger.debug('merge confidence API - successfully authenticated'); + logger.debug( + { supportedDatasources }, + 'merge confidence API - successfully authenticated', + ); return; } From 1786438d33c8282de786862dd2a863bf67109e0f Mon Sep 17 00:00:00 2001 From: joegoldman2 <147369450+joegoldman2@users.noreply.github.com> Date: Wed, 27 Dec 2023 11:17:03 +0200 Subject: [PATCH 113/173] feat(platform/azure): implement automergeStrategy for Azure DevOps platform (#26429) --- lib/config/options/index.ts | 2 +- lib/modules/platform/azure/index.spec.ts | 182 +++++++++++++++++++++- lib/modules/platform/azure/index.ts | 12 +- lib/modules/platform/azure/readme.md | 4 - lib/modules/platform/azure/util.ts | 18 +++ lib/modules/platform/types.ts | 1 + lib/workers/repository/update/pr/index.ts | 1 + 7 files changed, 210 insertions(+), 10 deletions(-) diff --git a/lib/config/options/index.ts b/lib/config/options/index.ts index 06319babafae1f..1a32eb51dc3e4c 100644 --- a/lib/config/options/index.ts +++ b/lib/config/options/index.ts @@ -1828,7 +1828,7 @@ const options: RenovateOptions[] = [ type: 'string', allowedValues: ['auto', 'fast-forward', 'merge-commit', 'rebase', 'squash'], default: 'auto', - supportedPlatforms: ['bitbucket', 'gitea'], + supportedPlatforms: ['azure', 'bitbucket', 'gitea'], }, { name: 'automergeComment', diff --git a/lib/modules/platform/azure/index.spec.ts b/lib/modules/platform/azure/index.spec.ts index 3924120dd94b7e..50610286181d1d 100644 --- a/lib/modules/platform/azure/index.spec.ts +++ b/lib/modules/platform/azure/index.spec.ts @@ -2,6 +2,7 @@ import { Readable } from 'node:stream'; import is from '@sindresorhus/is'; import type { IGitApi } from 'azure-devops-node-api/GitApi'; import { + GitPullRequest, GitPullRequestMergeStrategy, GitStatusState, PullRequestStatus, @@ -936,7 +937,7 @@ describe('modules/platform/azure/index', () => { expect(pr).toMatchSnapshot(); }); - it('should only call getMergeMethod once per run', async () => { + it('should only call getMergeMethod once per run when automergeStrategy is auto', async () => { await initRepo({ repository: 'some/repo' }); const prResult = [ { @@ -1001,7 +1002,10 @@ describe('modules/platform/azure/index', () => { prTitle: 'The Title', prBody: 'Hello world', labels: ['deps', 'renovate'], - platformOptions: { usePlatformAutomerge: true }, + platformOptions: { + automergeStrategy: 'auto', + usePlatformAutomerge: true, + }, }); await azure.createPr({ @@ -1010,12 +1014,128 @@ describe('modules/platform/azure/index', () => { prTitle: 'The Second Title', prBody: 'Hello world', labels: ['deps', 'renovate'], - platformOptions: { usePlatformAutomerge: true }, + platformOptions: { + automergeStrategy: 'auto', + usePlatformAutomerge: true, + }, }); expect(updateFn).toHaveBeenCalledTimes(2); expect(azureHelper.getMergeMethod).toHaveBeenCalledTimes(1); }); + + it.each` + automergeStrategy + ${'fast-forward'} + ${'merge-commit'} + ${'rebase'} + ${'squash'} + `( + 'should not call getMergeMethod when automergeStrategy is $automergeStrategy', + async (automergeStrategy) => { + await initRepo({ repository: 'some/repo' }); + const prResult = { + pullRequestId: 123, + title: 'The Title', + createdBy: { + id: '123', + }, + }; + const prUpdateResults = { + ...prResult, + autoCompleteSetBy: { + id: prResult.createdBy.id, + }, + completionOptions: { + squashMerge: true, + deleteSourceBranch: true, + mergeCommitMessage: 'The Title', + }, + }; + const updateFn = jest.fn(() => Promise.resolve(prUpdateResults)); + + azureApi.gitApi.mockResolvedValue( + partial({ + createPullRequest: jest.fn(() => Promise.resolve(prResult)), + createPullRequestLabel: jest.fn().mockResolvedValue({}), + updatePullRequest: updateFn, + }), + ); + await azure.createPr({ + sourceBranch: 'some-branch', + targetBranch: 'dev', + prTitle: 'The Title', + prBody: 'Hello world', + labels: ['deps', 'renovate'], + platformOptions: { + automergeStrategy, + usePlatformAutomerge: true, + }, + }); + + expect(azureHelper.getMergeMethod).toHaveBeenCalledTimes(0); + }, + ); + + it.each` + automergeStrategy | prMergeStrategy + ${'fast-forward'} | ${GitPullRequestMergeStrategy.Rebase} + ${'merge-commit'} | ${GitPullRequestMergeStrategy.NoFastForward} + ${'rebase'} | ${GitPullRequestMergeStrategy.Rebase} + ${'squash'} | ${GitPullRequestMergeStrategy.Squash} + `( + 'should create PR with mergeStrategy $prMergeStrategy', + async ({ automergeStrategy, prMergeStrategy }) => { + await initRepo({ repository: 'some/repo' }); + const prResult = { + pullRequestId: 456, + title: 'The Title', + createdBy: { + id: '123', + }, + }; + const prUpdateResult = { + ...prResult, + autoCompleteSetBy: { + id: prResult.createdBy.id, + }, + completionOptions: { + mergeStrategy: prMergeStrategy, + squashMerge: false, + deleteSourceBranch: true, + mergeCommitMessage: 'The Title', + }, + }; + const updateFn = jest.fn().mockResolvedValue(prUpdateResult); + azureApi.gitApi.mockResolvedValueOnce( + partial({ + createPullRequest: jest.fn().mockResolvedValue(prResult), + createPullRequestLabel: jest.fn().mockResolvedValue({}), + updatePullRequest: updateFn, + }), + ); + const pr = await azure.createPr({ + sourceBranch: 'some-branch', + targetBranch: 'dev', + prTitle: 'The Title', + prBody: 'Hello world', + labels: ['deps', 'renovate'], + platformOptions: { + automergeStrategy, + usePlatformAutomerge: true, + }, + }); + + expect((pr as GitPullRequest).completionOptions?.mergeStrategy).toBe( + prMergeStrategy, + ); + expect(updateFn).toHaveBeenCalled(); + expect( + updateFn.mock.calls[0][0].completionOptions.mergeStrategy, + ).toBe(prMergeStrategy); + expect(azureHelper.getMergeMethod).toHaveBeenCalledTimes(0); + }, + ); }); it('should create and return an approved PR object', async () => { @@ -1528,6 +1648,7 @@ describe('modules/platform/azure/index', () => { const res = await azure.mergePr({ branchName: branchNameMock, id: pullRequestIdMock, + strategy: 'auto', }); expect(updatePullRequestMock).toHaveBeenCalledWith( @@ -1546,6 +1667,59 @@ describe('modules/platform/azure/index', () => { expect(res).toBeTrue(); }); + it.each` + automergeStrategy | prMergeStrategy + ${'fast-forward'} | ${GitPullRequestMergeStrategy.Rebase} + ${'merge-commit'} | ${GitPullRequestMergeStrategy.NoFastForward} + ${'rebase'} | ${GitPullRequestMergeStrategy.Rebase} + ${'squash'} | ${GitPullRequestMergeStrategy.Squash} + `( + 'should complete PR with mergeStrategy $prMergeStrategy', + async ({ automergeStrategy, prMergeStrategy }) => { + await initRepo({ repository: 'some/repo' }); + const pullRequestIdMock = 12345; + const branchNameMock = 'test'; + const lastMergeSourceCommitMock = { commitId: 'abcd1234' }; + const updatePullRequestMock = jest.fn(() => ({ + status: 3, + })); + azureApi.gitApi.mockImplementationOnce( + () => + ({ + getPullRequestById: jest.fn(() => ({ + lastMergeSourceCommit: lastMergeSourceCommitMock, + targetRefName: 'refs/heads/ding', + title: 'title', + })), + updatePullRequest: updatePullRequestMock, + }) as any, + ); + + azureHelper.getMergeMethod = jest.fn().mockReturnValue(prMergeStrategy); + + const res = await azure.mergePr({ + branchName: branchNameMock, + id: pullRequestIdMock, + strategy: automergeStrategy, + }); + + expect(updatePullRequestMock).toHaveBeenCalledWith( + { + status: PullRequestStatus.Completed, + lastMergeSourceCommit: lastMergeSourceCommitMock, + completionOptions: { + mergeStrategy: prMergeStrategy, + deleteSourceBranch: true, + mergeCommitMessage: 'title', + }, + }, + '1', + pullRequestIdMock, + ); + expect(res).toBeTrue(); + }, + ); + it('should return false if the PR does not update successfully', async () => { await initRepo({ repository: 'some/repo' }); const pullRequestIdMock = 12345; @@ -1593,10 +1767,12 @@ describe('modules/platform/azure/index', () => { await azure.mergePr({ branchName: 'test-branch-1', id: 1234, + strategy: 'auto', }); await azure.mergePr({ branchName: 'test-branch-2', id: 5678, + strategy: 'auto', }); expect(azureHelper.getMergeMethod).toHaveBeenCalledTimes(1); diff --git a/lib/modules/platform/azure/index.ts b/lib/modules/platform/azure/index.ts index c154d4cd6b8c7b..fe9fa26c19d833 100644 --- a/lib/modules/platform/azure/index.ts +++ b/lib/modules/platform/azure/index.ts @@ -52,6 +52,7 @@ import { getRenovatePRFormat, getRepoByName, getStorageExtraCloneOpts, + mapMergeStrategy, max4000Chars, } from './util'; @@ -491,7 +492,10 @@ export async function createPr({ config.repoId, ); if (platformOptions?.usePlatformAutomerge) { - const mergeStrategy = await getMergeStrategy(pr.targetRefName!); + const mergeStrategy = + platformOptions.automergeStrategy === 'auto' + ? await getMergeStrategy(pr.targetRefName!) + : mapMergeStrategy(platformOptions.automergeStrategy); pr = await azureApiGit.updatePullRequest( { autoCompleteSetBy: { @@ -736,13 +740,17 @@ export async function setBranchStatus({ export async function mergePr({ branchName, id: pullRequestId, + strategy, }: MergePRConfig): Promise { logger.debug(`mergePr(${pullRequestId}, ${branchName!})`); const azureApiGit = await azureApi.gitApi(); let pr = await azureApiGit.getPullRequestById(pullRequestId, config.project); - const mergeStrategy = await getMergeStrategy(pr.targetRefName!); + const mergeStrategy = + strategy === 'auto' + ? await getMergeStrategy(pr.targetRefName!) + : mapMergeStrategy(strategy); const objToUpdate: GitPullRequest = { status: PullRequestStatus.Completed, lastMergeSourceCommit: pr.lastMergeSourceCommit, diff --git a/lib/modules/platform/azure/readme.md b/lib/modules/platform/azure/readme.md index b65aaa7b87f3e3..cb06f4b7a66080 100644 --- a/lib/modules/platform/azure/readme.md +++ b/lib/modules/platform/azure/readme.md @@ -18,10 +18,6 @@ Permissions for your PAT should be at minimum: Remember to set `platform=azure` somewhere in your Renovate config file. -## Features awaiting implementation - -- The `automergeStrategy` configuration option has not been implemented for this platform, and all values behave as if the value `auto` was used. Renovate will use the merge strategy configured in the Azure Repos repository itself, and this cannot be overridden yet - ## Running Renovate in Azure Pipelines ### Setting up a new pipeline diff --git a/lib/modules/platform/azure/util.ts b/lib/modules/platform/azure/util.ts index adbb2560a6ff86..9ca3563961bcb5 100644 --- a/lib/modules/platform/azure/util.ts +++ b/lib/modules/platform/azure/util.ts @@ -1,9 +1,11 @@ import { GitPullRequest, + GitPullRequestMergeStrategy, GitRepository, GitStatusContext, PullRequestStatus, } from 'azure-devops-node-api/interfaces/GitInterfaces.js'; +import type { MergeStrategy } from '../../../config/types'; import { logger } from '../../../logger'; import type { HostRule, PrState } from '../../../types'; import type { GitOptions } from '../../../types/git'; @@ -181,3 +183,19 @@ export function getRepoByName( } return foundRepo ?? null; } + +export function mapMergeStrategy( + mergeStrategy?: MergeStrategy, +): GitPullRequestMergeStrategy { + switch (mergeStrategy) { + case 'rebase': + case 'fast-forward': + return GitPullRequestMergeStrategy.Rebase; + case 'merge-commit': + return GitPullRequestMergeStrategy.NoFastForward; + case 'squash': + return GitPullRequestMergeStrategy.Squash; + default: + return GitPullRequestMergeStrategy.NoFastForward; + } +} diff --git a/lib/modules/platform/types.ts b/lib/modules/platform/types.ts index 4f9a980d566d81..78587912fe026f 100644 --- a/lib/modules/platform/types.ts +++ b/lib/modules/platform/types.ts @@ -96,6 +96,7 @@ export interface Issue { } export type PlatformPrOptions = { autoApprove?: boolean; + automergeStrategy?: MergeStrategy; azureWorkItemId?: number; bbUseDefaultReviewers?: boolean; gitLabIgnoreApprovals?: boolean; diff --git a/lib/workers/repository/update/pr/index.ts b/lib/workers/repository/update/pr/index.ts index 6eb44a70eb04a6..e9dccd6b4a1846 100644 --- a/lib/workers/repository/update/pr/index.ts +++ b/lib/workers/repository/update/pr/index.ts @@ -55,6 +55,7 @@ export function getPlatformPrOptions( return { autoApprove: !!config.autoApprove, + automergeStrategy: config.automergeStrategy, azureWorkItemId: config.azureWorkItemId ?? 0, bbUseDefaultReviewers: !!config.bbUseDefaultReviewers, gitLabIgnoreApprovals: !!config.gitLabIgnoreApprovals, From 4345212cff909ecfb8e749eaaa4946200cdf7a75 Mon Sep 17 00:00:00 2001 From: joegoldman2 <147369450+joegoldman2@users.noreply.github.com> Date: Wed, 27 Dec 2023 14:52:08 +0200 Subject: [PATCH 114/173] test(platform/azure): replace squashMerge by mergeStrategy (#26436) --- .../platform/azure/__snapshots__/index.spec.ts.snap | 2 +- lib/modules/platform/azure/index.spec.ts | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/modules/platform/azure/__snapshots__/index.spec.ts.snap b/lib/modules/platform/azure/__snapshots__/index.spec.ts.snap index ecd7882d4abbc2..14750606605808 100644 --- a/lib/modules/platform/azure/__snapshots__/index.spec.ts.snap +++ b/lib/modules/platform/azure/__snapshots__/index.spec.ts.snap @@ -60,7 +60,7 @@ exports[`modules/platform/azure/index createPr() when usePlatformAutomerge is se "completionOptions": { "deleteSourceBranch": true, "mergeCommitMessage": "The Title", - "squashMerge": true, + "mergeStrategy": 2, }, "createdAt": undefined, "createdBy": { diff --git a/lib/modules/platform/azure/index.spec.ts b/lib/modules/platform/azure/index.spec.ts index 50610286181d1d..9aaa23a87ef0fa 100644 --- a/lib/modules/platform/azure/index.spec.ts +++ b/lib/modules/platform/azure/index.spec.ts @@ -912,7 +912,7 @@ describe('modules/platform/azure/index', () => { id: prResult.createdBy.id, }, completionOptions: { - squashMerge: true, + mergeStrategy: GitPullRequestMergeStrategy.Squash, deleteSourceBranch: true, mergeCommitMessage: 'The Title', }, @@ -962,7 +962,7 @@ describe('modules/platform/azure/index', () => { id: prResult[0].createdBy.id, }, completionOptions: { - squashMerge: true, + mergeStrategy: GitPullRequestMergeStrategy.Squash, deleteSourceBranch: true, mergeCommitMessage: 'The Title', }, @@ -973,7 +973,7 @@ describe('modules/platform/azure/index', () => { id: prResult[1].createdBy.id, }, completionOptions: { - squashMerge: true, + mergeStrategy: GitPullRequestMergeStrategy.Squash, deleteSourceBranch: true, mergeCommitMessage: 'The Second Title', }, @@ -1047,7 +1047,7 @@ describe('modules/platform/azure/index', () => { id: prResult.createdBy.id, }, completionOptions: { - squashMerge: true, + mergeStrategy: GitPullRequestMergeStrategy.Squash, deleteSourceBranch: true, mergeCommitMessage: 'The Title', }, @@ -1101,7 +1101,6 @@ describe('modules/platform/azure/index', () => { }, completionOptions: { mergeStrategy: prMergeStrategy, - squashMerge: false, deleteSourceBranch: true, mergeCommitMessage: 'The Title', }, From 9e171ff861b6a125b6fbe796595bd02c278cbd6b Mon Sep 17 00:00:00 2001 From: RahulGautamSingh Date: Wed, 27 Dec 2023 20:39:32 +0545 Subject: [PATCH 115/173] fix(onboarding): add `commitBody` to commitMessage (#26426) --- lib/config/types.ts | 1 + .../onboarding/branch/create.spec.ts | 48 +++++++++++++++++++ .../repository/onboarding/branch/create.ts | 15 +++++- 3 files changed, 62 insertions(+), 2 deletions(-) diff --git a/lib/config/types.ts b/lib/config/types.ts index 777f27b3aa0a00..9f3a6d46f85879 100644 --- a/lib/config/types.ts +++ b/lib/config/types.ts @@ -208,6 +208,7 @@ export interface RenovateConfig Record { depName?: string; baseBranches?: string[]; + commitBody?: string; useBaseBranchConfig?: UseBaseBranchConfigType; baseBranch?: string; defaultBranch?: string; diff --git a/lib/workers/repository/onboarding/branch/create.spec.ts b/lib/workers/repository/onboarding/branch/create.spec.ts index e58bd7aec5ef1b..db9b3b8ddf75a4 100644 --- a/lib/workers/repository/onboarding/branch/create.spec.ts +++ b/lib/workers/repository/onboarding/branch/create.spec.ts @@ -57,6 +57,54 @@ describe('workers/repository/onboarding/branch/create', () => { }); }); + describe('applies the commitBody value', () => { + it('to the default commit message', async () => { + await createOnboardingBranch({ + ...config, + commitBody: 'some commit body', + }); + expect(scm.commitAndPush).toHaveBeenCalledWith({ + branchName: 'renovate/configure', + files: [ + { + type: 'addition', + path: 'renovate.json', + contents: '{"foo":"bar"}', + }, + ], + force: true, + message: `Add renovate.json\n\nsome commit body`, + platformCommit: false, + }); + }); + + it('to the supplied commit message', async () => { + const message = + 'We can Renovate if we want to, we can leave PRs in decline'; + + config.onboardingCommitMessage = message; + + await createOnboardingBranch({ + ...config, + commitBody: 'Signed Off: {{{gitAuthor}}}', + gitAuthor: '', + }); + expect(scm.commitAndPush).toHaveBeenCalledWith({ + branchName: 'renovate/configure', + files: [ + { + type: 'addition', + path: 'renovate.json', + contents: '{"foo":"bar"}', + }, + ], + force: true, + message: `We can Renovate if we want to, we can leave PRs in decline\n\nSigned Off: `, + platformCommit: false, + }); + }); + }); + describe('applies the commitMessagePrefix value', () => { it('to the default commit message', async () => { const prefix = 'RENOV-123'; diff --git a/lib/workers/repository/onboarding/branch/create.ts b/lib/workers/repository/onboarding/branch/create.ts index e90459e3100c8b..708d82cc33f167 100644 --- a/lib/workers/repository/onboarding/branch/create.ts +++ b/lib/workers/repository/onboarding/branch/create.ts @@ -3,6 +3,7 @@ import { GlobalConfig } from '../../../../config/global'; import type { RenovateConfig } from '../../../../config/types'; import { logger } from '../../../../logger'; import { scm } from '../../../../modules/platform/scm'; +import { compile } from '../../../../util/template'; import { OnboardingCommitMessageFactory } from './commit-message'; import { getOnboardingConfigContents } from './config'; @@ -25,7 +26,17 @@ export async function createOnboardingBranch( config, configFile!, ); - const commitMessage = commitMessageFactory.create(); + let commitMessage = commitMessageFactory.create().toString(); + + if (config.commitBody) { + commitMessage = `${commitMessage}\n\n${compile( + config.commitBody, + // only allow gitAuthor template value in the commitBody + { gitAuthor: config.gitAuthor }, + )}`; + + logger.trace(`commitMessage: ${commitMessage}`); + } // istanbul ignore if if (GlobalConfig.get('dryRun')) { @@ -44,7 +55,7 @@ export async function createOnboardingBranch( contents, }, ], - message: commitMessage.toString(), + message: commitMessage, platformCommit: !!config.platformCommit, force: true, }); From 3a8574bbd7e0a95006d6cfe847d00b7e0ffb4f95 Mon Sep 17 00:00:00 2001 From: Patrick Lannigan Date: Wed, 27 Dec 2023 14:52:22 -0500 Subject: [PATCH 116/173] feat(manager/pep621): Add support for python build-system dependencies (#26440) --- lib/modules/manager/pep621/extract.spec.ts | 45 ++++++++++++++++++++++ lib/modules/manager/pep621/extract.ts | 6 +++ lib/modules/manager/pep621/readme.md | 1 + lib/modules/manager/pep621/schema.ts | 5 +++ lib/modules/manager/pep621/utils.ts | 1 + 5 files changed, 58 insertions(+) diff --git a/lib/modules/manager/pep621/extract.spec.ts b/lib/modules/manager/pep621/extract.spec.ts index 63aa8bcbdd11ff..4911bc35b732ad 100644 --- a/lib/modules/manager/pep621/extract.spec.ts +++ b/lib/modules/manager/pep621/extract.spec.ts @@ -281,6 +281,13 @@ describe('modules/manager/pep621/extract', () => { depType: 'project.dependencies', packageName: 'requests', }, + { + datasource: 'pypi', + depName: 'hatchling', + depType: 'build-system.requires', + packageName: 'hatchling', + skipReason: 'unspecified-version', + }, { currentValue: '==6.5', datasource: 'pypi', @@ -323,5 +330,43 @@ describe('modules/manager/pep621/extract', () => { const res = extractPackageFile(content, 'pyproject.toml'); expect(res?.packageFileVersion).toBe('0.0.2'); }); + + it('should extract dependencies from build-system.requires', function () { + const content = codeBlock` + [build-system] + requires = ["hatchling==1.18.0", "setuptools==69.0.3"] + build-backend = "hatchling.build" + + [project] + name = "test" + version = "0.0.2" + dependencies = [ "requests==2.30.0" ] + `; + const result = extractPackageFile(content, 'pyproject.toml'); + + expect(result?.deps).toEqual([ + { + currentValue: '==2.30.0', + datasource: 'pypi', + depName: 'requests', + depType: 'project.dependencies', + packageName: 'requests', + }, + { + currentValue: '==1.18.0', + datasource: 'pypi', + depName: 'hatchling', + depType: 'build-system.requires', + packageName: 'hatchling', + }, + { + currentValue: '==69.0.3', + datasource: 'pypi', + depName: 'setuptools', + depType: 'build-system.requires', + packageName: 'setuptools', + }, + ]); + }); }); }); diff --git a/lib/modules/manager/pep621/extract.ts b/lib/modules/manager/pep621/extract.ts index d1f8e4accf7bf2..66648663dcddaf 100644 --- a/lib/modules/manager/pep621/extract.ts +++ b/lib/modules/manager/pep621/extract.ts @@ -43,6 +43,12 @@ export function extractPackageFile( def.project?.['optional-dependencies'], ), ); + deps.push( + ...parseDependencyList( + depTypes.buildSystemRequires, + def['build-system']?.requires, + ), + ); // process specific tool sets let processedDeps = deps; diff --git a/lib/modules/manager/pep621/readme.md b/lib/modules/manager/pep621/readme.md index 344e3948559e4e..3d3009e5b55856 100644 --- a/lib/modules/manager/pep621/readme.md +++ b/lib/modules/manager/pep621/readme.md @@ -9,5 +9,6 @@ Available `depType`s: - `project.dependencies` - `project.optional-dependencies` +- `build-system.requires` - `tool.pdm.dev-dependencies` - `tool.hatch.envs.` diff --git a/lib/modules/manager/pep621/schema.ts b/lib/modules/manager/pep621/schema.ts index 880336adb38dc5..212a1301c1b257 100644 --- a/lib/modules/manager/pep621/schema.ts +++ b/lib/modules/manager/pep621/schema.ts @@ -16,6 +16,11 @@ export const PyProjectSchema = z.object({ 'optional-dependencies': DependencyRecordSchema, }) .optional(), + 'build-system': z + .object({ + requires: DependencyListSchema, + }) + .optional(), tool: z .object({ pdm: z diff --git a/lib/modules/manager/pep621/utils.ts b/lib/modules/manager/pep621/utils.ts index 4420992bcb4f43..5b28541993508f 100644 --- a/lib/modules/manager/pep621/utils.ts +++ b/lib/modules/manager/pep621/utils.ts @@ -15,6 +15,7 @@ export const depTypes = { dependencies: 'project.dependencies', optionalDependencies: 'project.optional-dependencies', pdmDevDependencies: 'tool.pdm.dev-dependencies', + buildSystemRequires: 'build-system.requires', }; export function parsePEP508( From 53e1ca654c01340917c0ab1abf1991d6ad461b98 Mon Sep 17 00:00:00 2001 From: HonkingGoose <34918129+HonkingGoose@users.noreply.github.com> Date: Thu, 28 Dec 2023 11:48:41 +0100 Subject: [PATCH 117/173] docs(renovate style guide): avoid manually ordering numbered lists (#26445) --- docs/development/style-guide.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/docs/development/style-guide.md b/docs/development/style-guide.md index 82c5939dc4ee93..628697993fd0d8 100644 --- a/docs/development/style-guide.md +++ b/docs/development/style-guide.md @@ -21,6 +21,24 @@ Second sentence on a new line. And so on. ``` +## Avoid manually ordering numbered lists + +Avoid: + +```markdown +1. First item +2. Second item +3. Third item +``` + +Do: + +```markdown +1. First item +1. Second item +1. Third item +``` + ## Avoid punctuation at the end of list items In Markdown files, avoid punctuation at the end of a list item. From 0710a35205775aa836ad2bcdca5539f220ffee3a Mon Sep 17 00:00:00 2001 From: joegoldman2 <147369450+joegoldman2@users.noreply.github.com> Date: Thu, 28 Dec 2023 19:45:37 +0200 Subject: [PATCH 118/173] feat(platform/gitea): use automergeStrategy in createPr (#26448) --- lib/modules/platform/gitea/index.spec.ts | 75 ++++++++++++++++++++++++ lib/modules/platform/gitea/index.ts | 5 +- 2 files changed, 78 insertions(+), 2 deletions(-) diff --git a/lib/modules/platform/gitea/index.spec.ts b/lib/modules/platform/gitea/index.spec.ts index 1c1fc2b77e61f4..d4321b823be8f4 100644 --- a/lib/modules/platform/gitea/index.spec.ts +++ b/lib/modules/platform/gitea/index.spec.ts @@ -1217,6 +1217,81 @@ describe('modules/platform/gitea/index', () => { }); expect(helper.mergePR).not.toHaveBeenCalled(); }); + + it('should create PR with repository merge method when automergeStrategy is auto', async () => { + helper.createPR.mockResolvedValueOnce(mockNewPR); + await initFakePlatform('1.17.0'); + await initFakeRepo(); + await gitea.createPr({ + sourceBranch: mockNewPR.head.label, + targetBranch: 'master', + prTitle: mockNewPR.title, + prBody: mockNewPR.body, + platformOptions: { + automergeStrategy: 'auto', + usePlatformAutomerge: true, + }, + }); + + expect(helper.createPR).toHaveBeenCalledTimes(1); + expect(helper.createPR).toHaveBeenCalledWith(mockRepo.full_name, { + base: mockNewPR.base.ref, + head: mockNewPR.head.label, + title: mockNewPR.title, + body: mockNewPR.body, + labels: [], + }); + expect(helper.mergePR).toHaveBeenCalledWith( + mockRepo.full_name, + mockNewPR.number, + { + Do: 'rebase', + merge_when_checks_succeed: true, + }, + ); + }); + + it.each` + automergeStrategy | prMergeStrategy + ${'fast-forward'} | ${'rebase'} + ${'merge-commit'} | ${'merge'} + ${'rebase'} | ${'rebase-merge'} + ${'squash'} | ${'squash'} + `( + 'should create PR with mergeStrategy $prMergeStrategy', + async ({ automergeStrategy, prMergeStrategy }) => { + helper.createPR.mockResolvedValueOnce(mockNewPR); + await initFakePlatform('1.17.0'); + await initFakeRepo(); + await gitea.createPr({ + sourceBranch: mockNewPR.head.label, + targetBranch: 'master', + prTitle: mockNewPR.title, + prBody: mockNewPR.body, + platformOptions: { + automergeStrategy, + usePlatformAutomerge: true, + }, + }); + + expect(helper.createPR).toHaveBeenCalledTimes(1); + expect(helper.createPR).toHaveBeenCalledWith(mockRepo.full_name, { + base: mockNewPR.base.ref, + head: mockNewPR.head.label, + title: mockNewPR.title, + body: mockNewPR.body, + labels: [], + }); + expect(helper.mergePR).toHaveBeenCalledWith( + mockRepo.full_name, + mockNewPR.number, + { + Do: prMergeStrategy, + merge_when_checks_succeed: true, + }, + ); + }, + ); }); describe('updatePr', () => { diff --git a/lib/modules/platform/gitea/index.ts b/lib/modules/platform/gitea/index.ts index de33ac3623a889..923006afbbf9c5 100644 --- a/lib/modules/platform/gitea/index.ts +++ b/lib/modules/platform/gitea/index.ts @@ -544,8 +544,9 @@ const platform: Platform = { if (semver.gte(defaults.version, '1.17.0')) { try { await helper.mergePR(config.repository, gpr.number, { - // TODO: pass strategy (#16884) - Do: config.mergeMethod, + Do: + getMergeMethod(platformOptions?.automergeStrategy) ?? + config.mergeMethod, merge_when_checks_succeed: true, }); From f6cf9a4e0f488aeb0eb52d11900697a0e5a87ee9 Mon Sep 17 00:00:00 2001 From: Phil B Date: Fri, 29 Dec 2023 01:15:37 -0600 Subject: [PATCH 119/173] feat(presets): add Larastan to PHPStan group (#26450) --- lib/config/presets/internal/group.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/config/presets/internal/group.ts b/lib/config/presets/internal/group.ts index b3f8bfe3482f3e..713a538adf5998 100644 --- a/lib/config/presets/internal/group.ts +++ b/lib/config/presets/internal/group.ts @@ -318,7 +318,7 @@ const staticGroups = { { groupName: 'PHPStan packages', matchDatasources: ['packagist'], - matchPackagePatterns: ['^phpstan/phpstan$', '/phpstan-'], + matchPackagePatterns: ['^phpstan/phpstan$', '/phpstan-', '/larastan'], }, ], }, From 831fba026278d37d2fd2f8a55699fe5493ab7e48 Mon Sep 17 00:00:00 2001 From: Jan Gerlinger Date: Fri, 29 Dec 2023 15:17:10 +0800 Subject: [PATCH 120/173] fix(terraform): Escape literal . in Bitbucket module ref regex (#26452) --- .../manager/terraform/extractors/others/modules.spec.ts | 8 ++++++++ .../manager/terraform/extractors/others/modules.ts | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/modules/manager/terraform/extractors/others/modules.spec.ts b/lib/modules/manager/terraform/extractors/others/modules.spec.ts index 82be37043c1387..845e7b7c46e008 100644 --- a/lib/modules/manager/terraform/extractors/others/modules.spec.ts +++ b/lib/modules/manager/terraform/extractors/others/modules.spec.ts @@ -148,6 +148,9 @@ describe('modules/manager/terraform/extractors/others/modules', () => { const subfolderWithDoubleSlash = bitbucketRefMatchRegex.exec( 'bitbucket.org/hashicorp/example.git//terraform?ref=v1.0.0', )?.groups; + const subfolderWithGitInName = bitbucketRefMatchRegex.exec( + 'bitbucket.org/hashicorp/example.git//terraform-git?ref=v1.0.0', + )?.groups; const depth = bitbucketRefMatchRegex.exec( 'git::https://git@bitbucket.org/hashicorp/example.git?depth=1&ref=v1.0.0', )?.groups; @@ -180,6 +183,11 @@ describe('modules/manager/terraform/extractors/others/modules', () => { project: 'example', tag: 'v1.0.0', }); + expect(subfolderWithGitInName).toMatchObject({ + workspace: 'hashicorp', + project: 'example', + tag: 'v1.0.0', + }); expect(depth).toMatchObject({ workspace: 'hashicorp', project: 'example', diff --git a/lib/modules/manager/terraform/extractors/others/modules.ts b/lib/modules/manager/terraform/extractors/others/modules.ts index c6d129dcf5cf5e..5ba4f31c3ca122 100644 --- a/lib/modules/manager/terraform/extractors/others/modules.ts +++ b/lib/modules/manager/terraform/extractors/others/modules.ts @@ -13,7 +13,7 @@ export const githubRefMatchRegex = regEx( /github\.com([/:])(?[^/]+\/[a-z0-9-_.]+).*\?(depth=\d+&)?ref=(?.*?)(&depth=\d+)?$/i, ); export const bitbucketRefMatchRegex = regEx( - /(?:git::)?(?(?:http|https|ssh)?(?::\/\/)?(?:.*@)?(?bitbucket\.org\/(?.*)\/(?.*).git\/?(?.*)))\?(depth=\d+&)?ref=(?.*?)(&depth=\d+)?$/, + /(?:git::)?(?(?:http|https|ssh)?(?::\/\/)?(?:.*@)?(?bitbucket\.org\/(?.*)\/(?.*)\.git\/?(?.*)))\?(depth=\d+&)?ref=(?.*?)(&depth=\d+)?$/, ); export const gitTagsRefMatchRegex = regEx( /(?:git::)?(?(?:(?:http|https|ssh):\/\/)?(?:.*@)?(?.*\/(?.*\/.*)))\?(depth=\d+&)?ref=(?.*?)(&depth=\d+)?$/, From 5f163552a9f52a66bc6c3e5fa86ea80a037bc540 Mon Sep 17 00:00:00 2001 From: RahulGautamSingh Date: Fri, 29 Dec 2023 18:40:11 +0545 Subject: [PATCH 121/173] fix(reconfigure/pr): find reconfigure pr separately (#25954) Co-authored-by: Rhys Arkins --- .../platform/bitbucket-server/index.spec.ts | 44 ++++++++++++++++++ .../platform/bitbucket-server/index.ts | 26 +++++++++++ lib/modules/platform/bitbucket/index.spec.ts | 40 +++++++++++++++++ lib/modules/platform/bitbucket/index.ts | 18 ++++++++ lib/modules/platform/gitea/index.ts | 10 ++++- lib/modules/platform/github/index.spec.ts | 45 +++++++++++++++++++ lib/modules/platform/github/index.ts | 18 ++++++++ lib/modules/platform/gitlab/index.spec.ts | 43 ++++++++++++++++++ lib/modules/platform/gitlab/index.ts | 28 ++++++++++++ lib/modules/platform/types.ts | 1 + .../repository/reconfigure/index.spec.ts | 6 +-- lib/workers/repository/reconfigure/index.ts | 8 ++-- 12 files changed, 280 insertions(+), 7 deletions(-) diff --git a/lib/modules/platform/bitbucket-server/index.spec.ts b/lib/modules/platform/bitbucket-server/index.spec.ts index f925b30d298974..117bce84ef4045 100644 --- a/lib/modules/platform/bitbucket-server/index.spec.ts +++ b/lib/modules/platform/bitbucket-server/index.spec.ts @@ -1306,6 +1306,50 @@ describe('modules/platform/bitbucket-server/index', () => { }), ).toBeNull(); }); + + it('finds pr from other authors', async () => { + const scope = await initRepo(); + scope + .get( + `${urlPath}/rest/api/1.0/projects/SOME/repos/repo/pull-requests?state=OPEN&direction=outgoing&at=refs/heads/branch&limit=1`, + ) + .reply(200, { + isLastPage: true, + values: [prMock(url, 'SOME', 'repo')], + }); + expect( + await bitbucket.findPr({ + branchName: 'branch', + state: 'open', + includeOtherAuthors: true, + }), + ).toMatchObject({ + number: 5, + sourceBranch: 'userName1/pullRequest5', + targetBranch: 'master', + title: 'title', + state: 'open', + }); + }); + + it('returns null if no pr found - (includeOtherAuthors)', async () => { + const scope = await initRepo(); + scope + .get( + `${urlPath}/rest/api/1.0/projects/SOME/repos/repo/pull-requests?state=OPEN&direction=outgoing&at=refs/heads/branch&limit=1`, + ) + .reply(200, { + isLastPage: true, + values: [], + }); + + const pr = await bitbucket.findPr({ + branchName: 'branch', + state: 'open', + includeOtherAuthors: true, + }); + expect(pr).toBeNull(); + }); }); describe('createPr()', () => { diff --git a/lib/modules/platform/bitbucket-server/index.ts b/lib/modules/platform/bitbucket-server/index.ts index bd9a0be19c34c0..aa6bcc2e7a4828 100644 --- a/lib/modules/platform/bitbucket-server/index.ts +++ b/lib/modules/platform/bitbucket-server/index.ts @@ -324,8 +324,34 @@ export async function findPr({ prTitle, state = 'all', refreshCache, + includeOtherAuthors, }: FindPRConfig): Promise { logger.debug(`findPr(${branchName}, "${prTitle!}", "${state}")`); + + if (includeOtherAuthors) { + // PR might have been created by anyone, so don't use the cached Renovate PR list + const searchParams: Record = { + state: 'OPEN', + }; + searchParams['direction'] = 'outgoing'; + searchParams['at'] = `refs/heads/${branchName}`; + + const query = getQueryString(searchParams); + const prs = await utils.accumulateValues( + `./rest/api/1.0/projects/${config.projectKey}/repos/${config.repositorySlug}/pull-requests?${query}`, + 'get', + {}, + 1, // only fetch the latest pr + ); + + if (!prs.length) { + logger.debug(`No PR found for branch ${branchName}`); + return null; + } + + return utils.prInfo(prs[0]); + } + const prList = await getPrList(refreshCache); const pr = prList.find(isRelevantPr(branchName, prTitle, state)); if (pr) { diff --git a/lib/modules/platform/bitbucket/index.spec.ts b/lib/modules/platform/bitbucket/index.spec.ts index 8e5318b180de1b..b4b8b8782712b9 100644 --- a/lib/modules/platform/bitbucket/index.spec.ts +++ b/lib/modules/platform/bitbucket/index.spec.ts @@ -954,6 +954,46 @@ describe('modules/platform/bitbucket/index', () => { }); expect(pr?.number).toBe(5); }); + + it('finds pr from other authors', async () => { + const scope = await initRepoMock(); + scope + .get( + '/2.0/repositories/some/repo/pullrequests?q=source.branch.name="branch"&state=open', + ) + .reply(200, { values: [pr] }); + expect( + await bitbucket.findPr({ + branchName: 'branch', + state: 'open', + includeOtherAuthors: true, + }), + ).toMatchObject({ + number: 5, + sourceBranch: 'branch', + targetBranch: 'master', + title: 'title', + state: 'open', + }); + }); + + it('returns null if no open pr exists - (includeOtherAuthors)', async () => { + const scope = await initRepoMock(); + scope + .get( + '/2.0/repositories/some/repo/pullrequests?q=source.branch.name="branch"&state=open', + ) + .reply(200, { + values: [], + }); + + const pr = await bitbucket.findPr({ + branchName: 'branch', + state: 'open', + includeOtherAuthors: true, + }); + expect(pr).toBeNull(); + }); }); describe('createPr()', () => { diff --git a/lib/modules/platform/bitbucket/index.ts b/lib/modules/platform/bitbucket/index.ts index ad94a1e098be90..9ddef12de074a9 100644 --- a/lib/modules/platform/bitbucket/index.ts +++ b/lib/modules/platform/bitbucket/index.ts @@ -301,8 +301,26 @@ export async function findPr({ branchName, prTitle, state = 'all', + includeOtherAuthors, }: FindPRConfig): Promise { logger.debug(`findPr(${branchName}, ${prTitle}, ${state})`); + + if (includeOtherAuthors) { + // PR might have been created by anyone, so don't use the cached Renovate PR list + const prs = ( + await bitbucketHttp.getJson>( + `/2.0/repositories/${config.repository}/pullrequests?q=source.branch.name="${branchName}"&state=open`, + ) + ).body.values; + + if (prs.length === 0) { + logger.debug(`No PR found for branch ${branchName}`); + return null; + } + + return utils.prInfo(prs[0]); + } + const prList = await getPrList(); const pr = prList.find( (p) => diff --git a/lib/modules/platform/gitea/index.ts b/lib/modules/platform/gitea/index.ts index 923006afbbf9c5..f26814f268a267 100644 --- a/lib/modules/platform/gitea/index.ts +++ b/lib/modules/platform/gitea/index.ts @@ -13,6 +13,7 @@ import type { BranchStatus } from '../../../types'; import { parseJson } from '../../../util/common'; import * as git from '../../../util/git'; import { setBaseUrl } from '../../../util/http/gitea'; +import { regEx } from '../../../util/regex'; import { sanitize } from '../../../util/sanitize'; import { ensureTrailingSlash } from '../../../util/url'; import { getPrBodyStruct, hashBody } from '../pr-body'; @@ -70,6 +71,7 @@ interface GiteaRepoConfig { export const id = 'gitea'; const DRAFT_PREFIX = 'WIP: '; +const reconfigurePrRegex = regEx(/reconfigure$/g); const defaults = { hostType: 'gitea', @@ -109,7 +111,12 @@ function toRenovatePR(data: PR): Pr | null { } const createdBy = data.user?.username; - if (createdBy && botUserName && createdBy !== botUserName) { + if ( + createdBy && + botUserName && + !reconfigurePrRegex.test(data.head.label) && + createdBy !== botUserName + ) { return null; } @@ -493,6 +500,7 @@ const platform: Platform = { branchName, prTitle: title, state = 'all', + includeOtherAuthors, }: FindPRConfig): Promise { logger.debug(`findPr(${branchName}, ${title!}, ${state})`); const prList = await platform.getPrList(); diff --git a/lib/modules/platform/github/index.spec.ts b/lib/modules/platform/github/index.spec.ts index bdcd315bfc5086..653907f8cc4be5 100644 --- a/lib/modules/platform/github/index.spec.ts +++ b/lib/modules/platform/github/index.spec.ts @@ -2428,6 +2428,51 @@ describe('modules/platform/github/index', () => { res = await github.findPr({ branchName: 'branch-b' }); expect(res).toBeNull(); }); + + it('finds pr from other authors', async () => { + const scope = httpMock.scope(githubApiHost); + initRepoMock(scope, 'some/repo'); + scope + .get('/repos/some/repo/pulls?head=some/repo:branch&state=open') + .reply(200, [ + { + number: 1, + head: { ref: 'branch-a', repo: { full_name: 'some/repo' } }, + title: 'branch a pr', + state: 'open', + }, + ]); + await github.initRepo({ repository: 'some/repo' }); + expect( + await github.findPr({ + branchName: 'branch', + state: 'open', + includeOtherAuthors: true, + }), + ).toMatchObject({ + number: 1, + sourceBranch: 'branch-a', + sourceRepo: 'some/repo', + state: 'open', + title: 'branch a pr', + updated_at: undefined, + }); + }); + + it('returns null if no pr found - (includeOtherAuthors)', async () => { + const scope = httpMock.scope(githubApiHost); + initRepoMock(scope, 'some/repo'); + scope + .get('/repos/some/repo/pulls?head=some/repo:branch&state=open') + .reply(200, []); + await github.initRepo({ repository: 'some/repo' }); + const pr = await github.findPr({ + branchName: 'branch', + state: 'open', + includeOtherAuthors: true, + }); + expect(pr).toBeNull(); + }); }); describe('createPr()', () => { diff --git a/lib/modules/platform/github/index.ts b/lib/modules/platform/github/index.ts index fcc2a2d55cd5b5..4117a7be1033ce 100644 --- a/lib/modules/platform/github/index.ts +++ b/lib/modules/platform/github/index.ts @@ -798,8 +798,26 @@ export async function findPr({ branchName, prTitle, state = 'all', + includeOtherAuthors, }: FindPRConfig): Promise { logger.debug(`findPr(${branchName}, ${prTitle}, ${state})`); + + if (includeOtherAuthors) { + const repo = config.parentRepo ?? config.repository; + // PR might have been created by anyone, so don't use the cached Renovate PR list + const response = await githubApi.getJson( + `repos/${repo}/pulls?head=${repo}:${branchName}&state=open`, + ); + + const { body: prList } = response; + if (!prList.length) { + logger.debug(`No PR found for branch ${branchName}`); + return null; + } + + return coerceRestPr(prList[0]); + } + const prList = await getPrList(); const pr = prList.find((p) => { if (p.sourceBranch !== branchName) { diff --git a/lib/modules/platform/gitlab/index.spec.ts b/lib/modules/platform/gitlab/index.spec.ts index 9a30d26c551e1b..d10b776c062508 100644 --- a/lib/modules/platform/gitlab/index.spec.ts +++ b/lib/modules/platform/gitlab/index.spec.ts @@ -1678,6 +1678,49 @@ describe('modules/platform/gitlab/index', () => { }); expect(res).toBeDefined(); }); + + it('finds pr from other authors', async () => { + httpMock + .scope(gitlabApiHost) + .get( + '/api/v4/projects/undefined/merge_requests?source_branch=branch&state=opened', + ) + .reply(200, [ + { + iid: 1, + source_branch: 'branch', + title: 'branch a pr', + state: 'opened', + }, + ]); + expect( + await gitlab.findPr({ + branchName: 'branch', + state: 'open', + includeOtherAuthors: true, + }), + ).toMatchObject({ + number: 1, + sourceBranch: 'branch', + state: 'open', + title: 'branch a pr', + }); + }); + + it('returns null if no pr found - (includeOtherAuthors)', async () => { + httpMock + .scope(gitlabApiHost) + .get( + '/api/v4/projects/undefined/merge_requests?source_branch=branch&state=opened', + ) + .reply(200, []); + const pr = await gitlab.findPr({ + branchName: 'branch', + state: 'open', + includeOtherAuthors: true, + }); + expect(pr).toBeNull(); + }); }); async function initPlatform(gitlabVersion: string) { diff --git a/lib/modules/platform/gitlab/index.ts b/lib/modules/platform/gitlab/index.ts index be38419752c8f2..de5137f28e7441 100644 --- a/lib/modules/platform/gitlab/index.ts +++ b/lib/modules/platform/gitlab/index.ts @@ -863,8 +863,36 @@ export async function findPr({ branchName, prTitle, state = 'all', + includeOtherAuthors, }: FindPRConfig): Promise { logger.debug(`findPr(${branchName}, ${prTitle!}, ${state})`); + + if (includeOtherAuthors) { + // PR might have been created by anyone, so don't use the cached Renovate MR list + const response = await gitlabApi.getJson( + `projects/${config.repository}/merge_requests?source_branch=${branchName}&state=opened`, + ); + + const { body: mrList } = response; + if (!mrList.length) { + logger.debug(`No MR found for branch ${branchName}`); + return null; + } + + // return the latest merge request + const mr = mrList[0]; + + // only pass necessary info + const pr: GitlabPr = { + sourceBranch: mr.source_branch, + number: mr.iid, + state: 'open', + title: mr.title, + }; + + return massagePr(pr); + } + const prList = await getPrList(); return ( prList.find( diff --git a/lib/modules/platform/types.ts b/lib/modules/platform/types.ts index 78587912fe026f..f0209f6d23334d 100644 --- a/lib/modules/platform/types.ts +++ b/lib/modules/platform/types.ts @@ -143,6 +143,7 @@ export interface FindPRConfig { state?: 'open' | 'closed' | '!open' | 'all'; refreshCache?: boolean; targetBranch?: string | null; + includeOtherAuthors?: boolean; } export interface MergePRConfig { branchName?: string; diff --git a/lib/workers/repository/reconfigure/index.spec.ts b/lib/workers/repository/reconfigure/index.spec.ts index f7c97269ef01ef..4729c1e9ef1561 100644 --- a/lib/workers/repository/reconfigure/index.spec.ts +++ b/lib/workers/repository/reconfigure/index.spec.ts @@ -8,6 +8,7 @@ import { platform, scm, } from '../../../../test/util'; +import { GlobalConfig } from '../../../config/global'; import { logger } from '../../../logger'; import type { Pr } from '../../../modules/platform/types'; import * as _cache from '../../../util/cache/repository'; @@ -39,8 +40,8 @@ describe('workers/repository/reconfigure/index', () => { cache.getCache.mockReturnValue({}); git.getBranchCommit.mockReturnValue('sha' as LongCommitSha); fs.readLocalFile.mockResolvedValue(null); - platform.getBranchPr.mockResolvedValue(null); platform.getBranchStatusCheck.mockResolvedValue(null); + GlobalConfig.reset(); }); it('no effect on repo with no reconfigure branch', async () => { @@ -126,7 +127,7 @@ describe('workers/repository/reconfigure/index', () => { "enabledManagers": ["docker"] } `); - platform.getBranchPr.mockResolvedValueOnce(mock({ number: 1 })); + platform.findPr.mockResolvedValueOnce(mock({ number: 1 })); await validateReconfigureBranch(config); expect(logger.debug).toHaveBeenCalledWith( { errors: expect.any(String) }, @@ -229,7 +230,6 @@ describe('workers/repository/reconfigure/index', () => { "enabledManagers": ["npm",] } `); - platform.getBranchPr.mockResolvedValueOnce(mock({ number: 1 })); await validateReconfigureBranch(config); expect(platform.setBranchStatus).toHaveBeenCalledWith({ branchName: 'prefix/reconfigure', diff --git a/lib/workers/repository/reconfigure/index.ts b/lib/workers/repository/reconfigure/index.ts index 79a7e9f71f842c..0908bbf82c5e83 100644 --- a/lib/workers/repository/reconfigure/index.ts +++ b/lib/workers/repository/reconfigure/index.ts @@ -161,10 +161,11 @@ export async function validateReconfigureBranch( ); // add comment to reconfigure PR if it exists - const branchPr = await platform.getBranchPr( + const branchPr = await platform.findPr({ branchName, - config.defaultBranch, - ); + state: 'open', + includeOtherAuthors: true, + }); if (branchPr) { let body = `There is an error with this repository's Renovate configuration that needs to be fixed.\n\n`; body += `Location: \`${configFileName}\`\n`; @@ -179,6 +180,7 @@ export async function validateReconfigureBranch( content: body, }); } + await setBranchStatus(branchName, 'Validation Failed', 'red', context); setReconfigureBranchCache(branchSha, false); await scm.checkoutBranch(config.baseBranch!); From b2422d86fdeeccbdf05bbe4ae417e2ebf0766604 Mon Sep 17 00:00:00 2001 From: Markus Schulz Date: Fri, 29 Dec 2023 18:55:25 +0100 Subject: [PATCH 122/173] feat: Support for Platform "Gerrit" (#18961) Co-authored-by: HonkingGoose <34918129+HonkingGoose@users.noreply.github.com> Co-authored-by: Michael Kriese Co-authored-by: Rhys Arkins --- .../assets/images/gerrit-http-password.png | Bin 0 -> 6444 bytes lib/config/options/index.ts | 2 +- lib/config/presets/local/index.ts | 1 + lib/constants/platforms.ts | 1 + lib/modules/platform/api.ts | 2 + lib/modules/platform/gerrit/client.spec.ts | 482 +++++++++++ lib/modules/platform/gerrit/client.ts | 235 ++++++ lib/modules/platform/gerrit/index.md | 70 ++ lib/modules/platform/gerrit/index.spec.ts | 764 ++++++++++++++++++ lib/modules/platform/gerrit/index.ts | 454 +++++++++++ lib/modules/platform/gerrit/scm.spec.ts | 396 +++++++++ lib/modules/platform/gerrit/scm.ts | 171 ++++ lib/modules/platform/gerrit/types.ts | 93 +++ lib/modules/platform/gerrit/utils.spec.ts | 251 ++++++ lib/modules/platform/gerrit/utils.ts | 122 +++ lib/modules/platform/scm.ts | 2 + lib/util/http/gerrit.spec.ts | 74 ++ lib/util/http/gerrit.ts | 38 + lib/util/http/types.ts | 2 + readme.md | 1 + 20 files changed, 3160 insertions(+), 1 deletion(-) create mode 100644 docs/usage/assets/images/gerrit-http-password.png create mode 100644 lib/modules/platform/gerrit/client.spec.ts create mode 100644 lib/modules/platform/gerrit/client.ts create mode 100644 lib/modules/platform/gerrit/index.md create mode 100644 lib/modules/platform/gerrit/index.spec.ts create mode 100644 lib/modules/platform/gerrit/index.ts create mode 100644 lib/modules/platform/gerrit/scm.spec.ts create mode 100644 lib/modules/platform/gerrit/scm.ts create mode 100644 lib/modules/platform/gerrit/types.ts create mode 100644 lib/modules/platform/gerrit/utils.spec.ts create mode 100644 lib/modules/platform/gerrit/utils.ts create mode 100644 lib/util/http/gerrit.spec.ts create mode 100644 lib/util/http/gerrit.ts diff --git a/docs/usage/assets/images/gerrit-http-password.png b/docs/usage/assets/images/gerrit-http-password.png new file mode 100644 index 0000000000000000000000000000000000000000..fcbb6226f367567a5d0a853889dc1d7f43baef87 GIT binary patch literal 6444 zcmbt(bySqm|0ZHk5{iVRgEZ15-I9XfPy-CoFff#KjlvK^NrQAr3=AnXLntXA?a)ZK zFw!C5j^E$z*|TT&>>s=T-1ENobMHC#e&TtadoSXZt~xm>11SLk0lB7zssRDPtzrDP z3o+rpmaC_cfPnr;Q&kD*2j0txG<&q!-Z!G)vENqu(-{#RO2V1J6exHgHKs~^!VdXG ztnnZakLRHQ@U^%0SA*wacMGre$ZP%?cOM5v^v^0DO{&U?3Ju^&a zT&*AJrC^aYvCt*HAQ!Hl6?dNMk#TxD1}Rq+daSLa-Y;$NyS$?C zha&m;tH0cC=pHRlQMg#6_D66&o$v}z8W(YTzE~%4aE%jDk1aiD}`2uyx zbVog&Wp}=%J|`z*d% zKcGVeoCTqYeJpDK<=w3v&w85s6q`$1QOb_S7M2xeIjS3T)s_micMj}p;E*Pl1*8$w z3?GdP=0l&d)18K0ZaCt{$=4tU2PX3S6h^E`^|M_z9eI{E6W48vun$Zvu)jB70Zl!C z;x&5TwK9D_&|k<(_v_LT?%5J&k!%ZdA_@lh+gwp!f$_amK4TuBGnzU!J{D71IR18M zHu0&t^|59$C#!;oK~Rm6zG0isf;1x|yeyTii*tG#iI z(k{~}JgOlCj$)J9-w)&Ki#5j z(b3rcb#^x3TLNH5g>)(3wBA7w)Jp$CCG*$TT1v@SzHCR0Tun!&605Q7e%VQKy?0=d9ZU?zRkb{ zTH3FYFD9S}O)03q3RU)Rxo-8hKzkwLV(2j6s5WQkR2)b&M><5rmj?x{6fY#p@Ok=E zi7p8;SgrNaSPh_}^XM1x>+!jN=C6Z5`$+#1Q z^>+94XB8oW((w+(ujnP51DKVPZD48d|1VR7? zpL&O#_&k=a=hF$^bY+LIz3=hS1xExNsmJ92(tWpyqtAaQd5`P`rDt4D20G0ewE@i_#2 zn=kGIP0p|B7BcVRpq3Nl(2(F4xz*#DdIc8w&|=0M`btZEL%E=H_o(TwV`EFAw*YHH zqabYia>MLiyUddZ#Wqb{ofSANvO<%+w4|UtEUXB>>*tQ6Pd?QP!E0LLc=L5pH{!V% zccn4+gCvfBUT1q@%=o&@2xRLR2MJSggvK zs}ok+YwS!_$|ha7Ku?RB3>&_|Fkah)UA-LaS~PFoQX^@8h>PV)?J9WwD5K!lBgl;| zf>UW9O;#9H{2jf|RV2^emmj8T(CRhg=^d=3V{T5Q;`}xF?-8r!zd$iOwkVkOKVs6U z@M&wJ+=-m0NHxw7vI;fDk}`ar{Tp=cy*Zp?iJN*)0*?RNK`T2D8NoX?eI z@Z~XX(Xt9upF_`NQ2?sl*cF3?mDS2JBEyS1n@1EVNyt@3h$vV(VIXU?)l%`aPxK<2Cg@t%8?&S%;FKuYF)ZH(n^(w)z!+7#>Td8eLUiw10D5m*j>@oVMTnvxqPUn_gm_r zF})W?jp*flxj?ipPGIMF2TN882f@?CNeR0|Z~sfFCOyd|`t>C9bG7OSTtav=C| z`HnlM6GPnb994;uv1UI{=J#h44!Xp(OfWI*L*;KcDr6d!@-qrUZDIgzB$5M86{CXh zkLvk9&^A8+Zo>5cKD;j$;=4bi04)htGi(4_NLLA z3|D=GFH$$>IkM|0=?RDLCXGQ-5(9h{<_q&bVSj^xH>Y#kc(JqMNEB>N(u~Bu)IK4h z8t0s?2Az9sF!fbP5?aYMsSR4pr{@c8`8?loJ6T|+XWH3rxHZYgQ!%<@j__;>AM^>v zr5l^v!CFr_9GyB#-ku6@>-5nH8szX;`K-{W_s5brCd$jQjxYe#BQ_x@)OysqwTBJzh&<4SX>H(%c2$xO=s!d-aH#KfG?(q?t%gb|bj#`x?p zFf&H(wVa+>hMXAsxPo0nzBYTT=If6k*eb;R2;rX*rxiXU?YEU1S}wvrt*1))-;H~D zmZ&@IYsNlKlv2bGFT-N$D(keo2(h|(d+#cU=SVbpo_p~uNjHj{N*y5j3n}0+hu^c) zY)!@J7GCsmy!q3)p5}G?nK|0?!q>UR%Ej?;@)lM%SJu=;(y`$i^m-(Z4kPU0kt6Mm zM7h2Dr;&I`!$MW^?bqtLag##>f9H<|G7?lG?$5M2P&Ov^4*UA__Kw-~smIa-cx`R% z($f?=SaCBL->uOCYqKhl4c8MN5+@FOASQ5;(o>C4wga}=!orw}6%RaP&EDOLCLJbA zds40nNP78e;NoCQ6ZJE-69sC6^!R9HmZ;^V6V_N57`5A+$#eDix?Pp@g?#{8E~|+OPx**0wI^&>3RpZV(Z&_p{B&HUP6o$sN+4z^JbarmXD_^- z5FJhZ28pXUO>-0|pPU|DL#b4Ou0|8fz$DGlW|%wUhG9sxmef>ik9NA6l#i8O`RvwM z-X-(%cRz~}!d}xgpS080=^k09;HCO~;Nk^wkznZif{W9CndUj25+i(?jY&*zRbk@4M+Ri!r) z_ra$yi74{!$C(z!rgOHL&%T~!yKOwe94}MS(~Mmf8|cF8H>Corjx=>&(yc22tOkwz zhwJiiEA4CNJh0_HBP6Yjf91)Gxlep@?PoGkhjUgBqBjDtKOYTo{MV|vfnTISwVKAuG0-X!g>u8g()L^vtHId8YG2m}1BHy*1+;gvCzzm%f>oXg@q4<~MwnZo zo6W^=sBNU`K3>pl7h`G?W}%kk|0ALkjf_Nfn}%Qk5MIEE5nOiZ!T9B{Gh zt~Yrc-bKQ1g~A=plw*;!=|ok@f!-&E;%B@_XFM7X@bV4v5kjRi-sg9Xw zTx0I5frL9aLw2?Jco`dJ9Y%7+Md_jUbr^M6bO1W+vuUlX^si7Rl8PdsF~#i#`u?|s z>7gY5Ogdau>M67 zf)G8F^4~1vziuO_g^G>8ona=YivQUEu;}pOZT0vmrfPOt=okOf@NY^65XxXU=tuq@ zp^8oN#WSVVK|X|}0P>iY5}B5O=d$JHC1@X3G?MHXM;1mkCY8cb$;vg!{!3qJGV)^HU3ZVMmFc(=K&-QH|lZbTS5!xHIA zXczOgvSxe432lPgMENUL3J`~y?d9iV8qmFK5l$EFM4$A$@5~q;Qx{guYs49O>A~2c zW40(bhP!WTT=S-SBB#K4Rj?P!O>sSyJ<775s7oZOy~~17=?z746z3p=4}VQP0F#7G zb*tNoFKNjz8lLF&xtlkwaJw9y`7e8)v1A?Z7^7yWM()q$9PU z#pr$Y`elalS9cgzfS)XER5ZrgMOEdaTJ>CTX#K--JvQl<>SXV-5|+7|R-owuV(^1$ zvTt$pUU6ZG?(l=Yr@VhEqf>d8IG&888t7iJg63Jx?JH#^^vFaZFh~nIJFSFL-xj%N zw*Wlm=)IVS;Cq;!TDwM>$5c08&rqc)ZsI%$<>l2m`RL#jNg3QO<^S`&j*~Gn{>EVs zxR*pNRn$hk&LNcF+?Yi^qY94KW?*a1x|SUi-hT?D9g;H<5{&+jHBc}hOm zdj*vl7UC^EfNey`1^rl=6l`Q?CFSq4*bMOG_mQ*^Flg1^(fw_&Y-`OZeY-=}|DHnc zws#3n@VnBJu%^LJoTGd{iEP$8WSv?VNt#?KxRqBB0Hd7YE&=clORv%ZxpLag*h~X6 z_)wt+d(BWpP;}P&iLbPINXnd;^4_OC)q*F-26%+~{JNnzpcE$_aNG)cDQe<7qn)O7 zZ#GaZcC^skw!{pu!zv375uy9gCVu%z$Nb0-5|NeZT~T-=EI6r?MP5F+M0H5I_gp15 z-e~zF`73$}EoT@wSc2833s5}wuOOL}#adD2xUHbgKVJ-f$p>6j)@!SJ>JN&1t4nSf zUzJ_a@Vg5ZAKz=(Bz zBqx-F8=YvtN2}Q-y6cgvA(ZIICvW?@HQSYJzY}3iPOuHwr!8b?CAm9j%)-DTFU4de z?DJYg#I>nw=F;wV*ZLNR=_1zvpA%=Sg?EY>cS4&UWTIdmoi{y*Yevjj{5cK z9y)={bq;Gyto)EFB4TjO;LC0CB&~9k5>^YdkZPJoEV=W7P?iXLGYv?DWUgs~@ zVgwRRRlf0L*_vc3&ZrSry8*qUV*15{pm~ryci!Z0^=&aO)kfx75ewJ5+80%NRO(zV z+EOg~GuXZTp_H^#^4fR#%@fDwk2ow9saRvwY{m2KLH$Q=!DWUq*=MZr%jSwty6@}( z`RgP!UZSt4n%~V8&)P4fC*1Sv{z&t&l}T^DQM(AA+z&AhMM!zm$4~V{@u0=a3=I*- zN;F;Gf6yd;A`!!eFV(p3{x>7KA@zLZ{-3;5k~&SeK6!t5^SLrQa@=`_>6Mu4+rg%~ zY}ofCm>Jo@K{WlmcWkQ7>T*#j>?30Y^|aUe1*Ue>h{vZOWS*`zhLPaVoX1$Ld!vE9 zbOv1=!xI!8nK9z+P$&TCCtLZG{+~8ANy{0lpWCC3oqC6(G)fI$M!> zS`gUJ;QBi=&Yt?owVq>47tb=aG49+xME>osI&de}w(aUT;LP z&xtQGxs6R;Jd>gSGur=#&(UideWx$%V*=UytwHU`Ofz}OK*DvvHZ2B%WnfYU7ce_; zTc4xhrhmY#HqYgN?>dVgKG*?ddJFCpt&d@B7eCRwFP=6#+cq+9rzHuDyzrHlUVK~+ z&p&JiRyyR*`Zs5;dNBq!cVI>^1_OaM>BcQ$Q=8^#k33&(2BTrH8j0B@l zk}#*R{;>bZC%C2>Ugyx>Mq+oU=Q3xd&Dk|He-mVs^lNBN6&F7kCmk36FCCYmoS~uP z)Grfng@v3ns)^vmSoBWj;Q+F3V4#jv8Kh*#!Fj)goRhMIN=`dUA3unXq*+(dLggs{ zs{Ea)ijk^N90fuRH^N)lcKp@8VIm&m? { + beforeAll(() => { + setBaseUrl(gerritEndpointUrl); + }); + + describe('getRepos()', () => { + it('returns repos', async () => { + httpMock + .scope(gerritEndpointUrl) + .get('/a/projects/?type=CODE&state=ACTIVE') + .reply( + 200, + gerritRestResponse({ + repo1: { id: 'repo1', state: 'ACTIVE' }, + repo2: { id: 'repo2', state: 'ACTIVE' }, + }), + jsonResultHeader, + ); + expect(await client.getRepos()).toEqual(['repo1', 'repo2']); + }); + }); + + describe('getProjectInfo()', () => { + it('inactive', async () => { + httpMock + .scope(gerritEndpointUrl) + .get('/a/projects/test%2Frepo') + .reply( + 200, + gerritRestResponse({ + id: 'repo1', + name: 'test-repo', + state: 'READ_ONLY', + }), + jsonResultHeader, + ); + await expect(client.getProjectInfo('test/repo')).rejects.toThrow( + REPOSITORY_ARCHIVED, + ); + }); + + it('active', async () => { + httpMock + .scope(gerritEndpointUrl) + .get('/a/projects/test%2Frepo') + .reply( + 200, + gerritRestResponse({ + id: 'repo1', + name: 'test-repo', + state: 'ACTIVE', + }), + jsonResultHeader, + ); + await expect(client.getProjectInfo('test/repo')).resolves.toEqual({ + id: 'repo1', + name: 'test-repo', + state: 'ACTIVE', + }); + }); + }); + + describe('getBranchInfo()', () => { + it('info', async () => { + httpMock + .scope(gerritEndpointUrl) + .get('/a/projects/test%2Frepo/branches/HEAD') + .reply( + 200, + gerritRestResponse({ ref: 'sha-hash....', revision: 'main' }), + jsonResultHeader, + ); + await expect(client.getBranchInfo('test/repo')).resolves.toEqual({ + ref: 'sha-hash....', + revision: 'main', + }); + }); + }); + + describe('findChanges()', () => { + it.each([ + ['owner:self', { branchName: 'dependency-xyz' }], + ['project:repo', { branchName: 'dependency-xyz' }], + ['-is:wip', { branchName: 'dependency-xyz' }], + ['hashtag:sourceBranch-dependency-xyz', { branchName: 'dependency-xyz' }], + ['label:Code-Review=-2', { branchName: 'dependency-xyz', label: '-2' }], + [ + 'branch:otherTarget', + { branchName: 'dependency-xyz', targetBranch: 'otherTarget' }, + ], + [ + 'status:closed', + { + branchName: 'dependency-xyz', + state: 'closed' as FindPRConfig['state'], + }, + ], + ])( + 'query contains %p', + async (expectedQueryPart: string, config: GerritFindPRConfig) => { + httpMock + .scope(gerritEndpointUrl) + .get('/a/changes/') + .query((query) => query?.q?.includes(expectedQueryPart) ?? false) + .reply( + 200, + gerritRestResponse([{ _number: 1 }, { _number: 2 }]), + jsonResultHeader, + ); + await expect(client.findChanges('repo', config)).resolves.toEqual([ + { _number: 1 }, + { _number: 2 }, + ]); + }, + ); + }); + + describe('getChange()', () => { + it('get', async () => { + const change = partial({}); + httpMock + .scope(gerritEndpointUrl) + .get( + '/a/changes/123456?o=SUBMITTABLE&o=CHECK&o=MESSAGES&o=DETAILED_ACCOUNTS&o=LABELS&o=CURRENT_ACTIONS&o=CURRENT_REVISION', + ) + .reply(200, gerritRestResponse(change), jsonResultHeader); + await expect(client.getChange(123456)).resolves.toEqual(change); + }); + }); + + describe('getMergeableInfo()', () => { + it('get', async () => { + const mergeInfo: GerritMergeableInfo = { + mergeable: true, + submit_type: 'MERGE_IF_NECESSARY', + }; + httpMock + .scope(gerritEndpointUrl) + .get('/a/changes/123456/revisions/current/mergeable') + .reply(200, gerritRestResponse(mergeInfo), jsonResultHeader); + await expect( + client.getMergeableInfo(partial({ _number: 123456 })), + ).resolves.toEqual(mergeInfo); + }); + }); + + describe('abandonChange()', () => { + it('abandon', async () => { + httpMock + .scope(gerritEndpointUrl) + .post('/a/changes/123456/abandon') + .reply(200, gerritRestResponse({}), jsonResultHeader); + await expect(client.abandonChange(123456)).toResolve(); + }); + }); + + describe('submitChange()', () => { + it('submit', async () => { + const change = partial({}); + httpMock + .scope(gerritEndpointUrl) + .post('/a/changes/123456/submit') + .reply(200, gerritRestResponse(change), jsonResultHeader); + await expect(client.submitChange(123456)).resolves.toEqual(change); + }); + }); + + describe('setCommitMessage()', () => { + it('setCommitMessage', async () => { + const change = partial({}); + httpMock + .scope(gerritEndpointUrl) + .put('/a/changes/123456/message', { message: 'new message' }) + .reply(200, gerritRestResponse(change), jsonResultHeader); + await expect(client.setCommitMessage(123456, 'new message')).toResolve(); + }); + }); + + describe('updateCommitMessage', () => { + it('updateCommitMessage - success', async () => { + const change = partial({}); + httpMock + .scope(gerritEndpointUrl) + .put('/a/changes/123456/message', { + message: `new message\n\nChange-Id: changeID\n`, + }) + .reply(200, gerritRestResponse(change), jsonResultHeader); + await expect( + client.updateCommitMessage(123456, 'changeID', 'new message'), + ).toResolve(); + }); + }); + + describe('getMessages()', () => { + it('no messages', async () => { + httpMock + .scope(gerritEndpointUrl) + .get('/a/changes/123456/messages') + .reply(200, gerritRestResponse([]), jsonResultHeader); + await expect(client.getMessages(123456)).resolves.toEqual([]); + }); + + it('with messages', async () => { + httpMock + .scope(gerritEndpointUrl) + .get('/a/changes/123456/messages') + .reply( + 200, + gerritRestResponse([ + partial({ message: 'msg1' }), + partial({ message: 'msg2' }), + ]), + jsonResultHeader, + ); + await expect(client.getMessages(123456)).resolves.toEqual([ + { message: 'msg1' }, + { message: 'msg2' }, + ]); + }); + }); + + describe('addMessage()', () => { + it('add with tag', async () => { + httpMock + .scope(gerritEndpointUrl) + .post('/a/changes/123456/revisions/current/review', { + message: 'message', + tag: 'tag', + }) + .reply(200, gerritRestResponse([]), jsonResultHeader); + await expect(client.addMessage(123456, 'message', 'tag')).toResolve(); + }); + + it('add without tag', async () => { + httpMock + .scope(gerritEndpointUrl) + .post('/a/changes/123456/revisions/current/review', { + message: 'message', + }) + .reply(200, gerritRestResponse([]), jsonResultHeader); + await expect(client.addMessage(123456, 'message')).toResolve(); + }); + }); + + describe('checkForExistingMessage()', () => { + it('msg not found', async () => { + httpMock + .scope(gerritEndpointUrl) + .get('/a/changes/123456/messages') + .reply(200, gerritRestResponse([]), jsonResultHeader); + await expect( + client.checkForExistingMessage(123456, ' the message '), + ).resolves.toBeFalse(); + }); + + it('msg found', async () => { + httpMock + .scope(gerritEndpointUrl) + .get('/a/changes/123456/messages') + .reply( + 200, + gerritRestResponse([ + partial({ message: 'msg1' }), + partial({ message: 'the message' }), + ]), + jsonResultHeader, + ); + await expect( + client.checkForExistingMessage(123456, 'the message'), + ).resolves.toBeTrue(); + }); + }); + + describe('addMessageIfNotAlreadyExists()', () => { + it('msg not found', async () => { + httpMock + .scope(gerritEndpointUrl) + .get('/a/changes/123456/messages') + .reply(200, gerritRestResponse([]), jsonResultHeader); + httpMock + .scope(gerritEndpointUrl) + .post('/a/changes/123456/revisions/current/review', { + message: 'new trimmed message', + tag: 'TAG', + }) + .reply(200, gerritRestResponse([]), jsonResultHeader); + + await expect( + client.addMessageIfNotAlreadyExists( + 123456, + ' new trimmed message\n', + 'TAG', + ), + ).toResolve(); + }); + + it('msg already exists', async () => { + httpMock + .scope(gerritEndpointUrl) + .get('/a/changes/123456/messages') + .reply( + 200, + gerritRestResponse([ + partial({ message: 'msg1', tag: 'TAG' }), + ]), + jsonResultHeader, + ); + + await expect( + client.addMessageIfNotAlreadyExists(123456, 'msg1\n', 'TAG'), + ).toResolve(); + }); + }); + + describe('setLabel()', () => { + it('setLabel', async () => { + httpMock + .scope(gerritEndpointUrl) + .post('/a/changes/123456/revisions/current/review', { + labels: { 'Code-Review': 2 }, + }) + .reply(200, gerritRestResponse([]), jsonResultHeader); + await expect(client.setLabel(123456, 'Code-Review', +2)).toResolve(); + }); + }); + + describe('addReviewer()', () => { + it('add', async () => { + httpMock + .scope(gerritEndpointUrl) + .post('/a/changes/123456/reviewers', { + reviewer: 'username', + }) + .reply(200, gerritRestResponse([]), jsonResultHeader); + await expect(client.addReviewer(123456, 'username')).toResolve(); + }); + }); + + describe('addAssignee()', () => { + it('add', async () => { + httpMock + .scope(gerritEndpointUrl) + .put('/a/changes/123456/assignee', { + assignee: 'username', + }) + .reply(200, gerritRestResponse([]), jsonResultHeader); + await expect(client.addAssignee(123456, 'username')).toResolve(); + }); + }); + + describe('getFile()', () => { + it('getFile() - repo and branch', async () => { + httpMock + .scope(gerritEndpointUrl) + .get( + '/a/projects/test%2Frepo/branches/main/files/renovate.json/content', + ) + .reply(200, gerritFileResponse('{}')); + await expect( + client.getFile('test/repo', 'main', 'renovate.json'), + ).resolves.toBe('{}'); + }); + }); + + describe('approveChange()', () => { + it('already approved - do nothing', async () => { + const change = partial({}); + httpMock + .scope(gerritEndpointUrl) + .get((url) => url.includes('/a/changes/123456?o=')) + .reply(200, gerritRestResponse(change), jsonResultHeader); + await expect(client.approveChange(123456)).toResolve(); + }); + + it('label not available - do nothing', async () => { + const change = partial({ labels: {} }); + httpMock + .scope(gerritEndpointUrl) + .get((url) => url.includes('/a/changes/123456?o=')) + .reply(200, gerritRestResponse(change), jsonResultHeader); + + await expect(client.approveChange(123456)).toResolve(); + }); + + it('not already approved - approve now', async () => { + const change = partial({ labels: { 'Code-Review': {} } }); + httpMock + .scope(gerritEndpointUrl) + .get((url) => url.includes('/a/changes/123456?o=')) + .reply(200, gerritRestResponse(change), jsonResultHeader); + const approveMock = httpMock + .scope(gerritEndpointUrl) + .post('/a/changes/123456/revisions/current/review', { + labels: { 'Code-Review': +2 }, + }) + .reply(200, gerritRestResponse(''), jsonResultHeader); + await expect(client.approveChange(123456)).toResolve(); + expect(approveMock.isDone()).toBeTrue(); + }); + }); + + describe('wasApprovedBy()', () => { + it('label not exists', () => { + expect( + client.wasApprovedBy(partial({}), 'user'), + ).toBeUndefined(); + }); + + it('not approved by anyone', () => { + expect( + client.wasApprovedBy( + partial({ + labels: { + 'Code-Review': {}, + }, + }), + 'user', + ), + ).toBeUndefined(); + }); + + it('approved by given user', () => { + expect( + client.wasApprovedBy( + partial({ + labels: { + 'Code-Review': { + approved: { + _account_id: 1, + username: 'user', + }, + }, + }, + }), + 'user', + ), + ).toBeTrue(); + }); + + it('approved by given other', () => { + expect( + client.wasApprovedBy( + partial({ + labels: { + 'Code-Review': { + approved: { + _account_id: 1, + username: 'other', + }, + }, + }, + }), + 'user', + ), + ).toBeFalse(); + }); + }); +}); + +function gerritRestResponse(body: any): any { + return `)]}'\n${JSON.stringify(body)}`; +} + +function gerritFileResponse(content: string): any { + return Buffer.from(content).toString('base64'); +} diff --git a/lib/modules/platform/gerrit/client.ts b/lib/modules/platform/gerrit/client.ts new file mode 100644 index 00000000000000..4a5e3ccebab75c --- /dev/null +++ b/lib/modules/platform/gerrit/client.ts @@ -0,0 +1,235 @@ +import { REPOSITORY_ARCHIVED } from '../../../constants/error-messages'; +import { logger } from '../../../logger'; +import { GerritHttp } from '../../../util/http/gerrit'; +import type { + GerritAccountInfo, + GerritBranchInfo, + GerritChange, + GerritChangeMessageInfo, + GerritFindPRConfig, + GerritMergeableInfo, + GerritProjectInfo, +} from './types'; +import { mapPrStateToGerritFilter } from './utils'; + +class GerritClient { + private requestDetails = [ + 'SUBMITTABLE', //include the submittable field in ChangeInfo, which can be used to tell if the change is reviewed and ready for submit. + 'CHECK', // include potential problems with the change. + 'MESSAGES', + 'DETAILED_ACCOUNTS', + 'LABELS', + 'CURRENT_ACTIONS', //to check if current_revision can be "rebased" + 'CURRENT_REVISION', //get RevisionInfo::ref to fetch + ] as const; + + private gerritHttp = new GerritHttp(); + + async getRepos(): Promise { + const res = await this.gerritHttp.getJson( + 'a/projects/?type=CODE&state=ACTIVE', + {}, + ); + return Object.keys(res.body); + } + + async getProjectInfo(repository: string): Promise { + const projectInfo = await this.gerritHttp.getJson( + `a/projects/${encodeURIComponent(repository)}`, + ); + if (projectInfo.body.state !== 'ACTIVE') { + throw new Error(REPOSITORY_ARCHIVED); + } + return projectInfo.body; + } + + async getBranchInfo(repository: string): Promise { + const branchInfo = await this.gerritHttp.getJson( + `a/projects/${encodeURIComponent(repository)}/branches/HEAD`, + ); + return branchInfo.body; + } + + async findChanges( + repository: string, + findPRConfig: GerritFindPRConfig, + refreshCache?: boolean, + ): Promise { + const filters = GerritClient.buildSearchFilters(repository, findPRConfig); + const changes = await this.gerritHttp.getJson( + `a/changes/?q=` + + filters.join('+') + + this.requestDetails.map((det) => `&o=${det}`).join(''), + { memCache: !refreshCache }, + ); + logger.trace( + `findChanges(${filters.join(', ')}) => ${changes.body.length}`, + ); + return changes.body; + } + + async getChange(changeNumber: number): Promise { + const changes = await this.gerritHttp.getJson( + `a/changes/${changeNumber}?` + + this.requestDetails.map((det) => `o=${det}`).join('&'), + ); + return changes.body; + } + + async getMergeableInfo(change: GerritChange): Promise { + const mergeable = await this.gerritHttp.getJson( + `a/changes/${change._number}/revisions/current/mergeable`, + ); + return mergeable.body; + } + + async abandonChange(changeNumber: number): Promise { + await this.gerritHttp.postJson(`a/changes/${changeNumber}/abandon`); + } + + async submitChange(changeNumber: number): Promise { + const change = await this.gerritHttp.postJson( + `a/changes/${changeNumber}/submit`, + ); + return change.body; + } + + async setCommitMessage(changeNumber: number, message: string): Promise { + await this.gerritHttp.putJson(`a/changes/${changeNumber}/message`, { + body: { message }, + }); + } + + async updateCommitMessage( + number: number, + gerritChangeID: string, + prTitle: string, + ): Promise { + await this.setCommitMessage( + number, + `${prTitle}\n\nChange-Id: ${gerritChangeID}\n`, + ); + } + + async getMessages(changeNumber: number): Promise { + const messages = await this.gerritHttp.getJson( + `a/changes/${changeNumber}/messages`, + { memCache: false }, + ); + return messages.body; + } + + async addMessage( + changeNumber: number, + message: string, + tag?: string, + ): Promise { + await this.gerritHttp.postJson( + `a/changes/${changeNumber}/revisions/current/review`, + { body: { message, tag } }, + ); + } + + async checkForExistingMessage( + changeNumber: number, + newMessage: string, + msgType?: string, + ): Promise { + const messages = await this.getMessages(changeNumber); + return messages.some( + (existingMsg) => + (msgType === undefined || msgType === existingMsg.tag) && + existingMsg.message.includes(newMessage), + ); + } + + async addMessageIfNotAlreadyExists( + changeNumber: number, + message: string, + tag?: string, + ): Promise { + const newMsg = message.trim(); //the last \n was removed from gerrit after the comment was added... + if (!(await this.checkForExistingMessage(changeNumber, newMsg, tag))) { + await this.addMessage(changeNumber, newMsg, tag); + } + } + + async setLabel( + changeNumber: number, + label: string, + value: number, + ): Promise { + await this.gerritHttp.postJson( + `a/changes/${changeNumber}/revisions/current/review`, + { body: { labels: { [label]: value } } }, + ); + } + + async addReviewer(changeNumber: number, reviewer: string): Promise { + await this.gerritHttp.postJson(`a/changes/${changeNumber}/reviewers`, { + body: { reviewer }, + }); + } + + async addAssignee(changeNumber: number, assignee: string): Promise { + await this.gerritHttp.putJson( + `a/changes/${changeNumber}/assignee`, + { + body: { assignee }, + }, + ); + } + + async getFile( + repo: string, + branch: string, + fileName: string, + ): Promise { + const base64Content = await this.gerritHttp.get( + `a/projects/${encodeURIComponent( + repo, + )}/branches/${branch}/files/${encodeURIComponent(fileName)}/content`, + ); + return Buffer.from(base64Content.body, 'base64').toString(); + } + + async approveChange(changeId: number): Promise { + const isApproved = await this.checkIfApproved(changeId); + if (!isApproved) { + await this.setLabel(changeId, 'Code-Review', +2); + } + } + + async checkIfApproved(changeId: number): Promise { + const change = await client.getChange(changeId); + const reviewLabels = change?.labels?.['Code-Review']; + return reviewLabels === undefined || reviewLabels.approved !== undefined; + } + + wasApprovedBy(change: GerritChange, username: string): boolean | undefined { + return ( + change.labels?.['Code-Review'].approved && + change.labels['Code-Review'].approved.username === username + ); + } + + private static buildSearchFilters( + repository: string, + searchConfig: GerritFindPRConfig, + ): string[] { + const filterState = mapPrStateToGerritFilter(searchConfig.state); + const filters = ['owner:self', 'project:' + repository, filterState]; + if (searchConfig.branchName !== '') { + filters.push(`hashtag:sourceBranch-${searchConfig.branchName}`); + } + if (searchConfig.targetBranch) { + filters.push(`branch:${searchConfig.targetBranch}`); + } + if (searchConfig.label) { + filters.push(`label:Code-Review=${searchConfig.label}`); + } + return filters; + } +} + +export const client = new GerritClient(); diff --git a/lib/modules/platform/gerrit/index.md b/lib/modules/platform/gerrit/index.md new file mode 100644 index 00000000000000..bc82cee7a834ae --- /dev/null +++ b/lib/modules/platform/gerrit/index.md @@ -0,0 +1,70 @@ +# Gerrit + +## Supported Gerrit versions + +Renovate supports all Gerrit 3.x versions. +Support for Gerrit is currently _experimental_, meaning that it _might_ still have some undiscovered bugs or design limitations, and that we _might_ need to change functionality in a non-backwards compatible manner in a non-major release. + +The current implementation uses Gerrit's "hashtags" feature. +Therefore you must use a Gerrit version that uses the [NoteDB](https://gerrit-review.googlesource.com/Documentation/note-db.html) backend. +We did not test Gerrit `2.x` with NoteDB (only in `2.15` and `2.16`), but could work. + +## Authentication + +
+ ![Gerrit HTTP access token](/assets/images/gerrit-http-password.png){ loading=lazy } +
First, create a HTTP access token for the Renovate account.
+
+ +Let Renovate use your HTTP access token by doing _one_ of the following: + +- Set your HTTP access token as a `password` in your `config.js` file, or +- Set your HTTP access token as an environment variable `RENOVATE_PASSWORD`, or +- Set your HTTP access token when you run Renovate in the CLI with `--password=` + +The Gerrit user account must be allowed to assign the Code-Review label with "+2" to their own changes for "automerge" to work. + +You must set `platform=gerrit` in your Renovate config file. + +## Renovate PR/Branch-Model with Gerrit and needed permissions + +If you use the "Code-Review" label and want to get `automerge` working then you must set `autoApprove=true` in your Renovate config. +Renovate will now add the _Code-Review_ label with the value "+2" to each of its "pull requests" (Gerrit-Change). + + +!!! note + The bot's user account must have permission to give +2 for the Code-Review label. + +The Renovate option `automergeType: "branch"` makes no sense for Gerrit, because there are no branches used to create pull requests. +It works similar to the default option `"pr"`. + +## Optional features + +You can use the `statusCheckNames` configuration to map any of the available branch checks (like `minimumReleaseAge`, `mergeConfidence`, and so on) to a Gerrit label. + +For example, if you want to use the [Merge Confidence](https://docs.renovatebot.com/merge-confidence/) feature and map the result of the Merge Confidence check to your Gerrit label "Renovate-Merge-Confidence" you can configure: + +```json +{ + "statusCheckNames": { + "mergeConfidence": "Renovate-Merge-Confidence" + } +} +``` + +## Unsupported platform features/concepts + +- Creating issues (not a Gerrit concept) +- Dependency Dashboard (needs issues first) + +## Known problems + +### PR title is different from first commit message + +Sometimes the PR title passed to the Gerrit platform code is different from the first line of the commit message. +For example: + +Commit-Message=`Update keycloak.version to v21` \ +Pull-Request-Title=`Update keycloak.version to v21 (major)` + +In this case the Gerrit-Platform implementation tries to detect this and change the commit-message in a second patch-set. diff --git a/lib/modules/platform/gerrit/index.spec.ts b/lib/modules/platform/gerrit/index.spec.ts new file mode 100644 index 00000000000000..7b5fa75db6b5ea --- /dev/null +++ b/lib/modules/platform/gerrit/index.spec.ts @@ -0,0 +1,764 @@ +import { git, mocked, partial } from '../../../../test/util'; +import { REPOSITORY_ARCHIVED } from '../../../constants/error-messages'; +import type { BranchStatus } from '../../../types'; +import * as _hostRules from '../../../util/host-rules'; +import { repoFingerprint } from '../util'; +import { client as _client } from './client'; +import type { + GerritAccountInfo, + GerritChange, + GerritChangeMessageInfo, + GerritLabelInfo, + GerritLabelTypeInfo, + GerritProjectInfo, +} from './types'; +import { TAG_PULL_REQUEST_BODY, mapGerritChangeToPr } from './utils'; +import { writeToConfig } from '.'; +import * as gerrit from '.'; + +const gerritEndpointUrl = 'https://dev.gerrit.com/renovate'; + +const codeReviewLabel: GerritLabelTypeInfo = { + values: { + '-2': 'bad', + '-1': 'unlikely', + 0: 'neutral', + 1: 'ok', + 2: 'good', + }, + default_value: 0, +}; + +jest.mock('../../../util/host-rules'); +jest.mock('../../../util/git'); +jest.mock('./client'); +const clientMock = mocked(_client); +const hostRules = mocked(_hostRules); + +describe('modules/platform/gerrit/index', () => { + beforeEach(async () => { + hostRules.find.mockReturnValue({ + username: 'user', + password: 'pass', + }); + writeToConfig({ + repository: 'test/repo', + labels: {}, + }); + await gerrit.initPlatform({ + endpoint: gerritEndpointUrl, + username: 'user', + password: 'pass', + }); + }); + + describe('initPlatform()', () => { + it('should throw if no endpoint', () => { + expect.assertions(1); + expect(() => gerrit.initPlatform({})).toThrow(); + }); + + it('should throw if no username/password', () => { + expect.assertions(1); + expect(() => gerrit.initPlatform({ endpoint: 'endpoint' })).toThrow(); + }); + + it('should init', async () => { + expect( + await gerrit.initPlatform({ + endpoint: gerritEndpointUrl, + username: 'abc', + password: '123', + }), + ).toEqual({ endpoint: 'https://dev.gerrit.com/renovate/' }); + }); + }); + + describe('getRepos()', () => { + it('returns repos', async () => { + clientMock.getRepos.mockResolvedValueOnce(['repo1', 'repo2']); + expect(await gerrit.getRepos()).toEqual(['repo1', 'repo2']); + }); + }); + + it('initRepo() - inactive', async () => { + clientMock.getProjectInfo.mockRejectedValueOnce( + new Error(REPOSITORY_ARCHIVED), + ); + await expect(gerrit.initRepo({ repository: 'test/repo' })).rejects.toThrow( + REPOSITORY_ARCHIVED, + ); + }); + + describe('initRepo()', () => { + const projectInfo: GerritProjectInfo = { + id: 'repo1', + name: 'test-repo2', + }; + + beforeEach(() => { + clientMock.getBranchInfo.mockResolvedValueOnce({ + ref: 'sha-hash....', + revision: 'main', + }); + }); + + it('initRepo() - active', async () => { + clientMock.getProjectInfo.mockResolvedValueOnce(projectInfo); + clientMock.findChanges.mockResolvedValueOnce([]); + expect(await gerrit.initRepo({ repository: 'test/repo' })).toEqual({ + defaultBranch: 'main', + isFork: false, + repoFingerprint: repoFingerprint('test/repo', `${gerritEndpointUrl}/`), + }); + expect(git.initRepo).toHaveBeenCalledWith({ + url: 'https://user:pass@dev.gerrit.com/renovate/a/test%2Frepo', + }); + }); + + it('initRepo() - abandon rejected changes', async () => { + clientMock.getProjectInfo.mockResolvedValueOnce({ + ...projectInfo, + labels: { 'Code-Review': codeReviewLabel }, + }); + clientMock.findChanges.mockResolvedValueOnce([ + partial({ _number: 1 }), + partial({ _number: 2 }), + ]); + + await gerrit.initRepo({ repository: 'test/repo' }); + + expect(clientMock.findChanges.mock.calls[0]).toEqual([ + 'test/repo', + { branchName: '', label: '-2', state: 'open' }, + ]); + expect(clientMock.abandonChange.mock.calls).toEqual([[1], [2]]); + }); + }); + + describe('findPr()', () => { + it('findPr() - no results', async () => { + clientMock.findChanges.mockResolvedValueOnce([]); + await expect( + gerrit.findPr({ branchName: 'branch', state: 'open' }), + ).resolves.toBeNull(); + expect(clientMock.findChanges).toHaveBeenCalledWith( + 'test/repo', + { branchName: 'branch', state: 'open' }, + undefined, + ); + }); + + it('findPr() - return the last change from search results', async () => { + clientMock.findChanges.mockResolvedValueOnce([ + partial({ _number: 1 }), + partial({ _number: 2 }), + ]); + await expect( + gerrit.findPr({ branchName: 'branch', state: 'open' }), + ).resolves.toHaveProperty('number', 2); + }); + }); + + describe('getPr()', () => { + it('getPr() - found', async () => { + const change = partial({}); + clientMock.getChange.mockResolvedValueOnce(change); + await expect(gerrit.getPr(123456)).resolves.toEqual( + mapGerritChangeToPr(change), + ); + expect(clientMock.getChange).toHaveBeenCalledWith(123456); + }); + + it('getPr() - not found', async () => { + clientMock.getChange.mockRejectedValueOnce({ statusCode: 404 }); + await expect(gerrit.getPr(123456)).resolves.toBeNull(); + }); + + it('getPr() - other error', async () => { + clientMock.getChange.mockRejectedValueOnce(new Error('other error')); + await expect(gerrit.getPr(123456)).rejects.toThrow(); + }); + }); + + describe('updatePr()', () => { + beforeAll(() => { + gerrit.writeToConfig({ labels: {} }); + }); + + it('updatePr() - new prTitle => copy to commit msg', async () => { + const change = partial({ + change_id: '...', + subject: 'old title', + }); + clientMock.getChange.mockResolvedValueOnce(change); + await gerrit.updatePr({ number: 123456, prTitle: 'new title' }); + expect(clientMock.updateCommitMessage).toHaveBeenCalledWith( + 123456, + '...', + 'new title', + ); + }); + + it('updatePr() - auto approve enabled', async () => { + const change = partial({}); + clientMock.getChange.mockResolvedValueOnce(change); + await gerrit.updatePr({ + number: 123456, + prTitle: 'subject', + platformOptions: { + autoApprove: true, + }, + }); + expect(clientMock.approveChange).toHaveBeenCalledWith(123456); + }); + + it('updatePr() - closed => abandon the change', async () => { + const change = partial({}); + clientMock.getChange.mockResolvedValueOnce(change); + await gerrit.updatePr({ + number: 123456, + prTitle: change.subject, + state: 'closed', + }); + expect(clientMock.abandonChange).toHaveBeenCalledWith(123456); + }); + + it('updatePr() - existing prBody found in change.messages => nothing todo...', async () => { + const change = partial({}); + clientMock.getChange.mockResolvedValueOnce(change); + clientMock.getMessages.mockResolvedValueOnce([ + partial({ + tag: TAG_PULL_REQUEST_BODY, + message: 'Last PR-Body', + }), + ]); + await gerrit.updatePr({ + number: 123456, + prTitle: 'title', + prBody: 'Last PR-Body', + }); + expect(clientMock.addMessage).not.toHaveBeenCalled(); + }); + + it('updatePr() - new prBody found in change.messages => add as message', async () => { + const change = partial({}); + clientMock.getChange.mockResolvedValueOnce(change); + clientMock.getMessages.mockResolvedValueOnce([]); + await gerrit.updatePr({ + number: 123456, + prTitle: change.subject, + prBody: 'NEW PR-Body', + }); + expect(clientMock.addMessageIfNotAlreadyExists).toHaveBeenCalledWith( + 123456, + 'NEW PR-Body', + TAG_PULL_REQUEST_BODY, + ); + }); + }); + + describe('createPr() - error ', () => { + it('createPr() - no existing found => rejects', async () => { + clientMock.findChanges.mockResolvedValueOnce([]); + await expect( + gerrit.createPr({ + sourceBranch: 'source', + targetBranch: 'target', + prTitle: 'title', + prBody: 'body', + }), + ).rejects.toThrow( + `the change should be created automatically from previous push to refs/for/source`, + ); + }); + }); + + describe('createPr() - success', () => { + beforeAll(() => { + gerrit.writeToConfig({ labels: {} }); + }); + + const change = partial({ + _number: 123456, + change_id: '...', + }); + + beforeEach(() => { + clientMock.findChanges.mockResolvedValueOnce([change]); + clientMock.getChange.mockResolvedValueOnce(change); + clientMock.getMessages.mockResolvedValueOnce([ + partial({ + tag: TAG_PULL_REQUEST_BODY, + message: 'Last PR-Body', + }), + ]); + }); + + it('createPr() - update body/title WITHOUT approve', async () => { + const pr = await gerrit.createPr({ + sourceBranch: 'source', + targetBranch: 'target', + prTitle: 'title', + prBody: 'body', + platformOptions: { + autoApprove: false, + }, + }); + expect(pr).toHaveProperty('number', 123456); + expect(clientMock.addMessageIfNotAlreadyExists).toHaveBeenCalledWith( + 123456, + 'body', + TAG_PULL_REQUEST_BODY, + ); + expect(clientMock.approveChange).not.toHaveBeenCalled(); + expect(clientMock.updateCommitMessage).toHaveBeenCalledWith( + 123456, + '...', + 'title', + ); + }); + + it('createPr() - update body and approve', async () => { + const pr = await gerrit.createPr({ + sourceBranch: 'source', + targetBranch: 'target', + prTitle: change.subject, + prBody: 'body', + platformOptions: { + autoApprove: true, + }, + }); + expect(pr).toHaveProperty('number', 123456); + expect(clientMock.addMessageIfNotAlreadyExists).toHaveBeenCalledWith( + 123456, + 'body', + TAG_PULL_REQUEST_BODY, + ); + expect(clientMock.approveChange).toHaveBeenCalledWith(123456); + expect(clientMock.setCommitMessage).not.toHaveBeenCalled(); + }); + }); + + describe('getBranchPr()', () => { + it('getBranchPr() - no result', async () => { + clientMock.findChanges.mockResolvedValue([]); + await expect( + gerrit.getBranchPr('renovate/dependency-1.x'), + ).resolves.toBeNull(); + expect(clientMock.findChanges).toHaveBeenCalledWith('test/repo', { + branchName: 'renovate/dependency-1.x', + state: 'open', + }); + }); + + it('getBranchPr() - found', async () => { + const change = partial({ + _number: 123456, + }); + clientMock.findChanges.mockResolvedValue([change]); + await expect( + gerrit.getBranchPr('renovate/dependency-1.x'), + ).resolves.toHaveProperty('number', 123456); + expect(clientMock.findChanges.mock.lastCall).toEqual([ + 'test/repo', + { state: 'open', branchName: 'renovate/dependency-1.x' }, + ]); + }); + }); + + describe('getPrList()', () => { + it('getPrList() - empty list', async () => { + clientMock.findChanges.mockResolvedValue([]); + await expect(gerrit.getPrList()).resolves.toEqual([]); + expect(clientMock.findChanges).toHaveBeenCalledWith('test/repo', { + branchName: '', + }); + }); + + it('getPrList() - multiple results', async () => { + const change = partial({}); + clientMock.findChanges.mockResolvedValue([change, change, change]); + await expect(gerrit.getPrList()).resolves.toHaveLength(3); + }); + }); + + describe('mergePr()', () => { + it('mergePr() - blocker by Verified', async () => { + clientMock.submitChange.mockRejectedValueOnce({ + statusCode: 409, + message: 'blocked by Verified', + }); + await expect(gerrit.mergePr({ id: 123456 })).resolves.toBeFalse(); + expect(clientMock.submitChange).toHaveBeenCalledWith(123456); + }); + + it('mergePr() - success', async () => { + clientMock.submitChange.mockResolvedValueOnce( + partial({ status: 'MERGED' }), + ); + await expect(gerrit.mergePr({ id: 123456 })).resolves.toBeTrue(); + }); + + it('mergePr() - other errors', async () => { + clientMock.submitChange.mockRejectedValueOnce( + new Error('any other error'), + ); + await expect(gerrit.mergePr({ id: 123456 })).rejects.toThrow(); + }); + }); + + describe('getBranchStatus()', () => { + it('getBranchStatus() - branchname/change not found => yellow', async () => { + clientMock.findChanges.mockResolvedValueOnce([]); + await expect( + gerrit.getBranchStatus('renovate/dependency-1.x'), + ).resolves.toBe('yellow'); + }); + + it('getBranchStatus() - branchname/changes found, submittable and not hasProblems => green', async () => { + const change = partial({ + submittable: true, + }); + clientMock.findChanges.mockResolvedValueOnce([change]); + await expect( + gerrit.getBranchStatus('renovate/dependency-1.x'), + ).resolves.toBe('green'); + }); + + it('getBranchStatus() - branchname/changes found and hasProblems => red', async () => { + const submittableChange = partial({ + submittable: true, + problems: [], + }); + const changeWithProblems = { ...submittableChange }; + changeWithProblems.submittable = false; + changeWithProblems.problems = [ + { message: 'error1' }, + { message: 'error2' }, + ]; + clientMock.findChanges.mockResolvedValueOnce([ + changeWithProblems, + submittableChange, + ]); + await expect( + gerrit.getBranchStatus('renovate/dependency-1.x'), + ).resolves.toBe('red'); + }); + }); + + describe('getBranchStatusCheck()', () => { + describe('GerritLabel is not available', () => { + beforeAll(() => { + writeToConfig({ labels: {} }); + }); + + it.each([ + 'unknownCtx', + 'renovate/stability-days', + 'renovate/merge-confidence', + ])('getBranchStatusCheck() - %s ', async (ctx) => { + await expect( + gerrit.getBranchStatusCheck('renovate/dependency-1.x', ctx), + ).resolves.toBe('yellow'); + expect(clientMock.findChanges).not.toHaveBeenCalled(); + }); + }); + + describe('GerritLabel is available', () => { + beforeEach(() => { + writeToConfig({ + labels: { + 'Renovate-Merge-Confidence': { + values: { '0': 'default', '-1': 'Unsatisfied', '1': 'Satisfied' }, + default_value: 0, + }, + }, + }); + }); + + it.each([ + { + label: 'Renovate-Merge-Confidence', + labelValue: { rejected: partial({}) }, + expectedState: 'red' as BranchStatus, + }, + { + label: 'Renovate-Merge-Confidence', + labelValue: { approved: partial({}) }, + expectedState: 'green' as BranchStatus, + }, + ])('$ctx/$labels', async ({ label, labelValue, expectedState }) => { + const change = partial({ + labels: { + [label]: partial({ ...labelValue }), + }, + }); + clientMock.findChanges.mockResolvedValueOnce([change]); + await expect( + gerrit.getBranchStatusCheck('renovate/dependency-1.x', label), + ).resolves.toBe(expectedState); + }); + }); + }); + + describe('setBranchStatus()', () => { + describe('GerritLabel is not available', () => { + beforeEach(() => { + writeToConfig({ labels: {} }); + }); + + it('setBranchStatus(renovate/stability-days)', async () => { + await expect( + gerrit.setBranchStatus({ + branchName: 'branch', + context: 'renovate/stability-days', + state: 'red', + description: 'desc', + }), + ).resolves.toBeUndefined(); + expect(clientMock.setLabel).not.toHaveBeenCalled(); + }); + + it('setBranchStatus(renovate/merge-confidence)', async () => { + await expect( + gerrit.setBranchStatus({ + branchName: 'branch', + context: 'renovate/merge-confidence', + state: 'red', + description: 'desc', + }), + ).resolves.toBeUndefined(); + }); + }); + + describe('GerritLabel is available', () => { + beforeEach(() => { + writeToConfig({ + labels: { + 'Renovate-Merge-Confidence': { + values: { '0': 'default', '-1': 'Unsatisfied', '1': 'Satisfied' }, + default_value: 0, + }, + }, + }); + }); + + it.each([ + { + ctx: 'Renovate-Merge-Confidence', + branchState: 'red' as BranchStatus, + expectedVote: -1, + expectedLabel: 'Renovate-Merge-Confidence', + }, + { + ctx: 'Renovate-Merge-Confidence', + branchState: 'yellow' as BranchStatus, + expectedVote: -1, + expectedLabel: 'Renovate-Merge-Confidence', + }, + { + ctx: 'Renovate-Merge-Confidence', + branchState: 'green' as BranchStatus, + expectedVote: 1, + expectedLabel: 'Renovate-Merge-Confidence', + }, + ])( + '$ctx/$branchState', + async ({ ctx, branchState, expectedVote, expectedLabel }) => { + const change = partial({ _number: 123456 }); + clientMock.findChanges.mockResolvedValueOnce([change]); + await gerrit.setBranchStatus({ + branchName: 'renovate/dependency-1.x', + context: ctx, + state: branchState, + description: 'desc', + }); + expect(clientMock.setLabel).toHaveBeenCalledWith( + 123456, + expectedLabel, + expectedVote, + ); + }, + ); + + it('no change found', async () => { + clientMock.findChanges.mockResolvedValueOnce([]); + await expect( + gerrit.setBranchStatus({ + branchName: 'renovate/dependency-1.x', + context: 'Renovate-Merge-Confidence', + state: 'red', + description: 'desc', + }), + ).resolves.toBeUndefined(); + expect(clientMock.setLabel).not.toHaveBeenCalled(); + }); + }); + }); + + describe('addReviewers()', () => { + it('addReviewers() - add reviewers', async () => { + await expect( + gerrit.addReviewers(123456, ['user1', 'user2']), + ).resolves.toBeUndefined(); + expect(clientMock.addReviewer).toHaveBeenCalledTimes(2); + expect(clientMock.addReviewer).toHaveBeenNthCalledWith( + 1, + 123456, + 'user1', + ); + expect(clientMock.addReviewer).toHaveBeenNthCalledWith( + 2, + 123456, + 'user2', + ); + }); + }); + + describe('addAssignees()', () => { + it('addAssignees() - set assignee', async () => { + await expect( + gerrit.addAssignees(123456, ['user1', 'user2']), + ).resolves.toBeUndefined(); + expect(clientMock.addAssignee).toHaveBeenCalledTimes(1); + expect(clientMock.addAssignee).toHaveBeenCalledWith(123456, 'user1'); + }); + }); + + describe('ensureComment()', () => { + it('ensureComment() - without tag', async () => { + await expect( + gerrit.ensureComment({ + number: 123456, + topic: null, + content: 'My-Comment-Msg', + }), + ).resolves.toBeTrue(); + expect(clientMock.addMessageIfNotAlreadyExists).toHaveBeenCalledWith( + 123456, + 'My-Comment-Msg', + undefined, + ); + }); + + it('ensureComment() - with tag', async () => { + await expect( + gerrit.ensureComment({ + number: 123456, + topic: 'myTopic', + content: 'My-Comment-Msg', + }), + ).resolves.toBeTrue(); + expect(clientMock.addMessageIfNotAlreadyExists).toHaveBeenCalledWith( + 123456, + 'My-Comment-Msg', + 'myTopic', + ); + }); + }); + + describe('getRawFile()', () => { + beforeEach(() => { + clientMock.getFile.mockResolvedValueOnce('{}'); + }); + + it('getRawFile() - repo and branch', async () => { + await expect( + gerrit.getRawFile('renovate.json', 'test/repo', 'main'), + ).resolves.toBe('{}'); + expect(clientMock.getFile).toHaveBeenCalledWith( + 'test/repo', + 'main', + 'renovate.json', + ); + }); + + it('getRawFile() - repo/branch from config', async () => { + writeToConfig({ + repository: 'repo', + head: 'master', + labels: {}, + }); + await expect(gerrit.getRawFile('renovate.json')).resolves.toBe('{}'); + expect(clientMock.getFile).toHaveBeenCalledWith( + 'repo', + 'master', + 'renovate.json', + ); + }); + + it('getRawFile() - repo/branch defaults', async () => { + writeToConfig({ + repository: undefined, + head: undefined, + labels: {}, + }); + await expect(gerrit.getRawFile('renovate.json')).resolves.toBe('{}'); + expect(clientMock.getFile).toHaveBeenCalledWith( + 'All-Projects', + 'HEAD', + 'renovate.json', + ); + }); + }); + + describe('getJsonFile()', () => { + //TODO: the wanted semantic is not clear + it('getJsonFile()', async () => { + clientMock.getFile.mockResolvedValueOnce('{}'); + await expect( + gerrit.getJsonFile('renovate.json', 'test/repo', 'main'), + ).resolves.toEqual({}); + }); + }); + + describe('getRepoForceRebase()', () => { + it('getRepoForceRebase()', async () => { + await expect(gerrit.getRepoForceRebase()).resolves.toBeFalse(); + }); + }); + + describe('massageMarkdown()', () => { + it('massageMarkdown()', () => { + expect(gerrit.massageMarkdown('Pull Requests')).toBe('Change-Requests'); + }); + //TODO: add some tests for Gerrit-specific replacements.. + }); + + describe('currently unused/not-implemented functions', () => { + it('deleteLabel()', async () => { + await expect( + gerrit.deleteLabel(123456, 'label'), + ).resolves.toBeUndefined(); + }); + + it('ensureCommentRemoval()', async () => { + await expect( + gerrit.ensureCommentRemoval({ + type: 'by-topic', + number: 123456, + topic: 'topic', + }), + ).resolves.toBeUndefined(); + }); + + it('ensureIssueClosing()', async () => { + await expect(gerrit.ensureIssueClosing('title')).resolves.toBeUndefined(); + }); + + it('ensureIssue()', async () => { + await expect( + gerrit.ensureIssue({ body: 'body', title: 'title' }), + ).resolves.toBeNull(); + }); + + it('findIssue()', async () => { + await expect(gerrit.findIssue('title')).resolves.toBeNull(); + }); + + it('getIssueList()', async () => { + await expect(gerrit.getIssueList()).resolves.toStrictEqual([]); + }); + }); +}); diff --git a/lib/modules/platform/gerrit/index.ts b/lib/modules/platform/gerrit/index.ts new file mode 100644 index 00000000000000..8b7c8abd44c15d --- /dev/null +++ b/lib/modules/platform/gerrit/index.ts @@ -0,0 +1,454 @@ +import { logger } from '../../../logger'; +import type { BranchStatus } from '../../../types'; +import { parseJson } from '../../../util/common'; +import * as git from '../../../util/git'; +import { setBaseUrl } from '../../../util/http/gerrit'; +import { regEx } from '../../../util/regex'; +import { ensureTrailingSlash } from '../../../util/url'; +import type { + BranchStatusConfig, + CreatePRConfig, + EnsureCommentConfig, + EnsureCommentRemovalConfigByContent, + EnsureCommentRemovalConfigByTopic, + EnsureIssueConfig, + EnsureIssueResult, + FindPRConfig, + Issue, + MergePRConfig, + PlatformParams, + PlatformResult, + Pr, + RepoParams, + RepoResult, + UpdatePrConfig, +} from '../types'; +import { repoFingerprint } from '../util'; + +import { smartTruncate } from '../utils/pr-body'; +import { readOnlyIssueBody } from '../utils/read-only-issue-body'; +import { client } from './client'; +import { configureScm } from './scm'; +import type { GerritLabelTypeInfo, GerritProjectInfo } from './types'; +import { + TAG_PULL_REQUEST_BODY, + getGerritRepoUrl, + mapBranchStatusToLabel, + mapGerritChangeToPr, +} from './utils'; + +export const id = 'gerrit'; + +const defaults: { + endpoint?: string; +} = {}; + +let config: { + repository?: string; + head?: string; + config?: GerritProjectInfo; + labels: Record; + gerritUsername?: string; +} = { + labels: {}, +}; + +export function writeToConfig(newConfig: typeof config): void { + config = { ...config, ...newConfig }; +} + +export function initPlatform({ + endpoint, + username, + password, +}: PlatformParams): Promise { + logger.debug(`initPlatform(${endpoint!}, ${username!})`); + if (!endpoint) { + throw new Error('Init: You must configure a Gerrit Server endpoint'); + } + if (!(username && password)) { + throw new Error( + 'Init: You must configure a Gerrit Server username/password', + ); + } + config.gerritUsername = username; + defaults.endpoint = ensureTrailingSlash(endpoint); + setBaseUrl(defaults.endpoint); + const platformConfig: PlatformResult = { + endpoint: defaults.endpoint, + }; + return Promise.resolve(platformConfig); +} + +/** + * Get all state="ACTIVE" and type="CODE" repositories from gerrit + */ +export async function getRepos(): Promise { + logger.debug(`getRepos()`); + return await client.getRepos(); +} + +/** + * Clone repository to local directory + * @param config + */ +export async function initRepo({ + repository, + gitUrl, +}: RepoParams): Promise { + logger.debug(`initRepo(${repository}, ${gitUrl!})`); + const projectInfo = await client.getProjectInfo(repository); + const branchInfo = await client.getBranchInfo(repository); + + config = { + ...config, + repository, + head: branchInfo.revision, + config: projectInfo, + labels: projectInfo.labels ?? {}, + }; + const baseUrl = defaults.endpoint!; + const url = getGerritRepoUrl(repository, baseUrl); + configureScm(repository, config.gerritUsername!); + await git.initRepo({ url }); + + //abandon "open" and "rejected" changes at startup + const rejectedChanges = await client.findChanges(config.repository!, { + branchName: '', + state: 'open', + label: '-2', + }); + for (const change of rejectedChanges) { + await client.abandonChange(change._number); + } + const repoConfig: RepoResult = { + defaultBranch: config.head!, + isFork: false, + repoFingerprint: repoFingerprint(repository, baseUrl), + }; + return repoConfig; +} + +export async function findPr( + findPRConfig: FindPRConfig, + refreshCache?: boolean, +): Promise { + const change = ( + await client.findChanges(config.repository!, findPRConfig, refreshCache) + ).pop(); + return change ? mapGerritChangeToPr(change) : null; +} + +export async function getPr(number: number): Promise { + try { + const change = await client.getChange(number); + return mapGerritChangeToPr(change); + } catch (err) { + if (err.statusCode === 404) { + return null; + } + throw err; + } +} + +export async function updatePr(prConfig: UpdatePrConfig): Promise { + logger.debug(`updatePr(${prConfig.number}, ${prConfig.prTitle})`); + const change = await client.getChange(prConfig.number); + if (change.subject !== prConfig.prTitle) { + await client.updateCommitMessage( + prConfig.number, + change.change_id, + prConfig.prTitle, + ); + } + if (prConfig.prBody) { + await client.addMessageIfNotAlreadyExists( + prConfig.number, + prConfig.prBody, + TAG_PULL_REQUEST_BODY, + ); + } + if (prConfig.platformOptions?.autoApprove) { + await client.approveChange(prConfig.number); + } + if (prConfig.state && prConfig.state === 'closed') { + await client.abandonChange(prConfig.number); + } +} + +export async function createPr(prConfig: CreatePRConfig): Promise { + logger.debug( + `createPr(${prConfig.sourceBranch}, ${prConfig.prTitle}, ${ + prConfig.labels?.toString() ?? '' + })`, + ); + const pr = ( + await client.findChanges( + config.repository!, + { + branchName: prConfig.sourceBranch, + targetBranch: prConfig.targetBranch, + state: 'open', + }, + true, + ) + ).pop(); + if (pr === undefined) { + throw new Error( + `the change should be created automatically from previous push to refs/for/${prConfig.sourceBranch}`, + ); + } + //Workaround for "Known Problems.1" + if (pr.subject !== prConfig.prTitle) { + await client.updateCommitMessage( + pr._number, + pr.change_id, + prConfig.prTitle, + ); + } + await client.addMessageIfNotAlreadyExists( + pr._number, + prConfig.prBody, + TAG_PULL_REQUEST_BODY, + ); + if (prConfig.platformOptions?.autoApprove) { + await client.approveChange(pr._number); + } + return getPr(pr._number); +} + +export async function getBranchPr(branchName: string): Promise { + const change = ( + await client.findChanges(config.repository!, { branchName, state: 'open' }) + ).pop(); + return change ? mapGerritChangeToPr(change) : null; +} + +export function getPrList(): Promise { + return client + .findChanges(config.repository!, { branchName: '' }) + .then((res) => res.map((change) => mapGerritChangeToPr(change))); +} + +export async function mergePr(config: MergePRConfig): Promise { + logger.debug( + `mergePr(${config.id}, ${config.branchName!}, ${config.strategy!})`, + ); + try { + const change = await client.submitChange(config.id); + return change.status === 'MERGED'; + } catch (err) { + if (err.statusCode === 409) { + logger.warn( + { err }, + "Can't submit the change, because the submit rule doesn't allow it.", + ); + return false; + } + throw err; + } +} + +/** + * BranchStatus for Gerrit assumes that the branchName refers to a change. + * @param branchName + */ +export async function getBranchStatus( + branchName: string, +): Promise { + logger.debug(`getBranchStatus(${branchName})`); + const changes = await client.findChanges( + config.repository!, + { state: 'open', branchName }, + true, + ); + if (changes.length > 0) { + const allSubmittable = + changes.filter((change) => change.submittable === true).length === + changes.length; + if (allSubmittable) { + return 'green'; + } + const hasProblems = + changes.filter((change) => change.problems.length > 0).length > 0; + if (hasProblems) { + return 'red'; + } + } + return 'yellow'; +} + +/** + * check the gerrit-change for the presence of the corresponding "$context" Gerrit label if configured, + * return 'yellow' if not configured or not set + * @param branchName + * @param context renovate/stability-days || ... + */ +export async function getBranchStatusCheck( + branchName: string, + context: string, +): Promise { + const label = config.labels[context]; + if (label) { + const change = ( + await client.findChanges( + config.repository!, + { branchName, state: 'open' }, + true, + ) + ).pop(); + if (change) { + const labelRes = change.labels?.[context]; + if (labelRes) { + if (labelRes.approved) { + return 'green'; + } + if (labelRes.rejected) { + return 'red'; + } + } + } + } + return 'yellow'; +} + +/** + * Apply the branch state $context to the corresponding gerrit label (if available) + * context === "renovate/stability-days" / "renovate/merge-confidence" and state === "green"/... + * @param branchStatusConfig + */ +export async function setBranchStatus( + branchStatusConfig: BranchStatusConfig, +): Promise { + const label = config.labels[branchStatusConfig.context]; + const labelValue = + label && mapBranchStatusToLabel(branchStatusConfig.state, label); + if (branchStatusConfig.context && labelValue) { + const pr = await getBranchPr(branchStatusConfig.branchName); + if (pr === null) { + return; + } + await client.setLabel(pr.number, branchStatusConfig.context, labelValue); + } +} + +export function getRawFile( + fileName: string, + repoName?: string, + branchOrTag?: string, +): Promise { + const repo = repoName ?? config.repository ?? 'All-Projects'; + const branch = + branchOrTag ?? (repo === config.repository ? config.head! : 'HEAD'); + return client.getFile(repo, branch, fileName); +} + +export async function getJsonFile( + fileName: string, + repoName?: string, + branchOrTag?: string, +): Promise { + const raw = await getRawFile(fileName, repoName, branchOrTag); + return parseJson(raw, fileName); +} + +export function getRepoForceRebase(): Promise { + return Promise.resolve(false); +} + +export async function addReviewers( + number: number, + reviewers: string[], +): Promise { + for (const reviewer of reviewers) { + await client.addReviewer(number, reviewer); + } +} + +/** + * add "CC" (only one possible) + */ +export async function addAssignees( + number: number, + assignees: string[], +): Promise { + if (assignees.length) { + if (assignees.length > 1) { + logger.debug( + `addAssignees(${number}, ${assignees.toString()}) called with more then one assignee! Gerrit only supports one assignee! Using the first from list.`, + ); + } + await client.addAssignee(number, assignees[0]); + } +} + +export async function ensureComment( + ensureComment: EnsureCommentConfig, +): Promise { + logger.debug( + `ensureComment(${ensureComment.number}, ${ensureComment.topic!}, ${ + ensureComment.content + })`, + ); + await client.addMessageIfNotAlreadyExists( + ensureComment.number, + ensureComment.content, + ensureComment.topic ?? undefined, + ); + return true; +} + +export function massageMarkdown(prBody: string): string { + //TODO: do more Gerrit specific replacements? + return smartTruncate(readOnlyIssueBody(prBody), 16384) //TODO: check the real gerrit limit (max. chars) + .replace(regEx(/Pull Request(s)?/g), 'Change-Request$1') + .replace(regEx(/\bPR(s)?\b/g), 'Change-Request$1') + .replace(regEx(/<\/?summary>/g), '**') + .replace(regEx(/<\/?details>/g), '') + .replace(regEx(/​/g), '') //remove zero-width-space not supported in gerrit-markdown + .replace( + 'close this Change-Request unmerged.', + 'abandon or down vote this Change-Request with -2.', + ) + .replace('Branch creation', 'Change creation') + .replace( + 'Close this Change-Request', + 'Down-vote this Change-Request with -2', + ) + .replace( + 'you tick the rebase/retry checkbox', + 'add "rebase!" at the beginning of the commit message.', + ) + .replace(regEx(`\n---\n\n.*?.*?\n`), '') + .replace(regEx(//g), ''); +} + +export function deleteLabel(number: number, label: string): Promise { + return Promise.resolve(); +} + +export function ensureCommentRemoval( + ensureCommentRemoval: + | EnsureCommentRemovalConfigByTopic + | EnsureCommentRemovalConfigByContent, +): Promise { + return Promise.resolve(); +} + +export function ensureIssueClosing(title: string): Promise { + return Promise.resolve(); +} + +export function ensureIssue( + issueConfig: EnsureIssueConfig, +): Promise { + return Promise.resolve(null); +} + +export function findIssue(title: string): Promise { + return Promise.resolve(null); +} + +export function getIssueList(): Promise { + return Promise.resolve([]); +} diff --git a/lib/modules/platform/gerrit/scm.spec.ts b/lib/modules/platform/gerrit/scm.spec.ts new file mode 100644 index 00000000000000..18667a04c4d4c5 --- /dev/null +++ b/lib/modules/platform/gerrit/scm.spec.ts @@ -0,0 +1,396 @@ +import { git, mocked, partial } from '../../../../test/util'; +import type { LongCommitSha } from '../../../util/git/types'; +import { client as _client } from './client'; +import { GerritScm, configureScm } from './scm'; +import type { + GerritAccountInfo, + GerritChange, + GerritRevisionInfo, +} from './types'; + +jest.mock('../../../util/git'); +jest.mock('./client'); +const clientMock = mocked(_client); + +describe('modules/platform/gerrit/scm', () => { + const gerritScm = new GerritScm(); + + beforeEach(() => { + configureScm('test/repo', 'user'); + }); + + describe('isBranchBehindBase()', () => { + it('no open change for with branchname found -> isBehind == true', async () => { + clientMock.findChanges.mockResolvedValueOnce([]); + await expect( + gerritScm.isBranchBehindBase('myBranchName', 'baseBranch'), + ).resolves.toBeTrue(); + expect(clientMock.findChanges).toHaveBeenCalledWith( + 'test/repo', + { + branchName: 'myBranchName', + state: 'open', + targetBranch: 'baseBranch', + }, + true, + ); + }); + + it('open change found for branchname, rebase action is available -> isBehind == true ', async () => { + const change = partial({ + current_revision: 'currentRevSha', + revisions: { + currentRevSha: partial({ + actions: { + rebase: { + enabled: true, + }, + }, + }), + }, + }); + clientMock.findChanges.mockResolvedValueOnce([change]); + await expect( + gerritScm.isBranchBehindBase('myBranchName', 'baseBranch'), + ).resolves.toBeTrue(); + }); + + it('open change found for branch name, but rebase action is not available -> isBehind == false ', async () => { + const change = partial({ + current_revision: 'currentRevSha', + revisions: { + currentRevSha: partial({ + actions: { + rebase: {}, + }, + }), + }, + }); + clientMock.findChanges.mockResolvedValueOnce([change]); + await expect( + gerritScm.isBranchBehindBase('myBranchName', 'baseBranch'), + ).resolves.toBeFalse(); + }); + }); + + describe('isBranchModified()', () => { + it('no open change for with branchname found -> not modified', async () => { + clientMock.findChanges.mockResolvedValueOnce([]); + await expect( + gerritScm.isBranchModified('myBranchName'), + ).resolves.toBeFalse(); + expect(clientMock.findChanges).toHaveBeenCalledWith( + 'test/repo', + { branchName: 'myBranchName', state: 'open' }, + true, + ); + }); + + it('open change found for branchname, but not modified', async () => { + const change = partial({ + current_revision: 'currentRevSha', + revisions: { + currentRevSha: partial({ + uploader: partial({ username: 'user' }), + }), + }, + }); + clientMock.findChanges.mockResolvedValueOnce([change]); + await expect( + gerritScm.isBranchModified('myBranchName'), + ).resolves.toBeFalse(); + }); + + it('open change found for branchname, but modified from other user', async () => { + const change = partial({ + current_revision: 'currentRevSha', + revisions: { + currentRevSha: partial({ + uploader: partial({ username: 'other_user' }), //!== gerritLogin + }), + }, + }); + clientMock.findChanges.mockResolvedValueOnce([change]); + await expect( + gerritScm.isBranchModified('myBranchName'), + ).resolves.toBeTrue(); + }); + }); + + describe('isBranchConflicted()', () => { + it('no open change with branch name found -> return true', async () => { + clientMock.findChanges.mockResolvedValueOnce([]); + await expect( + gerritScm.isBranchConflicted('target', 'myBranchName'), + ).resolves.toBe(true); + expect(clientMock.findChanges).toHaveBeenCalledWith('test/repo', { + branchName: 'myBranchName', + state: 'open', + targetBranch: 'target', + }); + }); + + it('open change found for branch name/baseBranch and its mergeable', async () => { + const change = partial({}); + clientMock.findChanges.mockResolvedValueOnce([change]); + clientMock.getMergeableInfo.mockResolvedValueOnce({ + submit_type: 'MERGE_IF_NECESSARY', + mergeable: true, + }); + await expect( + gerritScm.isBranchConflicted('target', 'myBranchName'), + ).resolves.toBeFalse(); + expect(clientMock.getMergeableInfo).toHaveBeenCalledWith(change); + }); + + it('open change found for branch name/baseBranch and its NOT mergeable', async () => { + const change = partial({}); + clientMock.findChanges.mockResolvedValueOnce([change]); + clientMock.getMergeableInfo.mockResolvedValueOnce({ + submit_type: 'MERGE_IF_NECESSARY', + mergeable: false, + }); + await expect( + gerritScm.isBranchConflicted('target', 'myBranchName'), + ).resolves.toBeTrue(); + expect(clientMock.getMergeableInfo).toHaveBeenCalledWith(change); + }); + }); + + describe('branchExists()', () => { + it('no change found for branch name -> return result from git.branchExists', async () => { + clientMock.findChanges.mockResolvedValueOnce([]); + git.branchExists.mockReturnValueOnce(true); + await expect(gerritScm.branchExists('myBranchName')).resolves.toBeTrue(); + expect(clientMock.findChanges).toHaveBeenCalledWith( + 'test/repo', + { + branchName: 'myBranchName', + state: 'open', + }, + true, + ); + expect(git.branchExists).toHaveBeenCalledWith('myBranchName'); + }); + + it('open change found for branch name -> return true', async () => { + const change = partial({}); + clientMock.findChanges.mockResolvedValueOnce([change]); + await expect(gerritScm.branchExists('myBranchName')).resolves.toBeTrue(); + expect(git.branchExists).not.toHaveBeenCalledWith('myBranchName'); + }); + }); + + describe('getBranchCommit()', () => { + it('no change found for branch name -> return result from git.getBranchCommit', async () => { + git.getBranchCommit.mockReturnValueOnce('shaHashValue' as LongCommitSha); + clientMock.findChanges.mockResolvedValueOnce([]); + await expect(gerritScm.getBranchCommit('myBranchName')).resolves.toBe( + 'shaHashValue', + ); + expect(clientMock.findChanges).toHaveBeenCalledWith( + 'test/repo', + { + branchName: 'myBranchName', + state: 'open', + }, + true, + ); + }); + + it('open change found for branchname -> return true', async () => { + const change = partial({ current_revision: 'curSha' }); + clientMock.findChanges.mockResolvedValueOnce([change]); + await expect(gerritScm.getBranchCommit('myBranchName')).resolves.toBe( + 'curSha', + ); + }); + }); + + it('deleteBranch()', async () => { + await expect(gerritScm.deleteBranch('branchName')).toResolve(); + }); + + describe('mergeToLocal', () => { + it('no change exists', async () => { + clientMock.findChanges.mockResolvedValueOnce([]); + git.mergeToLocal.mockResolvedValueOnce(); + + await expect(gerritScm.mergeToLocal('nonExistingChange')).toResolve(); + + expect(clientMock.findChanges).toHaveBeenCalledWith( + 'test/repo', + { + branchName: 'nonExistingChange', + state: 'open', + }, + true, + ); + expect(git.mergeToLocal).toHaveBeenCalledWith('nonExistingChange'); + }); + + it('change exists', async () => { + const change = partial({ + current_revision: 'curSha', + revisions: { + curSha: partial({ + ref: 'refs/changes/34/1234/1', + }), + }, + }); + clientMock.findChanges.mockResolvedValueOnce([change]); + git.mergeToLocal.mockResolvedValueOnce(); + + await expect(gerritScm.mergeToLocal('existingChange')).toResolve(); + + expect(clientMock.findChanges).toHaveBeenCalledWith( + 'test/repo', + { + branchName: 'existingChange', + state: 'open', + }, + true, + ); + expect(git.mergeToLocal).toHaveBeenCalledWith('refs/changes/34/1234/1'); + }); + }); + + describe('commitFiles()', () => { + it('commitFiles() - empty commit', async () => { + clientMock.findChanges.mockResolvedValueOnce([]); + git.prepareCommit.mockResolvedValueOnce(null); //empty commit + + await expect( + gerritScm.commitAndPush({ + branchName: 'renovate/dependency-1.x', + baseBranch: 'main', + message: 'commit msg', + files: [], + }), + ).resolves.toBeNull(); + expect(clientMock.findChanges).toHaveBeenCalledWith( + 'test/repo', + { + branchName: 'renovate/dependency-1.x', + state: 'open', + targetBranch: 'main', + }, + true, + ); + }); + + it('commitFiles() - create first Patch', async () => { + clientMock.findChanges.mockResolvedValueOnce([]); + git.prepareCommit.mockResolvedValueOnce({ + commitSha: 'commitSha' as LongCommitSha, + parentCommitSha: 'parentSha' as LongCommitSha, + files: [], + }); + git.pushCommit.mockResolvedValueOnce(true); + + expect( + await gerritScm.commitAndPush({ + branchName: 'renovate/dependency-1.x', + baseBranch: 'main', + message: 'commit msg', + files: [], + }), + ).toBe('commitSha'); + expect(git.prepareCommit).toHaveBeenCalledWith({ + baseBranch: 'main', + branchName: 'renovate/dependency-1.x', + files: [], + message: ['commit msg', expect.stringMatching(/Change-Id: I.{32}/)], + force: true, + }); + expect(git.pushCommit).toHaveBeenCalledWith({ + files: [], + sourceRef: 'renovate/dependency-1.x', + targetRef: 'refs/for/main%t=sourceBranch-renovate/dependency-1.x', + }); + }); + + it('commitFiles() - existing change-set without new changes', async () => { + const existingChange = partial({ + change_id: '...', + current_revision: 'commitSha', + revisions: { + commitSha: partial({ ref: 'refs/changes/1/2' }), + }, + }); + clientMock.findChanges.mockResolvedValueOnce([existingChange]); + git.prepareCommit.mockResolvedValueOnce({ + commitSha: 'commitSha' as LongCommitSha, + parentCommitSha: 'parentSha' as LongCommitSha, + files: [], + }); + git.pushCommit.mockResolvedValueOnce(true); + git.hasDiff.mockResolvedValueOnce(false); //no changes + + expect( + await gerritScm.commitAndPush({ + branchName: 'renovate/dependency-1.x', + baseBranch: 'main', + message: ['commit msg'], + files: [], + }), + ).toBeNull(); + expect(git.prepareCommit).toHaveBeenCalledWith({ + baseBranch: 'main', + branchName: 'renovate/dependency-1.x', + files: [], + message: ['commit msg', 'Change-Id: ...'], + force: true, + }); + expect(git.fetchRevSpec).toHaveBeenCalledWith('refs/changes/1/2'); + expect(git.pushCommit).toHaveBeenCalledTimes(0); + }); + + it('commitFiles() - existing change-set with new changes - auto-approve again', async () => { + const existingChange = partial({ + _number: 123456, + change_id: '...', + current_revision: 'commitSha', + revisions: { + commitSha: partial({ ref: 'refs/changes/1/2' }), + }, + }); + clientMock.findChanges.mockResolvedValueOnce([existingChange]); + clientMock.wasApprovedBy.mockReturnValueOnce(true); + git.prepareCommit.mockResolvedValueOnce({ + commitSha: 'commitSha' as LongCommitSha, + parentCommitSha: 'parentSha' as LongCommitSha, + files: [], + }); + git.pushCommit.mockResolvedValueOnce(true); + git.hasDiff.mockResolvedValueOnce(true); + + expect( + await gerritScm.commitAndPush({ + branchName: 'renovate/dependency-1.x', + baseBranch: 'main', + message: 'commit msg', + files: [], + }), + ).toBe('commitSha'); + expect(git.prepareCommit).toHaveBeenCalledWith({ + baseBranch: 'main', + branchName: 'renovate/dependency-1.x', + files: [], + message: ['commit msg', 'Change-Id: ...'], + force: true, + }); + expect(git.fetchRevSpec).toHaveBeenCalledWith('refs/changes/1/2'); + expect(git.pushCommit).toHaveBeenCalledWith({ + files: [], + sourceRef: 'renovate/dependency-1.x', + targetRef: 'refs/for/main%t=sourceBranch-renovate/dependency-1.x', + }); + expect(clientMock.wasApprovedBy).toHaveBeenCalledWith( + existingChange, + 'user', + ); + expect(clientMock.approveChange).toHaveBeenCalledWith(123456); + }); + }); +}); diff --git a/lib/modules/platform/gerrit/scm.ts b/lib/modules/platform/gerrit/scm.ts new file mode 100644 index 00000000000000..40fc56c88aab2e --- /dev/null +++ b/lib/modules/platform/gerrit/scm.ts @@ -0,0 +1,171 @@ +import { randomUUID } from 'crypto'; +import { logger } from '../../../logger'; +import * as git from '../../../util/git'; +import type { CommitFilesConfig, LongCommitSha } from '../../../util/git/types'; +import { hash } from '../../../util/hash'; +import { DefaultGitScm } from '../default-scm'; +import { client } from './client'; +import type { GerritFindPRConfig } from './types'; + +let repository: string; +let username: string; +export function configureScm(repo: string, login: string): void { + repository = repo; + username = login; +} + +export class GerritScm extends DefaultGitScm { + override async branchExists(branchName: string): Promise { + const searchConfig: GerritFindPRConfig = { state: 'open', branchName }; + const change = await client + .findChanges(repository, searchConfig, true) + .then((res) => res.pop()); + if (change) { + return true; + } + return git.branchExists(branchName); + } + + override async getBranchCommit( + branchName: string, + ): Promise { + const searchConfig: GerritFindPRConfig = { state: 'open', branchName }; + const change = await client + .findChanges(repository, searchConfig, true) + .then((res) => res.pop()); + if (change) { + return change.current_revision! as LongCommitSha; + } + return git.getBranchCommit(branchName); + } + + override async isBranchBehindBase( + branchName: string, + baseBranch: string, + ): Promise { + const searchConfig: GerritFindPRConfig = { + state: 'open', + branchName, + targetBranch: baseBranch, + }; + const change = await client + .findChanges(repository, searchConfig, true) + .then((res) => res.pop()); + if (change) { + const currentGerritPatchset = change.revisions![change.current_revision!]; + return currentGerritPatchset.actions?.['rebase'].enabled === true; + } + return true; + } + + override async isBranchConflicted( + baseBranch: string, + branch: string, + ): Promise { + const searchConfig: GerritFindPRConfig = { + state: 'open', + branchName: branch, + targetBranch: baseBranch, + }; + const change = (await client.findChanges(repository, searchConfig)).pop(); + if (change) { + const mergeInfo = await client.getMergeableInfo(change); + return !mergeInfo.mergeable; + } else { + logger.warn( + `There is no open change with branch=${branch} and baseBranch=${baseBranch}`, + ); + return true; + } + } + + override async isBranchModified(branchName: string): Promise { + const searchConfig: GerritFindPRConfig = { state: 'open', branchName }; + const change = await client + .findChanges(repository, searchConfig, true) + .then((res) => res.pop()); + if (change) { + const currentGerritPatchset = change.revisions![change.current_revision!]; + return currentGerritPatchset.uploader.username !== username; + } + return false; + } + + override async commitAndPush( + commit: CommitFilesConfig, + ): Promise { + logger.debug(`commitAndPush(${commit.branchName})`); + const searchConfig: GerritFindPRConfig = { + state: 'open', + branchName: commit.branchName, + targetBranch: commit.baseBranch, + }; + const existingChange = await client + .findChanges(repository, searchConfig, true) + .then((res) => res.pop()); + + let hasChanges = true; + const origMsg = + typeof commit.message === 'string' ? [commit.message] : commit.message; + commit.message = [ + ...origMsg, + `Change-Id: ${existingChange?.change_id ?? generateChangeId()}`, + ]; + const commitResult = await git.prepareCommit({ ...commit, force: true }); + if (commitResult) { + const { commitSha } = commitResult; + if (existingChange?.revisions && existingChange.current_revision) { + const fetchRefSpec = + existingChange.revisions[existingChange.current_revision].ref; + await git.fetchRevSpec(fetchRefSpec); //fetch current ChangeSet for git diff + hasChanges = await git.hasDiff('HEAD', 'FETCH_HEAD'); //avoid empty patchsets + } + if (hasChanges || commit.force) { + const pushResult = await git.pushCommit({ + sourceRef: commit.branchName, + targetRef: `refs/for/${commit.baseBranch!}%t=sourceBranch-${ + commit.branchName + }`, + files: commit.files, + }); + if (pushResult) { + //existingChange was the old change before commit/push. we need to approve again, if it was previously approved from renovate + if ( + existingChange && + client.wasApprovedBy(existingChange, username) + ) { + await client.approveChange(existingChange._number); + } + return commitSha; + } + } + } + return null; //empty commit, no changes in this Gerrit-Change + } + + override deleteBranch(branchName: string): Promise { + return Promise.resolve(); + } + + override async mergeToLocal(branchName: string): Promise { + const searchConfig: GerritFindPRConfig = { state: 'open', branchName }; + const change = await client + .findChanges(repository, searchConfig, true) + .then((res) => res.pop()); + if (change) { + return super.mergeToLocal( + change.revisions![change.current_revision!].ref, + ); + } + return super.mergeToLocal(branchName); + } +} + +/** + * This function should generate a Gerrit Change-ID analogous to the commit hook. We avoid the commit hook cause of security concerns. + * random=$( (whoami ; hostname ; date; cat $1 ; echo $RANDOM) | git hash-object --stdin) prefixed with an 'I'. + * TODO: Gerrit don't accept longer Change-IDs (sha256), but what happens with this https://git-scm.com/docs/hash-function-transition/ ? + */ +function generateChangeId(): string { + return 'I' + hash(randomUUID(), 'sha1'); +} diff --git a/lib/modules/platform/gerrit/types.ts b/lib/modules/platform/gerrit/types.ts new file mode 100644 index 00000000000000..7ec71999f4f1e2 --- /dev/null +++ b/lib/modules/platform/gerrit/types.ts @@ -0,0 +1,93 @@ +import type { FindPRConfig } from '../types'; + +export interface GerritFindPRConfig extends FindPRConfig { + label?: string; +} + +/** + * The Interfaces for the Gerrit API Responses ({@link https://gerrit-review.googlesource.com/Documentation/rest-api.html | REST-API}) + * minimized to only needed properties. + * + * @packageDocumentation + */ + +export interface GerritProjectInfo { + id: string; + name: string; + state?: 'ACTIVE' | 'READ_ONLY' | 'HIDDEN'; + labels?: Record; +} + +export interface GerritLabelTypeInfo { + values: Record; + default_value: number; +} + +export interface GerritBranchInfo { + ref: string; + revision: string; +} + +export type GerritChangeStatus = 'NEW' | 'MERGED' | 'ABANDONED'; + +export type GerritReviewersType = 'REVIEWER' | 'CC' | 'REMOVED'; + +export interface GerritChange { + branch: string; + hashtags?: string[]; + change_id: string; + subject: string; + status: GerritChangeStatus; + submittable?: boolean; + _number: number; + labels?: Record; + reviewers?: Record; + messages?: GerritChangeMessageInfo[]; + current_revision?: string; + /** + * All patch sets of this change as a map that maps the commit ID of the patch set to a RevisionInfo entity. + */ + revisions?: Record; + problems: unknown[]; +} + +export interface GerritRevisionInfo { + uploader: GerritAccountInfo; + /** + * The Git reference for the patch set. + */ + ref: string; + actions?: Record; +} + +export interface GerritChangeMessageInfo { + id: string; + message: string; + tag?: string; +} + +export interface GerritLabelInfo { + approved?: GerritAccountInfo; + rejected?: GerritAccountInfo; +} + +export interface GerritActionInfo { + method?: string; + enabled?: boolean; +} + +export interface GerritAccountInfo { + _account_id: number; + username?: string; +} + +export interface GerritMergeableInfo { + submit_type: + | 'MERGE_IF_NECESSARY' + | 'FAST_FORWARD_ONLY' + | 'REBASE_IF_NECESSARY' + | 'REBASE_ALWAYS' + | 'MERGE_ALWAYS' + | 'CHERRY_PICK'; + mergeable: boolean; +} diff --git a/lib/modules/platform/gerrit/utils.spec.ts b/lib/modules/platform/gerrit/utils.spec.ts new file mode 100644 index 00000000000000..f5159804473bea --- /dev/null +++ b/lib/modules/platform/gerrit/utils.spec.ts @@ -0,0 +1,251 @@ +import { mocked, partial } from '../../../../test/util'; +import { CONFIG_GIT_URL_UNAVAILABLE } from '../../../constants/error-messages'; +import type { BranchStatus } from '../../../types'; +import * as _hostRules from '../../../util/host-rules'; +import { setBaseUrl } from '../../../util/http/gerrit'; +import { hashBody } from '../pr-body'; +import type { + GerritAccountInfo, + GerritChange, + GerritChangeMessageInfo, + GerritChangeStatus, + GerritLabelTypeInfo, +} from './types'; +import * as utils from './utils'; +import { mapBranchStatusToLabel } from './utils'; + +jest.mock('../../../util/host-rules'); + +const baseUrl = 'https://gerrit.example.com'; +const hostRules = mocked(_hostRules); + +describe('modules/platform/gerrit/utils', () => { + beforeEach(() => { + setBaseUrl(baseUrl); + }); + + describe('getGerritRepoUrl()', () => { + it('create a git url with username/password', () => { + hostRules.find.mockReturnValue({ + username: 'abc', + password: '123', + }); + const repoUrl = utils.getGerritRepoUrl('web/apps', baseUrl); + expect(repoUrl).toBe('https://abc:123@gerrit.example.com/a/web%2Fapps'); + }); + + it('create a git url without username/password', () => { + hostRules.find.mockReturnValue({}); + expect(() => utils.getGerritRepoUrl('web/apps', baseUrl)).toThrow( + 'Init: You must configure a Gerrit Server username/password', + ); + }); + + it('throws on invalid endpoint', () => { + expect(() => utils.getGerritRepoUrl('web/apps', '...')).toThrow( + Error(CONFIG_GIT_URL_UNAVAILABLE), + ); + }); + }); + + describe('mapPrStateToGerritFilter()', () => { + it.each([ + ['closed', 'status:closed'], + ['merged', 'status:merged'], + ['!open', '-status:open'], + ['open', 'status:open'], + ['all', '-is:wip'], + [undefined, '-is:wip'], + ])( + 'maps pr state %p to gerrit filter %p', + (prState: any, filter: string) => { + expect(utils.mapPrStateToGerritFilter(prState)).toEqual(filter); + }, + ); + }); + + describe('mapGerritChangeStateToPrState()', () => { + it.each([ + ['NEW' as GerritChangeStatus, 'open'], + ['MERGED' as GerritChangeStatus, 'merged'], + ['ABANDONED' as GerritChangeStatus, 'closed'], + ['unknown' as GerritChangeStatus, 'all'], + ])( + 'maps gerrit change state %p to PrState %p', + (state: GerritChangeStatus, prState: any) => { + expect(utils.mapGerritChangeStateToPrState(state)).toEqual(prState); + }, + ); + }); + + describe('mapGerritChangeToPr()', () => { + it('map a gerrit change to to Pr', () => { + const change = partial({ + _number: 123456, + status: 'NEW', + hashtags: ['other', 'sourceBranch-renovate/dependency-1.x'], + branch: 'main', + subject: 'Fix for', + reviewers: { + REVIEWER: [partial({ username: 'username' })], + REMOVED: [], + CC: [], + }, + messages: [ + partial({ + id: '9d78ac236714cee8c2d86e95d638358925cf6853', + tag: 'pull-request', + message: 'Patch Set 1:\n\nOld PR-Body', + }), + partial({ + id: '1d17c930381e88e177bbc59595c3ec941bd21028', + tag: 'pull-request', + message: 'Patch Set 12:\n\nLast PR-Body', + }), + partial({ + id: '9d78ac236714cee8c2d86e95d638358925cf6853', + message: 'other message...', + }), + ], + }); + + expect(utils.mapGerritChangeToPr(change)).toEqual({ + number: 123456, + state: 'open', + title: 'Fix for', + sourceBranch: 'renovate/dependency-1.x', + targetBranch: 'main', + reviewers: ['username'], + bodyStruct: { + hash: hashBody('Last PR-Body'), + }, + }); + }); + + it('map a gerrit change without sourceBranch-tag and reviewers to Pr', () => { + const change = partial({ + _number: 123456, + status: 'NEW', + hashtags: ['other'], + branch: 'main', + subject: 'Fix for', + }); + expect(utils.mapGerritChangeToPr(change)).toEqual({ + number: 123456, + state: 'open', + title: 'Fix for', + sourceBranch: 'main', + targetBranch: 'main', + reviewers: [], + bodyStruct: { + hash: hashBody(''), + }, + }); + }); + }); + + describe('extractSourceBranch()', () => { + it('without hashtags', () => { + const change = partial({ + hashtags: undefined, + }); + expect(utils.extractSourceBranch(change)).toBeUndefined(); + }); + + it('no hashtag with "sourceBranch-" prefix', () => { + const change = partial({ + hashtags: ['other', 'another'], + }); + expect(utils.extractSourceBranch(change)).toBeUndefined(); + }); + + it('hashtag with "sourceBranch-" prefix', () => { + const change = partial({ + hashtags: ['other', 'sourceBranch-renovate/dependency-1.x', 'another'], + }); + expect(utils.extractSourceBranch(change)).toBe('renovate/dependency-1.x'); + }); + }); + + describe('findPullRequestBody()', () => { + it('find pull-request-body', () => { + const change = partial({ + messages: [ + partial({ + id: '9d78ac236714cee8c2d86e95d638358925cf6853', + tag: 'pull-request', + message: 'Patch Set 1:\n\nOld PR-Body', + }), + partial({ + id: '1d17c930381e88e177bbc59595c3ec941bd21028', + tag: 'pull-request', + message: 'Patch Set 12:\n\nLast PR-Body', + }), + partial({ + id: '9d78ac236714cee8c2d86e95d638358925cf6853', + message: 'other message...', + }), + ], + }); + expect(utils.findPullRequestBody(change)).toBe('Last PR-Body'); + }); + + it('no pull-request-body message found', () => { + const change = partial({}); + expect(utils.findPullRequestBody(change)).toBeUndefined(); + change.messages = []; + expect(utils.findPullRequestBody(change)).toBeUndefined(); + change.messages = [ + partial({ + tag: 'other-tag', + message: 'message', + }), + ]; + expect(utils.findPullRequestBody(change)).toBeUndefined(); + }); + }); + + describe('mapBranchStatusToLabel()', () => { + const labelWithOne: GerritLabelTypeInfo = { + values: { '-1': 'rejected', '0': 'default', '1': 'accepted' }, + default_value: 0, + }; + + it.each([ + ['red' as BranchStatus, -1], + ['yellow' as BranchStatus, -1], + ['green' as BranchStatus, 1], + ])( + 'Label with +1/-1 map branchState=%p to %p', + (branchState, expectedValue) => { + expect(mapBranchStatusToLabel(branchState, labelWithOne)).toEqual( + expectedValue, + ); + }, + ); + + const labelWithTwo: GerritLabelTypeInfo = { + values: { + '-2': 'rejected', + '-1': 'disliked', + '0': 'default', + '1': 'looksOkay', + '2': 'approved', + }, + default_value: 0, + }; + + it.each([ + ['red' as BranchStatus, -2], + ['yellow' as BranchStatus, -2], + ['green' as BranchStatus, 2], + ])( + 'Label with +2/-2, map branchState=%p to %p', + (branchState, expectedValue) => { + expect(mapBranchStatusToLabel(branchState, labelWithTwo)).toEqual( + expectedValue, + ); + }, + ); + }); +}); diff --git a/lib/modules/platform/gerrit/utils.ts b/lib/modules/platform/gerrit/utils.ts new file mode 100644 index 00000000000000..d42ec4a463b2e1 --- /dev/null +++ b/lib/modules/platform/gerrit/utils.ts @@ -0,0 +1,122 @@ +import { CONFIG_GIT_URL_UNAVAILABLE } from '../../../constants/error-messages'; +import { logger } from '../../../logger'; +import type { BranchStatus, PrState } from '../../../types'; +import * as hostRules from '../../../util/host-rules'; +import { joinUrlParts, parseUrl } from '../../../util/url'; +import { hashBody } from '../pr-body'; +import type { Pr } from '../types'; +import type { + GerritChange, + GerritChangeStatus, + GerritLabelTypeInfo, +} from './types'; + +export const TAG_PULL_REQUEST_BODY = 'pull-request'; + +export function getGerritRepoUrl(repository: string, endpoint: string): string { + // Find options for current host and determine Git endpoint + const opts = hostRules.find({ + hostType: 'gerrit', + url: endpoint, + }); + + const url = parseUrl(endpoint); + if (!url) { + throw new Error(CONFIG_GIT_URL_UNAVAILABLE); + } + if (!(opts.username && opts.password)) { + throw new Error( + 'Init: You must configure a Gerrit Server username/password', + ); + } + url.username = opts.username; + url.password = opts.password; + url.pathname = joinUrlParts( + url.pathname, + 'a', + encodeURIComponent(repository), + ); + logger.trace( + { url: url.toString() }, + 'using URL based on configured endpoint', + ); + return url.toString(); +} + +export function mapPrStateToGerritFilter(state?: PrState): string { + switch (state) { + case 'closed': + return 'status:closed'; + case 'merged': + return 'status:merged'; + case '!open': + return '-status:open'; + case 'open': + return 'status:open'; + case 'all': + default: + return '-is:wip'; + } +} + +export function mapGerritChangeToPr(change: GerritChange): Pr { + return { + number: change._number, + state: mapGerritChangeStateToPrState(change.status), + sourceBranch: extractSourceBranch(change) ?? change.branch, + targetBranch: change.branch, + title: change.subject, + reviewers: + change.reviewers?.REVIEWER?.filter( + (reviewer) => typeof reviewer.username === 'string', + ).map((reviewer) => reviewer.username!) ?? [], + bodyStruct: { + hash: hashBody(findPullRequestBody(change)), + }, + }; +} + +export function mapGerritChangeStateToPrState( + state: GerritChangeStatus, +): PrState { + switch (state) { + case 'NEW': + return 'open'; + case 'MERGED': + return 'merged'; + case 'ABANDONED': + return 'closed'; + } + return 'all'; +} +export function extractSourceBranch(change: GerritChange): string | undefined { + return change.hashtags + ?.find((tag) => tag.startsWith('sourceBranch-')) + ?.replace('sourceBranch-', ''); +} + +export function findPullRequestBody(change: GerritChange): string | undefined { + const msg = Array.from(change.messages ?? []) + .reverse() + .find((msg) => msg.tag === TAG_PULL_REQUEST_BODY); + if (msg) { + return msg.message.replace(/^Patch Set \d+:\n\n/, ''); //TODO: check how to get rid of the auto-added prefix? + } + return undefined; +} + +export function mapBranchStatusToLabel( + state: BranchStatus, + label: GerritLabelTypeInfo, +): number { + const numbers = Object.keys(label.values).map((x) => parseInt(x, 10)); + switch (state) { + case 'green': + return Math.max(...numbers); + case 'yellow': + case 'red': + return Math.min(...numbers); + } + // istanbul ignore next + return label.default_value; +} diff --git a/lib/modules/platform/scm.ts b/lib/modules/platform/scm.ts index 8f80217ec36da5..7adc03b7fad70f 100644 --- a/lib/modules/platform/scm.ts +++ b/lib/modules/platform/scm.ts @@ -2,6 +2,7 @@ import type { Constructor } from 'type-fest'; import type { PlatformId } from '../../constants'; import { PLATFORM_NOT_FOUND } from '../../constants/error-messages'; import { DefaultGitScm } from './default-scm'; +import { GerritScm } from './gerrit/scm'; import { GithubScm } from './github/scm'; import { LocalFs } from './local/scm'; import type { PlatformScm } from './types'; @@ -11,6 +12,7 @@ platformScmImpls.set('azure', DefaultGitScm); platformScmImpls.set('codecommit', DefaultGitScm); platformScmImpls.set('bitbucket', DefaultGitScm); platformScmImpls.set('bitbucket-server', DefaultGitScm); +platformScmImpls.set('gerrit', GerritScm); platformScmImpls.set('gitea', DefaultGitScm); platformScmImpls.set('github', GithubScm); platformScmImpls.set('gitlab', DefaultGitScm); diff --git a/lib/util/http/gerrit.spec.ts b/lib/util/http/gerrit.spec.ts new file mode 100644 index 00000000000000..7c99f72d5f4f01 --- /dev/null +++ b/lib/util/http/gerrit.spec.ts @@ -0,0 +1,74 @@ +import * as httpMock from '../../../test/http-mock'; +import { GerritHttp, setBaseUrl } from './gerrit'; + +const baseUrl = 'https://gerrit.example.com/'; + +describe('util/http/gerrit', () => { + let api: GerritHttp; + + beforeEach(() => { + api = new GerritHttp(); + setBaseUrl(baseUrl); + }); + + it.each(['some-url/', baseUrl + 'some-url/'])('get %p', async (pathOrUrl) => { + const body = 'body result'; + httpMock + .scope(baseUrl) + .get(/some-url\/$/) + .reply(200, body, { 'content-type': 'text/plain;charset=utf-8' }); + + const res = await api.get(pathOrUrl); + expect(res.body).toEqual(body); + }); + + it('getJson', async () => { + const body = { key: 'value' }; + httpMock + .scope(baseUrl) + .get('/some-url') + .matchHeader('a', 'b') + .reply(200, gerritResult(JSON.stringify(body)), { + 'content-type': 'application/json;charset=utf-8', + }); + + const res = await api + .getJson('some-url', { headers: { a: 'b' } }) + .then((res) => res.body); + return expect(res).toEqual(body); + }); + + it('postJson', () => { + httpMock + .scope(baseUrl) + .post('/some-url') + .matchHeader('content-Type', 'application/json') + .reply(200, gerritResult('{"res":"success"}'), { + 'content-type': 'application/json;charset=utf-8', + }); + + return expect( + api + .postJson('some-url', { body: { key: 'value' } }) + .then((res) => res.body), + ).resolves.toEqual({ res: 'success' }); + }); + + it('putJson', () => { + httpMock + .scope(baseUrl) + .put('/some-url') + .matchHeader('content-Type', 'application/json') + .reply(200, gerritResult('{"res":"success"}'), { + 'content-type': 'application/json;charset=utf-8', + }); + + return expect( + api.putJson('some-url', { body: { key: 'value' } }).then((r) => r.body), + ).resolves.toEqual({ res: 'success' }); + }); +}); + +function gerritResult(body: string): string { + return `)]}'\n${body}`; +} diff --git a/lib/util/http/gerrit.ts b/lib/util/http/gerrit.ts new file mode 100644 index 00000000000000..a163da021fc5ee --- /dev/null +++ b/lib/util/http/gerrit.ts @@ -0,0 +1,38 @@ +import { parseJson } from '../common'; +import { regEx } from '../regex'; +import { validateUrl } from '../url'; +import type { HttpOptions, HttpResponse, InternalHttpOptions } from './types'; +import { Http } from './index'; + +let baseUrl: string; +export function setBaseUrl(url: string): void { + baseUrl = url; +} + +/** + * Access Gerrit REST-API and strip-of the "magic prefix" from responses. + * @see https://gerrit-review.googlesource.com/Documentation/rest-api.html + */ +export class GerritHttp extends Http { + private static magicPrefix = regEx(/^\)]}'\n/g); + + constructor(options?: HttpOptions) { + super('gerrit', options); + } + + protected override async request( + path: string, + options?: InternalHttpOptions, + ): Promise> { + const url = validateUrl(path) ? path : baseUrl + path; + const opts: InternalHttpOptions = { + parseJson: (text: string) => + parseJson(text.replace(GerritHttp.magicPrefix, ''), path), + ...options, + }; + opts.headers = { + ...opts.headers, + }; + return await super.request(url, opts); + } +} diff --git a/lib/util/http/types.ts b/lib/util/http/types.ts index 86b5366ac53b64..5d3d2770a29d0f 100644 --- a/lib/util/http/types.ts +++ b/lib/util/http/types.ts @@ -2,6 +2,7 @@ import type { IncomingHttpHeaders } from 'node:http'; import type { OptionsOfBufferResponseBody, OptionsOfJSONResponseBody, + ParseJsonFunction, } from 'got'; export type GotContextOptions = { @@ -79,6 +80,7 @@ export interface InternalHttpOptions extends HttpOptions { json?: HttpOptions['body']; responseType?: 'json' | 'buffer'; method?: 'get' | 'post' | 'put' | 'patch' | 'delete' | 'head'; + parseJson?: ParseJsonFunction; } export interface HttpHeaders extends IncomingHttpHeaders { diff --git a/readme.md b/readme.md index 42fe148987e700..2d08611e813b30 100644 --- a/readme.md +++ b/readme.md @@ -39,6 +39,7 @@ Renovate works on these platforms: - [Azure DevOps](https://docs.renovatebot.com/modules/platform/azure/) - [AWS CodeCommit](https://docs.renovatebot.com/modules/platform/codecommit/) - [Gitea and Forgejo](https://docs.renovatebot.com/modules/platform/gitea/) +- [Gerrit (experimental)](https://docs.renovatebot.com/modules/platform/gerrit/) ## Who Uses Renovate? From d8ad99facafc515c75999b0e69051f64bc49b76d Mon Sep 17 00:00:00 2001 From: valodzka Date: Sat, 30 Dec 2023 11:52:31 +0300 Subject: [PATCH 123/173] fix(platform/gerrit): Check for comment size limit (#26454) --- lib/modules/platform/gerrit/client.spec.ts | 12 ++++++++++++ lib/modules/platform/gerrit/client.ts | 10 ++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/lib/modules/platform/gerrit/client.spec.ts b/lib/modules/platform/gerrit/client.spec.ts index 8d64188c9f0fa3..620ec9d5baef57 100644 --- a/lib/modules/platform/gerrit/client.spec.ts +++ b/lib/modules/platform/gerrit/client.spec.ts @@ -256,6 +256,18 @@ describe('modules/platform/gerrit/client', () => { .reply(200, gerritRestResponse([]), jsonResultHeader); await expect(client.addMessage(123456, 'message')).toResolve(); }); + + it('add too big message', async () => { + const okMessage = 'a'.repeat(0x4000); + const tooBigMessage = okMessage + 'b'; + httpMock + .scope(gerritEndpointUrl) + .post('/a/changes/123456/revisions/current/review', { + message: okMessage, + }) + .reply(200, gerritRestResponse([]), jsonResultHeader); + await expect(client.addMessage(123456, tooBigMessage)).toResolve(); + }); }); describe('checkForExistingMessage()', () => { diff --git a/lib/modules/platform/gerrit/client.ts b/lib/modules/platform/gerrit/client.ts index 4a5e3ccebab75c..543328189ba7da 100644 --- a/lib/modules/platform/gerrit/client.ts +++ b/lib/modules/platform/gerrit/client.ts @@ -121,9 +121,10 @@ class GerritClient { async addMessage( changeNumber: number, - message: string, + fullMessage: string, tag?: string, ): Promise { + const message = this.normalizeMessage(fullMessage); await this.gerritHttp.postJson( `a/changes/${changeNumber}/revisions/current/review`, { body: { message, tag } }, @@ -148,7 +149,7 @@ class GerritClient { message: string, tag?: string, ): Promise { - const newMsg = message.trim(); //the last \n was removed from gerrit after the comment was added... + const newMsg = this.normalizeMessage(message); if (!(await this.checkForExistingMessage(changeNumber, newMsg, tag))) { await this.addMessage(changeNumber, newMsg, tag); } @@ -213,6 +214,11 @@ class GerritClient { ); } + normalizeMessage(message: string): string { + //the last \n was removed from gerrit after the comment was added... + return message.substring(0, 0x4000).trim(); + } + private static buildSearchFilters( repository: string, searchConfig: GerritFindPRConfig, From 7257145836f32f860ca2fbaa7b6418e3f938397e Mon Sep 17 00:00:00 2001 From: Adam Bouqdib Date: Sat, 30 Dec 2023 14:16:30 +0000 Subject: [PATCH 124/173] feat(presets): add testcontainers-go monorepo (#26457) --- lib/config/presets/internal/monorepo.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/config/presets/internal/monorepo.ts b/lib/config/presets/internal/monorepo.ts index 92d971222e7dc2..e7721bffd709a7 100644 --- a/lib/config/presets/internal/monorepo.ts +++ b/lib/config/presets/internal/monorepo.ts @@ -457,6 +457,7 @@ const repoGroups = { 'telus-tds': 'https://github.com/telusdigital/tds', 'telus-tds-core': 'https://github.com/telus/tds-core', 'temporalio-ts': 'https://github.com/temporalio/sdk-typescript', + 'testcontainers-go': 'https://github.com/testcontainers/testcontainers-go', 'testcontainers-java': 'https://github.com/testcontainers/testcontainers-java', 'testcontainers-node': From ed8e15eddbd32f61a7037d775afb52405508cf96 Mon Sep 17 00:00:00 2001 From: Adam Bouqdib Date: Sat, 30 Dec 2023 17:16:12 +0000 Subject: [PATCH 125/173] feat(presets): add gocloud.dev monorepo (#26456) --- lib/config/presets/internal/monorepo.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/config/presets/internal/monorepo.ts b/lib/config/presets/internal/monorepo.ts index e7721bffd709a7..bf310d9e5e83d6 100644 --- a/lib/config/presets/internal/monorepo.ts +++ b/lib/config/presets/internal/monorepo.ts @@ -287,6 +287,7 @@ const repoGroups = { gitbeaker: 'https://github.com/jdalrymple/gitbeaker', 'github-workflows-kt': 'https://github.com/typesafegithub/github-workflows-kt', + 'go-cloud': 'https://github.com/google/go-cloud', 'google-api-dotnet-client': 'https://github.com/googleapis/google-api-dotnet-client', grafana: 'https://github.com/grafana/grafana', From f8c7999eff5bed4032ed5ee50ddd5b232f9a481e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Zaj=C4=85czkowski?= <148013+szpak@users.noreply.github.com> Date: Sat, 30 Dec 2023 18:27:17 +0100 Subject: [PATCH 126/173] feat(autodiscover): restore INFO logging of number of found repos (#26458) --- lib/workers/global/autodiscover.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/workers/global/autodiscover.ts b/lib/workers/global/autodiscover.ts index 963ae4dbac6437..f70f925f030d1c 100644 --- a/lib/workers/global/autodiscover.ts +++ b/lib/workers/global/autodiscover.ts @@ -61,12 +61,12 @@ export async function autodiscoverRepositories( logger.debug('None of the discovered repositories matched the filter'); return config; } - logger.debug( - `Autodiscovered ${discovered.length} repositories after filter`, - ); } - logger.info({ repositories: discovered }, `Autodiscovered repositories`); + logger.info( + { length: discovered.length, repositories: discovered }, + `Autodiscovered repositories`, + ); // istanbul ignore if if (config.repositories?.length) { From f14bcc094d805b14d0857ca6b973cceb125e51c0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 1 Jan 2024 01:43:08 +0000 Subject: [PATCH 127/173] docs: update references to renovate/renovate to v37.115.0 (#26463) 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 958a4d00370a1d..f32118662c16b9 100644 --- a/docs/usage/docker.md +++ b/docs/usage/docker.md @@ -383,7 +383,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:37.107.0 +FROM renovate/renovate:37.115.0 # Include the "Docker tip" which you can find here https://cloud.google.com/sdk/docs/install # under "Installation" for "Debian/Ubuntu" RUN ... From f472aeaf84c9fa2acd8a616999cb7b95b17e57d4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 1 Jan 2024 01:45:48 +0000 Subject: [PATCH 128/173] chore(deps): lock file maintenance (#26464) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- pnpm-lock.yaml | 221 ++++++++++++++++++++++++------------------------- 1 file changed, 110 insertions(+), 111 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4dc154501e13e2..1d7d1e3a0a3388 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -591,7 +591,7 @@ importers: version: 3.0.3 ts-jest: specifier: 29.1.1 - version: 29.1.1(@babel/core@7.23.6)(@jest/types@29.6.3)(jest@29.7.0)(typescript@5.3.3) + version: 29.1.1(@babel/core@7.23.7)(@jest/types@29.6.3)(jest@29.7.0)(typescript@5.3.3) ts-node: specifier: 10.9.2 version: 10.9.2(@swc/core@1.3.101)(@types/node@18.19.3)(typescript@5.3.3) @@ -1574,19 +1574,19 @@ packages: engines: {node: '>=6.9.0'} dev: true - /@babel/core@7.23.6: - resolution: {integrity: sha512-FxpRyGjrMJXh7X3wGLGhNDCRiwpWEF74sKjTLDJSG5Kyvow3QZaG0Adbqzi9ZrVjTWpsX+2cxWXD71NMg93kdw==} + /@babel/core@7.23.7: + resolution: {integrity: sha512-+UpDgowcmqe36d4NwqvKsyPMlOLNGMsfMmQ5WGCu+siCe3t3dfe9njrzGfdN4qq+bcNUt0+Vw6haRxBOycs4dw==} engines: {node: '>=6.9.0'} dependencies: '@ampproject/remapping': 2.2.1 '@babel/code-frame': 7.23.5 '@babel/generator': 7.23.6 '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.6) - '@babel/helpers': 7.23.6 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.7) + '@babel/helpers': 7.23.7 '@babel/parser': 7.23.6 '@babel/template': 7.22.15 - '@babel/traverse': 7.23.6 + '@babel/traverse': 7.23.7 '@babel/types': 7.23.6 convert-source-map: 2.0.0 debug: 4.3.4 @@ -1645,13 +1645,13 @@ packages: '@babel/types': 7.23.6 dev: true - /@babel/helper-module-transforms@7.23.3(@babel/core@7.23.6): + /@babel/helper-module-transforms@7.23.3(@babel/core@7.23.7): resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.23.6 + '@babel/core': 7.23.7 '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-module-imports': 7.22.15 '@babel/helper-simple-access': 7.22.5 @@ -1692,12 +1692,12 @@ packages: engines: {node: '>=6.9.0'} dev: true - /@babel/helpers@7.23.6: - resolution: {integrity: sha512-wCfsbN4nBidDRhpDhvcKlzHWCTlgJYUUdSJfzXb2NuBssDSIjc3xcb+znA7l+zYsFljAcGM0aFkN40cR3lXiGA==} + /@babel/helpers@7.23.7: + resolution: {integrity: sha512-6AMnjCoC8wjqBzDHkuqpa7jAKwvMo4dC+lr/TFBz+ucfulO1XMpDnwWPGBNwClOKZ8h6xn5N81W/R5OrcKtCbQ==} engines: {node: '>=6.9.0'} dependencies: '@babel/template': 7.22.15 - '@babel/traverse': 7.23.6 + '@babel/traverse': 7.23.7 '@babel/types': 7.23.6 transitivePeerDependencies: - supports-color @@ -1719,140 +1719,140 @@ packages: '@babel/types': 7.23.6 dev: true - /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.23.6): + /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.23.7): resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.6 + '@babel/core': 7.23.7 '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.23.6): + /@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.23.7): resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.6 + '@babel/core': 7.23.7 '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.23.6): + /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.23.7): resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.6 + '@babel/core': 7.23.7 '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.23.6): + /@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.23.7): resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.6 + '@babel/core': 7.23.7 '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.23.6): + /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.23.7): resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.6 + '@babel/core': 7.23.7 '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-jsx@7.23.3(@babel/core@7.23.6): + /@babel/plugin-syntax-jsx@7.23.3(@babel/core@7.23.7): resolution: {integrity: sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.6 + '@babel/core': 7.23.7 '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.23.6): + /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.23.7): resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.6 + '@babel/core': 7.23.7 '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.23.6): + /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.23.7): resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.6 + '@babel/core': 7.23.7 '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.23.6): + /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.23.7): resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.6 + '@babel/core': 7.23.7 '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.23.6): + /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.23.7): resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.6 + '@babel/core': 7.23.7 '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.23.6): + /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.23.7): resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.6 + '@babel/core': 7.23.7 '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.23.6): + /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.23.7): resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.6 + '@babel/core': 7.23.7 '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.23.6): + /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.23.7): resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.6 + '@babel/core': 7.23.7 '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-typescript@7.23.3(@babel/core@7.23.6): + /@babel/plugin-syntax-typescript@7.23.3(@babel/core@7.23.7): resolution: {integrity: sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.6 + '@babel/core': 7.23.7 '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/runtime-corejs3@7.23.6: - resolution: {integrity: sha512-Djs/ZTAnpyj0nyg7p1J6oiE/tZ9G2stqAFlLGZynrW+F3k2w2jGK2mLOBxzYIOcZYA89+c3d3wXKpYLcpwcU6w==} + /@babel/runtime-corejs3@7.23.7: + resolution: {integrity: sha512-ER55qzLREVA5YxeyQ3Qu48tgsF2ZrFjFjUS6V6wF0cikSw+goBJgB9PBRM1T6+Ah4iiM+sxmfS/Sy/jdzFfhiQ==} engines: {node: '>=6.9.0'} dependencies: - core-js-pure: 3.34.0 + core-js-pure: 3.35.0 regenerator-runtime: 0.14.1 dev: false @@ -1865,8 +1865,8 @@ packages: '@babel/types': 7.23.6 dev: true - /@babel/traverse@7.23.6: - resolution: {integrity: sha512-czastdK1e8YByZqezMPFiZ8ahwVMh/ESl9vPgvgdB9AmFMGP5jfpFax74AQgl5zj4XHzqeYAg2l8PuUeRS1MgQ==} + /@babel/traverse@7.23.7: + resolution: {integrity: sha512-tY3mM8rH9jM0YHFGyfC0/xf+SB5eKUu7HPj7/k3fpi9dAlsMc5YbQvDi0Sh2QTPXqMhyaAtzAr807TIyfQrmyg==} engines: {node: '>=6.9.0'} dependencies: '@babel/code-frame': 7.23.5 @@ -2210,7 +2210,7 @@ packages: resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@babel/core': 7.23.6 + '@babel/core': 7.23.7 '@jest/types': 29.6.3 '@jridgewell/trace-mapping': 0.3.20 babel-plugin-istanbul: 6.1.1 @@ -2791,7 +2791,7 @@ packages: /@qnighy/marshal@0.1.3: resolution: {integrity: sha512-uaDZTJYtD2UgQTGemmgWeth+e2WapZm+GkAq8UU8AJ55PKRFaf1GkH7X/uzA+Ygu8iInzIlM2FGyCUnruyMKMg==} dependencies: - '@babel/runtime-corejs3': 7.23.6 + '@babel/runtime-corejs3': 7.23.7 dev: false /@redis/bloom@1.2.0(@redis/client@1.5.13): @@ -2950,7 +2950,7 @@ packages: issue-parser: 6.0.0 lodash-es: 4.17.21 mime: 4.0.1 - p-filter: 4.0.0 + p-filter: 4.1.0 semantic-release: 22.0.12(typescript@5.3.3) url-join: 5.0.0 transitivePeerDependencies: @@ -3652,7 +3652,7 @@ packages: '@babel/types': 7.23.6 '@types/babel__generator': 7.6.8 '@types/babel__template': 7.4.4 - '@types/babel__traverse': 7.20.4 + '@types/babel__traverse': 7.20.5 dev: true /@types/babel__generator@7.6.8: @@ -3668,8 +3668,8 @@ packages: '@babel/types': 7.23.6 dev: true - /@types/babel__traverse@7.20.4: - resolution: {integrity: sha512-mSM/iKUk5fDDrEV/e83qY+Cr3I1+Q3qqTuEn++HAWYjEa1+NxZr6CNrcJGf2ZTnq4HoFGC3zaTPZTobCzCFukA==} + /@types/babel__traverse@7.20.5: + resolution: {integrity: sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==} dependencies: '@babel/types': 7.23.6 dev: true @@ -4291,20 +4291,20 @@ packages: dev: false optional: true - /acorn-import-assertions@1.9.0(acorn@8.11.2): + /acorn-import-assertions@1.9.0(acorn@8.11.3): resolution: {integrity: sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==} peerDependencies: acorn: ^8 dependencies: - acorn: 8.11.2 + acorn: 8.11.3 dev: false - /acorn-jsx@5.3.2(acorn@8.11.2): + /acorn-jsx@5.3.2(acorn@8.11.3): resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: - acorn: 8.11.2 + acorn: 8.11.3 dev: true /acorn-walk@8.3.1: @@ -4312,8 +4312,8 @@ packages: engines: {node: '>=0.4.0'} dev: true - /acorn@8.11.2: - resolution: {integrity: sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==} + /acorn@8.11.3: + resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} engines: {node: '>=0.4.0'} hasBin: true @@ -4559,17 +4559,17 @@ packages: typed-rest-client: 1.8.11 dev: false - /babel-jest@29.7.0(@babel/core@7.23.6): + /babel-jest@29.7.0(@babel/core@7.23.7): resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: '@babel/core': ^7.8.0 dependencies: - '@babel/core': 7.23.6 + '@babel/core': 7.23.7 '@jest/transform': 29.7.0 '@types/babel__core': 7.20.5 babel-plugin-istanbul: 6.1.1 - babel-preset-jest: 29.6.3(@babel/core@7.23.6) + babel-preset-jest: 29.6.3(@babel/core@7.23.7) chalk: 4.1.2 graceful-fs: 4.2.11 slash: 3.0.0 @@ -4597,38 +4597,38 @@ packages: '@babel/template': 7.22.15 '@babel/types': 7.23.6 '@types/babel__core': 7.20.5 - '@types/babel__traverse': 7.20.4 + '@types/babel__traverse': 7.20.5 dev: true - /babel-preset-current-node-syntax@1.0.1(@babel/core@7.23.6): + /babel-preset-current-node-syntax@1.0.1(@babel/core@7.23.7): resolution: {integrity: sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.23.6 - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.23.6) - '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.23.6) - '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.23.6) - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.23.6) - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.23.6) - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.23.6) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.23.6) - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.23.6) - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.23.6) - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.23.6) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.6) - '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.23.6) - dev: true - - /babel-preset-jest@29.6.3(@babel/core@7.23.6): + '@babel/core': 7.23.7 + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.23.7) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.23.7) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.23.7) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.23.7) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.23.7) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.23.7) + dev: true + + /babel-preset-jest@29.6.3(@babel/core@7.23.7): resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.23.6 + '@babel/core': 7.23.7 babel-plugin-jest-hoist: 29.6.3 - babel-preset-current-node-syntax: 1.0.1(@babel/core@7.23.6) + babel-preset-current-node-syntax: 1.0.1(@babel/core@7.23.7) dev: true /backslash@0.2.0: @@ -4694,7 +4694,7 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true dependencies: - caniuse-lite: 1.0.30001571 + caniuse-lite: 1.0.30001572 electron-to-chromium: 1.4.616 node-releases: 2.0.14 update-browserslist-db: 1.0.13(browserslist@4.22.2) @@ -4736,7 +4736,7 @@ packages: hasBin: true optionalDependencies: dtrace-provider: 0.8.8 - moment: 2.29.4 + moment: 2.30.1 mv: 2.1.1 safe-json-stringify: 1.2.0 dev: false @@ -4821,8 +4821,8 @@ packages: engines: {node: '>=10'} dev: true - /caniuse-lite@1.0.30001571: - resolution: {integrity: sha512-tYq/6MoXhdezDLFZuCO/TKboTzuQ/xR5cFdgXPfDtM7/kchBO3b4VWghE/OAi/DV7tTdhmLjZiZBZi1fA/GheQ==} + /caniuse-lite@1.0.30001572: + resolution: {integrity: sha512-1Pbh5FLmn5y4+QhNyJE9j3/7dK44dGB83/ZMjv/qJk86TvDbjk0LosiZo0i0WB0Vx607qMX9jYrn1VLHCkN4rw==} dev: true /cardinal@2.1.1: @@ -5072,8 +5072,8 @@ packages: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} dev: true - /core-js-pure@3.34.0: - resolution: {integrity: sha512-pmhivkYXkymswFfbXsANmBAewXx86UBfmagP+w0wkK06kLsLlTK5oQmsURPivzMkIBQiYq2cjamcZExIwlFQIg==} + /core-js-pure@3.35.0: + resolution: {integrity: sha512-f+eRYmkou59uh7BPcyJ8MC76DiGhspj1KMxVIcF24tzP8NA9HVa1uC7BTW2tgx7E1QVCzDzsgp7kArrzhlz8Ew==} requiresBuild: true dev: false @@ -5838,8 +5838,8 @@ packages: resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: - acorn: 8.11.2 - acorn-jsx: 5.3.2(acorn@8.11.2) + acorn: 8.11.3 + acorn-jsx: 5.3.2(acorn@8.11.3) eslint-visitor-keys: 3.4.3 dev: true @@ -6684,8 +6684,8 @@ packages: /import-in-the-middle@1.4.2: resolution: {integrity: sha512-9WOz1Yh/cvO/p69sxRmhyQwrIGGSp7EIdcb+fFNVi7CzQGQB8U1/1XrKVSbEd/GNOAeM0peJtmi7+qphe7NvAw==} dependencies: - acorn: 8.11.2 - acorn-import-assertions: 1.9.0(acorn@8.11.2) + acorn: 8.11.3 + acorn-import-assertions: 1.9.0(acorn@8.11.3) cjs-module-lexer: 1.2.3 module-details-from-path: 1.0.3 dev: false @@ -6693,8 +6693,8 @@ packages: /import-in-the-middle@1.7.1: resolution: {integrity: sha512-1LrZPDtW+atAxH42S6288qyDFNQ2YCty+2mxEPRtfazH6Z5QwkaBSTS2ods7hnVJioF6rkRfNoA6A/MstpFXLg==} dependencies: - acorn: 8.11.2 - acorn-import-assertions: 1.9.0(acorn@8.11.2) + acorn: 8.11.3 + acorn-import-assertions: 1.9.0(acorn@8.11.3) cjs-module-lexer: 1.2.3 module-details-from-path: 1.0.3 dev: false @@ -7039,7 +7039,7 @@ packages: resolution: {integrity: sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==} engines: {node: '>=8'} dependencies: - '@babel/core': 7.23.6 + '@babel/core': 7.23.7 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.2 semver: 6.3.1 @@ -7051,7 +7051,7 @@ packages: resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} engines: {node: '>=8'} dependencies: - '@babel/core': 7.23.6 + '@babel/core': 7.23.7 '@babel/parser': 7.23.6 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.2 @@ -7064,7 +7064,7 @@ packages: resolution: {integrity: sha512-EAMEJBsYuyyztxMxW3g7ugGPkrZsV57v0Hmv3mm1uQsmB+QnZuepg731CRaIgeUVSdmsTngOkSnauNF8p7FIhA==} engines: {node: '>=10'} dependencies: - '@babel/core': 7.23.6 + '@babel/core': 7.23.7 '@babel/parser': 7.23.6 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.2 @@ -7204,11 +7204,11 @@ packages: ts-node: optional: true dependencies: - '@babel/core': 7.23.6 + '@babel/core': 7.23.7 '@jest/test-sequencer': 29.7.0 '@jest/types': 29.6.3 '@types/node': 18.19.3 - babel-jest: 29.7.0(@babel/core@7.23.6) + babel-jest: 29.7.0(@babel/core@7.23.7) chalk: 4.1.2 ci-info: 3.9.0 deepmerge: 4.3.1 @@ -7479,15 +7479,15 @@ packages: resolution: {integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@babel/core': 7.23.6 + '@babel/core': 7.23.7 '@babel/generator': 7.23.6 - '@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.23.6) - '@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.23.6) + '@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.23.7) '@babel/types': 7.23.6 '@jest/expect-utils': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - babel-preset-current-node-syntax: 1.0.1(@babel/core@7.23.6) + babel-preset-current-node-syntax: 1.0.1(@babel/core@7.23.7) chalk: 4.1.2 expect: 29.7.0 graceful-fs: 4.2.11 @@ -8267,8 +8267,8 @@ packages: resolution: {integrity: sha512-ySViT69/76t8VhE1xXHK6Ch4NcDd26gx0MzKXLO+F7NOtnqH68d9zF94nT8ZWSxXh8ELOERsnJO/sWt1xZYw5A==} dev: false - /moment@2.29.4: - resolution: {integrity: sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==} + /moment@2.30.1: + resolution: {integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==} requiresBuild: true dev: false optional: true @@ -8730,11 +8730,11 @@ packages: p-map: 2.1.0 dev: false - /p-filter@4.0.0: - resolution: {integrity: sha512-3gxOrNadcyxj+YKFyRmRIEuCMGayNNJoXL7Zf1dqfdfoDsVB190bHfFfhqfcNEDFLfQP1q2uir2cBgIqnIT+cQ==} + /p-filter@4.1.0: + resolution: {integrity: sha512-37/tPdZ3oJwHaS3gNJdenCDB3Tz26i9sjhnguBtvN0vYlRIiDNnvTWkuh+0hETV9rLPdJ3rlL3yVOYPIAnM8rw==} engines: {node: '>=18'} dependencies: - p-map: 7.0.0 + p-map: 7.0.1 dev: true /p-finally@1.0.0: @@ -8804,8 +8804,8 @@ packages: aggregate-error: 3.1.0 dev: false - /p-map@7.0.0: - resolution: {integrity: sha512-EZl03dLKv3RypkrjlevZoNwQMSy4bAblWcR18zhonktnN4fUs3asFQKSe0awn982omGxamvbejqQKQYDJYHCEg==} + /p-map@7.0.1: + resolution: {integrity: sha512-2wnaR0XL/FDOj+TgpDuRb2KTjLnu3Fma6b1ZUwGY7LcqenMcvP/YFpjpbPKY6WVGsbuJZRuoUz8iPrt8ORnAFw==} engines: {node: '>=18'} dev: true @@ -10156,7 +10156,7 @@ packages: typescript: 5.3.3 dev: true - /ts-jest@29.1.1(@babel/core@7.23.6)(@jest/types@29.6.3)(jest@29.7.0)(typescript@5.3.3): + /ts-jest@29.1.1(@babel/core@7.23.7)(@jest/types@29.6.3)(jest@29.7.0)(typescript@5.3.3): resolution: {integrity: sha512-D6xjnnbP17cC85nliwGiL+tpoKN0StpgE0TeOjXQTU6MVCfsB4v7aW05CgQ/1OywGb0x/oy9hHFnN+sczTiRaA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -10177,7 +10177,7 @@ packages: esbuild: optional: true dependencies: - '@babel/core': 7.23.6 + '@babel/core': 7.23.7 '@jest/types': 29.6.3 bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 @@ -10212,7 +10212,7 @@ packages: '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 '@types/node': 18.19.3 - acorn: 8.11.2 + acorn: 8.11.3 acorn-walk: 8.3.1 arg: 4.1.3 create-require: 1.1.1 @@ -10667,7 +10667,6 @@ packages: /wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - requiresBuild: true /write-file-atomic@3.0.3: resolution: {integrity: sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==} From 6d8a9fffc3d371e69d21a78e4d298cf817fc1370 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 1 Jan 2024 03:59:03 +0000 Subject: [PATCH 129/173] chore(deps): lock file maintenance (#26466) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> From b8d06fd3e007027064cfb5e93d0f14dcb7fead4d Mon Sep 17 00:00:00 2001 From: RahulGautamSingh Date: Mon, 1 Jan 2024 15:02:50 +0545 Subject: [PATCH 130/173] docs(config/templates): consistent default values (#26467) --- docs/usage/configuration-templates.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/usage/configuration-templates.md b/docs/usage/configuration-templates.md index c995e940791d0c..c37f45a28e2bce 100644 --- a/docs/usage/configuration-templates.md +++ b/docs/usage/configuration-templates.md @@ -32,7 +32,7 @@ Be careful, and consider creating a new "config help" post at the [discussions t Renovate uses one commit per branch. The `commitMessage` reflects the contents of the branch and is usually the same as the PR title. -`commitMessage` has a default value of `{{commitMessagePrefix}} {{commitMessageAction}} {{commitMessageTopic}} {{commitMessageExtra}} {{commitMessageSuffix}}`, with the intention that you only edit some of those subcomponents. +`commitMessage` has a default value of `{{{commitMessagePrefix}}} {{{commitMessageAction}}} {{{commitMessageTopic}}} {{{commitMessageExtra}}} {{{commitMessageSuffix}}}`, with the intention that you only edit some of those subcomponents. You usually don't need to edit `commitMessagePrefix`, this option is used by Renovate if it needs to add a prefix to conform to the Semantic Commit convention. Avoid editing the commit message, unless you know what you're doing. From b4dd814d12fdf30c8d343ef480ee09098ce6684c Mon Sep 17 00:00:00 2001 From: Dulmandakh Date: Tue, 2 Jan 2024 15:56:46 +0800 Subject: [PATCH 131/173] feat(presets): add mui-x to material ui preset (#26470) --- lib/config/presets/internal/monorepo.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/config/presets/internal/monorepo.ts b/lib/config/presets/internal/monorepo.ts index bf310d9e5e83d6..3bcc800bf49d15 100644 --- a/lib/config/presets/internal/monorepo.ts +++ b/lib/config/presets/internal/monorepo.ts @@ -340,6 +340,7 @@ const repoGroups = { 'material-ui': [ 'https://github.com/mui-org/material-ui', // Previous organization name (see: https://github.com/mui/material-ui/pull/30944) 'https://github.com/mui/material-ui', + 'https://github.com/mui/mui-x', ], 'mdc-react': 'material-components/material-components-web-react', mdx: 'https://github.com/mdx-js/mdx', From 4abc30682feefdb92f1ecd0d666f4fd820f97ce8 Mon Sep 17 00:00:00 2001 From: Dirk Klimpel <5740567+dklimpel@users.noreply.github.com> Date: Tue, 2 Jan 2024 16:26:26 +0100 Subject: [PATCH 132/173] docs(configuration-options): fix duplicated docs in bumpVersion (#26478) --- docs/usage/configuration-options.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/usage/configuration-options.md b/docs/usage/configuration-options.md index f93316f3c55efb..7e099f851b683d 100644 --- a/docs/usage/configuration-options.md +++ b/docs/usage/configuration-options.md @@ -410,7 +410,6 @@ This is an advance field and it's recommend you seek a config review before appl ## bumpVersion -Currently this setting supports `helmv3`, `npm`, `nuget`, `maven`, `pep621` and `sbt` only, so raise a feature request if you have a use for it with other package managers. Currently this setting supports `helmv3`, `npm`, `nuget`, `maven`, `pep621`, `poetry` and `sbt` only, so raise a feature request if you have a use for it with other package managers. Its purpose is if you want Renovate to update the `version` field within your package file any time it updates dependencies within. Usually this is for automatic release purposes, so that you don't need to add another step after Renovate before you can release a new version. From 320e80ed36be8fb8b1031dce3f57dd65816dcff1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Birger=20J=2E=20Nord=C3=B8lum?= Date: Tue, 2 Jan 2024 17:02:43 +0100 Subject: [PATCH 133/173] docs(gerrit): rename index.md -> readme.md (#26479) --- lib/modules/platform/gerrit/{index.md => readme.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename lib/modules/platform/gerrit/{index.md => readme.md} (100%) diff --git a/lib/modules/platform/gerrit/index.md b/lib/modules/platform/gerrit/readme.md similarity index 100% rename from lib/modules/platform/gerrit/index.md rename to lib/modules/platform/gerrit/readme.md From c21bc850533fc196911aa975911290d326263110 Mon Sep 17 00:00:00 2001 From: Bernat Mut <1116133+monwolf@users.noreply.github.com> Date: Tue, 2 Jan 2024 23:11:01 +0100 Subject: [PATCH 134/173] feat: redisPrefix (#26398) Co-authored-by: Rhys Arkins --- docs/usage/self-hosted-configuration.md | 5 +++++ lib/config/options/index.ts | 7 +++++++ lib/config/types.ts | 1 + lib/util/cache/package/index.ts | 2 +- lib/util/cache/package/redis.ts | 17 +++++++++++------ 5 files changed, 25 insertions(+), 7 deletions(-) diff --git a/docs/usage/self-hosted-configuration.md b/docs/usage/self-hosted-configuration.md index 56a07967d3010c..9d20a034c38d00 100644 --- a/docs/usage/self-hosted-configuration.md +++ b/docs/usage/self-hosted-configuration.md @@ -771,6 +771,11 @@ Used as an alternative to `privateKeyOld`, if you want the key to be read from d Override this object if you want to change the URLs that Renovate links to, e.g. if you have an internal forum for asking for help. +## redisPrefix + +If this value is set then Renovate will prepend this string to the name of all Redis cache entries used in Renovate. +It's only used if `redisUrl` is configured. + ## redisUrl If this value is set then Renovate will use Redis for its global cache instead of the local file system. diff --git a/lib/config/options/index.ts b/lib/config/options/index.ts index 33bf0affa54058..400bb304ddd9d1 100644 --- a/lib/config/options/index.ts +++ b/lib/config/options/index.ts @@ -334,6 +334,13 @@ const options: RenovateOptions[] = [ type: 'string', globalOnly: true, }, + { + name: 'redisPrefix', + description: 'Key prefix for redis cache entries.', + stage: 'global', + type: 'string', + globalOnly: true, + }, { name: 'baseDir', description: diff --git a/lib/config/types.ts b/lib/config/types.ts index 9f3a6d46f85879..b8f0cceb1c28e9 100644 --- a/lib/config/types.ts +++ b/lib/config/types.ts @@ -113,6 +113,7 @@ export interface GlobalOnlyConfig { privateKeyPath?: string; privateKeyPathOld?: string; redisUrl?: string; + redisPrefix?: string; repositories?: RenovateRepository[]; platform?: PlatformId; endpoint?: string; diff --git a/lib/util/cache/package/index.ts b/lib/util/cache/package/index.ts index 80834c30636574..4bc2a94966a35c 100644 --- a/lib/util/cache/package/index.ts +++ b/lib/util/cache/package/index.ts @@ -55,7 +55,7 @@ export async function set( export async function init(config: AllConfig): Promise { if (config.redisUrl) { - await redisCache.init(config.redisUrl); + await redisCache.init(config.redisUrl, config.redisPrefix); cacheProxy = { get: redisCache.get, set: redisCache.set, diff --git a/lib/util/cache/package/redis.ts b/lib/util/cache/package/redis.ts index 4b0fd7c9db58db..408e9263b084c0 100644 --- a/lib/util/cache/package/redis.ts +++ b/lib/util/cache/package/redis.ts @@ -5,9 +5,10 @@ import { logger } from '../../../logger'; import { compress, decompress } from '../../compress'; let client: ReturnType | undefined; +let rprefix: string | undefined; function getKey(namespace: string, key: string): string { - return `${namespace}-${key}`; + return `${rprefix}${namespace}-${key}`; } export async function end(): Promise { @@ -20,7 +21,7 @@ export async function end(): Promise { } async function rm(namespace: string, key: string): Promise { - logger.trace({ namespace, key }, 'Removing cache entry'); + logger.trace({ rprefix, namespace, key }, 'Removing cache entry'); await client?.del(getKey(namespace, key)); } @@ -37,7 +38,7 @@ export async function get( const cachedValue = res && JSON.parse(res); if (cachedValue) { if (DateTime.local() < DateTime.fromISO(cachedValue.expiry)) { - logger.trace({ namespace, key }, 'Returning cached value'); + logger.trace({ rprefix, namespace, key }, 'Returning cached value'); // istanbul ignore if if (!cachedValue.compress) { return cachedValue.value; @@ -49,7 +50,7 @@ export async function get( await rm(namespace, key); } } catch (err) { - logger.trace({ namespace, key }, 'Cache miss'); + logger.trace({ rprefix, namespace, key }, 'Cache miss'); } return undefined; } @@ -60,7 +61,7 @@ export async function set( value: unknown, ttlMinutes = 5, ): Promise { - logger.trace({ namespace, key, ttlMinutes }, 'Saving cached value'); + logger.trace({ rprefix, namespace, key, ttlMinutes }, 'Saving cached value'); // Redis requires TTL to be integer, not float const redisTTL = Math.floor(ttlMinutes * 60); @@ -80,10 +81,14 @@ export async function set( } } -export async function init(url: string): Promise { +export async function init( + url: string, + prefix: string | undefined, +): Promise { if (!url) { return; } + rprefix = prefix ?? ''; logger.debug('Redis cache init'); client = createClient({ url, From a5099e036843f332ddc8ec03cea28c704ca3c588 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 3 Jan 2024 00:14:04 +0000 Subject: [PATCH 135/173] chore(deps): update ghcr.io/containerbase/devcontainer docker tag to v9.30.10 (#26480) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .devcontainer/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 9c12781223a183..3a1a6c5a221889 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1 +1 @@ -FROM ghcr.io/containerbase/devcontainer:9.30.9 +FROM ghcr.io/containerbase/devcontainer:9.30.10 From c684dad95b4a7fe74cbc842d8c3107ced1483278 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 3 Jan 2024 00:14:22 +0000 Subject: [PATCH 136/173] fix(deps): update ghcr.io/containerbase/sidecar docker tag to v9.30.10 (#26481) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- lib/config/options/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/config/options/index.ts b/lib/config/options/index.ts index 400bb304ddd9d1..29a281f5688682 100644 --- a/lib/config/options/index.ts +++ b/lib/config/options/index.ts @@ -400,7 +400,7 @@ const options: RenovateOptions[] = [ description: 'Change this value to override the default Renovate sidecar image.', type: 'string', - default: 'ghcr.io/containerbase/sidecar:9.30.9', + default: 'ghcr.io/containerbase/sidecar:9.30.10', globalOnly: true, }, { From 17577427b34287383e6625a61b8c4df836eaaa75 Mon Sep 17 00:00:00 2001 From: Akshay Joshi Date: Wed, 3 Jan 2024 03:11:54 -0500 Subject: [PATCH 137/173] feat(presets): add sentry-rust to list of monorepos (#26482) --- lib/config/presets/internal/monorepo.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/config/presets/internal/monorepo.ts b/lib/config/presets/internal/monorepo.ts index 3bcc800bf49d15..ba213b43904c5d 100644 --- a/lib/config/presets/internal/monorepo.ts +++ b/lib/config/presets/internal/monorepo.ts @@ -436,6 +436,7 @@ const repoGroups = { 'sentry-dotnet': 'https://github.com/getsentry/sentry-dotnet', 'sentry-javascript': 'https://github.com/getsentry/sentry-javascript', 'sentry-ruby': 'https://github.com/getsentry/sentry-ruby', + 'sentry-rust': 'https://github.com/getsentry/sentry-rust', serde: 'https://github.com/serde-rs/serde', shedlock: 'https://github.com/lukas-krecan/ShedLock', 'shopify-app-bridge': 'https://github.com/Shopify/app-bridge', From deb9ab25ac8200067cdd8d0064efdb97fbe8fd94 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 3 Jan 2024 18:58:10 +0000 Subject: [PATCH 138/173] chore(deps): update ghcr.io/containerbase/devcontainer docker tag to v9.31.2 (#26491) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .devcontainer/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 3a1a6c5a221889..2e78b241ba72ca 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1 +1 @@ -FROM ghcr.io/containerbase/devcontainer:9.30.10 +FROM ghcr.io/containerbase/devcontainer:9.31.2 From dcfc508344e89ac95a86abb384efd328d04ebfda Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 3 Jan 2024 18:59:36 +0000 Subject: [PATCH 139/173] chore(deps): update dependency type-fest to v4.9.0 (#26490) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 15 ++++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index 7977ec473cc803..f51b38b2d9fc2e 100644 --- a/package.json +++ b/package.json @@ -344,7 +344,7 @@ "tmp-promise": "3.0.3", "ts-jest": "29.1.1", "ts-node": "10.9.2", - "type-fest": "4.8.3", + "type-fest": "4.9.0", "typescript": "5.3.3", "unified": "9.2.2" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1d7d1e3a0a3388..729b8b1f1f353c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -596,8 +596,8 @@ importers: specifier: 10.9.2 version: 10.9.2(@swc/core@1.3.101)(@types/node@18.19.3)(typescript@5.3.3) type-fest: - specifier: 4.8.3 - version: 4.8.3 + specifier: 4.9.0 + version: 4.9.0 typescript: specifier: 5.3.3 version: 5.3.3 @@ -8894,7 +8894,7 @@ packages: dependencies: '@babel/code-frame': 7.23.5 index-to-position: 0.1.2 - type-fest: 4.8.3 + type-fest: 4.9.0 dev: true /parse-link-header@2.0.0: @@ -9164,7 +9164,7 @@ packages: dependencies: find-up-simple: 1.0.0 read-pkg: 9.0.1 - type-fest: 4.8.3 + type-fest: 4.9.0 dev: true /read-pkg-up@7.0.1: @@ -9202,7 +9202,7 @@ packages: '@types/normalize-package-data': 2.4.4 normalize-package-data: 6.0.0 parse-json: 8.1.0 - type-fest: 4.8.3 + type-fest: 4.9.0 unicorn-magic: 0.1.0 dev: true @@ -10312,8 +10312,8 @@ packages: engines: {node: '>=14.16'} dev: true - /type-fest@4.8.3: - resolution: {integrity: sha512-//BaTm14Q/gHBn09xlnKNqfI8t6bmdzx2DXYfPBNofN0WUybCEUDcbCWcTa0oF09lzLjZgPphXAsvRiMK0V6Bw==} + /type-fest@4.9.0: + resolution: {integrity: sha512-KS/6lh/ynPGiHD/LnAobrEFq3Ad4pBzOlJ1wAnJx9N4EYoqFhMfLIBjUT2UEx4wg5ZE+cC1ob6DCSpppVo+rtg==} engines: {node: '>=16'} dev: true @@ -10667,6 +10667,7 @@ packages: /wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + requiresBuild: true /write-file-atomic@3.0.3: resolution: {integrity: sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==} From 6b7710f79f7dcd65e7c07d5e9f497c2783a44ec1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 3 Jan 2024 19:03:17 +0000 Subject: [PATCH 140/173] fix(deps): update ghcr.io/containerbase/sidecar docker tag to v9.31.2 (#26492) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- lib/config/options/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/config/options/index.ts b/lib/config/options/index.ts index 29a281f5688682..280ec218acf1cc 100644 --- a/lib/config/options/index.ts +++ b/lib/config/options/index.ts @@ -400,7 +400,7 @@ const options: RenovateOptions[] = [ description: 'Change this value to override the default Renovate sidecar image.', type: 'string', - default: 'ghcr.io/containerbase/sidecar:9.30.10', + default: 'ghcr.io/containerbase/sidecar:9.31.2', globalOnly: true, }, { From cf5a7d60bd68ff0230336f0a39040d9f5cf2935d Mon Sep 17 00:00:00 2001 From: HonkingGoose <34918129+HonkingGoose@users.noreply.github.com> Date: Thu, 4 Jan 2024 05:11:35 +0100 Subject: [PATCH 141/173] feat(presets): pinGitHubActionDigestsToSemver (#23663) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Róbert Papp --- lib/config/presets/internal/helpers.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/config/presets/internal/helpers.ts b/lib/config/presets/internal/helpers.ts index 805d0de92de292..cfe7ba427f9e1d 100644 --- a/lib/config/presets/internal/helpers.ts +++ b/lib/config/presets/internal/helpers.ts @@ -30,4 +30,15 @@ export const presets: Record = { }, ], }, + pinGitHubActionDigestsToSemver: { + description: 'Convert pinned GitHub Action digests to SemVer.', + packageRules: [ + { + extends: ['helpers:pinGitHubActionDigests'], + extractVersion: '^(?v\\d+\\.\\d+\\.\\d+)$', + versioning: + 'regex:^v(?\\d+)(\\.(?\\d+)\\.(?\\d+))?$', + }, + ], + }, }; From 11e35e4292a913a641b1bd7fc8c8a1d4b6e2d2f7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 4 Jan 2024 07:39:47 +0000 Subject: [PATCH 142/173] chore(deps): update dependency @types/luxon to v3.3.7 (#26193) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Michael Kriese --- .../graphql/cache-strategies/abstract-cache-strategy.ts | 2 +- lib/workers/repository/update/branch/schedule.ts | 2 +- package.json | 2 +- pnpm-lock.yaml | 8 ++++---- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/util/github/graphql/cache-strategies/abstract-cache-strategy.ts b/lib/util/github/graphql/cache-strategies/abstract-cache-strategy.ts index 0be63859206112..004fa16bfb4851 100644 --- a/lib/util/github/graphql/cache-strategies/abstract-cache-strategy.ts +++ b/lib/util/github/graphql/cache-strategies/abstract-cache-strategy.ts @@ -35,7 +35,7 @@ export abstract class AbstractGithubGraphqlCacheStrategy< * These fields will be persisted. */ private items: Record | undefined; - protected createdAt = this.now; + protected createdAt: DateTime = this.now; /** * This flag indicates whether there is any new or updated items diff --git a/lib/workers/repository/update/branch/schedule.ts b/lib/workers/repository/update/branch/schedule.ts index 43ed2bc2981f29..22c12166779e41 100644 --- a/lib/workers/repository/update/branch/schedule.ts +++ b/lib/workers/repository/update/branch/schedule.ts @@ -166,7 +166,7 @@ export function isScheduledNow( logger.warn(validSchedule[1]); return true; } - let now = DateTime.local(); + let now: DateTime = DateTime.local(); logger.trace(`now=${now.toISO()!}`); // Adjust the time if repo is in a different timezone to renovate if (config.timezone) { diff --git a/package.json b/package.json index f51b38b2d9fc2e..1980f1026c5c17 100644 --- a/package.json +++ b/package.json @@ -288,7 +288,7 @@ "@types/json-dup-key-validator": "1.0.2", "@types/linkify-markdown": "1.0.3", "@types/lodash": "4.14.202", - "@types/luxon": "3.3.5", + "@types/luxon": "3.3.7", "@types/markdown-it": "13.0.7", "@types/markdown-table": "2.0.0", "@types/marshal": "0.5.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 729b8b1f1f353c..50b8d58548d51e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -428,8 +428,8 @@ importers: specifier: 4.14.202 version: 4.14.202 '@types/luxon': - specifier: 3.3.5 - version: 3.3.5 + specifier: 3.3.7 + version: 3.3.7 '@types/markdown-it': specifier: 13.0.7 version: 13.0.7 @@ -3833,8 +3833,8 @@ packages: resolution: {integrity: sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==} dev: true - /@types/luxon@3.3.5: - resolution: {integrity: sha512-1cyf6Ge/94zlaWIZA2ei1pE6SZ8xpad2hXaYa5JEFiaUH0YS494CZwyi4MXNpXD9oEuv6ZH0Bmh0e7F9sPhmZA==} + /@types/luxon@3.3.7: + resolution: {integrity: sha512-gKc9P2d4g5uYwmy4s/MO/yOVPmvHyvzka1YH6i5dM03UrFofHSmgc0D0ymbDRStFWHusk6cwwF6nhLm/ckBbbQ==} dev: true /@types/markdown-it@13.0.7: From 597167ae2edd4eeacc33a02dc22399f25bca47cb Mon Sep 17 00:00:00 2001 From: Sergei Zharinov Date: Thu, 4 Jan 2024 04:43:18 -0300 Subject: [PATCH 143/173] feat(bitbucket): Implement PR cache for repositories (#26345) --- lib/modules/platform/bitbucket/index.spec.ts | 71 +++++---- lib/modules/platform/bitbucket/index.ts | 60 ++++---- .../platform/bitbucket/pr-cache.spec.ts | 137 ++++++++++++++++++ lib/modules/platform/bitbucket/pr-cache.ts | 135 +++++++++++++++++ lib/modules/platform/bitbucket/types.ts | 8 +- lib/modules/platform/bitbucket/utils.ts | 1 + lib/util/cache/repository/types.ts | 4 + 7 files changed, 351 insertions(+), 65 deletions(-) create mode 100644 lib/modules/platform/bitbucket/pr-cache.spec.ts create mode 100644 lib/modules/platform/bitbucket/pr-cache.ts diff --git a/lib/modules/platform/bitbucket/index.spec.ts b/lib/modules/platform/bitbucket/index.spec.ts index b4b8b8782712b9..ab13c73de1277d 100644 --- a/lib/modules/platform/bitbucket/index.spec.ts +++ b/lib/modules/platform/bitbucket/index.spec.ts @@ -1,9 +1,9 @@ import * as httpMock from '../../../../test/http-mock'; import type { logger as _logger } from '../../../logger'; +import { reset as memCacheReset } from '../../../util/cache/memory'; import type * as _git from '../../../util/git'; import { setBaseUrl } from '../../../util/http/bitbucket'; import type { Platform, PlatformResult, RepoParams } from '../types'; -import { prFieldsFilter } from './utils'; jest.mock('../../../util/git'); jest.mock('../../../util/host-rules'); @@ -43,6 +43,7 @@ describe('modules/platform/bitbucket/index', () => { }); setBaseUrl(baseUrl); + memCacheReset(); }); async function initRepoMock( @@ -235,9 +236,8 @@ describe('modules/platform/bitbucket/index', () => { it('bitbucket finds PR for branch', async () => { const scope = await initRepoMock(); scope - .get( - `/2.0/repositories/some/repo/pullrequests?state=OPEN&state=MERGED&state=DECLINED&state=SUPERSEDED&fields=${prFieldsFilter}&pagelen=50`, - ) + .get(`/2.0/repositories/some/repo/pullrequests`) + .query(true) .reply(200, { values: [pr] }) .get('/2.0/repositories/some/repo/pullrequests/5') .reply(200, pr); @@ -248,9 +248,8 @@ describe('modules/platform/bitbucket/index', () => { it('returns null if no PR for branch', async () => { const scope = await initRepoMock(); scope - .get( - `/2.0/repositories/some/repo/pullrequests?state=OPEN&state=MERGED&state=DECLINED&state=SUPERSEDED&fields=${prFieldsFilter}&pagelen=50`, - ) + .get(`/2.0/repositories/some/repo/pullrequests`) + .query(true) .reply(200, { values: [pr] }); const res = await bitbucket.getBranchPr('branch_without_pr'); @@ -753,9 +752,8 @@ describe('modules/platform/bitbucket/index', () => { await bitbucket.initPlatform({ username: 'renovate', password: 'pass' }); await initRepoMock(undefined, null, scope); scope - .get( - `/2.0/repositories/some/repo/pullrequests?state=OPEN&state=MERGED&state=DECLINED&state=SUPERSEDED&q=author.uuid="12345"&fields=${prFieldsFilter}&pagelen=50`, - ) + .get(`/2.0/repositories/some/repo/pullrequests`) + .query(true) .reply(200, { values: [ { @@ -779,9 +777,8 @@ describe('modules/platform/bitbucket/index', () => { it('finds pr', async () => { const scope = await initRepoMock(); scope - .get( - `/2.0/repositories/some/repo/pullrequests?state=OPEN&state=MERGED&state=DECLINED&state=SUPERSEDED&fields=${prFieldsFilter}&pagelen=50`, - ) + .get(`/2.0/repositories/some/repo/pullrequests`) + .query(true) .reply(200, { values: [pr] }); expect( await bitbucket.findPr({ @@ -805,9 +802,8 @@ describe('modules/platform/bitbucket/index', () => { const scope = await initRepoMock(); scope - .get( - `/2.0/repositories/some/repo/pullrequests?state=OPEN&state=MERGED&state=DECLINED&state=SUPERSEDED&fields=${prFieldsFilter}&pagelen=50`, - ) + .get(`/2.0/repositories/some/repo/pullrequests`) + .query(true) .reply(200, { values: [ { @@ -843,9 +839,8 @@ describe('modules/platform/bitbucket/index', () => { const scope = await initRepoMock({}, { is_private: true }); scope - .get( - `/2.0/repositories/some/repo/pullrequests?state=OPEN&state=MERGED&state=DECLINED&state=SUPERSEDED&fields=${prFieldsFilter}&pagelen=50`, - ) + .get(`/2.0/repositories/some/repo/pullrequests`) + .query(true) .reply(200, { values: [ { @@ -883,9 +878,8 @@ describe('modules/platform/bitbucket/index', () => { const scope = await initRepoMock({}, { is_private: false }); scope - .get( - `/2.0/repositories/some/repo/pullrequests?state=OPEN&state=MERGED&state=DECLINED&state=SUPERSEDED&fields=${prFieldsFilter}&pagelen=50`, - ) + .get(`/2.0/repositories/some/repo/pullrequests`) + .query(true) .reply(200, { values: [ { @@ -927,9 +921,8 @@ describe('modules/platform/bitbucket/index', () => { const scope = await initRepoMock({}, { is_private: false }); scope - .get( - `/2.0/repositories/some/repo/pullrequests?state=OPEN&state=MERGED&state=DECLINED&state=SUPERSEDED&fields=${prFieldsFilter}&pagelen=50`, - ) + .get(`/2.0/repositories/some/repo/pullrequests`) + .query(true) .reply(200, { values: [ { @@ -1025,7 +1018,12 @@ describe('modules/platform/bitbucket/index', () => { values: [projectReviewer, repoReviewer], }) .post('/2.0/repositories/some/repo/pullrequests') - .reply(200, { id: 5 }); + .reply(200, { id: 5 }) + .get(`/2.0/repositories/some/repo/pullrequests`) + .query(true) + .reply(200, { + values: [{ id: 5 }], + }); const pr = await bitbucket.createPr({ sourceBranch: 'branch', targetBranch: 'master', @@ -1103,7 +1101,12 @@ describe('modules/platform/bitbucket/index', () => { account_status: 'inactive', }) .post('/2.0/repositories/some/repo/pullrequests') - .reply(200, { id: 5 }); + .reply(200, { id: 5 }) + .get(`/2.0/repositories/some/repo/pullrequests`) + .query(true) + .reply(200, { + values: [{ id: 5 }], + }); const pr = await bitbucket.createPr({ sourceBranch: 'branch', targetBranch: 'master', @@ -1161,7 +1164,12 @@ describe('modules/platform/bitbucket/index', () => { ) .reply(200) .post('/2.0/repositories/some/repo/pullrequests') - .reply(200, { id: 5 }); + .reply(200, { id: 5 }) + .get(`/2.0/repositories/some/repo/pullrequests`) + .query(true) + .reply(200, { + values: [{ id: 5 }], + }); const pr = await bitbucket.createPr({ sourceBranch: 'branch', targetBranch: 'master', @@ -1257,7 +1265,12 @@ describe('modules/platform/bitbucket/index', () => { }, }) .post('/2.0/repositories/some/repo/pullrequests') - .reply(200, { id: 5 }); + .reply(200, { id: 5 }) + .get(`/2.0/repositories/some/repo/pullrequests`) + .query(true) + .reply(200, { + values: [{ id: 5 }], + }); const pr = await bitbucket.createPr({ sourceBranch: 'branch', targetBranch: 'master', diff --git a/lib/modules/platform/bitbucket/index.ts b/lib/modules/platform/bitbucket/index.ts index 9ddef12de074a9..165a09d446c9d8 100644 --- a/lib/modules/platform/bitbucket/index.ts +++ b/lib/modules/platform/bitbucket/index.ts @@ -31,6 +31,7 @@ import { repoFingerprint } from '../util'; import { smartTruncate } from '../utils/pr-body'; import { readOnlyIssueBody } from '../utils/read-only-issue-body'; import * as comments from './comments'; +import { BitbucketPrCache } from './pr-cache'; import type { Account, BitbucketStatus, @@ -44,7 +45,7 @@ import type { RepoInfoBody, } from './types'; import * as utils from './utils'; -import { mergeBodyTransformer, prFieldsFilter } from './utils'; +import { mergeBodyTransformer } from './utils'; export const id = 'bitbucket'; @@ -273,28 +274,11 @@ function matchesState(state: string, desiredState: string): boolean { export async function getPrList(): Promise { logger.debug('getPrList()'); - if (!config.prList) { - logger.debug('Retrieving PR list'); - const querySearchParams = new URL.URLSearchParams(); - for (const state of utils.prStates.all) { - querySearchParams.append('state', state); - } - if (renovateUserUuid && !config.ignorePrAuthor) { - querySearchParams.append('q', `author.uuid="${renovateUserUuid}"`); - } - querySearchParams.append('fields', prFieldsFilter); - const query = querySearchParams.toString(); - const url = `/2.0/repositories/${config.repository}/pullrequests?${query}`; - const prs = ( - await bitbucketHttp.getJson>(url, { - paginate: true, - pagelen: 50, - }) - ).body.values; - config.prList = prs.map(utils.prInfo); - logger.debug(`Retrieved Pull Requests, count: ${config.prList.length}`); - } - return config.prList; + return await BitbucketPrCache.getPrs( + bitbucketHttp, + config.repository, + renovateUserUuid, + ); } export async function findPr({ @@ -328,15 +312,17 @@ export async function findPr({ (!prTitle || p.title.toUpperCase() === prTitle.toUpperCase()) && matchesState(p.state, state), ); - if (pr) { - logger.debug(`Found PR #${pr.number}`); + + if (!pr) { + return null; } + logger.debug(`Found PR #${pr.number}`); /** * Bitbucket doesn't support renaming or reopening declined PRs. * Instead, we have to use comment-driven signals. */ - if (pr?.state === 'closed') { + if (pr.state === 'closed') { const reopenComments = await comments.reopenComments(config, pr.number); if (is.nonEmptyArray(reopenComments)) { @@ -359,7 +345,7 @@ export async function findPr({ } } - return pr ?? null; + return pr; } // Gets details for a PR @@ -913,10 +899,12 @@ export async function createPr({ ) ).body; const pr = utils.prInfo(prRes); - // istanbul ignore if - if (config.prList) { - config.prList.push(pr); - } + await BitbucketPrCache.addPr( + bitbucketHttp, + config.repository, + renovateUserUuid, + pr, + ); return pr; } catch (err) /* istanbul ignore next */ { // Try sanitizing reviewers @@ -938,10 +926,12 @@ export async function createPr({ ) ).body; const pr = utils.prInfo(prRes); - // istanbul ignore if - if (config.prList) { - config.prList.push(pr); - } + await BitbucketPrCache.addPr( + bitbucketHttp, + config.repository, + renovateUserUuid, + pr, + ); return pr; } } diff --git a/lib/modules/platform/bitbucket/pr-cache.spec.ts b/lib/modules/platform/bitbucket/pr-cache.spec.ts new file mode 100644 index 00000000000000..2dea9fe977b49a --- /dev/null +++ b/lib/modules/platform/bitbucket/pr-cache.spec.ts @@ -0,0 +1,137 @@ +import * as httpMock from '../../../../test/http-mock'; +import { reset as memCacheReset } from '../../../util/cache/memory'; +import { + getCache, + resetCache as repoCacheReset, +} from '../../../util/cache/repository'; +import { BitbucketHttp } from '../../../util/http/bitbucket'; +import { BitbucketPrCache } from './pr-cache'; +import type { PrResponse } from './types'; +import { prInfo } from './utils'; + +const http = new BitbucketHttp(); + +const pr1: PrResponse = { + id: 1, + title: 'title', + state: 'OPEN', + links: { + commits: { + href: 'https://api.bitbucket.org/2.0/repositories/some/repo/pullrequests/1/commits', + }, + }, + source: { branch: { name: 'branch' } }, + destination: { branch: { name: 'master' } }, + reviewers: [], + created_on: '2020-01-01T00:00:00.000Z', + updated_on: '2020-01-01T00:00:00.000Z', +}; + +const pr2: PrResponse = { + id: 2, + title: 'title', + state: 'OPEN', + links: { + commits: { + href: 'https://api.bitbucket.org/2.0/repositories/some/repo/pullrequests/2/commits', + }, + }, + source: { branch: { name: 'branch' } }, + destination: { branch: { name: 'master' } }, + reviewers: [], + created_on: '2023-01-01T00:00:00.000Z', + updated_on: '2023-01-01T00:00:00.000Z', +}; + +describe('modules/platform/bitbucket/pr-cache', () => { + let cache = getCache(); + + beforeEach(() => { + memCacheReset(); + repoCacheReset(); + cache = getCache(); + }); + + it('fetches cache', async () => { + httpMock + .scope('https://api.bitbucket.org') + .get(`/2.0/repositories/some-workspace/some-repo/pullrequests`) + .query(true) + .reply(200, { + values: [pr1], + }); + + const res = await BitbucketPrCache.getPrs( + http, + 'some-workspace/some-repo', + 'some-author', + ); + + expect(res).toMatchObject([ + { + number: 1, + title: 'title', + }, + ]); + expect(cache).toEqual({ + platform: { + bitbucket: { + pullRequestsCache: { + author: 'some-author', + items: { + '1': prInfo(pr1), + }, + updated_on: '2020-01-01T00:00:00.000Z', + }, + }, + }, + }); + }); + + it('syncs cache', async () => { + cache.platform = { + bitbucket: { + pullRequestsCache: { + items: { + '1': prInfo(pr1), + }, + author: 'some-author', + updated_on: '2020-01-01T00:00:00.000Z', + }, + }, + }; + + httpMock + .scope('https://api.bitbucket.org') + .get(`/2.0/repositories/some-workspace/some-repo/pullrequests`) + .query(true) + .reply(200, { + values: [pr2], + }); + + const res = await BitbucketPrCache.getPrs( + http, + 'some-workspace/some-repo', + 'some-author', + ); + + expect(res).toMatchObject([ + { number: 1, title: 'title' }, + { number: 2, title: 'title' }, + ]); + expect(cache).toEqual({ + platform: { + bitbucket: { + pullRequestsCache: { + items: { + '1': prInfo(pr1), + '2': prInfo(pr2), + }, + author: 'some-author', + updated_on: '2023-01-01T00:00:00.000Z', + }, + }, + }, + }); + }); +}); diff --git a/lib/modules/platform/bitbucket/pr-cache.ts b/lib/modules/platform/bitbucket/pr-cache.ts new file mode 100644 index 00000000000000..95fb4b947a7af0 --- /dev/null +++ b/lib/modules/platform/bitbucket/pr-cache.ts @@ -0,0 +1,135 @@ +import { dequal } from 'dequal'; +import { DateTime } from 'luxon'; +import { logger } from '../../../logger'; +import * as memCache from '../../../util/cache/memory'; +import { getCache } from '../../../util/cache/repository'; +import type { BitbucketHttp } from '../../../util/http/bitbucket'; +import type { Pr } from '../types'; +import type { BitbucketPrCacheData, PagedResult, PrResponse } from './types'; +import { prFieldsFilter, prInfo, prStates } from './utils'; + +export class BitbucketPrCache { + private cache: BitbucketPrCacheData; + + private constructor( + private repo: string, + private author: string | null, + ) { + const repoCache = getCache(); + repoCache.platform ??= {}; + repoCache.platform.bitbucket ??= {}; + + let pullRequestCache: BitbucketPrCacheData | undefined = + repoCache.platform.bitbucket.pullRequestsCache; + if (!pullRequestCache || pullRequestCache.author !== author) { + pullRequestCache = { + items: {}, + updated_on: null, + author, + }; + } + repoCache.platform.bitbucket.pullRequestsCache = pullRequestCache; + this.cache = pullRequestCache; + } + + private static async init( + http: BitbucketHttp, + repo: string, + author: string | null, + ): Promise { + const res = new BitbucketPrCache(repo, author); + const isSynced = memCache.get( + 'bitbucket-pr-cache-synced', + ); + + if (!isSynced) { + await res.sync(http); + memCache.set('bitbucket-pr-cache-synced', true); + } + + return res; + } + + private getPrs(): Pr[] { + return Object.values(this.cache.items); + } + + static async getPrs( + http: BitbucketHttp, + repo: string, + author: string | null, + ): Promise { + const prCache = await BitbucketPrCache.init(http, repo, author); + return prCache.getPrs(); + } + + private addPr(pr: Pr): void { + this.cache.items[pr.number] = pr; + } + + static async addPr( + http: BitbucketHttp, + repo: string, + author: string | null, + item: Pr, + ): Promise { + const prCache = await BitbucketPrCache.init(http, repo, author); + prCache.addPr(item); + } + + private reconcile(rawItems: PrResponse[]): void { + const { items: oldItems } = this.cache; + let { updated_on } = this.cache; + + for (const rawItem of rawItems) { + const id = rawItem.id; + + const oldItem = oldItems[id]; + const newItem = prInfo(rawItem); + + const itemNewTime = DateTime.fromISO(rawItem.updated_on); + + if (!dequal(oldItem, newItem)) { + oldItems[id] = newItem; + } + + const cacheOldTime = updated_on ? DateTime.fromISO(updated_on) : null; + if (!cacheOldTime || itemNewTime > cacheOldTime) { + updated_on = rawItem.updated_on; + } + } + + this.cache.updated_on = updated_on; + } + + private getUrl(): string { + const params = new URLSearchParams(); + + for (const state of prStates.all) { + params.append('state', state); + } + + params.append('fields', prFieldsFilter); + + const q: string[] = []; + if (this.author) { + q.push(`author.uuid = "${this.author}"`); + } + if (this.cache.updated_on) { + q.push(`updated_on > "${this.cache.updated_on}"`); + } + params.append('q', q.join(' AND ')); + + const query = params.toString(); + return `/2.0/repositories/${this.repo}/pullrequests?${query}`; + } + + private async sync(http: BitbucketHttp): Promise { + logger.debug('Syncing PR list'); + const url = this.getUrl(); + const opts = { paginate: true, pagelen: 50 }; + const res = await http.getJson>(url, opts); + this.reconcile(res.body.values); + return this; + } +} diff --git a/lib/modules/platform/bitbucket/types.ts b/lib/modules/platform/bitbucket/types.ts index 56bc4f82717cb1..35fba3d1638a5e 100644 --- a/lib/modules/platform/bitbucket/types.ts +++ b/lib/modules/platform/bitbucket/types.ts @@ -13,7 +13,6 @@ export interface Config { has_issues: boolean; mergeMethod: string; owner: string; - prList: Pr[]; repository: string; ignorePrAuthor: boolean; is_private: boolean; @@ -91,6 +90,7 @@ export interface PrResponse { }; reviewers: Account[]; created_on: string; + updated_on: string; } export interface Account { @@ -105,3 +105,9 @@ export interface EffectiveReviewer { reviewer_type: string; user: Account; } + +export interface BitbucketPrCacheData { + items: Record; + updated_on: string | null; + author: string | null; +} diff --git a/lib/modules/platform/bitbucket/utils.ts b/lib/modules/platform/bitbucket/utils.ts index 4d9ee1e87967d3..852f61611164f5 100644 --- a/lib/modules/platform/bitbucket/utils.ts +++ b/lib/modules/platform/bitbucket/utils.ts @@ -86,4 +86,5 @@ export const prFieldsFilter = [ 'values.reviewers.nickname', 'values.reviewers.account_status', 'values.created_on', + 'values.updated_on', ].join(','); diff --git a/lib/util/cache/repository/types.ts b/lib/util/cache/repository/types.ts index 4560e7aa74023a..89d454aa89c893 100644 --- a/lib/util/cache/repository/types.ts +++ b/lib/util/cache/repository/types.ts @@ -4,6 +4,7 @@ import type { UpdateType, } from '../../../config/types'; import type { PackageFile } from '../../../modules/manager/types'; +import type { BitbucketPrCacheData } from '../../../modules/platform/bitbucket/types'; import type { RepoInitConfig } from '../../../workers/repository/init/types'; import type { PrBlockedBy } from '../../../workers/types'; @@ -131,6 +132,9 @@ export interface RepoCacheData { lastPlatformAutomergeFailure?: string; platform?: { github?: Record; + bitbucket?: { + pullRequestsCache?: BitbucketPrCacheData; + }; }; prComments?: Record>; onboardingBranchCache?: OnboardingBranchCache; From e4e1b47c10b4179dd2101ae490b758c6be5e5909 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 4 Jan 2024 07:43:36 +0000 Subject: [PATCH 144/173] build(deps): update dependency node-html-parser to v6.1.12 (#26465) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Michael Kriese --- lib/modules/datasource/artifactory/index.ts | 2 +- package.json | 2 +- pnpm-lock.yaml | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/modules/datasource/artifactory/index.ts b/lib/modules/datasource/artifactory/index.ts index 2668182e800fa6..86fe6918b04b44 100644 --- a/lib/modules/datasource/artifactory/index.ts +++ b/lib/modules/datasource/artifactory/index.ts @@ -69,7 +69,7 @@ export class ArtifactoryDatasource extends Datasource { : node.innerHTML; const published = ArtifactoryDatasource.parseReleaseTimestamp( - node.nextSibling?.text, + node.nextSibling!.text, // TODO: can be null (#22198) ); const thisRelease: Release = { diff --git a/package.json b/package.json index 1980f1026c5c17..1515a6ae723e99 100644 --- a/package.json +++ b/package.json @@ -223,7 +223,7 @@ "moo": "0.5.2", "ms": "2.1.3", "nanoid": "3.3.7", - "node-html-parser": "6.1.11", + "node-html-parser": "6.1.12", "openpgp": "5.11.0", "p-all": "3.0.0", "p-map": "4.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 50b8d58548d51e..891eb8d110fb1d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -243,8 +243,8 @@ importers: specifier: 3.3.7 version: 3.3.7 node-html-parser: - specifier: 6.1.11 - version: 6.1.11 + specifier: 6.1.12 + version: 6.1.12 openpgp: specifier: 5.11.0 version: 5.11.0 @@ -8399,8 +8399,8 @@ packages: dev: false optional: true - /node-html-parser@6.1.11: - resolution: {integrity: sha512-FAgwwZ6h0DSDWxfD0Iq1tsDcBCxdJB1nXpLPPxX8YyVWzbfCjKWEzaynF4gZZ/8hziUmp7ZSaKylcn0iKhufUQ==} + /node-html-parser@6.1.12: + resolution: {integrity: sha512-/bT/Ncmv+fbMGX96XG9g05vFt43m/+SYKIs9oAemQVYyVcZmDAI2Xq/SbNcpOA35eF0Zk2av3Ksf+Xk8Vt8abA==} dependencies: css-select: 5.1.0 he: 1.2.0 From a101cf1237f6bdcfa9af8833575aed841c129a85 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 4 Jan 2024 07:56:01 +0000 Subject: [PATCH 145/173] chore(deps): update dependency @types/luxon to v3.3.8 (#26494) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 1515a6ae723e99..3404939c03a1a4 100644 --- a/package.json +++ b/package.json @@ -288,7 +288,7 @@ "@types/json-dup-key-validator": "1.0.2", "@types/linkify-markdown": "1.0.3", "@types/lodash": "4.14.202", - "@types/luxon": "3.3.7", + "@types/luxon": "3.3.8", "@types/markdown-it": "13.0.7", "@types/markdown-table": "2.0.0", "@types/marshal": "0.5.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 891eb8d110fb1d..cd935eac856192 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -428,8 +428,8 @@ importers: specifier: 4.14.202 version: 4.14.202 '@types/luxon': - specifier: 3.3.7 - version: 3.3.7 + specifier: 3.3.8 + version: 3.3.8 '@types/markdown-it': specifier: 13.0.7 version: 13.0.7 @@ -3833,8 +3833,8 @@ packages: resolution: {integrity: sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==} dev: true - /@types/luxon@3.3.7: - resolution: {integrity: sha512-gKc9P2d4g5uYwmy4s/MO/yOVPmvHyvzka1YH6i5dM03UrFofHSmgc0D0ymbDRStFWHusk6cwwF6nhLm/ckBbbQ==} + /@types/luxon@3.3.8: + resolution: {integrity: sha512-jYvz8UMLDgy3a5SkGJne8H7VA7zPV2Lwohjx0V8V31+SqAjNmurWMkk9cQhfvlcnXWudBpK9xPM1n4rljOcHYQ==} dev: true /@types/markdown-it@13.0.7: From 5130d5be108e839e63d2e1b519134a5c8fdd8fff Mon Sep 17 00:00:00 2001 From: Marc Mognol <8171300+marcmognol@users.noreply.github.com> Date: Thu, 4 Jan 2024 08:56:55 +0100 Subject: [PATCH 146/173] feat(manager/nuget): extract ContainerBaseImage property (#26400) Co-authored-by: Rhys Arkins Co-authored-by: Michael Kriese --- lib/modules/manager/nuget/extract.spec.ts | 47 +++++++++++++++++++++++ lib/modules/manager/nuget/extract.ts | 16 ++++++++ lib/modules/manager/nuget/index.ts | 2 + 3 files changed, 65 insertions(+) diff --git a/lib/modules/manager/nuget/extract.spec.ts b/lib/modules/manager/nuget/extract.spec.ts index c60eec0e467813..7070e8f62c5032 100644 --- a/lib/modules/manager/nuget/extract.spec.ts +++ b/lib/modules/manager/nuget/extract.spec.ts @@ -1,3 +1,4 @@ +import { codeBlock } from 'common-tags'; import upath from 'upath'; import { Fixtures } from '../../../../test/fixtures'; import { GlobalConfig } from '../../../config/global'; @@ -67,6 +68,52 @@ describe('modules/manager/nuget/extract', () => { expect(res?.deps).toHaveLength(17); }); + it('extracts ContainerBaseImage', async () => { + const contents = codeBlock` + + + 0.1.0 + mcr.microsoft.com/dotnet/runtime:7.0.10 + + `; + + expect(await extractPackageFile(contents, contents, config)).toEqual({ + deps: [ + { + depName: 'mcr.microsoft.com/dotnet/runtime', + depType: 'docker', + datasource: 'docker', + currentValue: '7.0.10', + }, + ], + packageFileVersion: '0.1.0', + }); + }); + + it('extracts ContainerBaseImage with pinned digest', async () => { + const contents = codeBlock` + + + 0.1.0 + mcr.microsoft.com/dotnet/runtime:7.0.10@sha256:181067029e094856691ee1ce3782ea3bd3fda01bb5b6d19411d0f673cab1ab19 + + `; + + expect(await extractPackageFile(contents, contents, config)).toEqual({ + deps: [ + { + depName: 'mcr.microsoft.com/dotnet/runtime', + depType: 'docker', + datasource: 'docker', + currentValue: '7.0.10', + currentDigest: + 'sha256:181067029e094856691ee1ce3782ea3bd3fda01bb5b6d19411d0f673cab1ab19', + }, + ], + packageFileVersion: '0.1.0', + }); + }); + it('considers NuGet.config', async () => { const packageFile = 'with-config-file/with-config-file.csproj'; const contents = Fixtures.get(packageFile); diff --git a/lib/modules/manager/nuget/extract.ts b/lib/modules/manager/nuget/extract.ts index 0ad9632a4fa723..f127f32f8160a8 100644 --- a/lib/modules/manager/nuget/extract.ts +++ b/lib/modules/manager/nuget/extract.ts @@ -4,7 +4,9 @@ import { logger } from '../../../logger'; import { getSiblingFileName, localPathExists } from '../../../util/fs'; import { hasKey } from '../../../util/object'; import { regEx } from '../../../util/regex'; +import { DockerDatasource } from '../../datasource/docker'; import { NugetDatasource } from '../../datasource/nuget'; +import { getDep } from '../dockerfile/extract'; import type { ExtractConfig, PackageDependency, @@ -46,6 +48,20 @@ function extractDepsFromXml(xmlNode: XmlDocument): NugetPackageDependency[] { const child = todo.pop()!; const { name, attr } = child; + if (name === 'ContainerBaseImage') { + const dep = getDep(child.val, true); + + if (is.nonEmptyStringAndNotWhitespace(dep.depName)) { + results.push({ + datasource: DockerDatasource.id, + depType: 'docker', + depName: dep.depName, + currentValue: dep.currentValue, + currentDigest: dep.currentDigest, + }); + } + } + if (elemNames.has(name)) { const depName = attr?.Include || attr?.Update; const version = diff --git a/lib/modules/manager/nuget/index.ts b/lib/modules/manager/nuget/index.ts index 88e1ccdc01066b..2f439599b7f6c1 100644 --- a/lib/modules/manager/nuget/index.ts +++ b/lib/modules/manager/nuget/index.ts @@ -1,4 +1,5 @@ import type { Category } from '../../../constants'; +import { DockerDatasource } from '../../datasource/docker'; import { DotnetVersionDatasource } from '../../datasource/dotnet-version'; import { NugetDatasource } from '../../datasource/nuget'; @@ -18,6 +19,7 @@ export const defaultConfig = { export const categories: Category[] = ['dotnet']; export const supportedDatasources = [ + DockerDatasource.id, DotnetVersionDatasource.id, NugetDatasource.id, ]; From 72fe67dd27bc539f26efc671c20938ca29bc5099 Mon Sep 17 00:00:00 2001 From: Nam Vu Date: Thu, 4 Jan 2024 09:48:39 +0100 Subject: [PATCH 147/173] feat(manager/poetry): support git rev dependencies (#26367) Co-authored-by: Sebastian Poxhofer Co-authored-by: Michael Kriese --- lib/modules/manager/poetry/extract.spec.ts | 103 +++++++++++++++++++++ lib/modules/manager/poetry/index.ts | 2 + lib/modules/manager/poetry/schema.ts | 58 +++++++----- lib/modules/manager/poetry/types.ts | 2 + 4 files changed, 142 insertions(+), 23 deletions(-) diff --git a/lib/modules/manager/poetry/extract.spec.ts b/lib/modules/manager/poetry/extract.spec.ts index 13c11daa9045eb..62f43868f7287a 100644 --- a/lib/modules/manager/poetry/extract.spec.ts +++ b/lib/modules/manager/poetry/extract.spec.ts @@ -1,8 +1,10 @@ import { codeBlock } from 'common-tags'; import { Fixtures } from '../../../../test/fixtures'; import { fs } from '../../../../test/util'; +import { GitRefsDatasource } from '../../datasource/git-refs'; import { GithubReleasesDatasource } from '../../datasource/github-releases'; import { GithubTagsDatasource } from '../../datasource/github-tags'; +import { PypiDatasource } from '../../datasource/pypi'; import { extractPackageFile } from '.'; jest.mock('../../../util/fs'); @@ -169,6 +171,107 @@ describe('modules/manager/poetry/extract', () => { }); }); + it('parses git dependencies long commit hashs on http urls', async () => { + const content = codeBlock` + [tool.poetry.dependencies] + fastapi = {git = "https://github.com/tiangolo/fastapi.git", rev="6f5aa81c076d22e38afbe7d602db6730e28bc3cc"} + dep = "^2.0" + `; + const res = await extractPackageFile(content, filename); + expect(res?.deps).toMatchObject([ + { + depType: 'dependencies', + depName: 'fastapi', + datasource: GitRefsDatasource.id, + currentDigest: '6f5aa81c076d22e38afbe7d602db6730e28bc3cc', + replaceString: '6f5aa81c076d22e38afbe7d602db6730e28bc3cc', + packageName: 'https://github.com/tiangolo/fastapi.git', + }, + { + depType: 'dependencies', + depName: 'dep', + datasource: PypiDatasource.id, + currentValue: '^2.0', + }, + ]); + }); + + it('parses git dependencies short commit hashs on http urls', async () => { + const content = codeBlock` + [tool.poetry.dependencies] + fastapi = {git = "https://github.com/tiangolo/fastapi.git", rev="6f5aa81"} + dep = "^2.0" + `; + const res = await extractPackageFile(content, filename); + expect(res?.deps).toMatchObject([ + { + depType: 'dependencies', + depName: 'fastapi', + datasource: GitRefsDatasource.id, + currentDigest: '6f5aa81', + replaceString: '6f5aa81', + packageName: 'https://github.com/tiangolo/fastapi.git', + }, + { + depType: 'dependencies', + depName: 'dep', + datasource: PypiDatasource.id, + currentValue: '^2.0', + }, + ]); + }); + + it('parses git dependencies long commit hashs on ssh urls', async () => { + const content = codeBlock` + [tool.poetry.dependencies] + fastapi = {git = "git@github.com:tiangolo/fastapi.git", rev="6f5aa81c076d22e38afbe7d602db6730e28bc3cc"} + dep = "^2.0" + `; + const res = await extractPackageFile(content, filename); + expect(res?.deps).toMatchObject([ + { + depType: 'dependencies', + depName: 'fastapi', + datasource: GitRefsDatasource.id, + currentDigest: '6f5aa81c076d22e38afbe7d602db6730e28bc3cc', + replaceString: '6f5aa81c076d22e38afbe7d602db6730e28bc3cc', + packageName: 'git@github.com:tiangolo/fastapi.git', + }, + { + depType: 'dependencies', + depName: 'dep', + datasource: PypiDatasource.id, + currentValue: '^2.0', + }, + ]); + }); + + it('parses git dependencies long commit hashs on http urls with branch marker', async () => { + const content = codeBlock` + [tool.poetry.dependencies] + fastapi = {git = "https://github.com/tiangolo/fastapi.git", branch="develop", rev="6f5aa81c076d22e38afbe7d602db6730e28bc3cc"} + dep = "^2.0" + `; + const res = await extractPackageFile(content, filename); + expect(res?.deps).toMatchObject([ + { + depType: 'dependencies', + depName: 'fastapi', + datasource: GitRefsDatasource.id, + currentValue: 'develop', + currentDigest: '6f5aa81c076d22e38afbe7d602db6730e28bc3cc', + replaceString: '6f5aa81c076d22e38afbe7d602db6730e28bc3cc', + packageName: 'https://github.com/tiangolo/fastapi.git', + }, + { + depType: 'dependencies', + depName: 'dep', + datasource: PypiDatasource.id, + currentValue: '^2.0', + }, + ]); + }); + it('parses github dependencies tags on ssh urls', async () => { const content = codeBlock` [tool.poetry.dependencies] diff --git a/lib/modules/manager/poetry/index.ts b/lib/modules/manager/poetry/index.ts index 0b69f3415625bf..82a131c8e26ea9 100644 --- a/lib/modules/manager/poetry/index.ts +++ b/lib/modules/manager/poetry/index.ts @@ -1,4 +1,5 @@ import type { Category } from '../../../constants'; +import { GitRefsDatasource } from '../../datasource/git-refs'; import { GithubReleasesDatasource } from '../../datasource/github-releases'; import { GithubTagsDatasource } from '../../datasource/github-tags'; import { PypiDatasource } from '../../datasource/pypi'; @@ -12,6 +13,7 @@ export const supportedDatasources = [ PypiDatasource.id, GithubTagsDatasource.id, GithubReleasesDatasource.id, + GitRefsDatasource.id, ]; export const supportsLockFileMaintenance = true; diff --git a/lib/modules/manager/poetry/schema.ts b/lib/modules/manager/poetry/schema.ts index 460ddee33812ff..621f844b7c5a48 100644 --- a/lib/modules/manager/poetry/schema.ts +++ b/lib/modules/manager/poetry/schema.ts @@ -7,6 +7,7 @@ import { uniq } from '../../../util/uniq'; import { GitRefsDatasource } from '../../datasource/git-refs'; import { GithubTagsDatasource } from '../../datasource/github-tags'; import { PypiDatasource } from '../../datasource/pypi'; +import * as gitVersioning from '../../versioning/git'; import * as pep440Versioning from '../../versioning/pep440'; import * as poetryVersioning from '../../versioning/poetry'; import { dependencyPattern } from '../pip_requirements/extract'; @@ -35,39 +36,45 @@ const PoetryGitDependency = z git: z.string(), tag: z.string().optional().catch(undefined), version: z.string().optional().catch(undefined), + branch: z.string().optional().catch(undefined), + rev: z.string().optional().catch(undefined), }) - .transform(({ git, tag, version }): PackageDependency => { - if (!tag) { - const res: PackageDependency = { - datasource: GitRefsDatasource.id, - packageName: git, - skipReason: 'git-dependency', - }; - - if (version) { - res.currentValue = version; + .transform(({ git, tag, version, branch, rev }): PackageDependency => { + if (tag) { + const { source, owner, name } = parseGitUrl(git); + if (source === 'github.com') { + const repo = `${owner}/${name}`; + return { + datasource: GithubTagsDatasource.id, + currentValue: tag, + packageName: repo, + }; + } else { + return { + datasource: GitRefsDatasource.id, + currentValue: tag, + packageName: git, + skipReason: 'git-dependency', + }; } - - return res; } - const parsedUrl = parseGitUrl(git); - if (parsedUrl.source !== 'github.com') { + if (rev) { + return { + datasource: GitRefsDatasource.id, + currentValue: branch, + currentDigest: rev, + replaceString: rev, + packageName: git, + }; + } else { return { datasource: GitRefsDatasource.id, - currentValue: tag, + currentValue: version, packageName: git, skipReason: 'git-dependency', }; } - - const { owner, name } = parsedUrl; - const repo = `${owner}/${name}`; - return { - datasource: GithubTagsDatasource.id, - currentValue: tag, - packageName: repo, - }; }); const PoetryPypiDependency = z.union([ @@ -114,6 +121,11 @@ export const PoetryDependencies = LooseRecord( return dep; } + if (dep.datasource === GitRefsDatasource.id && dep.currentDigest) { + dep.versioning = gitVersioning.id; + return dep; + } + // istanbul ignore if: normaly should not happen if (!dep.currentValue) { dep.skipReason = 'unspecified-version'; diff --git a/lib/modules/manager/poetry/types.ts b/lib/modules/manager/poetry/types.ts index d88e278b78dbac..97191116dc18e6 100644 --- a/lib/modules/manager/poetry/types.ts +++ b/lib/modules/manager/poetry/types.ts @@ -22,6 +22,8 @@ export interface PoetryDependency { git?: string; tag?: string; version?: string; + branch?: string; + rev?: string; } export interface PoetrySource { From fdf3adfe24e5e311b2fea78665b139d40a6932a9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 4 Jan 2024 15:47:50 +0000 Subject: [PATCH 148/173] chore(deps): update actions/dependency-review-action action to v3.1.5 (#26506) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/dependency-review.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index b3d1eaf354c805..2df475006e109d 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -12,4 +12,4 @@ jobs: uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: 'Dependency Review' - uses: actions/dependency-review-action@01bc87099ba56df1e897b6874784491ea6309bc4 # v3.1.4 + uses: actions/dependency-review-action@c74b580d73376b7750d3d2a50bfb8adc2c937507 # v3.1.5 From 561ec80bad0da234ea55c38d0f97bae53ddc31c8 Mon Sep 17 00:00:00 2001 From: Danny Koppenhagen Date: Thu, 4 Jan 2024 23:29:18 +0100 Subject: [PATCH 149/173] feat(presets): add Analog monorepo group (#26468) --- lib/config/presets/internal/monorepo.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/config/presets/internal/monorepo.ts b/lib/config/presets/internal/monorepo.ts index ba213b43904c5d..be75e781267c41 100644 --- a/lib/config/presets/internal/monorepo.ts +++ b/lib/config/presets/internal/monorepo.ts @@ -16,6 +16,7 @@ const repoGroups = { 'algoliasearch-autocomplete': 'https://github.com/algolia/autocomplete', 'algoliasearch-client-javascript': 'https://github.com/algolia/algoliasearch-client-javascript', + analog: 'https://github.com/analogjs/analog', angular: 'https://github.com/angular/angular', 'angular-cli': 'https://github.com/angular/angular-cli', 'angular-eslint': 'https://github.com/angular-eslint/angular-eslint', From a03994f75776153eff54cf2edae6e59b3c1592a2 Mon Sep 17 00:00:00 2001 From: Michael Kriese Date: Fri, 5 Jan 2024 10:40:37 +0100 Subject: [PATCH 150/173] feat(config-migration): support editorconfig `max_line_length` (#26513) --- .../__fixtures__/.global_editorconfig | 1 + .../__fixtures__/.json_editorconfig | 3 ++ lib/util/json-writer/code-format.ts | 1 + lib/util/json-writer/editor-config.spec.ts | 8 ++--- lib/util/json-writer/editor-config.ts | 1 + .../branch/migrated-data.spec.ts | 35 +++++++++++++++++-- .../config-migration/branch/migrated-data.ts | 27 ++++++++++++-- 7 files changed, 66 insertions(+), 10 deletions(-) diff --git a/lib/util/json-writer/__fixtures__/.global_editorconfig b/lib/util/json-writer/__fixtures__/.global_editorconfig index 712d48e6c0cedd..54a4aa49ab63bc 100644 --- a/lib/util/json-writer/__fixtures__/.global_editorconfig +++ b/lib/util/json-writer/__fixtures__/.global_editorconfig @@ -1,3 +1,4 @@ [*] indent_style = space indent_size = 6 +max_line_length = 160 diff --git a/lib/util/json-writer/__fixtures__/.json_editorconfig b/lib/util/json-writer/__fixtures__/.json_editorconfig index c7a221961de91a..487051e1763595 100644 --- a/lib/util/json-writer/__fixtures__/.json_editorconfig +++ b/lib/util/json-writer/__fixtures__/.json_editorconfig @@ -1,2 +1,5 @@ +[*] +max_line_length = off + [*.json] indent_style = tab diff --git a/lib/util/json-writer/code-format.ts b/lib/util/json-writer/code-format.ts index 2e86f0f592268f..e435f905f0662d 100644 --- a/lib/util/json-writer/code-format.ts +++ b/lib/util/json-writer/code-format.ts @@ -3,4 +3,5 @@ import type { IndentationType } from './indentation-type'; export interface CodeFormat { indentationSize?: number; indentationType?: IndentationType; + maxLineLength?: number | 'off'; } diff --git a/lib/util/json-writer/editor-config.spec.ts b/lib/util/json-writer/editor-config.spec.ts index 0139c907666dc5..f015329f36588a 100644 --- a/lib/util/json-writer/editor-config.spec.ts +++ b/lib/util/json-writer/editor-config.spec.ts @@ -33,7 +33,6 @@ describe('util/json-writer/editor-config', () => { }); it('should handle empty .editorconfig file', async () => { - expect.assertions(2); Fixtures.mock({ '.editorconfig': '', }); @@ -41,20 +40,20 @@ describe('util/json-writer/editor-config', () => { expect(format.indentationSize).toBeUndefined(); expect(format.indentationType).toBeUndefined(); + expect(format.maxLineLength).toBeUndefined(); }); it('should handle global config from .editorconfig', async () => { - expect.assertions(2); Fixtures.mock({ '.editorconfig': Fixtures.get('.global_editorconfig'), }); const format = await EditorConfig.getCodeFormat(defaultConfigFile); expect(format.indentationSize).toBe(6); expect(format.indentationType).toBe('space'); + expect(format.maxLineLength).toBe(160); }); it('should return undefined in case of exception', async () => { - expect.assertions(2); Fixtures.mock({ '.editorconfig': Fixtures.get('.global_editorconfig'), }); @@ -70,7 +69,6 @@ describe('util/json-writer/editor-config', () => { }); it('should not handle non json config from .editorconfig', async () => { - expect.assertions(2); Fixtures.mock({ '.editorconfig': Fixtures.get('.non_json_editorconfig'), }); @@ -81,12 +79,12 @@ describe('util/json-writer/editor-config', () => { }); it('should handle json config from .editorconfig', async () => { - expect.assertions(1); Fixtures.mock({ '.editorconfig': Fixtures.get('.json_editorconfig'), }); const format = await EditorConfig.getCodeFormat(defaultConfigFile); expect(format.indentationType).toBe('tab'); + expect(format.maxLineLength).toBe('off'); }); }); diff --git a/lib/util/json-writer/editor-config.ts b/lib/util/json-writer/editor-config.ts index 5216039a1f550a..5474e655dee114 100644 --- a/lib/util/json-writer/editor-config.ts +++ b/lib/util/json-writer/editor-config.ts @@ -13,6 +13,7 @@ export class EditorConfig { return { indentationSize: EditorConfig.getIndentationSize(knownProps), indentationType: EditorConfig.getIndentationType(knownProps), + maxLineLength: knownProps.max_line_length as number | 'off' | undefined, }; } catch (err) { logger.warn({ err }, 'Failed to parse editor config'); 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 acafa26226c39a..c63ca22f81730c 100644 --- a/lib/workers/repository/config-migration/branch/migrated-data.spec.ts +++ b/lib/workers/repository/config-migration/branch/migrated-data.spec.ts @@ -5,12 +5,14 @@ import { mockedFunction, scm } from '../../../../../test/util'; import { migrateConfig } from '../../../../config/migration'; import { logger } from '../../../../logger'; import { readLocalFile } from '../../../../util/fs'; +import { EditorConfig } from '../../../../util/json-writer'; import { detectRepoFileConfig } from '../../init/merge'; import { MigratedDataFactory, applyPrettierFormatting } from './migrated-data'; jest.mock('../../../../config/migration'); jest.mock('../../../../util/git'); jest.mock('../../../../util/fs'); +jest.mock('../../../../util/json-writer'); jest.mock('../../init/merge'); jest.mock('detect-indent'); @@ -191,13 +193,42 @@ describe('workers/repository/config-migration/branch/migrated-data', () => { }); it('formats with default 2 spaces', async () => { - mockedFunction(scm.getFileList).mockResolvedValue(['.prettierrc']); + mockedFunction(scm.getFileList).mockResolvedValue([ + '.prettierrc', + '.editorconfig', + ]); + mockedFunction(EditorConfig.getCodeFormat).mockResolvedValueOnce({ + maxLineLength: 80, + }); await expect( - applyPrettierFormatting(migratedData.content, 'json', { + applyPrettierFormatting('.prettierrc', migratedData.content, 'json', { amount: 0, indent: ' ', }), ).resolves.toEqual(formattedMigratedData.content); }); + + it('formats with printWith=Infinity', async () => { + mockedFunction(scm.getFileList).mockResolvedValue([ + '.prettierrc', + '.editorconfig', + ]); + mockedFunction(EditorConfig.getCodeFormat).mockResolvedValueOnce({ + maxLineLength: 'off', + }); + await expect( + applyPrettierFormatting( + '.prettierrc', + `{\n"extends":[":separateMajorReleases",":prImmediately",":renovatePrefix",":semanticPrefixFixDepsChoreOthers"]}`, + 'json', + { + amount: 0, + indent: ' ', + }, + ), + ).resolves.toBe( + `{\n "extends": [":separateMajorReleases", ":prImmediately", ":renovatePrefix", ":semanticPrefixFixDepsChoreOthers"]\n}\n`, + ); + }); }); }); diff --git a/lib/workers/repository/config-migration/branch/migrated-data.ts b/lib/workers/repository/config-migration/branch/migrated-data.ts index 84d91607357de9..e96a24d9ecdb75 100644 --- a/lib/workers/repository/config-migration/branch/migrated-data.ts +++ b/lib/workers/repository/config-migration/branch/migrated-data.ts @@ -1,12 +1,14 @@ +import is from '@sindresorhus/is'; import detectIndent from 'detect-indent'; import JSON5 from 'json5'; -import type { BuiltInParserName } from 'prettier'; +import type { BuiltInParserName, Options } from 'prettier'; 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 { EditorConfig } from '../../../../util/json-writer'; import { detectRepoFileConfig } from '../../init/merge'; export interface MigratedData { @@ -37,6 +39,7 @@ const prettierConfigFilenames = new Set([ export type PrettierParser = BuiltInParserName; export async function applyPrettierFormatting( + filename: string, content: string, parser: PrettierParser, indent?: Indent, @@ -48,6 +51,10 @@ export async function applyPrettierFormatting( prettierConfigFilenames.has(file), ); + const editorconfigExists = fileList.some( + (file) => file === '.editorconfig', + ); + if (!prettierExists) { try { const packageJsonContent = await readLocalFile('package.json', 'utf8'); @@ -63,12 +70,26 @@ export async function applyPrettierFormatting( if (!prettierExists) { return content; } - const options = { + + const options: Options = { parser, tabWidth: indent?.amount === 0 ? 2 : indent?.amount, useTabs: indent?.type === 'tab', }; + if (editorconfigExists) { + const editorconf = await EditorConfig.getCodeFormat(filename); + + // https://github.com/prettier/prettier/blob/bab892242a1f9d8fcae50514b9304bf03f2e25ab/src/config/editorconfig/editorconfig-to-prettier.js#L47 + if (editorconf.maxLineLength) { + options.printWidth = is.number(editorconf.maxLineLength) + ? editorconf.maxLineLength + : Number.POSITIVE_INFINITY; + } + + // TODO: support editor config `indent_style` and `indent_size` + } + return prettier().format(content, options); } finally { logger.trace('applyPrettierFormatting - END'); @@ -103,7 +124,7 @@ export class MigratedDataFactory { indent, }: MigratedData): Promise { const parser = upath.extname(filename).replace('.', '') as PrettierParser; - return applyPrettierFormatting(content, parser, indent); + return applyPrettierFormatting(filename, content, parser, indent); } private static async build(): Promise { From 4c1f3892587b7ad2eb8b5f08f52cb25a1fc7b67c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 5 Jan 2024 09:55:22 +0000 Subject: [PATCH 151/173] build(deps): update dependency simple-git to v3.22.0 (#26514) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 3404939c03a1a4..220620b46a9a44 100644 --- a/package.json +++ b/package.json @@ -239,7 +239,7 @@ "semver-stable": "3.0.0", "semver-utils": "1.1.4", "shlex": "2.1.2", - "simple-git": "3.21.0", + "simple-git": "3.22.0", "slugify": "1.6.6", "source-map-support": "0.5.21", "toml-eslint-parser": "0.9.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cd935eac856192..09b0e8ef118333 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -291,8 +291,8 @@ importers: specifier: 2.1.2 version: 2.1.2 simple-git: - specifier: 3.21.0 - version: 3.21.0 + specifier: 3.22.0 + version: 3.22.0 slugify: specifier: 1.6.6 version: 1.6.6 @@ -9656,8 +9656,8 @@ packages: pkg-conf: 2.1.0 dev: true - /simple-git@3.21.0: - resolution: {integrity: sha512-oTzw9248AF5bDTMk9MrxsRzEzivMlY+DWH0yWS4VYpMhNLhDWnN06pCtaUyPnqv/FpsdeNmRqmZugMABHRPdDA==} + /simple-git@3.22.0: + resolution: {integrity: sha512-6JujwSs0ac82jkGjMHiCnTifvf1crOiY/+tfs/Pqih6iow7VrpNKRRNdWm6RtaXpvvv/JGNYhlUtLhGFqHF+Yw==} dependencies: '@kwsites/file-exists': 1.1.1 '@kwsites/promise-deferred': 1.1.1 From 0c9266967323b6666bfe8834c06e67f34434888f Mon Sep 17 00:00:00 2001 From: laundry-96 Date: Fri, 5 Jan 2024 18:41:45 +0800 Subject: [PATCH 152/173] feat(rpm): added rpm versioning functionality (#26340) Co-authored-by: Michael Kriese --- lib/modules/versioning/api.ts | 2 + lib/modules/versioning/rpm/index.spec.ts | 189 +++++++++++++++ lib/modules/versioning/rpm/index.ts | 282 +++++++++++++++++++++++ 3 files changed, 473 insertions(+) create mode 100644 lib/modules/versioning/rpm/index.spec.ts create mode 100644 lib/modules/versioning/rpm/index.ts diff --git a/lib/modules/versioning/api.ts b/lib/modules/versioning/api.ts index 417c8657a7e2d1..aaf75903ff3150 100644 --- a/lib/modules/versioning/api.ts +++ b/lib/modules/versioning/api.ts @@ -29,6 +29,7 @@ import * as python from './python'; import * as redhat from './redhat'; import * as regex from './regex'; import * as rez from './rez'; +import * as rpm from './rpm'; import * as ruby from './ruby'; import * as semver from './semver'; import * as semverCoerced from './semver-coerced'; @@ -70,6 +71,7 @@ api.set(python.id, python.api); api.set(redhat.id, redhat.api); api.set(regex.id, regex.api); api.set(rez.id, rez.api); +api.set(rpm.id, rpm.api); api.set(ruby.id, ruby.api); api.set(semver.id, semver.api); api.set(semverCoerced.id, semverCoerced.api); diff --git a/lib/modules/versioning/rpm/index.spec.ts b/lib/modules/versioning/rpm/index.spec.ts new file mode 100644 index 00000000000000..117e89aa40fb63 --- /dev/null +++ b/lib/modules/versioning/rpm/index.spec.ts @@ -0,0 +1,189 @@ +import rpm from '.'; + +describe('modules/versioning/rpm/index', () => { + test.each` + version | expected + ${'1.1'} | ${true} + ${'1.3.RC2'} | ${true} + ${'0:1.1-1'} | ${true} + ${'a:1.1-1'} | ${false} + ${'1.1:1.3-1'} | ${false} + ${'1.1a:1.3-1'} | ${false} + ${'1a:1.3-1'} | ${false} + ${'-1:1.3-1'} | ${false} + ${'1:1:1:2-1'} | ${true} + ${'1:a:b:c:2-1'} | ${true} + ${'1:3_3.2-1'} | ${true} + ${'1:3!3.2-1'} | ${true} + ${'1:3/3.2-1'} | ${true} + ${'1.0-3_2'} | ${true} + ${'1.0-3!3'} | ${true} + ${'1.0-3/3'} | ${true} + ${'1.0+ä1-1'} | ${true} + ${'1,0-1'} | ${true} + ${'2:1.1-1'} | ${true} + ${'1.1.1-0rpmian1'} | ${true} + ${'1.1.1+really1.1.2-0rpmian1'} | ${true} + ${'2.31-13+rpm11u5'} | ${true} + ${'1:0.17.20140318svn632.el7'} | ${true} + ${'2.7.7+dfsg-12'} | ${true} + ${'8.20140605hgacf1c26e3029.el7'} | ${true} + ${'5:0.5.20120830CVS.el7'} | ${true} + ${'1:6.0.1r16-1.1build1'} | ${true} + ${'1.el6'} | ${true} + ${'1:2.20.1-1~bpo9+1'} | ${true} + ${'v1.4'} | ${true} + ${'3.5.0'} | ${true} + ${'4.2.21.Final'} | ${true} + ${'0.6.5.1'} | ${true} + ${'20100527'} | ${true} + ${'2.1.0-M3'} | ${true} + ${'4.3.20.RELEASE'} | ${true} + ${'1.1-groovy-2.4'} | ${true} + ${'0.8a'} | ${true} + ${'3.1.0.GA'} | ${true} + ${'3.0.0-beta.3'} | ${true} + ${'foo'} | ${true} + ${'1.2.3.4.5.6.7'} | ${true} + ${'0a1b2c3'} | ${true} + ${'0a1b2c3d'} | ${true} + ${'0a1b2c3d4e5f6a7b8c9d0a1b2c3d4e5f6a7b8c9d'} | ${true} + ${'0a1b2c3d4e5f6a7b8c9d0a1b2c3d4e5f6a7b8c9d0'} | ${true} + ${'0a1b2C3'} | ${true} + ${'0z1b2c3'} | ${true} + ${'0A1b2c3d4e5f6a7b8c9d0a1b2c3d4e5f6a7b8c9d'} | ${true} + ${'123098140293'} | ${true} + ${'3.12.0-1~a1^20231001'} | ${true} + ${'1.2.3^20231001'} | ${true} + `('isValid("$version") === $expected', ({ version, expected }) => { + expect(rpm.isValid(version)).toBe(expected); + }); + + test.each` + a | b | expected + ${''} | ${''} | ${true} + ${'~a'} | ${'~~'} | ${false} + ${'~'} | ${'~'} | ${true} + ${'~'} | ${'1'} | ${false} + ${'1~'} | ${'~'} | ${false} + ${'1'} | ${'a'} | ${false} + ${'2.4'} | ${'2.4'} | ${true} + ${'2.4.~'} | ${'2.4'} | ${false} + ${'2.4'} | ${'2.4.~'} | ${false} + ${'2.4.0'} | ${'2.4.0'} | ${true} + ${'2.4.0'} | ${'2.4'} | ${false} + ${'2.4.1'} | ${'2.4'} | ${false} + ${'2.4.2'} | ${'2.4.1'} | ${false} + ${'0.8a'} | ${'0.8a'} | ${true} + ${'90.5.20120830CVS.el6'} | ${'0.5.20120830CVS.el7'} | ${false} + ${'0.5.20120830CVS.el7'} | ${'0.5.20120830CVS.el6'} | ${false} + ${'0.5.20120830CVS.el7'} | ${'0.5.20120830CVS.el7'} | ${true} + ${'2.31-13+rpm11u5'} | ${'2.31-13+rpm11u5'} | ${true} + ${'2.31-13+rpm11u5'} | ${'2.31-13+rpm11u4'} | ${false} + ${'1.4-'} | ${'1.4'} | ${true} + ${'v1.4'} | ${'1.4'} | ${false} + ${'0:1.4'} | ${'1.4'} | ${true} + ${'1:1.4'} | ${'1.4'} | ${false} + ${'1.4-1'} | ${'1.4-2'} | ${false} + ${'0:1.4'} | ${'a:1.4'} | ${false} + ${'a:1.4'} | ${'0:1.4'} | ${false} + ${'3.12.0-1~^2023'} | ${'3.12.0-1^2023'} | ${false} + `('equals("$a", "$b") === $expected', ({ a, b, expected }) => { + expect(rpm.equals(a, b)).toBe(expected); + }); + + test.each` + a | b | expected + ${'2.4.0'} | ${'2.4'} | ${true} + ${'2.4.2'} | ${'2.4.1'} | ${true} + ${'2.4.beta'} | ${'2.4.alpha'} | ${true} + ${'1.9'} | ${'2'} | ${false} + ${'1.9'} | ${'1.9.1'} | ${false} + ${'2.4'} | ${'2.4.beta'} | ${false} + ${'2.4.0'} | ${'2.4.beta'} | ${true} + ${'2.4.beta'} | ${'2.4'} | ${true} + ${'2.4.beta'} | ${'2.4.0'} | ${false} + ${'2.4~'} | ${'2.4~~'} | ${true} + ${'2.4'} | ${'2.4~'} | ${true} + ${'2.4a'} | ${'2.4'} | ${true} + ${'2.31-13+rpm11u5'} | ${'2.31-9'} | ${true} + ${'2.31-13+rpm11u5'} | ${'2.31-13+rpm10u5'} | ${true} + ${'2.31-13+rpm11u5'} | ${'2.31-13+rpm11u4'} | ${true} + ${'1.9'} | ${'1:1.7'} | ${false} + ${'1.9'} | ${'1.12'} | ${false} + ${'1.12'} | ${'1.9'} | ${true} + ${'1:1.9'} | ${'1:1.7'} | ${true} + ${'2.4.0.beta1'} | ${'2.4.0.Beta1'} | ${true} + ${'1:1.0'} | ${'1:1.0~'} | ${true} + ${'1:1.0Z0-0'} | ${'1:1.0'} | ${true} + ${'1:1.0Z0-0'} | ${'1:1.0A0-0'} | ${true} + ${'1:1.0a0-0'} | ${'1:1.0Z0-0'} | ${true} + ${'1:1.0z0-0'} | ${'1:1.0a0-0'} | ${true} + ${'1:1.0+0-0'} | ${'1:1.0z0-0'} | ${true} + ${'1:1.0-0-0'} | ${'1:1.0+0-0'} | ${false} + ${'1:1.0.0-0'} | ${'1:1.0-0-0'} | ${true} + ${'1:1.0:0-0'} | ${'1:1.0.0-0'} | ${false} + ${'a:1.4'} | ${'0:1.4'} | ${true} + ${'0:1.4'} | ${'a:1.4'} | ${true} + ${'a:1.4'} | ${'a:1.4'} | ${true} + ${'a1'} | ${'a~'} | ${true} + ${'a0'} | ${'a~'} | ${true} + ${'aa'} | ${'a1'} | ${true} + ${'ab'} | ${'a0'} | ${true} + ${'10'} | ${'1.'} | ${true} + ${'10'} | ${'1a'} | ${true} + ${'a'} | ${'A'} | ${true} + ${'A'} | ${'a'} | ${false} + ${'A1'} | ${'Aa'} | ${false} + ${'aaaaa1'} | ${'aaaaaaaaaaaa2'} | ${false} + ${'a-1~^20231001'} | ${'a-1^20231001'} | ${false} + ${'1'} | ${'2'} | ${false} + ${'a-1~pre2^20231001'} | ${'a-1~pre2^20231002'} | ${false} + ${'a-1'} | ${'a-1~pre1'} | ${true} + ${'4.20-4~beta4'} | ${'4.20-4'} | ${false} + ${'1.2.3~beta2'} | ${'1.2.3~alpha1'} | ${true} + ${'1.2.3-4~alpha1'} | ${'1.2.3-4~beta2'} | ${false} + ${'}}}'} | ${'{{{'} | ${false} + `('isGreaterThan("$a", "$b") === $expected', ({ a, b, expected }) => { + expect(rpm.isGreaterThan(a, b)).toBe(expected); + }); + + test.each` + version | expected + ${'v1.3.0'} | ${1} + ${'2-0-1'} | ${2} + ${'2.31-13+rpm11u5'} | ${2} + ${'1:2.3.1'} | ${2} + ${'foo'} | ${null} + ${'8'} | ${8} + ${'1.0'} | ${1} + `('getMajor("$version") === $expected', ({ version, expected }) => { + expect(rpm.getMajor(version)).toBe(expected); + }); + + test.each` + version | expected + ${'v1.3.0'} | ${3} + ${'2-0-1'} | ${0} + ${'2.31-13+rpm11u5'} | ${31} + ${'1:2.3.1'} | ${3} + ${'foo'} | ${null} + ${'8'} | ${null} + ${'1.0'} | ${0} + `('getMinor("$version") === $expected', ({ version, expected }) => { + expect(rpm.getMinor(version)).toBe(expected); + }); + + test.each` + version | expected + ${'v1.3.0'} | ${0} + ${'2-0-1'} | ${1} + ${'2.31-13+rpm11u5'} | ${13} + ${'1:2.3.1'} | ${1} + ${'foo'} | ${null} + ${'8'} | ${null} + ${'1.0'} | ${null} + `('getPatch("$version") === $expected', ({ version, expected }) => { + expect(rpm.getPatch(version)).toBe(expected); + }); +}); diff --git a/lib/modules/versioning/rpm/index.ts b/lib/modules/versioning/rpm/index.ts new file mode 100644 index 00000000000000..1c4fa202f3cce9 --- /dev/null +++ b/lib/modules/versioning/rpm/index.ts @@ -0,0 +1,282 @@ +import is from '@sindresorhus/is'; +import { regEx } from '../../../util/regex'; +import { GenericVersion, GenericVersioningApi } from '../generic'; +import type { VersioningApi } from '../types'; + +export const id = 'rpm'; +export const displayName = 'RPM version'; +export const urls = [ + 'https://docs.fedoraproject.org/en-US/packaging-guidelines/Versioning/', + 'https://fedoraproject.org/wiki/Package_Versioning_Examples', + 'https://fedoraproject.org/wiki/User:Tibbs/TildeCaretVersioning', +]; +export const supportsRanges = false; + +const alphaNumPattern = regEx(/([a-zA-Z]+)|(\d+)|(~)/g); +const epochPattern = regEx(/^\d+$/); + +export interface RpmVersion extends GenericVersion { + /** + * epoch, defaults to 0 if not present, are used to leave version mistakes and previous + * versioning schemes behind. + */ + epoch: number; + /** + * upstreamVersion is the main version part: it defines the version of origin software + * that was packaged. + */ + upstreamVersion: string; + /** + * rpmRelease is used to distinguish between different versions of packaging for the + * same upstream version. + */ + rpmRelease: string; + + /** + * rpmPreRelease is used to distinguish versions of prerelease of the same upstream and release version + * Example: Python 3.12.0-1 > Python 3.12.0-1~a1 + */ + rpmPreRelease: string; + + /** + * snapshot is an archive taken from upstream's source code control system which is not equivalent to any release version. + * This field must at minimum consist of the date in eight-digit "YYYYMMDD" format. The packager MAY + * include up to 17 characters of additional information after the date. The following formats are suggested: + * YYYYMMDD. + * YYYYMMDD + */ + snapshot: string; +} + +class RpmVersioningApi extends GenericVersioningApi { + /** + * https://github.com/rpm-software-management/rpm/blob/e3c11a790367016aed7ea48cfcc78751a71ce862/rpmio/rpmvercmp.c#L16 + */ + protected _parse(version: string): RpmVersion | null { + let remainingVersion = version; + + let epoch = 0; + const epochIndex = remainingVersion.indexOf(':'); + if (epochIndex !== -1) { + const epochStr = remainingVersion.slice(0, epochIndex); + if (epochPattern.test(epochStr)) { + epoch = parseInt(epochStr, 10); + } else { + return null; + } + + remainingVersion = remainingVersion.slice(epochIndex + 1); + } + + let upstreamVersion: string; + let rpmRelease = ''; + let rpmPreRelease = ''; + let snapshot = ''; + const releaseIndex = remainingVersion.indexOf('-'); + const prereleaseIndex = remainingVersion.indexOf('~'); + + // Note: There can be a snapshot if there is no prerelease. Snapshot always beat no snapshot, + // so if there is 3.12.0-1 vs 3.12.0-1^20231110, the snapshot wins. + // The logic below only creates snapshot IF there is a prerleease version. This logic is NOT + // correct, but the result is still correct due to the caret being ignored in release, and + // release continue comparing + // + // Note: If there IS a tilde preceding the caret, then snapshot DOES NOT win + // Example: 3.12.0-1~^20231001 LOSES to 3.12.0-1 and + // 3.12.0-1~^20231001 LOSES to 3.12.0-1^20231001 + const snapshotIndex = remainingVersion.indexOf('^'); + + if (releaseIndex >= 0) { + upstreamVersion = remainingVersion.slice(0, releaseIndex); + + // Do NOT splice out prerelease, we need to distinguish if the flag is set or not, regardless if there is a version. + // The tilde will get filtered out during regex + if (prereleaseIndex >= 0) { + rpmRelease = remainingVersion.slice(releaseIndex, prereleaseIndex); + if (snapshotIndex >= 0) { + rpmPreRelease = remainingVersion.slice( + prereleaseIndex, + snapshotIndex, + ); + snapshot = remainingVersion.slice(snapshotIndex + 1); + } else { + rpmPreRelease = remainingVersion.slice(prereleaseIndex); + } + } else { + rpmRelease = remainingVersion.slice(releaseIndex + 1); + } + } else { + upstreamVersion = remainingVersion; + } + + upstreamVersion; + + const release = [...remainingVersion.matchAll(regEx(/\d+/g))].map((m) => + parseInt(m[0], 10), + ); + + return { + epoch, + upstreamVersion, + rpmRelease, + release, + rpmPreRelease, + snapshot, + }; + } + + protected _compare_string(s1: string, s2: string): number { + if (s1 === s2) { + return 0; + } + + const minLength = Math.min(s1.length, s2.length); + + for (let i = 0; i < minLength; i++) { + const c1 = s1[i]; + const c2 = s2[i]; + + if (c1 === c2) { + continue; + } + + if (c1 > c2) { + return 1; + } else if (c1 < c2) { + return -1; + } + } + + // Okay, they've been the exact same up until now, so return the longer one + return s1.length > s2.length ? 1 : -1; + } + + /** + * Taken from https://github.com/rpm-software-management/rpm/blob/master/rpmio/rpmvercmp.c + */ + protected _compare_glob(v1: string, v2: string): number { + if (v1 === v2) { + return 0; + } + + const matchesv1 = v1.match(alphaNumPattern) ?? []; + const matchesv2 = v2.match(alphaNumPattern) ?? []; + const matches = Math.min(matchesv1.length, matchesv2.length); + + for (let i = 0; i < matches; i++) { + const matchv1 = matchesv1[i]; + const matchv2 = matchesv2[i]; + + // compare tildes + if (matchv1?.[0] === '~' || matchv2?.[0] === '~') { + if (matchv1?.[0] !== '~') { + return 1; + } + + if (matchv2?.[0] !== '~') { + return -1; + } + } + + if (is.numericString(matchv1?.[0])) { + // numbers are greater than letters + if (!is.numericString(matchv2?.[0])) { + return 1; + } + + //We clearly have a number here, so return which is greater + const result = matchv1.localeCompare(matchv2, undefined, { + numeric: true, + }); + + if (result === 0) { + continue; + } + + return Math.sign(result); + } else if (is.numericString(matchv2?.[0])) { + return -1; + } + + // We have two string globs, compare them + const compared_value = this._compare_string(matchv1, matchv2); + if (compared_value !== 0) { + return compared_value; + } + } + + // segments were all the same, but separators were different + if (matchesv1.length === matchesv2.length) { + return 0; + } + + // If there is a tilde in a segment past the minimum number of segments, find it + if (matchesv1.length > matches && matchesv1[matches][0] === '~') { + return -1; + } + + if (matchesv2.length > matches && matchesv2[matches][0] === '~') { + return 1; + } + + // whichever has the most segments wins + return matchesv1.length > matchesv2.length ? 1 : -1; + } + + protected override _compare(version: string, other: string): number { + const parsed1 = this._parse(version); + const parsed2 = this._parse(other); + + if (!(parsed1 && parsed2)) { + return 1; + } + + // Greater epoch wins + if (parsed1.epoch !== parsed2.epoch) { + return Math.sign(parsed1.epoch - parsed2.epoch); + } + + // Greater upstream version wins + const upstreamVersionDifference = this._compare_glob( + parsed1.upstreamVersion, + parsed2.upstreamVersion, + ); + + if (upstreamVersionDifference !== 0) { + return upstreamVersionDifference; + } + + // Greater release version wins + const releaseVersionDifference = this._compare_glob( + parsed1.rpmRelease, + parsed2.rpmRelease, + ); + + if (releaseVersionDifference !== 0) { + return releaseVersionDifference; + } + + // No Prerelease wins + if (parsed1.rpmPreRelease === '' && parsed2.rpmPreRelease !== '') { + return 1; + } else if (parsed1.rpmPreRelease !== '' && parsed2.rpmPreRelease === '') { + return -1; + } + + const preReleaseDifference = this._compare_glob( + parsed1.rpmPreRelease, + parsed2.rpmPreRelease, + ); + + if (preReleaseDifference !== 0) { + return releaseVersionDifference; + } + + // Greater Snapshot wins + return this._compare_glob(parsed1.snapshot, parsed2.snapshot); + } +} + +export const api: VersioningApi = new RpmVersioningApi(); + +export default api; From 8bcf740626fff1d24f96cbc25bf037068c83ed9a Mon Sep 17 00:00:00 2001 From: Michael Kriese Date: Fri, 5 Jan 2024 11:44:05 +0100 Subject: [PATCH 153/173] docs(gerrit): make image link relative (#26515) --- lib/modules/platform/gerrit/readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/modules/platform/gerrit/readme.md b/lib/modules/platform/gerrit/readme.md index bc82cee7a834ae..ec753c7ab66e1a 100644 --- a/lib/modules/platform/gerrit/readme.md +++ b/lib/modules/platform/gerrit/readme.md @@ -12,7 +12,7 @@ We did not test Gerrit `2.x` with NoteDB (only in `2.15` and `2.16`), but could ## Authentication
- ![Gerrit HTTP access token](/assets/images/gerrit-http-password.png){ loading=lazy } + ![Gerrit HTTP access token](../../../assets/images/gerrit-http-password.png){ loading=lazy }
First, create a HTTP access token for the Renovate account.
From 31dc0fd0780104590456630cd9e6b42afa2fbdeb Mon Sep 17 00:00:00 2001 From: javaxiss Date: Fri, 5 Jan 2024 11:56:21 +0100 Subject: [PATCH 154/173] feat(platform/gitlab): handle detailed_merge_status to proceed with automerge (#26438) Co-authored-by: Michael Kriese --- docs/usage/self-hosted-experimental.md | 8 ++++- lib/modules/platform/gitlab/index.spec.ts | 40 +++++++++++++++++++++++ lib/modules/platform/gitlab/index.ts | 26 +++++++++++++-- 3 files changed, 70 insertions(+), 4 deletions(-) diff --git a/docs/usage/self-hosted-experimental.md b/docs/usage/self-hosted-experimental.md index 01a2993e414873..7ee6a8ee1f39df 100644 --- a/docs/usage/self-hosted-experimental.md +++ b/docs/usage/self-hosted-experimental.md @@ -96,7 +96,7 @@ If set, Renovate will terminate the whole process group of a terminated child pr ## `RENOVATE_X_GITLAB_AUTO_MERGEABLE_CHECK_ATTEMPS` If set to an positive integer, Renovate will use this as the number of attempts to check if a merge request on GitLab is mergable before trying to automerge. -The formula for the delay between attempts is `250 * attempt * attempt` milliseconds. +The formula for the delay between attempts is `RENOVATE_X_GITLAB_MERGE_REQUEST_DELAY * attempt * attempt` milliseconds. Default value: `5` (attempts results in max. 13.75 seconds timeout). @@ -108,6 +108,12 @@ Can be useful for slow-running, self-hosted GitLab instances that don't react fa Default value: `1000` (milliseconds). +## `RENOVATE_X_GITLAB_MERGE_REQUEST_DELAY` + +If set, Renovate will use this as a delay to proceed with an automerge. + +Default value: `250` (milliseconds). + ## `RENOVATE_X_HARD_EXIT` If set to any value, Renovate will use a "hard" `process.exit()` once all work is done, even if a sub-process is otherwise delaying Node.js from exiting. diff --git a/lib/modules/platform/gitlab/index.spec.ts b/lib/modules/platform/gitlab/index.spec.ts index d10b776c062508..57970274be0945 100644 --- a/lib/modules/platform/gitlab/index.spec.ts +++ b/lib/modules/platform/gitlab/index.spec.ts @@ -52,6 +52,7 @@ describe('modules/platform/gitlab/index', () => { delete process.env.GITLAB_IGNORE_REPO_URL; delete process.env.RENOVATE_X_GITLAB_BRANCH_STATUS_DELAY; delete process.env.RENOVATE_X_GITLAB_AUTO_MERGEABLE_CHECK_ATTEMPS; + delete process.env.RENOVATE_X_GITLAB_MERGE_REQUEST_DELAY; }); async function initFakePlatform(version: string) { @@ -1867,6 +1868,45 @@ describe('modules/platform/gitlab/index', () => { ]); }); + it('should parse detailed_merge_status attribute on >= 15.6', async () => { + await initPlatform('15.6.0-ee'); + httpMock + .scope(gitlabApiHost) + .post('/api/v4/projects/undefined/merge_requests') + .reply(200, { + id: 1, + iid: 12345, + title: 'some title', + }) + .get('/api/v4/projects/undefined/merge_requests/12345') + .reply(200) + .get('/api/v4/projects/undefined/merge_requests/12345') + .reply(200) + .get('/api/v4/projects/undefined/merge_requests/12345') + .reply(200) + .put('/api/v4/projects/undefined/merge_requests/12345/merge') + .reply(200); + process.env.RENOVATE_X_GITLAB_AUTO_MERGEABLE_CHECK_ATTEMPS = '3'; + process.env.RENOVATE_X_GITLAB_MERGE_REQUEST_DELAY = '100'; + const pr = await gitlab.createPr({ + sourceBranch: 'some-branch', + targetBranch: 'master', + prTitle: 'some-title', + prBody: 'the-body', + platformOptions: { + usePlatformAutomerge: true, + }, + }); + expect(pr).toEqual({ + id: 1, + iid: 12345, + number: 12345, + sourceBranch: 'some-branch', + title: 'some title', + }); + expect(timers.setTimeout.mock.calls).toMatchObject([[100], [400], [900]]); + }); + it('raises with squash enabled when repository squash option is default_on', async () => { await initPlatform('14.0.0'); diff --git a/lib/modules/platform/gitlab/index.ts b/lib/modules/platform/gitlab/index.ts index de5137f28e7441..44d47ffce053ba 100644 --- a/lib/modules/platform/gitlab/index.ts +++ b/lib/modules/platform/gitlab/index.ts @@ -644,26 +644,46 @@ async function tryPrAutomerge( await ignoreApprovals(pr); } - const desiredStatus = 'can_be_merged'; + let desiredStatus = 'can_be_merged'; // The default value of 5 attempts results in max. 13.75 seconds timeout if no pipeline created. const retryTimes = parseInteger( process.env.RENOVATE_X_GITLAB_AUTO_MERGEABLE_CHECK_ATTEMPS, 5, ); + if (semver.gte(defaults.version, '15.6.0')) { + logger.trace( + { version: defaults.version }, + 'In GitLab 15.6 merge_status, using detailed_merge_status to check the merge request status', + ); + desiredStatus = 'mergeable'; + } + + const mergeDelay = parseInteger( + process.env.RENOVATE_X_GITLAB_MERGE_REQUEST_DELAY, + 250, + ); + // Check for correct merge request status before setting `merge_when_pipeline_succeeds` to `true`. for (let attempt = 1; attempt <= retryTimes; attempt += 1) { const { body } = await gitlabApi.getJson<{ merge_status: string; + detailed_merge_status?: string; pipeline: string; }>(`projects/${config.repository}/merge_requests/${pr}`, { memCache: false, }); // Only continue if the merge request can be merged and has a pipeline. - if (body.merge_status === desiredStatus && body.pipeline !== null) { + if ( + ((desiredStatus === 'mergeable' && + body.detailed_merge_status === desiredStatus) || + (desiredStatus === 'can_be_merged' && + body.merge_status === desiredStatus)) && + body.pipeline !== null + ) { break; } - await setTimeout(250 * attempt ** 2); // exponential backoff + await setTimeout(mergeDelay * attempt ** 2); // exponential backoff } await gitlabApi.putJson( From b39ad3a90b9c61711a7b3e13e5fa3d26f7635fcb Mon Sep 17 00:00:00 2001 From: Marc Mognol <8171300+marcmognol@users.noreply.github.com> Date: Fri, 5 Jan 2024 12:31:53 +0100 Subject: [PATCH 155/173] fix(manager/nuget): Add autoReplaceStringTemplate (#26508) Co-authored-by: Michael Kriese --- lib/modules/manager/nuget/extract.spec.ts | 7 +++++++ lib/modules/manager/nuget/extract.ts | 13 +++---------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/modules/manager/nuget/extract.spec.ts b/lib/modules/manager/nuget/extract.spec.ts index 7070e8f62c5032..69c2cb01e1b005 100644 --- a/lib/modules/manager/nuget/extract.spec.ts +++ b/lib/modules/manager/nuget/extract.spec.ts @@ -80,10 +80,13 @@ describe('modules/manager/nuget/extract', () => { expect(await extractPackageFile(contents, contents, config)).toEqual({ deps: [ { + autoReplaceStringTemplate: + '{{depName}}{{#if newValue}}:{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}', depName: 'mcr.microsoft.com/dotnet/runtime', depType: 'docker', datasource: 'docker', currentValue: '7.0.10', + replaceString: 'mcr.microsoft.com/dotnet/runtime:7.0.10', }, ], packageFileVersion: '0.1.0', @@ -102,12 +105,16 @@ describe('modules/manager/nuget/extract', () => { expect(await extractPackageFile(contents, contents, config)).toEqual({ deps: [ { + autoReplaceStringTemplate: + '{{depName}}{{#if newValue}}:{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}', depName: 'mcr.microsoft.com/dotnet/runtime', depType: 'docker', datasource: 'docker', currentValue: '7.0.10', currentDigest: 'sha256:181067029e094856691ee1ce3782ea3bd3fda01bb5b6d19411d0f673cab1ab19', + replaceString: + 'mcr.microsoft.com/dotnet/runtime:7.0.10@sha256:181067029e094856691ee1ce3782ea3bd3fda01bb5b6d19411d0f673cab1ab19', }, ], packageFileVersion: '0.1.0', diff --git a/lib/modules/manager/nuget/extract.ts b/lib/modules/manager/nuget/extract.ts index f127f32f8160a8..bded64973137c0 100644 --- a/lib/modules/manager/nuget/extract.ts +++ b/lib/modules/manager/nuget/extract.ts @@ -4,7 +4,6 @@ import { logger } from '../../../logger'; import { getSiblingFileName, localPathExists } from '../../../util/fs'; import { hasKey } from '../../../util/object'; import { regEx } from '../../../util/regex'; -import { DockerDatasource } from '../../datasource/docker'; import { NugetDatasource } from '../../datasource/nuget'; import { getDep } from '../dockerfile/extract'; import type { @@ -49,16 +48,10 @@ function extractDepsFromXml(xmlNode: XmlDocument): NugetPackageDependency[] { const { name, attr } = child; if (name === 'ContainerBaseImage') { - const dep = getDep(child.val, true); + const { depName, ...dep } = getDep(child.val, true); - if (is.nonEmptyStringAndNotWhitespace(dep.depName)) { - results.push({ - datasource: DockerDatasource.id, - depType: 'docker', - depName: dep.depName, - currentValue: dep.currentValue, - currentDigest: dep.currentDigest, - }); + if (is.nonEmptyStringAndNotWhitespace(depName)) { + results.push({ ...dep, depName, depType: 'docker' }); } } From a8043366322dfac942f048275355a3f2ce9e148d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 5 Jan 2024 16:16:41 +0000 Subject: [PATCH 156/173] chore(deps): update ghcr.io/containerbase/devcontainer docker tag to v9.31.3 (#26524) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .devcontainer/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 2e78b241ba72ca..9cfb7c0528f506 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1 +1 @@ -FROM ghcr.io/containerbase/devcontainer:9.31.2 +FROM ghcr.io/containerbase/devcontainer:9.31.3 From b837e9db88ddcb66483027e5f07a08652e66b419 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 5 Jan 2024 16:17:52 +0000 Subject: [PATCH 157/173] fix(deps): update ghcr.io/containerbase/sidecar docker tag to v9.31.3 (#26525) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- lib/config/options/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/config/options/index.ts b/lib/config/options/index.ts index 280ec218acf1cc..f088fb11af463c 100644 --- a/lib/config/options/index.ts +++ b/lib/config/options/index.ts @@ -400,7 +400,7 @@ const options: RenovateOptions[] = [ description: 'Change this value to override the default Renovate sidecar image.', type: 'string', - default: 'ghcr.io/containerbase/sidecar:9.31.2', + default: 'ghcr.io/containerbase/sidecar:9.31.3', globalOnly: true, }, { From ecc6028b2a60199418044affdea4512febde1624 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 6 Jan 2024 01:12:19 +0000 Subject: [PATCH 158/173] chore(deps): update dependency @types/node to v18.19.4 (#26530) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 104 ++++++++++++++++++++++++------------------------- 2 files changed, 53 insertions(+), 53 deletions(-) diff --git a/package.json b/package.json index 220620b46a9a44..da939d1a5343f5 100644 --- a/package.json +++ b/package.json @@ -295,7 +295,7 @@ "@types/mdast": "3.0.15", "@types/moo": "0.5.9", "@types/nock": "10.0.3", - "@types/node": "18.19.3", + "@types/node": "18.19.4", "@types/parse-link-header": "2.0.3", "@types/prettier": "2.7.3", "@types/semver": "7.5.6", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 09b0e8ef118333..b7a2c7168e1616 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -449,8 +449,8 @@ importers: specifier: 10.0.3 version: 10.0.3 '@types/node': - specifier: 18.19.3 - version: 18.19.3 + specifier: 18.19.4 + version: 18.19.4 '@types/parse-link-header': specifier: 2.0.3 version: 2.0.3 @@ -546,7 +546,7 @@ importers: version: 8.0.3 jest: specifier: 29.7.0 - version: 29.7.0(@types/node@18.19.3)(ts-node@10.9.2) + version: 29.7.0(@types/node@18.19.4)(ts-node@10.9.2) jest-extended: specifier: 4.0.2 version: 4.0.2(jest@29.7.0) @@ -594,7 +594,7 @@ importers: version: 29.1.1(@babel/core@7.23.7)(@jest/types@29.6.3)(jest@29.7.0)(typescript@5.3.3) ts-node: specifier: 10.9.2 - version: 10.9.2(@swc/core@1.3.101)(@types/node@18.19.3)(typescript@5.3.3) + version: 10.9.2(@swc/core@1.3.101)(@types/node@18.19.4)(typescript@5.3.3) type-fest: specifier: 4.9.0 version: 4.9.0 @@ -2025,7 +2025,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.6.3 - '@types/node': 18.19.3 + '@types/node': 18.19.4 chalk: 4.1.2 jest-message-util: 29.7.0 jest-util: 29.7.0 @@ -2046,14 +2046,14 @@ packages: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 18.19.3 + '@types/node': 18.19.4 ansi-escapes: 4.3.2 chalk: 4.1.2 ci-info: 3.9.0 exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@18.19.3)(ts-node@10.9.2) + jest-config: 29.7.0(@types/node@18.19.4)(ts-node@10.9.2) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -2081,7 +2081,7 @@ packages: dependencies: '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 18.19.3 + '@types/node': 18.19.4 jest-mock: 29.7.0 dev: true @@ -2115,7 +2115,7 @@ packages: dependencies: '@jest/types': 29.6.3 '@sinonjs/fake-timers': 10.3.0 - '@types/node': 18.19.3 + '@types/node': 18.19.4 jest-message-util: 29.7.0 jest-mock: 29.7.0 jest-util: 29.7.0 @@ -2148,7 +2148,7 @@ packages: '@jest/transform': 29.7.0 '@jest/types': 29.6.3 '@jridgewell/trace-mapping': 0.3.20 - '@types/node': 18.19.3 + '@types/node': 18.19.4 chalk: 4.1.2 collect-v8-coverage: 1.0.2 exit: 0.1.2 @@ -2236,7 +2236,7 @@ packages: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 18.19.3 + '@types/node': 18.19.4 '@types/yargs': 17.0.32 chalk: 4.1.2 dev: true @@ -3642,7 +3642,7 @@ packages: /@types/aws4@1.11.6: resolution: {integrity: sha512-5CnVUkHNyLGpD9AnOcK66YyP0qvIh6nhJJoeK8zSl5YKikUcUbdB7SlHevUYVqicgeh6j5AJa1qa/h08dSZHoA==} dependencies: - '@types/node': 18.19.3 + '@types/node': 18.19.4 dev: true /@types/babel__core@7.20.5: @@ -3681,19 +3681,19 @@ packages: /@types/bunyan@1.8.11: resolution: {integrity: sha512-758fRH7umIMk5qt5ELmRMff4mLDlN+xyYzC+dkPTdKwbSkJFvz6xwyScrytPU0QIBbRRwbiE8/BIg8bpajerNQ==} dependencies: - '@types/node': 18.19.3 + '@types/node': 18.19.4 dev: true /@types/bunyan@1.8.9: resolution: {integrity: sha512-ZqS9JGpBxVOvsawzmVt30sP++gSQMTejCkIAQ3VdadOcRE8izTyW66hufvwLeH+YEGP6Js2AW7Gz+RMyvrEbmw==} dependencies: - '@types/node': 18.19.3 + '@types/node': 18.19.4 dev: false /@types/cacache@17.0.2: resolution: {integrity: sha512-IrqHzVX2VRMDQQKa7CtKRnuoCLdRJiLW6hWU+w7i7+AaQ0Ii5bKwJxd5uRK4zBCyrHd3tG6G8zOm2LplxbSfQg==} dependencies: - '@types/node': 18.19.3 + '@types/node': 18.19.4 dev: true /@types/cacheable-request@6.0.3: @@ -3701,7 +3701,7 @@ packages: dependencies: '@types/http-cache-semantics': 4.0.4 '@types/keyv': 3.1.4 - '@types/node': 18.19.3 + '@types/node': 18.19.4 '@types/responselike': 1.0.3 dev: false @@ -3748,7 +3748,7 @@ packages: resolution: {integrity: sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==} dependencies: '@types/jsonfile': 6.1.4 - '@types/node': 18.19.3 + '@types/node': 18.19.4 dev: true /@types/git-url-parse@9.0.3: @@ -3766,7 +3766,7 @@ packages: /@types/graceful-fs@4.1.9: resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} dependencies: - '@types/node': 18.19.3 + '@types/node': 18.19.4 dev: true /@types/http-cache-semantics@4.0.4: @@ -3812,13 +3812,13 @@ packages: /@types/jsonfile@6.1.4: resolution: {integrity: sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==} dependencies: - '@types/node': 18.19.3 + '@types/node': 18.19.4 dev: true /@types/keyv@3.1.4: resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} dependencies: - '@types/node': 18.19.3 + '@types/node': 18.19.4 dev: false /@types/linkify-it@3.0.5: @@ -3851,7 +3851,7 @@ packages: /@types/marshal@0.5.3: resolution: {integrity: sha512-ptxKIirn/lt95Zi/MErrtn/K8VvrByNOAF9gxbIJCxWj9CXAifjAvm/bRMg7WXQjwi1DlbXG6HJ1RzHe6oYEug==} dependencies: - '@types/node': 18.19.3 + '@types/node': 18.19.4 dev: true /@types/mdast@3.0.15: @@ -3882,11 +3882,11 @@ packages: /@types/nock@10.0.3: resolution: {integrity: sha512-OthuN+2FuzfZO3yONJ/QVjKmLEuRagS9TV9lEId+WHL9KhftYG+/2z+pxlr0UgVVXSpVD8woie/3fzQn8ft/Ow==} dependencies: - '@types/node': 18.19.3 + '@types/node': 18.19.4 dev: true - /@types/node@18.19.3: - resolution: {integrity: sha512-k5fggr14DwAytoA/t8rPrIz++lXK7/DqckthCmoZOKNsEbJkId4Z//BqgApXBUGrGddrigYa1oqheo/7YmW4rg==} + /@types/node@18.19.4: + resolution: {integrity: sha512-xNzlUhzoHotIsnFoXmJB+yWmBvFZgKCI9TtPIEdYIMM1KWfwuY8zh7wvc1u1OAXlC7dlf6mZVx/s+Y5KfFz19A==} dependencies: undici-types: 5.26.5 @@ -3904,7 +3904,7 @@ packages: /@types/responselike@1.0.3: resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==} dependencies: - '@types/node': 18.19.3 + '@types/node': 18.19.4 dev: false /@types/semver-stable@3.0.2: @@ -3939,7 +3939,7 @@ packages: /@types/tar@6.1.10: resolution: {integrity: sha512-60ZO+W0tRKJ3ggdzJKp75xKVlNogKYMqGvr2bMH/+k3T0BagfYTnbmVDFMJB1BFttz6yRgP5MDGP27eh7brrqw==} dependencies: - '@types/node': 18.19.3 + '@types/node': 18.19.4 minipass: 4.2.8 dev: true @@ -3984,7 +3984,7 @@ packages: resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} requiresBuild: true dependencies: - '@types/node': 18.19.3 + '@types/node': 18.19.4 dev: false optional: true @@ -5096,7 +5096,7 @@ packages: typescript: 5.3.3 dev: true - /create-jest@29.7.0(@types/node@18.19.3)(ts-node@10.9.2): + /create-jest@29.7.0(@types/node@18.19.4)(ts-node@10.9.2): resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -5105,7 +5105,7 @@ packages: chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@18.19.3)(ts-node@10.9.2) + jest-config: 29.7.0(@types/node@18.19.4)(ts-node@10.9.2) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -5742,7 +5742,7 @@ packages: '@typescript-eslint/eslint-plugin': 6.16.0(@typescript-eslint/parser@6.16.0)(eslint@8.56.0)(typescript@5.3.3) '@typescript-eslint/utils': 5.62.0(eslint@8.56.0)(typescript@5.3.3) eslint: 8.56.0 - jest: 29.7.0(@types/node@18.19.3)(ts-node@10.9.2) + jest: 29.7.0(@types/node@18.19.4)(ts-node@10.9.2) transitivePeerDependencies: - supports-color - typescript @@ -7143,7 +7143,7 @@ packages: '@jest/expect': 29.7.0 '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 18.19.3 + '@types/node': 18.19.4 chalk: 4.1.2 co: 4.6.0 dedent: 1.5.1 @@ -7164,7 +7164,7 @@ packages: - supports-color dev: true - /jest-cli@29.7.0(@types/node@18.19.3)(ts-node@10.9.2): + /jest-cli@29.7.0(@types/node@18.19.4)(ts-node@10.9.2): resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -7178,10 +7178,10 @@ packages: '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@18.19.3)(ts-node@10.9.2) + create-jest: 29.7.0(@types/node@18.19.4)(ts-node@10.9.2) exit: 0.1.2 import-local: 3.1.0 - jest-config: 29.7.0(@types/node@18.19.3)(ts-node@10.9.2) + jest-config: 29.7.0(@types/node@18.19.4)(ts-node@10.9.2) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -7192,7 +7192,7 @@ packages: - ts-node dev: true - /jest-config@29.7.0(@types/node@18.19.3)(ts-node@10.9.2): + /jest-config@29.7.0(@types/node@18.19.4)(ts-node@10.9.2): resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: @@ -7207,7 +7207,7 @@ packages: '@babel/core': 7.23.7 '@jest/test-sequencer': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 18.19.3 + '@types/node': 18.19.4 babel-jest: 29.7.0(@babel/core@7.23.7) chalk: 4.1.2 ci-info: 3.9.0 @@ -7227,7 +7227,7 @@ packages: pretty-format: 29.7.0 slash: 3.0.0 strip-json-comments: 3.1.1 - ts-node: 10.9.2(@swc/core@1.3.101)(@types/node@18.19.3)(typescript@5.3.3) + ts-node: 10.9.2(@swc/core@1.3.101)(@types/node@18.19.4)(typescript@5.3.3) transitivePeerDependencies: - babel-plugin-macros - supports-color @@ -7268,7 +7268,7 @@ packages: '@jest/environment': 29.7.0 '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 18.19.3 + '@types/node': 18.19.4 jest-mock: 29.7.0 jest-util: 29.7.0 dev: true @@ -7282,7 +7282,7 @@ packages: jest: optional: true dependencies: - jest: 29.7.0(@types/node@18.19.3)(ts-node@10.9.2) + jest: 29.7.0(@types/node@18.19.4)(ts-node@10.9.2) jest-diff: 29.7.0 jest-get-type: 29.6.3 dev: true @@ -7298,7 +7298,7 @@ packages: dependencies: '@jest/types': 29.6.3 '@types/graceful-fs': 4.1.9 - '@types/node': 18.19.3 + '@types/node': 18.19.4 anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.11 @@ -7360,7 +7360,7 @@ packages: jest: ^24.0.0 || ^25.0.0 || ^26.0.0 || ^27.0.0 || ^28.0.0 || ^29.0.0 typescript: ^3.0.0 || ^4.0.0 || ^5.0.0 dependencies: - jest: 29.7.0(@types/node@18.19.3)(ts-node@10.9.2) + jest: 29.7.0(@types/node@18.19.4)(ts-node@10.9.2) ts-essentials: 7.0.3(typescript@5.3.3) typescript: 5.3.3 dev: true @@ -7370,7 +7370,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.6.3 - '@types/node': 18.19.3 + '@types/node': 18.19.4 jest-util: 29.7.0 dev: true @@ -7425,7 +7425,7 @@ packages: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 18.19.3 + '@types/node': 18.19.4 chalk: 4.1.2 emittery: 0.13.1 graceful-fs: 4.2.11 @@ -7456,7 +7456,7 @@ packages: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 18.19.3 + '@types/node': 18.19.4 chalk: 4.1.2 cjs-module-lexer: 1.2.3 collect-v8-coverage: 1.0.2 @@ -7508,7 +7508,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.6.3 - '@types/node': 18.19.3 + '@types/node': 18.19.4 chalk: 4.1.2 ci-info: 3.9.0 graceful-fs: 4.2.11 @@ -7533,7 +7533,7 @@ packages: dependencies: '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 18.19.3 + '@types/node': 18.19.4 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.13.1 @@ -7545,13 +7545,13 @@ packages: resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@types/node': 18.19.3 + '@types/node': 18.19.4 jest-util: 29.7.0 merge-stream: 2.0.0 supports-color: 8.1.1 dev: true - /jest@29.7.0(@types/node@18.19.3)(ts-node@10.9.2): + /jest@29.7.0(@types/node@18.19.4)(ts-node@10.9.2): resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -7564,7 +7564,7 @@ packages: '@jest/core': 29.7.0(ts-node@10.9.2) '@jest/types': 29.6.3 import-local: 3.1.0 - jest-cli: 29.7.0(@types/node@18.19.3)(ts-node@10.9.2) + jest-cli: 29.7.0(@types/node@18.19.4)(ts-node@10.9.2) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -10181,7 +10181,7 @@ packages: '@jest/types': 29.6.3 bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@18.19.3)(ts-node@10.9.2) + jest: 29.7.0(@types/node@18.19.4)(ts-node@10.9.2) jest-util: 29.7.0 json5: 2.2.3 lodash.memoize: 4.1.2 @@ -10191,7 +10191,7 @@ packages: yargs-parser: 21.1.1 dev: true - /ts-node@10.9.2(@swc/core@1.3.101)(@types/node@18.19.3)(typescript@5.3.3): + /ts-node@10.9.2(@swc/core@1.3.101)(@types/node@18.19.4)(typescript@5.3.3): resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} hasBin: true peerDependencies: @@ -10211,7 +10211,7 @@ packages: '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 18.19.3 + '@types/node': 18.19.4 acorn: 8.11.3 acorn-walk: 8.3.1 arg: 4.1.3 From da8396e384776b3ee0d0a4c9dc7cc7109b1e1f59 Mon Sep 17 00:00:00 2001 From: Johannes Feichtner <343448+Churro@users.noreply.github.com> Date: Sat, 6 Jan 2024 09:01:31 +0100 Subject: [PATCH 159/173] feat(manager/gradle): add support for micronaut plugin (#26519) --- lib/modules/manager/gradle/parser.spec.ts | 1 + lib/modules/manager/gradle/parser/common.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/lib/modules/manager/gradle/parser.spec.ts b/lib/modules/manager/gradle/parser.spec.ts index 2fb70034c1abc1..a6d35c004757f1 100644 --- a/lib/modules/manager/gradle/parser.spec.ts +++ b/lib/modules/manager/gradle/parser.spec.ts @@ -925,6 +925,7 @@ describe('modules/manager/gradle/parser', () => { ${''} | ${'unknown { toolVersion = "1.2.3" }'} | ${null} ${''} | ${'composeOptions { kotlinCompilerExtensionVersion = "1.2.3" }'} | ${{ depName: 'composeOptions', packageName: GRADLE_PLUGINS['composeOptions'][1], currentValue: '1.2.3' }} ${''} | ${'jmh { jmhVersion = "1.2.3" }'} | ${{ depName: 'jmh', packageName: GRADLE_PLUGINS['jmh'][1], currentValue: '1.2.3' }} + ${''} | ${'micronaut { version = "1.2.3" }'} | ${{ depName: 'micronaut', packageName: GRADLE_PLUGINS['micronaut'][1], currentValue: '1.2.3' }} `('$def | $input', ({ def, input, output }) => { const { deps } = parseGradle([def, input].join('\n')); expect(deps).toMatchObject([output].filter(is.truthy)); diff --git a/lib/modules/manager/gradle/parser/common.ts b/lib/modules/manager/gradle/parser/common.ts index b564fd30c86e61..9505df5137cf77 100644 --- a/lib/modules/manager/gradle/parser/common.ts +++ b/lib/modules/manager/gradle/parser/common.ts @@ -31,6 +31,7 @@ export const GRADLE_PLUGINS = { jacoco: ['toolVersion', 'org.jacoco:jacoco'], jmh: ['jmhVersion', 'org.openjdk.jmh:jmh-core'], lombok: ['version', 'org.projectlombok:lombok'], + micronaut: ['version', 'io.micronaut.platform:micronaut-platform'], pmd: ['toolVersion', 'net.sourceforge.pmd:pmd-java'], spotbugs: ['toolVersion', 'com.github.spotbugs:spotbugs'], }; From a17713c7c3c50cff72b5423a1362b81f4c757b7c Mon Sep 17 00:00:00 2001 From: Norbert Szulc Date: Sat, 6 Jan 2024 10:03:23 +0100 Subject: [PATCH 160/173] fix(manager/pip-compile): mark GitTagsDatasource as supported (#26504) --- lib/modules/manager/pip-compile/index.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/modules/manager/pip-compile/index.ts b/lib/modules/manager/pip-compile/index.ts index dac650f2bcb360..98e616010896be 100644 --- a/lib/modules/manager/pip-compile/index.ts +++ b/lib/modules/manager/pip-compile/index.ts @@ -1,4 +1,5 @@ import type { Category } from '../../../constants'; +import { GitTagsDatasource } from '../../datasource/git-tags'; import { PypiDatasource } from '../../datasource/pypi'; export { extractPackageFile } from '../pip_requirements/extract'; @@ -6,8 +7,6 @@ export { updateArtifacts } from './artifacts'; export const supportsLockFileMaintenance = true; -export const supportedDatasources = [PypiDatasource.id]; - export const defaultConfig = { fileMatch: [], lockFileMaintenance: { @@ -18,3 +17,5 @@ export const defaultConfig = { }; export const categories: Category[] = ['python']; + +export const supportedDatasources = [PypiDatasource.id, GitTagsDatasource.id]; From 290e15752e8ab03d080dcea7f4d4eb4aebb2c3f7 Mon Sep 17 00:00:00 2001 From: RahulGautamSingh Date: Sun, 7 Jan 2024 18:56:57 +0545 Subject: [PATCH 161/173] fix(containerbase): support ranges in flutter and dart sdks (#26535) --- lib/util/exec/containerbase.spec.ts | 62 +++++++++++++++++++++++++++++ lib/util/exec/containerbase.ts | 4 +- 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/lib/util/exec/containerbase.spec.ts b/lib/util/exec/containerbase.spec.ts index 0f73c6f74b053a..f8b7ec829339ac 100644 --- a/lib/util/exec/containerbase.spec.ts +++ b/lib/util/exec/containerbase.spec.ts @@ -172,6 +172,68 @@ describe('util/exec/containerbase', () => { }), ).toBe('2020.8.13'); }); + + it.each` + version | expected + ${'>=2.5.0 <2.6.0'} | ${'2.5.1'} + ${'>=2.6.0-0.0.pre <2.7.0-0.0.pre'} | ${'2.6.0-0.0.pre'} + ${'>=2.8.0'} | ${'2.8.1'} + ${'<2.9.0-0.1.pre'} | ${'2.8.1'} + ${'2.10.0-0.2.pre'} | ${'2.10.0-0.2.pre'} + ${'>=2.11.0-0.1.pre'} | ${'2.12.0-4.1.pre'} + ${'<=2.10.0'} | ${'2.8.1'} + `( + 'supports flutter ranges "$version" => "$expected"', + async ({ version: constraint, expected }) => { + datasource.getPkgReleases.mockResolvedValueOnce({ + releases: [ + { version: '2.5.0-1.0.pre', isStable: false }, + { version: '2.5.0', isStable: true }, + { version: '2.5.1', isStable: true }, + { version: '2.6.0-0.0.pre', isStable: false }, + { version: '2.8.0', isStable: true }, + { version: '2.8.1', isStable: true }, + { version: '2.9.0-0.1.pre', isStable: false }, + { version: '2.12.0-4.1.pre', isStable: false }, + ], + }); + expect( + await resolveConstraint({ toolName: 'flutter', constraint }), + ).toBe(expected); + }, + ); + + it.each` + version | expected + ${'>2.17.0 <2.17.8'} | ${'2.17.7'} + ${'>2.19.0'} | ${'2.19.0-81.0.dev'} + ${'<=2.17.5'} | ${'2.17.5'} + ${'<2.17.5'} | ${'2.19.0-81.0.dev'} + ${'<2.17.6'} | ${'2.17.5'} + `( + 'supports dart ranges "$version" => "$expected"', + async ({ version: constraint, expected }) => { + datasource.getPkgReleases.mockResolvedValueOnce({ + releases: [ + { version: '2.17.0-69.2.beta', isStable: false }, + { version: '2.17.0-7.0.dev', isStable: false }, + { version: '2.17.5', isStable: true }, + { version: '2.17.6', isStable: true }, + { version: '2.17.7', isStable: true }, + { version: '2.18.0', isStable: true }, + { version: '2.18.0-44.1.beta', isStable: false }, + { version: '2.18.0-99.0.dev', isStable: false }, + { version: '2.18.4', isStable: true }, + { version: '2.18.5', isStable: true }, + { version: '2.19.0-255.2.beta', isStable: false }, + { version: '2.19.0-81.0.dev', isStable: false }, + ], + }); + expect(await resolveConstraint({ toolName: 'dart', constraint })).toBe( + expected, + ); + }, + ); }); describe('generateInstallCommands()', () => { diff --git a/lib/util/exec/containerbase.ts b/lib/util/exec/containerbase.ts index 3df791e8dfe3a8..73111067539ba1 100644 --- a/lib/util/exec/containerbase.ts +++ b/lib/util/exec/containerbase.ts @@ -189,12 +189,12 @@ const allToolConfig: Record = { dart: { datasource: 'dart-version', packageName: 'dart', - versioning: semverVersioningId, + versioning: npmVersioningId, }, flutter: { datasource: 'flutter-version', packageName: 'flutter', - versioning: semverVersioningId, + versioning: npmVersioningId, }, }; From d39e107c4ce8098be3438ed877ceefe0c1c007b7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 7 Jan 2024 13:24:11 +0000 Subject: [PATCH 162/173] chore(deps): update dependency @swc/core to v1.3.102 (#26536) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 76 +++++++++++++++++++++++++------------------------- 2 files changed, 39 insertions(+), 39 deletions(-) diff --git a/package.json b/package.json index da939d1a5343f5..7b45650c3fcd3f 100644 --- a/package.json +++ b/package.json @@ -266,7 +266,7 @@ "@openpgp/web-stream-tools": "0.0.14", "@renovate/eslint-plugin": "file:tools/eslint", "@semantic-release/exec": "6.0.3", - "@swc/core": "1.3.101", + "@swc/core": "1.3.102", "@types/auth-header": "1.0.6", "@types/aws4": "1.11.6", "@types/breejs__later": "4.1.5", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b7a2c7168e1616..a64256a6f70dd3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -362,8 +362,8 @@ importers: specifier: 6.0.3 version: 6.0.3(semantic-release@22.0.12) '@swc/core': - specifier: 1.3.101 - version: 1.3.101 + specifier: 1.3.102 + version: 1.3.102 '@types/auth-header': specifier: 1.0.6 version: 1.0.6 @@ -594,7 +594,7 @@ importers: version: 29.1.1(@babel/core@7.23.7)(@jest/types@29.6.3)(jest@29.7.0)(typescript@5.3.3) ts-node: specifier: 10.9.2 - version: 10.9.2(@swc/core@1.3.101)(@types/node@18.19.4)(typescript@5.3.3) + version: 10.9.2(@swc/core@1.3.102)(@types/node@18.19.4)(typescript@5.3.3) type-fest: specifier: 4.9.0 version: 4.9.0 @@ -3434,8 +3434,8 @@ packages: tslib: 2.6.2 dev: false - /@swc/core-darwin-arm64@1.3.101: - resolution: {integrity: sha512-mNFK+uHNPRXSnfTOG34zJOeMl2waM4hF4a2NY7dkMXrPqw9CoJn4MwTXJcyMiSz1/BnNjjTCHF3Yhj0jPxmkzQ==} + /@swc/core-darwin-arm64@1.3.102: + resolution: {integrity: sha512-CJDxA5Wd2cUMULj3bjx4GEoiYyyiyL8oIOu4Nhrs9X+tlg8DnkCm4nI57RJGP8Mf6BaXPIJkHX8yjcefK2RlDA==} engines: {node: '>=10'} cpu: [arm64] os: [darwin] @@ -3443,8 +3443,8 @@ packages: dev: true optional: true - /@swc/core-darwin-x64@1.3.101: - resolution: {integrity: sha512-B085j8XOx73Fg15KsHvzYWG262bRweGr3JooO1aW5ec5pYbz5Ew9VS5JKYS03w2UBSxf2maWdbPz2UFAxg0whw==} + /@swc/core-darwin-x64@1.3.102: + resolution: {integrity: sha512-X5akDkHwk6oAer49oER0qZMjNMkLH3IOZaV1m98uXIasAGyjo5WH1MKPeMLY1sY6V6TrufzwiSwD4ds571ytcg==} engines: {node: '>=10'} cpu: [x64] os: [darwin] @@ -3452,8 +3452,8 @@ packages: dev: true optional: true - /@swc/core-linux-arm-gnueabihf@1.3.101: - resolution: {integrity: sha512-9xLKRb6zSzRGPqdz52Hy5GuB1lSjmLqa0lST6MTFads3apmx4Vgs8Y5NuGhx/h2I8QM4jXdLbpqQlifpzTlSSw==} + /@swc/core-linux-arm-gnueabihf@1.3.102: + resolution: {integrity: sha512-kJH3XtZP9YQdjq/wYVBeFuiVQl4HaC4WwRrIxAHwe2OyvrwUI43dpW3LpxSggBnxXcVCXYWf36sTnv8S75o2Gw==} engines: {node: '>=10'} cpu: [arm] os: [linux] @@ -3461,8 +3461,8 @@ packages: dev: true optional: true - /@swc/core-linux-arm64-gnu@1.3.101: - resolution: {integrity: sha512-oE+r1lo7g/vs96Weh2R5l971dt+ZLuhaUX+n3BfDdPxNHfObXgKMjO7E+QS5RbGjv/AwiPCxQmbdCp/xN5ICJA==} + /@swc/core-linux-arm64-gnu@1.3.102: + resolution: {integrity: sha512-flQP2WDyCgO24WmKA1wjjTx+xfCmavUete2Kp6yrM+631IHLGnr17eu7rYJ/d4EnDBId/ytMyrnWbTVkaVrpbQ==} engines: {node: '>=10'} cpu: [arm64] os: [linux] @@ -3470,8 +3470,8 @@ packages: dev: true optional: true - /@swc/core-linux-arm64-musl@1.3.101: - resolution: {integrity: sha512-OGjYG3H4BMOTnJWJyBIovCez6KiHF30zMIu4+lGJTCrxRI2fAjGLml3PEXj8tC3FMcud7U2WUn6TdG0/te2k6g==} + /@swc/core-linux-arm64-musl@1.3.102: + resolution: {integrity: sha512-bQEQSnC44DyoIGLw1+fNXKVGoCHi7eJOHr8BdH0y1ooy9ArskMjwobBFae3GX4T1AfnrTaejyr0FvLYIb0Zkog==} engines: {node: '>=10'} cpu: [arm64] os: [linux] @@ -3479,8 +3479,8 @@ packages: dev: true optional: true - /@swc/core-linux-x64-gnu@1.3.101: - resolution: {integrity: sha512-/kBMcoF12PRO/lwa8Z7w4YyiKDcXQEiLvM+S3G9EvkoKYGgkkz4Q6PSNhF5rwg/E3+Hq5/9D2R+6nrkF287ihg==} + /@swc/core-linux-x64-gnu@1.3.102: + resolution: {integrity: sha512-dFvnhpI478svQSxqISMt00MKTDS0e4YtIr+ioZDG/uJ/q+RpcNy3QI2KMm05Fsc8Y0d4krVtvCKWgfUMsJZXAg==} engines: {node: '>=10'} cpu: [x64] os: [linux] @@ -3488,8 +3488,8 @@ packages: dev: true optional: true - /@swc/core-linux-x64-musl@1.3.101: - resolution: {integrity: sha512-kDN8lm4Eew0u1p+h1l3JzoeGgZPQ05qDE0czngnjmfpsH2sOZxVj1hdiCwS5lArpy7ktaLu5JdRnx70MkUzhXw==} + /@swc/core-linux-x64-musl@1.3.102: + resolution: {integrity: sha512-+a0M3CvjeIRNA/jTCzWEDh2V+mhKGvLreHOL7J97oULZy5yg4gf7h8lQX9J8t9QLbf6fsk+0F8bVH1Ie/PbXjA==} engines: {node: '>=10'} cpu: [x64] os: [linux] @@ -3497,8 +3497,8 @@ packages: dev: true optional: true - /@swc/core-win32-arm64-msvc@1.3.101: - resolution: {integrity: sha512-9Wn8TTLWwJKw63K/S+jjrZb9yoJfJwCE2RV5vPCCWmlMf3U1AXj5XuWOLUX+Rp2sGKau7wZKsvywhheWm+qndQ==} + /@swc/core-win32-arm64-msvc@1.3.102: + resolution: {integrity: sha512-w76JWLjkZNOfkB25nqdWUNCbt0zJ41CnWrJPZ+LxEai3zAnb2YtgB/cCIrwxDebRuMgE9EJXRj7gDDaTEAMOOQ==} engines: {node: '>=10'} cpu: [arm64] os: [win32] @@ -3506,8 +3506,8 @@ packages: dev: true optional: true - /@swc/core-win32-ia32-msvc@1.3.101: - resolution: {integrity: sha512-onO5KvICRVlu2xmr4//V2je9O2XgS1SGKpbX206KmmjcJhXN5EYLSxW9qgg+kgV5mip+sKTHTAu7IkzkAtElYA==} + /@swc/core-win32-ia32-msvc@1.3.102: + resolution: {integrity: sha512-vlDb09HiGqKwz+2cxDS9T5/461ipUQBplvuhW+cCbzzGuPq8lll2xeyZU0N1E4Sz3MVdSPx1tJREuRvlQjrwNg==} engines: {node: '>=10'} cpu: [ia32] os: [win32] @@ -3515,8 +3515,8 @@ packages: dev: true optional: true - /@swc/core-win32-x64-msvc@1.3.101: - resolution: {integrity: sha512-T3GeJtNQV00YmiVw/88/nxJ/H43CJvFnpvBHCVn17xbahiVUOPOduh3rc9LgAkKiNt/aV8vU3OJR+6PhfMR7UQ==} + /@swc/core-win32-x64-msvc@1.3.102: + resolution: {integrity: sha512-E/jfSD7sShllxBwwgDPeXp1UxvIqehj/ShSUqq1pjR/IDRXngcRSXKJK92mJkNFY7suH6BcCWwzrxZgkO7sWmw==} engines: {node: '>=10'} cpu: [x64] os: [win32] @@ -3524,8 +3524,8 @@ packages: dev: true optional: true - /@swc/core@1.3.101: - resolution: {integrity: sha512-w5aQ9qYsd/IYmXADAnkXPGDMTqkQalIi+kfFf/MHRKTpaOL7DHjMXwPp/n8hJ0qNjRvchzmPtOqtPBiER50d8A==} + /@swc/core@1.3.102: + resolution: {integrity: sha512-OAjNLY/f6QWKSDzaM3bk31A+OYHu6cPa9P/rFIx8X5d24tHXUpRiiq6/PYI6SQRjUPlB72GjsjoEU8F+ALadHg==} engines: {node: '>=10'} requiresBuild: true peerDependencies: @@ -3537,16 +3537,16 @@ packages: '@swc/counter': 0.1.2 '@swc/types': 0.1.5 optionalDependencies: - '@swc/core-darwin-arm64': 1.3.101 - '@swc/core-darwin-x64': 1.3.101 - '@swc/core-linux-arm-gnueabihf': 1.3.101 - '@swc/core-linux-arm64-gnu': 1.3.101 - '@swc/core-linux-arm64-musl': 1.3.101 - '@swc/core-linux-x64-gnu': 1.3.101 - '@swc/core-linux-x64-musl': 1.3.101 - '@swc/core-win32-arm64-msvc': 1.3.101 - '@swc/core-win32-ia32-msvc': 1.3.101 - '@swc/core-win32-x64-msvc': 1.3.101 + '@swc/core-darwin-arm64': 1.3.102 + '@swc/core-darwin-x64': 1.3.102 + '@swc/core-linux-arm-gnueabihf': 1.3.102 + '@swc/core-linux-arm64-gnu': 1.3.102 + '@swc/core-linux-arm64-musl': 1.3.102 + '@swc/core-linux-x64-gnu': 1.3.102 + '@swc/core-linux-x64-musl': 1.3.102 + '@swc/core-win32-arm64-msvc': 1.3.102 + '@swc/core-win32-ia32-msvc': 1.3.102 + '@swc/core-win32-x64-msvc': 1.3.102 dev: true /@swc/counter@0.1.2: @@ -7227,7 +7227,7 @@ packages: pretty-format: 29.7.0 slash: 3.0.0 strip-json-comments: 3.1.1 - ts-node: 10.9.2(@swc/core@1.3.101)(@types/node@18.19.4)(typescript@5.3.3) + ts-node: 10.9.2(@swc/core@1.3.102)(@types/node@18.19.4)(typescript@5.3.3) transitivePeerDependencies: - babel-plugin-macros - supports-color @@ -10191,7 +10191,7 @@ packages: yargs-parser: 21.1.1 dev: true - /ts-node@10.9.2(@swc/core@1.3.101)(@types/node@18.19.4)(typescript@5.3.3): + /ts-node@10.9.2(@swc/core@1.3.102)(@types/node@18.19.4)(typescript@5.3.3): resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} hasBin: true peerDependencies: @@ -10206,7 +10206,7 @@ packages: optional: true dependencies: '@cspotcode/source-map-support': 0.8.1 - '@swc/core': 1.3.101 + '@swc/core': 1.3.102 '@tsconfig/node10': 1.0.9 '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 From d79115b09f2ad0f8bff2df7015cb0e9e2cfcb187 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 8 Jan 2024 01:53:17 +0000 Subject: [PATCH 163/173] docs: update references to renovate/renovate to v37.126.2 (#26539) 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 f32118662c16b9..9e250ee1b7113a 100644 --- a/docs/usage/docker.md +++ b/docs/usage/docker.md @@ -383,7 +383,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:37.115.0 +FROM renovate/renovate:37.126.2 # Include the "Docker tip" which you can find here https://cloud.google.com/sdk/docs/install # under "Installation" for "Debian/Ubuntu" RUN ... From 60fa5f6a3084e47d5d1708b0528300bfd3f43635 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 8 Jan 2024 01:55:03 +0000 Subject: [PATCH 164/173] chore(deps): lock file maintenance (#26540) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- pnpm-lock.yaml | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a64256a6f70dd3..8ff4b6faf475d2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4694,8 +4694,8 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true dependencies: - caniuse-lite: 1.0.30001572 - electron-to-chromium: 1.4.616 + caniuse-lite: 1.0.30001576 + electron-to-chromium: 1.4.623 node-releases: 2.0.14 update-browserslist-db: 1.0.13(browserslist@4.22.2) dev: true @@ -4821,8 +4821,8 @@ packages: engines: {node: '>=10'} dev: true - /caniuse-lite@1.0.30001572: - resolution: {integrity: sha512-1Pbh5FLmn5y4+QhNyJE9j3/7dK44dGB83/ZMjv/qJk86TvDbjk0LosiZo0i0WB0Vx607qMX9jYrn1VLHCkN4rw==} + /caniuse-lite@1.0.30001576: + resolution: {integrity: sha512-ff5BdakGe2P3SQsMsiqmt1Lc8221NR1VzHj5jXN5vBny9A6fpze94HiVV/n7XRosOlsShJcvMv5mdnpjOGCEgg==} dev: true /cardinal@2.1.1: @@ -5394,8 +5394,8 @@ packages: semver: 7.5.4 dev: false - /electron-to-chromium@1.4.616: - resolution: {integrity: sha512-1n7zWYh8eS0L9Uy+GskE0lkBUNK83cXTVJI0pU3mGprFsbfSdAc15VTFbo+A+Bq4pwstmL30AVcEU3Fo463lNg==} + /electron-to-chromium@1.4.623: + resolution: {integrity: sha512-lKoz10iCYlP1WtRYdh5MvocQPWVRoI7ysp6qf18bmeBgR8abE6+I2CsfyNKztRDZvhdWc+krKT6wS7Neg8sw3A==} dev: true /email-addresses@5.0.0: @@ -10667,7 +10667,6 @@ packages: /wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - requiresBuild: true /write-file-atomic@3.0.3: resolution: {integrity: sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==} From 085ef7c0387efa4d8c7050ef8876d7e443a81761 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20Goinvic?= <97093369+gaelgatelement@users.noreply.github.com> Date: Mon, 8 Jan 2024 09:09:45 +0100 Subject: [PATCH 165/173] fix(helmv3): add --force-update when adding a repo (#26512) --- .../__snapshots__/artifacts.spec.ts.snap | 30 +++++++++---------- lib/modules/manager/helmv3/artifacts.spec.ts | 10 +++---- lib/modules/manager/helmv3/artifacts.ts | 2 +- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/lib/modules/manager/helmv3/__snapshots__/artifacts.spec.ts.snap b/lib/modules/manager/helmv3/__snapshots__/artifacts.spec.ts.snap index 974ad178fb2648..61454159f84dc4 100644 --- a/lib/modules/manager/helmv3/__snapshots__/artifacts.spec.ts.snap +++ b/lib/modules/manager/helmv3/__snapshots__/artifacts.spec.ts.snap @@ -3,7 +3,7 @@ exports[`modules/manager/helmv3/artifacts alias name is picked, when repository is as alias and dependency defined 1`] = ` [ { - "cmd": "helm repo add repo1 https://gitlab.com/api/v4/projects/xxxxxxx/packages/helm/stable --username basicUser --password secret", + "cmd": "helm repo add repo1 https://gitlab.com/api/v4/projects/xxxxxxx/packages/helm/stable --force-update --username basicUser --password secret", "options": { "cwd": "/tmp/github/some/repo", "encoding": "utf-8", @@ -52,7 +52,7 @@ exports[`modules/manager/helmv3/artifacts alias name is picked, when repository exports[`modules/manager/helmv3/artifacts do not add registryAliases to repository list 1`] = ` [ { - "cmd": "helm repo add jetstack https://charts.jetstack.io", + "cmd": "helm repo add jetstack https://charts.jetstack.io --force-update", "options": { "cwd": "/tmp/github/some/repo", "encoding": "utf-8", @@ -74,7 +74,7 @@ exports[`modules/manager/helmv3/artifacts do not add registryAliases to reposito }, }, { - "cmd": "helm repo add nginx https://kubernetes.github.io/ingress-nginx", + "cmd": "helm repo add nginx https://kubernetes.github.io/ingress-nginx --force-update", "options": { "cwd": "/tmp/github/some/repo", "encoding": "utf-8", @@ -145,7 +145,7 @@ exports[`modules/manager/helmv3/artifacts log into private registries and reposi }, }, { - "cmd": "helm repo add repo-test https://gitlab.com/api/v4/projects/xxxxxxx/packages/helm/stable --username basicUser --password secret", + "cmd": "helm repo add repo-test https://gitlab.com/api/v4/projects/xxxxxxx/packages/helm/stable --force-update --username basicUser --password secret", "options": { "cwd": "/tmp/github/some/repo", "encoding": "utf-8", @@ -216,7 +216,7 @@ exports[`modules/manager/helmv3/artifacts log into private registries and reposi }, }, { - "cmd": "helm repo add stable the_stable_url", + "cmd": "helm repo add stable the_stable_url --force-update", "options": { "cwd": "/tmp/github/some/repo", "encoding": "utf-8", @@ -238,7 +238,7 @@ exports[`modules/manager/helmv3/artifacts log into private registries and reposi }, }, { - "cmd": "helm repo add repo1 https://the_repo1_url --username basicUser --password secret", + "cmd": "helm repo add repo1 https://the_repo1_url --force-update --username basicUser --password secret", "options": { "cwd": "/tmp/github/some/repo", "encoding": "utf-8", @@ -260,7 +260,7 @@ exports[`modules/manager/helmv3/artifacts log into private registries and reposi }, }, { - "cmd": "helm repo add repo-test https://gitlab.com/api/v4/projects/xxxxxxx/packages/helm/stable", + "cmd": "helm repo add repo-test https://gitlab.com/api/v4/projects/xxxxxxx/packages/helm/stable --force-update", "options": { "cwd": "/tmp/github/some/repo", "encoding": "utf-8", @@ -309,7 +309,7 @@ exports[`modules/manager/helmv3/artifacts log into private registries and reposi exports[`modules/manager/helmv3/artifacts returns null if unchanged 1`] = ` [ { - "cmd": "helm repo add repo-test https://gitlab.com/api/v4/projects/xxxxxxx/packages/helm/stable", + "cmd": "helm repo add repo-test https://gitlab.com/api/v4/projects/xxxxxxx/packages/helm/stable --force-update", "options": { "cwd": "/tmp/github/some/repo", "encoding": "utf-8", @@ -358,7 +358,7 @@ exports[`modules/manager/helmv3/artifacts returns null if unchanged 1`] = ` exports[`modules/manager/helmv3/artifacts returns updated Chart.lock 1`] = ` [ { - "cmd": "helm repo add repo-test https://gitlab.com/api/v4/projects/xxxxxxx/packages/helm/stable", + "cmd": "helm repo add repo-test https://gitlab.com/api/v4/projects/xxxxxxx/packages/helm/stable --force-update", "options": { "cwd": "/tmp/github/some/repo", "encoding": "utf-8", @@ -407,7 +407,7 @@ exports[`modules/manager/helmv3/artifacts returns updated Chart.lock 1`] = ` exports[`modules/manager/helmv3/artifacts returns updated Chart.lock for lockfile maintenance 1`] = ` [ { - "cmd": "helm repo add repo-test https://gitlab.com/api/v4/projects/xxxxxxx/packages/helm/stable", + "cmd": "helm repo add repo-test https://gitlab.com/api/v4/projects/xxxxxxx/packages/helm/stable --force-update", "options": { "cwd": "/tmp/github/some/repo", "encoding": "utf-8", @@ -468,7 +468,7 @@ exports[`modules/manager/helmv3/artifacts returns updated Chart.lock with docker }, }, { - "cmd": "docker run --rm --name=renovate_sidecar --label=renovate_child -v "/tmp/github/some/repo":"/tmp/github/some/repo" -v "/tmp/renovate/cache":"/tmp/renovate/cache" -e HELM_EXPERIMENTAL_OCI -e HELM_REGISTRY_CONFIG -e HELM_REPOSITORY_CONFIG -e HELM_REPOSITORY_CACHE -e CONTAINERBASE_CACHE_DIR -w "/tmp/github/some/repo" ghcr.io/containerbase/sidecar bash -l -c "install-tool helm v3.7.2 && helm repo add repo-test https://gitlab.com/api/v4/projects/xxxxxxx/packages/helm/stable && helm dependency update ''"", + "cmd": "docker run --rm --name=renovate_sidecar --label=renovate_child -v "/tmp/github/some/repo":"/tmp/github/some/repo" -v "/tmp/renovate/cache":"/tmp/renovate/cache" -e HELM_EXPERIMENTAL_OCI -e HELM_REGISTRY_CONFIG -e HELM_REPOSITORY_CONFIG -e HELM_REPOSITORY_CACHE -e CONTAINERBASE_CACHE_DIR -w "/tmp/github/some/repo" ghcr.io/containerbase/sidecar bash -l -c "install-tool helm v3.7.2 && helm repo add repo-test https://gitlab.com/api/v4/projects/xxxxxxx/packages/helm/stable --force-update && helm dependency update ''"", "options": { "cwd": "/tmp/github/some/repo", "encoding": "utf-8", @@ -496,7 +496,7 @@ exports[`modules/manager/helmv3/artifacts returns updated Chart.lock with docker exports[`modules/manager/helmv3/artifacts sets repositories from registryAliases 1`] = ` [ { - "cmd": "helm repo add stable the_stable_url", + "cmd": "helm repo add stable the_stable_url --force-update", "options": { "cwd": "/tmp/github/some/repo", "encoding": "utf-8", @@ -518,7 +518,7 @@ exports[`modules/manager/helmv3/artifacts sets repositories from registryAliases }, }, { - "cmd": "helm repo add repo1 the_repo1_url", + "cmd": "helm repo add repo1 the_repo1_url --force-update", "options": { "cwd": "/tmp/github/some/repo", "encoding": "utf-8", @@ -540,7 +540,7 @@ exports[`modules/manager/helmv3/artifacts sets repositories from registryAliases }, }, { - "cmd": "helm repo add repo-test https://gitlab.com/api/v4/projects/xxxxxxx/packages/helm/stable", + "cmd": "helm repo add repo-test https://gitlab.com/api/v4/projects/xxxxxxx/packages/helm/stable --force-update", "options": { "cwd": "/tmp/github/some/repo", "encoding": "utf-8", @@ -601,7 +601,7 @@ exports[`modules/manager/helmv3/artifacts sets repositories from registryAliases }, }, { - "cmd": "docker run --rm --name=renovate_sidecar --label=renovate_child -v "/tmp/github/some/repo":"/tmp/github/some/repo" -v "/tmp/renovate/cache":"/tmp/renovate/cache" -e HELM_EXPERIMENTAL_OCI -e HELM_REGISTRY_CONFIG -e HELM_REPOSITORY_CONFIG -e HELM_REPOSITORY_CACHE -e CONTAINERBASE_CACHE_DIR -w "/tmp/github/some/repo" ghcr.io/containerbase/sidecar bash -l -c "install-tool helm v3.7.2 && helm repo add stable the_stable_url && helm repo add repo1 the_repo1_url && helm repo add repo-test https://gitlab.com/api/v4/projects/xxxxxxx/packages/helm/stable && helm dependency update ''"", + "cmd": "docker run --rm --name=renovate_sidecar --label=renovate_child -v "/tmp/github/some/repo":"/tmp/github/some/repo" -v "/tmp/renovate/cache":"/tmp/renovate/cache" -e HELM_EXPERIMENTAL_OCI -e HELM_REGISTRY_CONFIG -e HELM_REPOSITORY_CONFIG -e HELM_REPOSITORY_CACHE -e CONTAINERBASE_CACHE_DIR -w "/tmp/github/some/repo" ghcr.io/containerbase/sidecar bash -l -c "install-tool helm v3.7.2 && helm repo add stable the_stable_url --force-update && helm repo add repo1 the_repo1_url --force-update && helm repo add repo-test https://gitlab.com/api/v4/projects/xxxxxxx/packages/helm/stable --force-update && helm dependency update ''"", "options": { "cwd": "/tmp/github/some/repo", "encoding": "utf-8", diff --git a/lib/modules/manager/helmv3/artifacts.spec.ts b/lib/modules/manager/helmv3/artifacts.spec.ts index dcc9351d49a27f..2a551f1c4b6898 100644 --- a/lib/modules/manager/helmv3/artifacts.spec.ts +++ b/lib/modules/manager/helmv3/artifacts.spec.ts @@ -290,7 +290,7 @@ describe('modules/manager/helmv3/artifacts', () => { ]); expect(execSnapshots).toMatchObject([ { - cmd: 'helm repo add repo-test https://gitlab.com/api/v4/projects/xxxxxxx/packages/helm/stable', + cmd: 'helm repo add repo-test https://gitlab.com/api/v4/projects/xxxxxxx/packages/helm/stable --force-update', }, { cmd: "helm dependency update ''", @@ -343,7 +343,7 @@ describe('modules/manager/helmv3/artifacts', () => { ]); expect(execSnapshots).toMatchObject([ { - cmd: 'helm repo add repo-test https://gitlab.com/api/v4/projects/xxxxxxx/packages/helm/stable', + cmd: 'helm repo add repo-test https://gitlab.com/api/v4/projects/xxxxxxx/packages/helm/stable --force-update', options: { env: { HELM_EXPERIMENTAL_OCI: '1', @@ -411,7 +411,7 @@ describe('modules/manager/helmv3/artifacts', () => { ]); expect(execSnapshots).toMatchObject([ { - cmd: 'helm repo add repo-test https://gitlab.com/api/v4/projects/xxxxxxx/packages/helm/stable', + cmd: 'helm repo add repo-test https://gitlab.com/api/v4/projects/xxxxxxx/packages/helm/stable --force-update', options: { env: { HELM_EXPERIMENTAL_OCI: '1', @@ -486,7 +486,7 @@ describe('modules/manager/helmv3/artifacts', () => { ]); expect(execSnapshots).toMatchObject([ { - cmd: 'helm repo add repo-test https://gitlab.com/api/v4/projects/xxxxxxx/packages/helm/stable', + cmd: 'helm repo add repo-test https://gitlab.com/api/v4/projects/xxxxxxx/packages/helm/stable --force-update', options: { env: { HELM_EXPERIMENTAL_OCI: '1', @@ -546,7 +546,7 @@ describe('modules/manager/helmv3/artifacts', () => { ).toBeNull(); expect(execSnapshots).toMatchObject([ { - cmd: 'helm repo add repo-test https://gitlab.com/api/v4/projects/xxxxxxx/packages/helm/stable', + cmd: 'helm repo add repo-test https://gitlab.com/api/v4/projects/xxxxxxx/packages/helm/stable --force-update', options: { env: { HELM_EXPERIMENTAL_OCI: '1', diff --git a/lib/modules/manager/helmv3/artifacts.ts b/lib/modules/manager/helmv3/artifacts.ts index 0228d5f9d82da3..f7d18c092efe0b 100644 --- a/lib/modules/manager/helmv3/artifacts.ts +++ b/lib/modules/manager/helmv3/artifacts.ts @@ -70,7 +70,7 @@ async function helmCommands( // add helm repos if an alias or credentials for the url are defined classicRepositories.forEach((value) => { const { username, password } = value.hostRule; - const parameters = [`${value.repository}`]; + const parameters = [`${value.repository}`, `--force-update`]; const isPrivateRepo = username && password; if (isPrivateRepo) { parameters.push(`--username ${quote(username)}`); From b33d09cbc7cb8aec579f2b61ed2c6e647fc69f45 Mon Sep 17 00:00:00 2001 From: Michael Kriese Date: Mon, 8 Jan 2024 12:34:55 +0100 Subject: [PATCH 166/173] fix(datasource/docker): add cache decorator to `getDockerHubTags` (#26546) --- lib/modules/datasource/docker/index.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/modules/datasource/docker/index.ts b/lib/modules/datasource/docker/index.ts index b18db9417eb3f0..ea9e6dd897098e 100644 --- a/lib/modules/datasource/docker/index.ts +++ b/lib/modules/datasource/docker/index.ts @@ -176,7 +176,7 @@ export class DockerDatasource extends Datasource { ) => `${registryHost}:${dockerRepository}@${configDigest}`, ttlMinutes: 1440 * 28, }) - public async getImageConfig( + async getImageConfig( registryHost: string, dockerRepository: string, configDigest: string, @@ -221,7 +221,7 @@ export class DockerDatasource extends Datasource { ) => `${registryHost}:${dockerRepository}@${configDigest}`, ttlMinutes: 1440 * 28, }) - public async getHelmConfig( + async getHelmConfig( registryHost: string, dockerRepository: string, configDigest: string, @@ -336,7 +336,7 @@ export class DockerDatasource extends Datasource { ) => `${registryHost}:${dockerRepository}@${currentDigest}`, ttlMinutes: 1440 * 28, }) - public async getImageArchitecture( + async getImageArchitecture( registryHost: string, dockerRepository: string, currentDigest: string, @@ -434,7 +434,7 @@ export class DockerDatasource extends Datasource { `${registryHost}:${dockerRepository}:${tag}`, ttlMinutes: 24 * 60, }) - public async getLabels( + async getLabels( registryHost: string, dockerRepository: string, tag: string, @@ -687,7 +687,7 @@ export class DockerDatasource extends Datasource { key: (registryHost: string, dockerRepository: string) => `${registryHost}:${dockerRepository}`, }) - public async getTags( + async getTags( registryHost: string, dockerRepository: string, ): Promise { @@ -913,6 +913,10 @@ export class DockerDatasource extends Datasource { return digest; } + @cache({ + namespace: 'datasource-docker-hub-tags', + key: (dockerRepository: string) => `${dockerRepository}`, + }) async getDockerHubTags(dockerRepository: string): Promise { const result: Release[] = []; let url: null | string = From 5f24ab9f0623cb0cc847222544fced9bf2dd3a50 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 8 Jan 2024 11:49:00 +0000 Subject: [PATCH 167/173] chore(deps): update dependency aws-sdk-client-mock to v3.0.1 (#26548) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 37 ++++++++++++------------------------- 2 files changed, 13 insertions(+), 26 deletions(-) diff --git a/package.json b/package.json index 7b45650c3fcd3f..aef1f37315ae26 100644 --- a/package.json +++ b/package.json @@ -308,7 +308,7 @@ "@types/xmldoc": "1.1.9", "@typescript-eslint/eslint-plugin": "6.16.0", "@typescript-eslint/parser": "6.16.0", - "aws-sdk-client-mock": "3.0.0", + "aws-sdk-client-mock": "3.0.1", "callsite": "1.0.0", "common-tags": "1.8.2", "conventional-changelog-conventionalcommits": "7.0.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8ff4b6faf475d2..5431667e0db76e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -488,8 +488,8 @@ importers: specifier: 6.16.0 version: 6.16.0(eslint@8.56.0)(typescript@5.3.3) aws-sdk-client-mock: - specifier: 3.0.0 - version: 3.0.0 + specifier: 3.0.1 + version: 3.0.1 callsite: specifier: 1.0.0 version: 1.0.0 @@ -3013,12 +3013,6 @@ packages: engines: {node: '>=18'} dev: true - /@sinonjs/commons@1.8.6: - resolution: {integrity: sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==} - dependencies: - type-detect: 4.0.8 - dev: true - /@sinonjs/commons@2.0.0: resolution: {integrity: sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==} dependencies: @@ -3037,14 +3031,8 @@ packages: '@sinonjs/commons': 3.0.0 dev: true - /@sinonjs/fake-timers@9.1.2: - resolution: {integrity: sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==} - dependencies: - '@sinonjs/commons': 1.8.6 - dev: true - - /@sinonjs/samsam@7.0.1: - resolution: {integrity: sha512-zsAk2Jkiq89mhZovB2LLOdTCxJF4hqqTToGP0ASWlhp4I1hqOjcfmZGafXntCN7MDC6yySH0mFHrYtHceOeLmw==} + /@sinonjs/samsam@8.0.0: + resolution: {integrity: sha512-Bp8KUVlLp8ibJZrnvq2foVhP0IVX2CIprMJPK0vqGqgrDa0OHVKeZyBykqskkrdxV6yKBPmGasO8LVjAKR3Gew==} dependencies: '@sinonjs/commons': 2.0.0 lodash.get: 4.4.2 @@ -4540,11 +4528,11 @@ packages: resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==} engines: {node: '>= 0.4'} - /aws-sdk-client-mock@3.0.0: - resolution: {integrity: sha512-4mBiWhuLYLZe1+K/iB8eYy5SAZyW2se+Keyh5u9QouMt6/qJ5SRZhss68xvUX5g3ApzROJ06QPRziYHP6buuvQ==} + /aws-sdk-client-mock@3.0.1: + resolution: {integrity: sha512-9VAzJLl8mz99KP9HjOm/93d8vznRRUTpJooPBOunRdUAnVYopCe9xmMuu7eVemu8fQ+w6rP7o5bBK1kAFkB2KQ==} dependencies: '@types/sinon': 10.0.20 - sinon: 14.0.2 + sinon: 16.1.3 tslib: 2.6.2 dev: true @@ -9666,13 +9654,12 @@ packages: - supports-color dev: false - /sinon@14.0.2: - resolution: {integrity: sha512-PDpV0ZI3ZCS3pEqx0vpNp6kzPhHrLx72wA0G+ZLaaJjLIYeE0n8INlgaohKuGy7hP0as5tbUd23QWu5U233t+w==} - deprecated: 16.1.1 + /sinon@16.1.3: + resolution: {integrity: sha512-mjnWWeyxcAf9nC0bXcPmiDut+oE8HYridTNzBbF98AYVLmWwGRp2ISEpyhYflG1ifILT+eNn3BmKUJPxjXUPlA==} dependencies: - '@sinonjs/commons': 2.0.0 - '@sinonjs/fake-timers': 9.1.2 - '@sinonjs/samsam': 7.0.1 + '@sinonjs/commons': 3.0.0 + '@sinonjs/fake-timers': 10.3.0 + '@sinonjs/samsam': 8.0.0 diff: 5.1.0 nise: 5.1.5 supports-color: 7.2.0 From b14661fd0cdd9d363e630d89895acb3005ea0b11 Mon Sep 17 00:00:00 2001 From: Sebastian Poxhofer Date: Mon, 8 Jan 2024 16:59:20 +0100 Subject: [PATCH 168/173] feat(managers/ocb): add new manager for OpenTelemetryCollectorBuilder (#26509) Co-authored-by: HonkingGoose <34918129+HonkingGoose@users.noreply.github.com> --- docs/usage/configuration-options.md | 18 +++++- lib/modules/manager/api.ts | 2 + lib/modules/manager/ocb/extract.spec.ts | 74 ++++++++++++++++++++++ lib/modules/manager/ocb/extract.ts | 81 +++++++++++++++++++++++++ lib/modules/manager/ocb/index.ts | 13 ++++ lib/modules/manager/ocb/readme.md | 23 +++++++ lib/modules/manager/ocb/schema.ts | 22 +++++++ lib/modules/manager/ocb/update.spec.ts | 77 +++++++++++++++++++++++ lib/modules/manager/ocb/update.ts | 47 ++++++++++++++ 9 files changed, 354 insertions(+), 3 deletions(-) create mode 100644 lib/modules/manager/ocb/extract.spec.ts create mode 100644 lib/modules/manager/ocb/extract.ts create mode 100644 lib/modules/manager/ocb/index.ts create mode 100644 lib/modules/manager/ocb/readme.md create mode 100644 lib/modules/manager/ocb/schema.ts create mode 100644 lib/modules/manager/ocb/update.spec.ts create mode 100644 lib/modules/manager/ocb/update.ts diff --git a/docs/usage/configuration-options.md b/docs/usage/configuration-options.md index 7e099f851b683d..bb4a74e298a9ad 100644 --- a/docs/usage/configuration-options.md +++ b/docs/usage/configuration-options.md @@ -410,9 +410,21 @@ This is an advance field and it's recommend you seek a config review before appl ## bumpVersion -Currently this setting supports `helmv3`, `npm`, `nuget`, `maven`, `pep621`, `poetry` and `sbt` only, so raise a feature request if you have a use for it with other package managers. -Its purpose is if you want Renovate to update the `version` field within your package file any time it updates dependencies within. -Usually this is for automatic release purposes, so that you don't need to add another step after Renovate before you can release a new version. +Currently, this config option only works with these managers: + +- `helmv3` +- `npm` +- `nuget` +- `maven` +- `ocb` +- `pep621` +- `poetry` +- `sbt` + +Raise a feature request if you want to use this config option with other package managers. + +Use `bumpVersion` if you want Renovate to update the `version` field in your package file when it updates the dependencies in that file. +This can be handy when you have automated your package's release, as you you don't need extra steps after the Renovate upgrade, you can just release a new version. Configure this value to `"prerelease"`, `"patch"`, `"minor"` or `"major"` to have Renovate update the version in your edited package file. e.g. if you wish Renovate to always increase the target `package.json` version with a patch update, configure this to `"patch"`. diff --git a/lib/modules/manager/api.ts b/lib/modules/manager/api.ts index ba08a398818dbd..6f618abaee49d2 100644 --- a/lib/modules/manager/api.ts +++ b/lib/modules/manager/api.ts @@ -61,6 +61,7 @@ import * as nodenv from './nodenv'; import * as npm from './npm'; import * as nuget from './nuget'; import * as nvm from './nvm'; +import * as ocb from './ocb'; import * as osgi from './osgi'; import * as pep621 from './pep621'; import * as pipCompile from './pip-compile'; @@ -153,6 +154,7 @@ api.set('nodenv', nodenv); api.set('npm', npm); api.set('nuget', nuget); api.set('nvm', nvm); +api.set('ocb', ocb); api.set('osgi', osgi); api.set('pep621', pep621); api.set('pip-compile', pipCompile); diff --git a/lib/modules/manager/ocb/extract.spec.ts b/lib/modules/manager/ocb/extract.spec.ts new file mode 100644 index 00000000000000..99fd13ec2a1f71 --- /dev/null +++ b/lib/modules/manager/ocb/extract.spec.ts @@ -0,0 +1,74 @@ +import { codeBlock } from 'common-tags'; +import { extractPackageFile } from '.'; + +describe('modules/manager/ocb/extract', () => { + describe('extractPackageFile', () => { + it('run successfully with full example', () => { + const content = codeBlock` + dist: + name: otelcol-custom + description: Local OpenTelemetry Collector binary + module: github.com/open-telemetry/opentelemetry-collector + otelcol_version: 0.40.0 + version: 1.0.0 + output_path: /tmp/dist + exporters: + - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/exporter/alibabacloudlogserviceexporter v0.86.0 + - gomod: go.opentelemetry.io/collector/exporter/debugexporter v0.86.0 + + receivers: + - gomod: go.opentelemetry.io/collector/receiver/otlpreceiver v0.86.0 + + processors: + - gomod: go.opentelemetry.io/collector/processor/batchprocessor v0.86.0 + `; + const result = extractPackageFile(content, 'builder-config.yaml'); + expect(result?.deps).toEqual([ + { + currentValue: '0.40.0', + datasource: 'go', + depName: 'github.com/open-telemetry/opentelemetry-collector', + depType: 'collector', + extractVersion: '^v(?\\S+)', + }, + { + currentValue: 'v0.86.0', + datasource: 'go', + depName: + 'github.com/open-telemetry/opentelemetry-collector-contrib/exporter/alibabacloudlogserviceexporter', + depType: 'exports', + }, + { + currentValue: 'v0.86.0', + datasource: 'go', + depName: 'go.opentelemetry.io/collector/exporter/debugexporter', + depType: 'exports', + }, + { + currentValue: 'v0.86.0', + datasource: 'go', + depName: 'go.opentelemetry.io/collector/processor/batchprocessor', + depType: 'processors', + }, + ]); + }); + + it('return null for unknown content', () => { + expect(extractPackageFile('foo', 'bar.yaml')).toBeNull(); + }); + + it('return null for content which is not YAML', () => { + expect( + extractPackageFile( + codeBlock` + myObject: + aString: value + --- + foo: bar + `, + 'bar.yaml', + ), + ).toBeNull(); + }); + }); +}); diff --git a/lib/modules/manager/ocb/extract.ts b/lib/modules/manager/ocb/extract.ts new file mode 100644 index 00000000000000..99416851bce64f --- /dev/null +++ b/lib/modules/manager/ocb/extract.ts @@ -0,0 +1,81 @@ +import is from '@sindresorhus/is'; +import { logger } from '../../../logger'; +import { regEx } from '../../../util/regex'; +import { parseSingleYaml } from '../../../util/yaml'; +import { GoDatasource } from '../../datasource/go'; +import type { + ExtractConfig, + PackageDependency, + PackageFileContent, +} from '../types'; +import { type Module, type OCBConfig, OCBConfigSchema } from './schema'; + +export function extractPackageFile( + content: string, + packageFile: string, + _config?: ExtractConfig, +): PackageFileContent | null { + let definition: OCBConfig | null = null; + try { + const yaml = parseSingleYaml(content); + const parsed = OCBConfigSchema.safeParse(yaml); + if (!parsed.success) { + logger.trace( + { packageFile, error: parsed.error }, + 'Failed to parse OCB schema', + ); + return null; + } + + definition = parsed.data; + } catch (error) { + logger.debug( + { packageFile, error }, + 'OCB manager failed to parse file as YAML', + ); + return null; + } + + const deps: PackageDependency[] = []; + if (definition.dist.module && definition.dist.otelcol_version) { + deps.push({ + datasource: GoDatasource.id, + depType: 'collector', + depName: definition.dist.module, + currentValue: definition.dist.otelcol_version, + extractVersion: '^v(?\\S+)', + }); + } + + deps.push(...processModule(definition.connectors, 'connectors')); + deps.push(...processModule(definition.exporters, 'exports')); + deps.push(...processModule(definition.extension, 'extensions')); + deps.push(...processModule(definition.processors, 'processors')); + + return { + packageFileVersion: definition.dist.version, + deps, + }; +} + +export function processModule( + module: Module, + depType: string, +): PackageDependency[] { + const deps: PackageDependency[] = []; + if (is.nullOrUndefined(module)) { + return deps; + } + + for (const element of module) { + const [depName, currentValue] = element.gomod.trim().split(regEx(/\s+/)); + deps.push({ + datasource: GoDatasource.id, + depType, + depName, + currentValue, + }); + } + + return deps; +} diff --git a/lib/modules/manager/ocb/index.ts b/lib/modules/manager/ocb/index.ts new file mode 100644 index 00000000000000..013a7f62965a02 --- /dev/null +++ b/lib/modules/manager/ocb/index.ts @@ -0,0 +1,13 @@ +import type { Category } from '../../../constants'; +import { GoDatasource } from '../../datasource/go'; + +export { extractPackageFile } from './extract'; +export { bumpPackageVersion } from './update'; + +export const supportedDatasources = [GoDatasource.id]; + +export const categories: Category[] = ['golang']; + +export const defaultConfig = { + fileMatch: [], +}; diff --git a/lib/modules/manager/ocb/readme.md b/lib/modules/manager/ocb/readme.md new file mode 100644 index 00000000000000..2ca2119d6aedd0 --- /dev/null +++ b/lib/modules/manager/ocb/readme.md @@ -0,0 +1,23 @@ +Renovate uses this manager to update dependencies defined in the build definitions for the [OpenTelemetry Collector Builder (ocb)](https://github.com/open-telemetry/opentelemetry-collector/tree/main/cmd/builder). + +By default, the `ocb` manager has no `fileMatch` patterns. +This means you must set a `fileMatch` pattern for the `ocb` manager, in order for Renovate to update your `ocb` files. +Here's a configuration example: + +```json title="If your builder files are named like foo-builder.yml or builder.yaml" +{ + "ocb": { + "fileMatch": ["builder.ya?ml$"] + } +} +``` + +Supported dependencies and their respective `depType`s are: + +| Name | depType | +| -------------- | ------------ | +| base collector | `collector` | +| connectors | `connectors` | +| exports | `exports` | +| extensions | `extensions` | +| processors | `processors` | diff --git a/lib/modules/manager/ocb/schema.ts b/lib/modules/manager/ocb/schema.ts new file mode 100644 index 00000000000000..0b8bd927b469a5 --- /dev/null +++ b/lib/modules/manager/ocb/schema.ts @@ -0,0 +1,22 @@ +import { z } from 'zod'; + +const Entry = z.object({ + gomod: z.string(), +}); + +const ModuleSchema = z.array(Entry).optional(); +export type Module = z.infer; + +export const OCBConfigSchema = z.object({ + dist: z.object({ + otelcol_version: z.string().optional(), + module: z.string().optional(), + version: z.string().optional(), + }), + extension: ModuleSchema, + exporters: ModuleSchema, + receivers: ModuleSchema, + processors: ModuleSchema, + connectors: ModuleSchema, +}); +export type OCBConfig = z.infer; diff --git a/lib/modules/manager/ocb/update.spec.ts b/lib/modules/manager/ocb/update.spec.ts new file mode 100644 index 00000000000000..dc1e8cda5f9463 --- /dev/null +++ b/lib/modules/manager/ocb/update.spec.ts @@ -0,0 +1,77 @@ +import { codeBlock } from 'common-tags'; +import { bumpPackageVersion } from '.'; + +describe('modules/manager/ocb/update', () => { + describe('bumpPackageVersion()', () => { + it('increments with all fields', () => { + const content = codeBlock` + dist: + name: otelcol-custom + description: Local OpenTelemetry Collector binary + module: github.com/open-telemetry/opentelemetry-collector + otelcol_version: 0.40.0 + version: 1.0.0 + output_path: /tmp/dist + `; + const expected = content.replace('1.0.0', '1.0.1'); + + const { bumpedContent } = bumpPackageVersion(content, '1.0.0', 'patch'); + expect(bumpedContent).toEqual(expected); + }); + + it('increments with double quotes', () => { + const content = codeBlock` + dist: + version: "1.0.0" + `; + const expected = content.replace('1.0.0', '1.0.1'); + + const { bumpedContent } = bumpPackageVersion(content, '1.0.0', 'patch'); + expect(bumpedContent).toEqual(expected); + }); + + it('increments with single quotes', () => { + const content = codeBlock` + dist: + version: '1.0.0' + `; + const expected = content.replace('1.0.0', '1.0.1'); + + const { bumpedContent } = bumpPackageVersion(content, '1.0.0', 'patch'); + expect(bumpedContent).toEqual(expected); + }); + + it('no ops', () => { + const content = codeBlock` + dist: + version: '0.0.2' + `; + const { bumpedContent } = bumpPackageVersion(content, '0.0.1', 'patch'); + expect(bumpedContent).toEqual(content); + }); + + it('updates', () => { + const content = codeBlock` + dist: + version: '0.0.2' + `; + const { bumpedContent } = bumpPackageVersion(content, '0.0.1', 'minor'); + const expected = content.replace('0.0.2', '0.1.0'); + expect(bumpedContent).toEqual(expected); + }); + + it('returns content if bumping errors', () => { + const content = codeBlock` + dist: + version: '1.0.0' + `; + const { bumpedContent } = bumpPackageVersion( + content, + '0.0.2', + // @ts-expect-error supplying a wrong parameter to trigger an exception + true, + ); + expect(bumpedContent).toEqual(content); + }); + }); +}); diff --git a/lib/modules/manager/ocb/update.ts b/lib/modules/manager/ocb/update.ts new file mode 100644 index 00000000000000..7e893c699b0f03 --- /dev/null +++ b/lib/modules/manager/ocb/update.ts @@ -0,0 +1,47 @@ +import { type ReleaseType, inc } from 'semver'; +import { logger } from '../../../logger'; +import { regEx } from '../../../util/regex'; +import type { BumpPackageVersionResult } from '../types'; + +export function bumpPackageVersion( + content: string, + currentValue: string, + bumpVersion: ReleaseType, +): BumpPackageVersionResult { + logger.debug( + { bumpVersion, currentValue }, + 'Checking if we should bump OCB version', + ); + + let bumpedContent = content; + try { + const newProjectVersion = inc(currentValue, bumpVersion); + if (!newProjectVersion) { + throw new Error('semver inc failed'); + } + + logger.debug(`newProjectVersion: ${newProjectVersion}`); + bumpedContent = content.replace( + regEx(/\b(?version:\s+["']?)(?[^'"\s]*)/), + `$${newProjectVersion}`, + ); + + if (bumpedContent === content) { + logger.debug('Version was already bumped'); + } else { + logger.debug('Bumped OCB version'); + } + } catch (err) { + logger.warn( + { + content, + currentValue, + bumpVersion, + manager: 'ocb', + }, + 'Failed to bumpVersion', + ); + } + + return { bumpedContent }; +} From 796b93e9e2f9a6faf4946bc350a03f6f43d20d3e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 8 Jan 2024 17:15:50 +0100 Subject: [PATCH 169/173] chore(deps): update github/codeql-action action to v3.23.0 (#26551) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/codeql-analysis.yml | 6 +++--- .github/workflows/scorecard.yml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index e2389c9409962d..0f8bfb56c0837c 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -39,7 +39,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@012739e5082ff0c22ca6d6ab32e07c36df03c4a4 # v3.22.12 + uses: github/codeql-action/init@e5f05b81d5b6ff8cfa111c80c22c5fd02a384118 # v3.23.0 with: languages: javascript @@ -49,7 +49,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@012739e5082ff0c22ca6d6ab32e07c36df03c4a4 # v3.22.12 + uses: github/codeql-action/autobuild@e5f05b81d5b6ff8cfa111c80c22c5fd02a384118 # v3.23.0 # ℹ️ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -63,4 +63,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@012739e5082ff0c22ca6d6ab32e07c36df03c4a4 # v3.22.12 + uses: github/codeql-action/analyze@e5f05b81d5b6ff8cfa111c80c22c5fd02a384118 # v3.23.0 diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 50fd61b3941c16..d19ded7344caa5 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -50,6 +50,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: 'Upload to code-scanning' - uses: github/codeql-action/upload-sarif@012739e5082ff0c22ca6d6ab32e07c36df03c4a4 # v3.22.12 + uses: github/codeql-action/upload-sarif@e5f05b81d5b6ff8cfa111c80c22c5fd02a384118 # v3.23.0 with: sarif_file: results.sarif From 2e84c14327d8d98e8a05623867907be41d38c933 Mon Sep 17 00:00:00 2001 From: Koen van Zuijlen <8818390+kvanzuijlen@users.noreply.github.com> Date: Mon, 8 Jan 2024 17:45:16 +0100 Subject: [PATCH 170/173] refactor: Pass packageFile to bumpPackageVersion (#26538) Co-authored-by: Michael Kriese --- lib/modules/manager/types.ts | 1 + .../repository/update/branch/get-updated.ts | 41 ++++++++++++------- 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/lib/modules/manager/types.ts b/lib/modules/manager/types.ts index 8435b4e9b9d467..f3743f241a50a7 100644 --- a/lib/modules/manager/types.ts +++ b/lib/modules/manager/types.ts @@ -235,6 +235,7 @@ export interface ManagerApi extends ModuleApi { content: string, currentValue: string, bumpVersion: ReleaseType, + packageFile: string, ): Result; detectGlobalConfig?(): Result; diff --git a/lib/workers/repository/update/branch/get-updated.ts b/lib/workers/repository/update/branch/get-updated.ts index 648f107c25b213..1adfb25bd34637 100644 --- a/lib/workers/repository/update/branch/get-updated.ts +++ b/lib/workers/repository/update/branch/get-updated.ts @@ -20,6 +20,21 @@ export interface PackageFilesResult { updatedArtifacts: FileChange[]; } +async function getFileContent( + updatedFileContents: Record, + filePath: string, + config: BranchConfig, +): Promise { + let fileContent: string | null = updatedFileContents[filePath]; + if (!fileContent) { + fileContent = await getFile( + filePath, + config.reuseExistingBranch ? config.branchName : config.baseBranch, + ); + } + return fileContent; +} + export async function getUpdatedPackageFiles( config: BranchConfig, ): Promise { @@ -46,23 +61,19 @@ export async function getUpdatedPackageFiles( packageFileUpdatedDeps[packageFile] = packageFileUpdatedDeps[packageFile] || []; packageFileUpdatedDeps[packageFile].push({ ...upgrade }); - let packageFileContent: string | null = updatedFileContents[packageFile]; - if (!packageFileContent) { - packageFileContent = await getFile( - packageFile, - reuseExistingBranch ? config.branchName : config.baseBranch, - ); - } + const packageFileContent = await getFileContent( + updatedFileContents, + packageFile, + config, + ); let lockFileContent: string | null = null; const lockFile = upgrade.lockFile ?? upgrade.lockFiles?.[0] ?? ''; if (lockFile) { - lockFileContent = updatedFileContents[lockFile]; - if (!lockFileContent) { - lockFileContent = await getFile( - lockFile, - reuseExistingBranch ? config.branchName : config.baseBranch, - ); - } + lockFileContent = await getFileContent( + updatedFileContents, + lockFile, + config, + ); } // istanbul ignore if if ( @@ -183,6 +194,7 @@ export async function getUpdatedPackageFiles( res, upgrade.packageFileVersion, upgrade.bumpVersion, + packageFile, ); res = bumpedContent; } @@ -217,6 +229,7 @@ export async function getUpdatedPackageFiles( newContent, upgrade.packageFileVersion, upgrade.bumpVersion, + packageFile, ); newContent = bumpedContent; } From f6d86f8bb105b83f8d5209b35ea53801b8d178de Mon Sep 17 00:00:00 2001 From: Sergei Zharinov Date: Mon, 8 Jan 2024 13:53:23 -0300 Subject: [PATCH 171/173] refactor(gitea): Refactor tests (#26537) --- .../gitea/__snapshots__/index.spec.ts.snap | 235 -- lib/modules/platform/gitea/index.spec.ts | 2368 ++++++++++------- lib/modules/platform/gitea/index.ts | 5 +- 3 files changed, 1469 insertions(+), 1139 deletions(-) delete mode 100644 lib/modules/platform/gitea/__snapshots__/index.spec.ts.snap diff --git a/lib/modules/platform/gitea/__snapshots__/index.spec.ts.snap b/lib/modules/platform/gitea/__snapshots__/index.spec.ts.snap deleted file mode 100644 index c08c86e20b0000..00000000000000 --- a/lib/modules/platform/gitea/__snapshots__/index.spec.ts.snap +++ /dev/null @@ -1,235 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`modules/platform/gitea/index createPr should use base branch by default 1`] = ` -{ - "bodyStruct": { - "hash": "9d586a6aedc4e7cb205276933c9e474cd3c2b341d3340458c31eb750795f197d", - }, - "cannotMergeReason": undefined, - "createdAt": "2014-04-01T05:14:20Z", - "hasAssignees": false, - "isDraft": false, - "number": 42, - "sha": "0d9c7726c3d628b7e28af234595cfd20febdbf8e", - "sourceBranch": "pr-branch", - "sourceRepo": "some/repo", - "state": "open", - "targetBranch": "devel", - "title": "pr-title", -} -`; - -exports[`modules/platform/gitea/index createPr should use default branch if requested 1`] = ` -{ - "bodyStruct": { - "hash": "9d586a6aedc4e7cb205276933c9e474cd3c2b341d3340458c31eb750795f197d", - }, - "cannotMergeReason": undefined, - "createdAt": "2014-04-01T05:14:20Z", - "hasAssignees": false, - "isDraft": false, - "number": 42, - "sha": "0d9c7726c3d628b7e28af234595cfd20febdbf8e", - "sourceBranch": "pr-branch", - "sourceRepo": "some/repo", - "state": "open", - "targetBranch": "master", - "title": "pr-title", -} -`; - -exports[`modules/platform/gitea/index getPr should fallback to direct fetching if cache fails 1`] = ` -{ - "bodyStruct": { - "hash": "f41557d6153a316ee747e13de8952c4068de931585c1a18d095d6703254de6af", - }, - "cannotMergeReason": "pr.mergeable="false"", - "createdAt": "2015-03-22T20:36:16Z", - "hasAssignees": false, - "isDraft": false, - "number": 1, - "sha": "some-head-sha", - "sourceBranch": "some-head-branch", - "sourceRepo": "some/repo", - "state": "open", - "targetBranch": "some-base-branch", - "title": "Some PR", -} -`; - -exports[`modules/platform/gitea/index getPr should return enriched pull request which exists if open 1`] = ` -{ - "bodyStruct": { - "hash": "f41557d6153a316ee747e13de8952c4068de931585c1a18d095d6703254de6af", - }, - "cannotMergeReason": undefined, - "createdAt": "2015-03-22T20:36:16Z", - "hasAssignees": false, - "isDraft": false, - "number": 1, - "sha": "some-head-sha", - "sourceBranch": "some-head-branch", - "sourceRepo": "some/repo", - "state": "open", - "targetBranch": "some-base-branch", - "title": "Some PR", -} -`; - -exports[`modules/platform/gitea/index getPrList should filter list by creator 1`] = ` -{ - "endpoint": "https://gitea.com/", - "gitAuthor": "Renovate Bot ", -} -`; - -exports[`modules/platform/gitea/index getPrList should filter list by creator 2`] = ` -[ - { - "bodyStruct": { - "hash": "f41557d6153a316ee747e13de8952c4068de931585c1a18d095d6703254de6af", - }, - "cannotMergeReason": undefined, - "createdAt": "2015-03-22T20:36:16Z", - "hasAssignees": false, - "isDraft": false, - "number": 1, - "sha": "some-head-sha", - "sourceBranch": "some-head-branch", - "sourceRepo": "some/repo", - "state": "open", - "targetBranch": "some-base-branch", - "title": "Some PR", - }, - { - "bodyStruct": { - "hash": "916e5965a20785df1883ff5dc219508a1070ae1f37ccb64e954526f3ca1d22f4", - }, - "cannotMergeReason": undefined, - "createdAt": "2011-08-18T22:30:38Z", - "hasAssignees": false, - "isDraft": false, - "number": 2, - "sha": "other-head-sha", - "sourceBranch": "other-head-branch", - "sourceRepo": "some/repo", - "state": "closed", - "targetBranch": "other-base-branch", - "title": "Other PR", - }, - { - "bodyStruct": { - "hash": "916e5965a20785df1883ff5dc219508a1070ae1f37ccb64e954526f3ca1d22f4", - }, - "cannotMergeReason": undefined, - "createdAt": "2011-08-18T22:30:39Z", - "hasAssignees": false, - "isDraft": true, - "number": 3, - "sha": "draft-head-sha", - "sourceBranch": "draft-head-branch", - "sourceRepo": "some/repo", - "state": "open", - "targetBranch": "draft-base-branch", - "title": "Draft PR", - }, -] -`; - -exports[`modules/platform/gitea/index getPrList should return list of pull requests 1`] = ` -[ - { - "bodyStruct": { - "hash": "f41557d6153a316ee747e13de8952c4068de931585c1a18d095d6703254de6af", - }, - "cannotMergeReason": undefined, - "createdAt": "2015-03-22T20:36:16Z", - "hasAssignees": false, - "isDraft": false, - "number": 1, - "sha": "some-head-sha", - "sourceBranch": "some-head-branch", - "sourceRepo": "some/repo", - "state": "open", - "targetBranch": "some-base-branch", - "title": "Some PR", - }, - { - "bodyStruct": { - "hash": "916e5965a20785df1883ff5dc219508a1070ae1f37ccb64e954526f3ca1d22f4", - }, - "cannotMergeReason": undefined, - "createdAt": "2011-08-18T22:30:38Z", - "hasAssignees": false, - "isDraft": false, - "number": 2, - "sha": "other-head-sha", - "sourceBranch": "other-head-branch", - "sourceRepo": "some/repo", - "state": "closed", - "targetBranch": "other-base-branch", - "title": "Other PR", - }, - { - "bodyStruct": { - "hash": "916e5965a20785df1883ff5dc219508a1070ae1f37ccb64e954526f3ca1d22f4", - }, - "cannotMergeReason": undefined, - "createdAt": "2011-08-18T22:30:39Z", - "hasAssignees": false, - "isDraft": true, - "number": 3, - "sha": "draft-head-sha", - "sourceBranch": "draft-head-branch", - "sourceRepo": "some/repo", - "state": "open", - "targetBranch": "draft-base-branch", - "title": "Draft PR", - }, -] -`; - -exports[`modules/platform/gitea/index initPlatform() should support custom endpoint 1`] = ` -{ - "endpoint": "https://gitea.renovatebot.com/", - "gitAuthor": "Renovate Bot ", -} -`; - -exports[`modules/platform/gitea/index initPlatform() should support default endpoint 1`] = ` -{ - "endpoint": "https://gitea.com/", - "gitAuthor": "Renovate Bot ", -} -`; - -exports[`modules/platform/gitea/index initPlatform() should use username as author name if full name is missing 1`] = ` -{ - "endpoint": "https://gitea.com/", - "gitAuthor": "renovate ", -} -`; - -exports[`modules/platform/gitea/index initRepo should fall back to merge method "merge" 1`] = ` -{ - "defaultBranch": "master", - "isFork": false, - "repoFingerprint": "c48ad9428365701f1a7f4798a410db2401b13267c205e345beb5b469a4a1480b163e1ce663ce483cfe579b2748a807cbeeba2035dc55eca5fe46d60d182510ec", -} -`; - -exports[`modules/platform/gitea/index initRepo should fall back to merge method "rebase-merge" 1`] = ` -{ - "defaultBranch": "master", - "isFork": false, - "repoFingerprint": "c48ad9428365701f1a7f4798a410db2401b13267c205e345beb5b469a4a1480b163e1ce663ce483cfe579b2748a807cbeeba2035dc55eca5fe46d60d182510ec", -} -`; - -exports[`modules/platform/gitea/index initRepo should fall back to merge method "squash" 1`] = ` -{ - "defaultBranch": "master", - "isFork": false, - "repoFingerprint": "c48ad9428365701f1a7f4798a410db2401b13267c205e345beb5b469a4a1480b163e1ce663ce483cfe579b2748a807cbeeba2035dc55eca5fe46d60d182510ec", -} -`; diff --git a/lib/modules/platform/gitea/index.spec.ts b/lib/modules/platform/gitea/index.spec.ts index d4321b823be8f4..a7e8280aba1009 100644 --- a/lib/modules/platform/gitea/index.spec.ts +++ b/lib/modules/platform/gitea/index.spec.ts @@ -1,10 +1,5 @@ -import type { - BranchStatusConfig, - EnsureIssueConfig, - Platform, - RepoParams, - RepoResult, -} from '..'; +import type { EnsureIssueConfig, Platform, RepoParams } from '..'; +import * as httpMock from '../../../../test/http-mock'; import { mocked, partial } from '../../../../test/util'; import { CONFIG_GIT_URL_UNAVAILABLE, @@ -16,27 +11,20 @@ import { REPOSITORY_MIRRORED, } from '../../../constants/error-messages'; import type { logger as _logger } from '../../../logger'; -import type { BranchStatus, PrState } from '../../../types'; import type * as _git from '../../../util/git'; import type { LongCommitSha } from '../../../util/git/types'; import { setBaseUrl } from '../../../util/http/gitea'; -import type { PlatformResult } from '../types'; import type { - Branch, - CombinedCommitStatus, Comment, CommitStatus, CommitStatusType, - CommitUser, Issue, Label, PR, Repo, - RepoContents, User, } from './types'; -jest.mock('./gitea-helper'); jest.mock('../../../util/git'); /** @@ -46,9 +34,8 @@ const GITEA_VERSION = '1.14.0+dev-754-g5d2b7ba63'; describe('modules/platform/gitea/index', () => { let gitea: Platform; - let helper: jest.Mocked; let logger: jest.Mocked; - let gitvcs: jest.Mocked; + let git: jest.Mocked; let hostRules: typeof import('../../../util/host-rules'); const mockCommitHash = @@ -123,7 +110,7 @@ describe('modules/platform/gitea/index', () => { diff_url: 'https://gitea.renovatebot.com/some/repo/pulls/3.diff', created_at: '2011-08-18T22:30:39Z', closed_at: '2016-01-09T10:03:22Z', - mergeable: true, + mergeable: false, base: { ref: 'draft-base-branch' }, head: { label: 'draft-head-branch', @@ -206,11 +193,10 @@ describe('modules/platform/gitea/index', () => { jest.resetModules(); gitea = await import('.'); - helper = jest.requireMock('./gitea-helper'); logger = mocked(await import('../../../logger')).logger; - gitvcs = jest.requireMock('../../../util/git'); - gitvcs.isBranchBehindBase.mockResolvedValue(false); - gitvcs.getBranchCommit.mockReturnValue(mockCommitHash); + git = jest.requireMock('../../../util/git'); + git.isBranchBehindBase.mockResolvedValue(false); + git.getBranchCommit.mockReturnValue(mockCommitHash); hostRules = await import('../../../util/host-rules'); hostRules.clear(); @@ -220,22 +206,27 @@ describe('modules/platform/gitea/index', () => { delete process.env.RENOVATE_X_AUTODISCOVER_REPO_ORDER; }); - function initFakePlatform(version = GITEA_VERSION): Promise { - helper.getCurrentUser.mockResolvedValueOnce(mockUser); - helper.getVersion.mockResolvedValueOnce(version); - return gitea.initPlatform({ token: 'abc' }); + async function initFakePlatform( + scope: httpMock.Scope, + version = GITEA_VERSION, + ): Promise { + scope + .get('/user') + .reply(200, mockUser) + .get('/version') + .reply(200, { version }); + await gitea.initPlatform({ token: 'abc' }); } - function initFakeRepo( + async function initFakeRepo( + scope: httpMock.Scope, repo?: Partial, config?: Partial, - ): Promise { - helper.getRepo.mockResolvedValueOnce({ ...mockRepo, ...repo }); - - return gitea.initRepo({ - repository: mockRepo.full_name, - ...config, - }); + ): Promise { + const repoResult = { ...mockRepo, ...repo }; + const repository = repoResult.full_name; + scope.get(`/repos/${repository}`).reply(200, repoResult); + await gitea.initRepo({ repository, ...config }); } describe('initPlatform()', () => { @@ -244,7 +235,8 @@ describe('modules/platform/gitea/index', () => { }); it('should throw if auth fails', async () => { - helper.getCurrentUser.mockRejectedValueOnce(new Error()); + const scope = httpMock.scope('https://gitea.com/api/v1'); + scope.get('/user').reply(500); await expect( gitea.initPlatform({ token: 'some-token' }), @@ -252,81 +244,128 @@ describe('modules/platform/gitea/index', () => { }); it('should support default endpoint', async () => { - helper.getCurrentUser.mockResolvedValueOnce(mockUser); + const scope = httpMock.scope('https://gitea.com/api/v1'); + scope + .get('/user') + .reply(200, mockUser) + .get('/version') + .reply(200, { version: GITEA_VERSION }); - expect( - await gitea.initPlatform({ token: 'some-token' }), - ).toMatchSnapshot(); + expect(await gitea.initPlatform({ token: 'some-token' })).toEqual({ + endpoint: 'https://gitea.com/', + gitAuthor: 'Renovate Bot ', + }); }); it('should support custom endpoint', async () => { - helper.getCurrentUser.mockResolvedValueOnce(mockUser); + const scope = httpMock.scope('https://gitea.renovatebot.com/api/v1'); + scope + .get('/user') + .reply(200, mockUser) + .get('/version') + .reply(200, { version: GITEA_VERSION }); expect( await gitea.initPlatform({ token: 'some-token', endpoint: 'https://gitea.renovatebot.com', }), - ).toMatchSnapshot(); + ).toEqual({ + endpoint: 'https://gitea.renovatebot.com/', + gitAuthor: 'Renovate Bot ', + }); }); it('should support custom endpoint including api path', async () => { - helper.getCurrentUser.mockResolvedValueOnce(mockUser); + const scope = httpMock.scope('https://gitea.renovatebot.com/api/v1'); + scope + .get('/user') + .reply(200, mockUser) + .get('/version') + .reply(200, { version: GITEA_VERSION }); expect( await gitea.initPlatform({ token: 'some-token', - endpoint: 'https://gitea.renovatebot.com/api/v1', + endpoint: 'https://gitea.renovatebot.com', }), - ).toMatchObject({ + ).toEqual({ endpoint: 'https://gitea.renovatebot.com/', + gitAuthor: 'Renovate Bot ', }); }); it('should use username as author name if full name is missing', async () => { - helper.getCurrentUser.mockResolvedValueOnce({ - ...mockUser, - full_name: undefined, - }); + const scope = httpMock.scope('https://gitea.com/api/v1'); + scope + .get('/user') + .reply(200, { + ...mockUser, + full_name: undefined, + }) + .get('/version') + .reply(200, { version: GITEA_VERSION }); - expect( - await gitea.initPlatform({ token: 'some-token' }), - ).toMatchSnapshot(); + expect(await gitea.initPlatform({ token: 'some-token' })).toEqual({ + endpoint: 'https://gitea.com/', + gitAuthor: 'renovate ', + }); }); }); describe('getRepos', () => { it('should propagate any other errors', async () => { - helper.searchRepos.mockRejectedValueOnce(new Error('searchRepos()')); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get('/repos/search') + .query({ + uid: 1, + archived: false, + }) + .replyWithError(new Error('searchRepos()')); + await initFakePlatform(scope); await expect(gitea.getRepos()).rejects.toThrow('searchRepos()'); }); it('should return an array of repos', async () => { - helper.searchRepos.mockResolvedValueOnce(mockRepos); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get('/repos/search') + .query({ + uid: 1, + archived: false, + }) + .reply(200, { + ok: true, + data: mockRepos, + }); + await initFakePlatform(scope); const repos = await gitea.getRepos(); expect(repos).toEqual(['a/b', 'c/d']); - expect(helper.searchRepos).toHaveBeenCalledWith({ - uid: undefined, - archived: false, - }); }); it('Sorts repos', async () => { process.env.RENOVATE_X_AUTODISCOVER_REPO_SORT = 'updated'; process.env.RENOVATE_X_AUTODISCOVER_REPO_ORDER = 'desc'; - helper.searchRepos.mockResolvedValueOnce(mockRepos); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get('/repos/search') + .query({ + uid: 1, + archived: false, + sort: 'updated', + order: 'desc', + }) + .reply(200, { + ok: true, + data: mockRepos, + }); + await initFakePlatform(scope); const repos = await gitea.getRepos(); expect(repos).toEqual(['a/b', 'c/d']); - - expect(helper.searchRepos).toHaveBeenCalledWith({ - uid: undefined, - archived: false, - sort: 'updated', - order: 'desc', - }); }); }); @@ -336,119 +375,208 @@ describe('modules/platform/gitea/index', () => { }; it('should propagate API errors', async () => { - helper.getRepo.mockRejectedValueOnce(new Error('getRepo()')); - + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get(`/repos/${initRepoCfg.repository}`) + .replyWithError(new Error('getRepo()')); + await initFakePlatform(scope); await expect(gitea.initRepo(initRepoCfg)).rejects.toThrow('getRepo()'); }); it('should abort when repo is archived', async () => { - await expect(initFakeRepo({ archived: true })).rejects.toThrow( + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get(`/repos/${initRepoCfg.repository}`) + .reply(200, { + ...mockRepo, + archived: true, + }); + await initFakePlatform(scope); + await expect(gitea.initRepo(initRepoCfg)).rejects.toThrow( REPOSITORY_ARCHIVED, ); }); it('should abort when repo is mirrored', async () => { - await expect(initFakeRepo({ mirror: true })).rejects.toThrow( + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get(`/repos/${initRepoCfg.repository}`) + .reply(200, { + ...mockRepo, + mirror: true, + }); + await initFakePlatform(scope); + await expect(gitea.initRepo(initRepoCfg)).rejects.toThrow( REPOSITORY_MIRRORED, ); }); it('should abort when repo is empty', async () => { - await expect(initFakeRepo({ empty: true })).rejects.toThrow( + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get(`/repos/${initRepoCfg.repository}`) + .reply(200, { + ...mockRepo, + empty: true, + }); + await initFakePlatform(scope); + await expect(gitea.initRepo(initRepoCfg)).rejects.toThrow( REPOSITORY_EMPTY, ); }); it('should abort when repo has insufficient permissions', async () => { - await expect( - initFakeRepo({ + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get(`/repos/${initRepoCfg.repository}`) + .reply(200, { + ...mockRepo, permissions: { pull: false, push: false, admin: false, }, - }), - ).rejects.toThrow(REPOSITORY_ACCESS_FORBIDDEN); + }); + await initFakePlatform(scope); + await expect(gitea.initRepo(initRepoCfg)).rejects.toThrow( + REPOSITORY_ACCESS_FORBIDDEN, + ); }); it('should abort when repo has no available merge methods', async () => { - await expect(initFakeRepo({ allow_rebase: false })).rejects.toThrow( + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get(`/repos/${initRepoCfg.repository}`) + .reply(200, { + ...mockRepo, + allow_rebase: false, + }); + await initFakePlatform(scope); + await expect(gitea.initRepo(initRepoCfg)).rejects.toThrow( REPOSITORY_BLOCKED, ); }); it('should fall back to merge method "rebase-merge"', async () => { - expect( - await initFakeRepo({ + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get(`/repos/${initRepoCfg.repository}`) + .reply(200, { + ...mockRepo, allow_rebase: false, allow_rebase_explicit: true, + }); + await initFakePlatform(scope); + + await gitea.initRepo(initRepoCfg); + + expect(git.initRepo).toHaveBeenCalledExactlyOnceWith( + expect.objectContaining({ + mergeMethod: 'rebase-merge', }), - ).toMatchSnapshot(); + ); }); it('should fall back to merge method "squash"', async () => { - expect( - await initFakeRepo({ allow_rebase: false, allow_squash_merge: true }), - ).toMatchSnapshot(); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get(`/repos/${initRepoCfg.repository}`) + .reply(200, { + ...mockRepo, + allow_rebase: false, + allow_squash_merge: true, + }); + await initFakePlatform(scope); + + await gitea.initRepo(initRepoCfg); + + expect(git.initRepo).toHaveBeenCalledExactlyOnceWith( + expect.objectContaining({ + mergeMethod: 'squash', + }), + ); }); it('should fall back to merge method "merge"', async () => { - expect( - await initFakeRepo({ + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get(`/repos/${initRepoCfg.repository}`) + .reply(200, { + ...mockRepo, allow_rebase: false, allow_merge_commits: true, + }); + await initFakePlatform(scope); + + await gitea.initRepo(initRepoCfg); + + expect(git.initRepo).toHaveBeenCalledExactlyOnceWith( + expect.objectContaining({ + mergeMethod: 'merge', }), - ).toMatchSnapshot(); + ); }); it('should use clone_url of repo if gitUrl is not specified', async () => { - expect.assertions(1); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get(`/repos/${initRepoCfg.repository}`) + .reply(200, mockRepo); + await initFakePlatform(scope); - helper.getRepo.mockResolvedValueOnce(mockRepo); const repoCfg: RepoParams = { repository: mockRepo.full_name, }; await gitea.initRepo(repoCfg); - expect(gitvcs.initRepo).toHaveBeenCalledWith( + expect(git.initRepo).toHaveBeenCalledWith( expect.objectContaining({ url: mockRepo.clone_url }), ); }); it('should use clone_url of repo if gitUrl has value default', async () => { - expect.assertions(1); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get(`/repos/${initRepoCfg.repository}`) + .reply(200, mockRepo); + await initFakePlatform(scope); - helper.getRepo.mockResolvedValueOnce(mockRepo); const repoCfg: RepoParams = { repository: mockRepo.full_name, gitUrl: 'default', }; await gitea.initRepo(repoCfg); - expect(gitvcs.initRepo).toHaveBeenCalledWith( + expect(git.initRepo).toHaveBeenCalledWith( expect.objectContaining({ url: mockRepo.clone_url }), ); }); it('should use ssh_url of repo if gitUrl has value ssh', async () => { - expect.assertions(1); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get(`/repos/${initRepoCfg.repository}`) + .reply(200, mockRepo); + await initFakePlatform(scope); - helper.getRepo.mockResolvedValueOnce(mockRepo); const repoCfg: RepoParams = { repository: mockRepo.full_name, gitUrl: 'ssh', }; await gitea.initRepo(repoCfg); - expect(gitvcs.initRepo).toHaveBeenCalledWith( + expect(git.initRepo).toHaveBeenCalledWith( expect.objectContaining({ url: mockRepo.ssh_url }), ); }); it('should abort when gitUrl has value ssh but ssh_url is empty', async () => { - expect.assertions(1); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get(`/repos/${initRepoCfg.repository}`) + .reply(200, { ...mockRepo, ssh_url: undefined }); + await initFakePlatform(scope); - helper.getRepo.mockResolvedValueOnce({ ...mockRepo, ssh_url: undefined }); const repoCfg: RepoParams = { repository: mockRepo.full_name, gitUrl: 'ssh', @@ -460,16 +588,19 @@ describe('modules/platform/gitea/index', () => { }); it('should use generated url of repo if gitUrl has value endpoint', async () => { - expect.assertions(1); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get(`/repos/${initRepoCfg.repository}`) + .reply(200, mockRepo); + await initFakePlatform(scope); - helper.getRepo.mockResolvedValueOnce(mockRepo); const repoCfg: RepoParams = { repository: mockRepo.full_name, gitUrl: 'endpoint', }; await gitea.initRepo(repoCfg); - expect(gitvcs.initRepo).toHaveBeenCalledWith( + expect(git.initRepo).toHaveBeenCalledWith( expect.objectContaining({ url: `https://gitea.com/${mockRepo.full_name}.git`, }), @@ -477,12 +608,15 @@ describe('modules/platform/gitea/index', () => { }); it('should abort when clone_url is empty', async () => { - expect.assertions(1); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get(`/repos/${initRepoCfg.repository}`) + .reply(200, { + ...mockRepo, + clone_url: undefined, + }); + await initFakePlatform(scope); - helper.getRepo.mockResolvedValueOnce({ - ...mockRepo, - clone_url: undefined, - }); const repoCfg: RepoParams = { repository: mockRepo.full_name, }; @@ -493,7 +627,11 @@ describe('modules/platform/gitea/index', () => { }); it('should use given access token if gitUrl has value endpoint', async () => { - expect.assertions(1); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get(`/repos/${initRepoCfg.repository}`) + .reply(200, mockRepo); + await initFakePlatform(scope); const token = 'abc'; hostRules.add({ @@ -502,7 +640,6 @@ describe('modules/platform/gitea/index', () => { token, }); - helper.getRepo.mockResolvedValueOnce(mockRepo); const repoCfg: RepoParams = { repository: mockRepo.full_name, gitUrl: 'endpoint', @@ -511,7 +648,7 @@ describe('modules/platform/gitea/index', () => { const url = new URL(`${mockRepo.clone_url}`); url.username = token; - expect(gitvcs.initRepo).toHaveBeenCalledWith( + expect(git.initRepo).toHaveBeenCalledWith( expect.objectContaining({ url: `https://${token}@gitea.com/${mockRepo.full_name}.git`, }), @@ -519,7 +656,11 @@ describe('modules/platform/gitea/index', () => { }); it('should use given access token if gitUrl is not specified', async () => { - expect.assertions(1); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get(`/repos/${initRepoCfg.repository}`) + .reply(200, mockRepo); + await initFakePlatform(scope); const token = 'abc'; hostRules.add({ @@ -528,7 +669,6 @@ describe('modules/platform/gitea/index', () => { token, }); - helper.getRepo.mockResolvedValueOnce(mockRepo); const repoCfg: RepoParams = { repository: mockRepo.full_name, }; @@ -536,18 +676,21 @@ describe('modules/platform/gitea/index', () => { const url = new URL(`${mockRepo.clone_url}`); url.username = token; - expect(gitvcs.initRepo).toHaveBeenCalledWith( + expect(git.initRepo).toHaveBeenCalledWith( expect.objectContaining({ url: url.toString() }), ); }); it('should abort when clone_url is not valid', async () => { - expect.assertions(1); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get(`/repos/${initRepoCfg.repository}`) + .reply(200, { + ...mockRepo, + clone_url: 'abc', + }); + await initFakePlatform(scope); - helper.getRepo.mockResolvedValueOnce({ - ...mockRepo, - clone_url: 'abc', - }); const repoCfg: RepoParams = { repository: mockRepo.full_name, }; @@ -559,101 +702,190 @@ describe('modules/platform/gitea/index', () => { }); describe('setBranchStatus', () => { - const setBranchStatus = async (bsc?: Partial) => { - await initFakeRepo(); - await gitea.setBranchStatus({ - branchName: 'some-branch', - state: 'green', - context: 'some-context', - description: 'some-description', - ...bsc, - }); - }; - it('should create a new commit status', async () => { - await setBranchStatus(); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .post( + '/repos/some/repo/statuses/0d9c7726c3d628b7e28af234595cfd20febdbf8e', + { + state: 'success', + context: 'some-context', + description: 'some-description', + }, + ) + .reply(200) + .get('/repos/some/repo/commits/some-branch/statuses') + .reply(200, []); - expect(helper.createCommitStatus).toHaveBeenCalledTimes(1); - expect(helper.createCommitStatus).toHaveBeenCalledWith( - mockRepo.full_name, - mockCommitHash, - { - state: 'success', + await initFakePlatform(scope); + await initFakeRepo(scope); + + await expect( + gitea.setBranchStatus({ + branchName: 'some-branch', + state: 'green', context: 'some-context', description: 'some-description', - }, - ); + }), + ).toResolve(); }); it('should default to pending state', async () => { - await setBranchStatus({ state: undefined }); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .post( + '/repos/some/repo/statuses/0d9c7726c3d628b7e28af234595cfd20febdbf8e', + { + state: 'pending', + context: 'some-context', + description: 'some-description', + }, + ) + .reply(200) + .get('/repos/some/repo/commits/some-branch/statuses') + .reply(200, []); - expect(helper.createCommitStatus).toHaveBeenCalledTimes(1); - expect(helper.createCommitStatus).toHaveBeenCalledWith( - mockRepo.full_name, - mockCommitHash, - { - state: 'pending', + await initFakePlatform(scope); + await initFakeRepo(scope); + + await expect( + gitea.setBranchStatus({ + branchName: 'some-branch', context: 'some-context', description: 'some-description', - }, - ); + state: undefined as never, + }), + ).toResolve(); }); it('should include url if specified', async () => { - await setBranchStatus({ url: 'some-url' }); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .post( + '/repos/some/repo/statuses/0d9c7726c3d628b7e28af234595cfd20febdbf8e', + { + state: 'success', + context: 'some-context', + description: 'some-description', + target_url: 'some-url', + }, + ) + .reply(200) + .get('/repos/some/repo/commits/some-branch/statuses') + .reply(200, []); - expect(helper.createCommitStatus).toHaveBeenCalledTimes(1); - expect(helper.createCommitStatus).toHaveBeenCalledWith( - mockRepo.full_name, - mockCommitHash, - { - state: 'success', + await initFakePlatform(scope); + await initFakeRepo(scope); + + await expect( + gitea.setBranchStatus({ + branchName: 'some-branch', + state: 'green', context: 'some-context', description: 'some-description', - target_url: 'some-url', - }, - ); + url: 'some-url', + }), + ).toResolve(); }); it('should gracefully fail with warning', async () => { - helper.createCommitStatus.mockRejectedValueOnce(new Error()); - await setBranchStatus(); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .post( + '/repos/some/repo/statuses/0d9c7726c3d628b7e28af234595cfd20febdbf8e', + ) + .replyWithError('unknown error'); - expect(logger.warn).toHaveBeenCalledTimes(1); - }); - }); + await initFakePlatform(scope); + await initFakeRepo(scope); - describe('getBranchStatus', () => { - const getBranchStatus = async (state: string): Promise => { - await initFakeRepo(); - helper.getCombinedCommitStatus.mockResolvedValueOnce( - partial({ - worstStatus: state as CommitStatusType, + await expect( + gitea.setBranchStatus({ + branchName: 'some-branch', + state: 'green', + context: 'some-context', + description: 'some-description', }), + ).toResolve(); + + expect(logger.warn).toHaveBeenCalledWith( + { + err: expect.any(Error), + }, + 'Failed to set branch status', ); + }); + }); - return gitea.getBranchStatus('some-branch', true); - }; + describe('getBranchStatus', () => { + const commitStatus = (status: CommitStatusType): CommitStatus => ({ + id: 1, + status, + context: '', + description: '', + target_url: '', + created_at: '', + }); it('should return yellow for unknown result', async () => { - expect(await getBranchStatus('unknown')).toBe('yellow'); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get('/repos/some/repo/commits/some-branch/statuses') + .reply(200, [commitStatus('unknown')]); + await initFakePlatform(scope); + await initFakeRepo(scope); + + const res = await gitea.getBranchStatus('some-branch', true); + + expect(res).toBe('yellow'); }); it('should return pending state for pending result', async () => { - expect(await getBranchStatus('pending')).toBe('yellow'); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get('/repos/some/repo/commits/some-branch/statuses') + .reply(200, [commitStatus('pending')]); + await initFakePlatform(scope); + await initFakeRepo(scope); + + const res = await gitea.getBranchStatus('some-branch', true); + + expect(res).toBe('yellow'); }); - it('should return success state for success result', async () => { - expect(await getBranchStatus('success')).toBe('green'); + it('should return green state for success result', async () => { + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get('/repos/some/repo/commits/some-branch/statuses') + .reply(200, [commitStatus('success')]); + await initFakePlatform(scope); + await initFakeRepo(scope); + + const res = await gitea.getBranchStatus('some-branch', true); + + expect(res).toBe('green'); }); - it('should return null for all other results', async () => { - expect(await getBranchStatus('invalid')).toBe('yellow'); + it('should return yellow for all other results', async () => { + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get('/repos/some/repo/commits/some-branch/statuses') + .reply(200, [commitStatus('invalid' as never)]); + await initFakePlatform(scope); + await initFakeRepo(scope); + + const res = await gitea.getBranchStatus('some-branch', true); + + expect(res).toBe('yellow'); }); it('should abort when branch status returns 404', async () => { - helper.getCombinedCommitStatus.mockRejectedValueOnce({ statusCode: 404 }); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get('/repos/some/repo/commits/some-branch/statuses') + .reply(404); + await initFakePlatform(scope); + await initFakeRepo(scope); await expect(gitea.getBranchStatus('some-branch', true)).rejects.toThrow( REPOSITORY_CHANGED, @@ -661,19 +893,23 @@ describe('modules/platform/gitea/index', () => { }); it('should propagate any other errors', async () => { - helper.getCombinedCommitStatus.mockRejectedValueOnce( - new Error('getCombinedCommitStatus()'), - ); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get('/repos/some/repo/commits/some-branch/statuses') + .replyWithError('unknown error'); + await initFakePlatform(scope); + await initFakeRepo(scope); await expect(gitea.getBranchStatus('some-branch', true)).rejects.toThrow( - 'getCombinedCommitStatus()', + 'unknown error', ); }); it('should treat internal checks as success', async () => { - helper.getCombinedCommitStatus.mockResolvedValueOnce({ - worstStatus: 'success', - statuses: [ + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get('/repos/some/repo/commits/some-branch/statuses') + .reply(200, [ { id: 1, status: 'success', @@ -682,39 +918,46 @@ describe('modules/platform/gitea/index', () => { target_url: '', created_at: '', }, - ], - }); - expect(await gitea.getBranchStatus('some-branch', true)).toBe('green'); + ]); + await initFakePlatform(scope); + await initFakeRepo(scope); + + const res = await gitea.getBranchStatus('some-branch', true); + + expect(res).toBe('green'); }); it('should not treat internal checks as success', async () => { - await initFakeRepo(); - helper.getCombinedCommitStatus.mockResolvedValueOnce( - partial({ - worstStatus: 'success', - statuses: [ - { - id: 1, - status: 'success', - context: 'renovate/stability-days', - description: 'internal check', - target_url: '', - created_at: '', - }, - ], - }), - ); - expect(await gitea.getBranchStatus('some-branch', false)).toBe('yellow'); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get('/repos/some/repo/commits/some-branch/statuses') + .reply(200, [ + { + id: 1, + status: 'success', + context: 'renovate/stability-days', + description: 'internal check', + target_url: '', + created_at: '', + }, + ]); + await initFakePlatform(scope); + await initFakeRepo(scope); + + const res = await gitea.getBranchStatus('some-branch', false); + + expect(res).toBe('yellow'); }); }); describe('getBranchStatusCheck', () => { it('should return null with no results', async () => { - helper.getCombinedCommitStatus.mockResolvedValueOnce( - partial({ - statuses: [], - }), - ); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get('/repos/some/repo/commits/some-branch/statuses') + .reply(200, []); + await initFakePlatform(scope); + await initFakeRepo(scope); expect( await gitea.getBranchStatusCheck('some-branch', 'some-context'), @@ -722,241 +965,341 @@ describe('modules/platform/gitea/index', () => { }); it('should return null with no matching results', async () => { - helper.getCombinedCommitStatus.mockResolvedValueOnce( - partial({ - statuses: [partial({ context: 'other-context' })], - }), + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get('/repos/some/repo/commits/some-branch/statuses') + .reply(200, [ + { + id: 1, + status: 'success', + context: 'other-context', + description: 'internal check', + target_url: '', + created_at: '', + }, + ]); + await initFakePlatform(scope); + await initFakeRepo(scope); + + const res = await gitea.getBranchStatusCheck( + 'some-branch', + 'some-context', ); - expect( - await gitea.getBranchStatusCheck('some-branch', 'some-context'), - ).toBeNull(); + expect(res).toBeNull(); }); it('should return yellow with unknown status', async () => { - helper.getCombinedCommitStatus.mockResolvedValueOnce( - partial({ - statuses: [ - partial({ - context: 'some-context', - }), - ], - }), + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get('/repos/some/repo/commits/some-branch/statuses') + .reply(200, [ + { + id: 1, + status: 'xyz', + context: 'some-context', + description: '', + target_url: '', + created_at: '', + }, + ]); + await initFakePlatform(scope); + await initFakeRepo(scope); + + const res = await gitea.getBranchStatusCheck( + 'some-branch', + 'some-context', ); - expect( - await gitea.getBranchStatusCheck('some-branch', 'some-context'), - ).toBe('yellow'); + expect(res).toBe('yellow'); }); it('should return green of matching result', async () => { - helper.getCombinedCommitStatus.mockResolvedValueOnce( - partial({ - statuses: [ - partial({ - status: 'success', - context: 'some-context', - }), - ], - }), + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get('/repos/some/repo/commits/some-branch/statuses') + .reply(200, [ + { + id: 1, + status: 'success', + context: 'some-context', + description: '', + target_url: '', + created_at: '', + }, + ]); + await initFakePlatform(scope); + await initFakeRepo(scope); + + const res = await gitea.getBranchStatusCheck( + 'some-branch', + 'some-context', ); - expect( - await gitea.getBranchStatusCheck('some-branch', 'some-context'), - ).toBe('green'); + expect(res).toBe('green'); }); }); describe('getPrList', () => { it('should return list of pull requests', async () => { - helper.searchPRs.mockResolvedValueOnce(mockPRs); - await initFakeRepo(); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get('/repos/some/repo/pulls') + .query({ state: 'all' }) + .reply(200, mockPRs); + await initFakePlatform(scope); + await initFakeRepo(scope); const res = await gitea.getPrList(); - expect(res).toHaveLength(mockPRs.length); - expect(res).toMatchSnapshot(); + expect(res).toMatchObject([ + { number: 1, title: 'Some PR' }, + { number: 2, title: 'Other PR' }, + { number: 3, title: 'Draft PR' }, + ]); }); it('should filter list by creator', async () => { - helper.getCurrentUser.mockResolvedValueOnce(mockUser); - - expect( - await gitea.initPlatform({ token: 'some-token' }), - ).toMatchSnapshot(); + const thirdPartyPr = partial({ + number: 42, + title: 'Third-party PR', + body: 'other random pull request', + state: 'open', + diff_url: 'https://gitea.renovatebot.com/some/repo/pulls/3.diff', + created_at: '2011-08-18T22:30:38Z', + closed_at: '2016-01-09T10:03:21Z', + mergeable: true, + base: { ref: 'third-party-base-branch' }, + head: { + label: 'other-head-branch', + sha: 'other-head-sha' as LongCommitSha, + repo: partial({ full_name: mockRepo.full_name }), + }, + user: { username: 'not-renovate' }, + }); + + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get('/repos/some/repo/pulls') + .query({ state: 'all' }) + .reply(200, [ + thirdPartyPr, + ...mockPRs.map((pr) => ({ + ...pr, + user: { username: 'renovate' }, + })), + ]); + await initFakePlatform(scope); + await initFakeRepo(scope); - await initFakeRepo(); + const res = await gitea.getPrList(); - helper.searchPRs.mockResolvedValueOnce([ - partial({ - number: 3, - title: 'Third-party PR', - body: 'other random pull request', - state: 'open', - diff_url: 'https://gitea.renovatebot.com/some/repo/pulls/3.diff', - created_at: '2011-08-18T22:30:38Z', - closed_at: '2016-01-09T10:03:21Z', - mergeable: true, - base: { ref: 'third-party-base-branch' }, - head: { - label: 'other-head-branch', - sha: 'other-head-sha' as LongCommitSha, - repo: partial({ full_name: mockRepo.full_name }), - }, - user: { username: 'not-renovate' }, - }), - ...mockPRs.map((pr) => ({ ...pr, user: { username: 'renovate' } })), + expect(res).toMatchObject([ + { number: 1, title: 'Some PR' }, + { number: 2, title: 'Other PR' }, + { number: 3, title: 'Draft PR' }, ]); - - const res = await gitea.getPrList(); - expect(res).toHaveLength(mockPRs.length); - expect(res).toMatchSnapshot(); }); it('should cache results after first query', async () => { - helper.searchPRs.mockResolvedValueOnce(mockPRs); - await initFakeRepo(); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get('/repos/some/repo/pulls') + .query({ state: 'all' }) + .reply(200, mockPRs); + await initFakePlatform(scope); + await initFakeRepo(scope); const res1 = await gitea.getPrList(); const res2 = await gitea.getPrList(); + expect(res1).toEqual(res2); - expect(helper.searchPRs).toHaveBeenCalledTimes(1); }); }); describe('getPr', () => { it('should return enriched pull request which exists if open', async () => { - const mockPR = mockPRs[0]; - helper.searchPRs.mockResolvedValueOnce(mockPRs); - helper.getBranch.mockResolvedValueOnce( - partial({ - commit: { - id: mockCommitHash, - author: partial({ - email: 'renovate@whitesourcesoftware.com', - }), - }, - }), - ); - await initFakeRepo(); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get('/repos/some/repo/pulls') + .query({ state: 'all' }) + .reply(200, mockPRs); + await initFakePlatform(scope); + await initFakeRepo(scope); + + const res = await gitea.getPr(1); - const res = await gitea.getPr(mockPR.number); - expect(res).toHaveProperty('number', mockPR.number); - expect(res).toMatchSnapshot(); + expect(res).toMatchObject({ number: 1, title: 'Some PR' }); }); it('should fallback to direct fetching if cache fails', async () => { - const mockPR = mockPRs[0]; - helper.searchPRs.mockResolvedValueOnce([]); - helper.getPR.mockResolvedValueOnce({ ...mockPR, mergeable: false }); - await initFakeRepo(); + const pr = mockPRs.find((pr) => pr.number === 1); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get('/repos/some/repo/pulls') + .query({ state: 'all' }) + .reply(200, []) + .get('/repos/some/repo/pulls/1') + .reply(200, pr); + await initFakePlatform(scope); + await initFakeRepo(scope); - const res = await gitea.getPr(mockPR.number); - expect(res).toHaveProperty('number', mockPR.number); - expect(res).toMatchSnapshot(); - expect(helper.getPR).toHaveBeenCalledTimes(1); - }); + const res = await gitea.getPr(1); - it('should return null for missing pull request', async () => { - helper.searchPRs.mockResolvedValueOnce(mockPRs); - await initFakeRepo(); - - expect(await gitea.getPr(42)).toBeNull(); + expect(res).toMatchObject({ number: 1, title: 'Some PR' }); }); - it('should block modified pull request for rebasing', async () => { - const mockPR = mockPRs[0]; - helper.searchPRs.mockResolvedValueOnce(mockPRs); - await initFakeRepo(); + it('should return null for missing pull request', async () => { + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get('/repos/some/repo/pulls') + .query({ state: 'all' }) + .reply(200, []) + .get('/repos/some/repo/pulls/42') + .reply(200); // TODO: 404 should be handled + await initFakePlatform(scope); + await initFakeRepo(scope); + + const res = await gitea.getPr(42); - const res = await gitea.getPr(mockPR.number); - expect(res).toHaveProperty('number', mockPR.number); + expect(res).toBeNull(); }); }); describe('findPr', () => { it('should find pull request without title or state', async () => { - const mockPR = mockPRs[0]; - helper.searchPRs.mockResolvedValueOnce(mockPRs); - await initFakeRepo(); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get('/repos/some/repo/pulls') + .query({ state: 'all' }) + .reply(200, mockPRs); + await initFakePlatform(scope); + await initFakeRepo(scope); - const res = await gitea.findPr({ branchName: mockPR.head.label }); - expect(res).toHaveProperty('sourceBranch', mockPR.head.label); + const res = await gitea.findPr({ branchName: 'some-head-branch' }); + + expect(res).toMatchObject({ + number: 1, + sourceBranch: 'some-head-branch', + }); }); it('should find pull request with title', async () => { - const mockPR = mockPRs[0]; - helper.searchPRs.mockResolvedValueOnce(mockPRs); - await initFakeRepo(); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get('/repos/some/repo/pulls') + .query({ state: 'all' }) + .reply(200, mockPRs); + await initFakePlatform(scope); + await initFakeRepo(scope); const res = await gitea.findPr({ - branchName: mockPR.head.label, - prTitle: mockPR.title, + branchName: 'some-head-branch', + prTitle: 'Some PR', + }); + + expect(res).toMatchObject({ + number: 1, + title: 'Some PR', }); - expect(res).toHaveProperty('sourceBranch', mockPR.head.label); - expect(res).toHaveProperty('title', mockPR.title); }); it('should find pull request with state', async () => { - const mockPR = mockPRs[1]; - helper.searchPRs.mockResolvedValueOnce(mockPRs); - await initFakeRepo(); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get('/repos/some/repo/pulls') + .query({ state: 'all' }) + .reply(200, mockPRs); + await initFakePlatform(scope); + await initFakeRepo(scope); const res = await gitea.findPr({ - branchName: mockPR.head.label, - state: mockPR.state, + branchName: 'some-head-branch', + state: 'open', + }); + + expect(res).toMatchObject({ + number: 1, + state: 'open', }); - expect(res).toHaveProperty('sourceBranch', mockPR.head.label); - expect(res).toHaveProperty('state', mockPR.state); }); it('should not find pull request with inverted state', async () => { - const mockPR = mockPRs[1]; - helper.searchPRs.mockResolvedValueOnce(mockPRs); - await initFakeRepo(); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get('/repos/some/repo/pulls') + .query({ state: 'all' }) + .reply(200, mockPRs); + await initFakePlatform(scope); + await initFakeRepo(scope); - expect( - await gitea.findPr({ - branchName: mockPR.head.label, - state: `!${mockPR.state as PrState}` as never, // wrong argument being passed intentionally - }), - ).toBeNull(); + const res = await gitea.findPr({ + branchName: 'other-head-branch', + state: `!open`, + }); + + expect(res).toMatchObject({ + number: 2, + state: 'closed', + title: 'Other PR', + }); }); it('should find pull request with title and state', async () => { - const mockPR = mockPRs[1]; - helper.searchPRs.mockResolvedValueOnce(mockPRs); - await initFakeRepo(); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get('/repos/some/repo/pulls') + .query({ state: 'all' }) + .reply(200, mockPRs); + await initFakePlatform(scope); + await initFakeRepo(scope); const res = await gitea.findPr({ - branchName: mockPR.head.label, - prTitle: mockPR.title, - state: mockPR.state, + branchName: 'other-head-branch', + prTitle: 'Other PR', + state: 'closed', + }); + + expect(res).toMatchObject({ + number: 2, + state: 'closed', + title: 'Other PR', }); - expect(res).toHaveProperty('sourceBranch', mockPR.head.label); - expect(res).toHaveProperty('title', mockPR.title); - expect(res).toHaveProperty('state', mockPR.state); }); it('should find pull request with draft', async () => { - const mockPR = mockPRs[2]; - helper.searchPRs.mockResolvedValueOnce(mockPRs); - await initFakeRepo(); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get('/repos/some/repo/pulls') + .query({ state: 'all' }) + .reply(200, mockPRs); + await initFakePlatform(scope); + await initFakeRepo(scope); const res = await gitea.findPr({ - branchName: mockPR.head.label, + branchName: 'draft-head-branch', prTitle: 'Draft PR', - state: mockPR.state, + state: 'open', + }); + + expect(res).toMatchObject({ + number: 3, + title: 'Draft PR', + isDraft: true, }); - expect(res).toHaveProperty('sourceBranch', mockPR.head.label); - expect(res).toHaveProperty('title', 'Draft PR'); - expect(res).toHaveProperty('state', mockPR.state); }); it('should return null for missing pull request', async () => { - helper.searchPRs.mockResolvedValueOnce(mockPRs); - await initFakeRepo(); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get('/repos/some/repo/pulls') + .query({ state: 'all' }) + .reply(200, mockPRs); + await initFakePlatform(scope); + await initFakeRepo(scope); + + const res = await gitea.findPr({ branchName: 'missing' }); - expect(await gitea.findPr({ branchName: 'missing' })).toBeNull(); + expect(res).toBeNull(); }); }); @@ -981,12 +1324,16 @@ describe('modules/platform/gitea/index', () => { }; it('should use base branch by default', async () => { - helper.createPR.mockResolvedValueOnce({ - ...mockNewPR, - base: { ref: 'devel' }, - }); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .post('/repos/some/repo/pulls') + .reply(200, { + ...mockNewPR, + base: { ref: 'devel' }, + }); + await initFakePlatform(scope); + await initFakeRepo(scope); - await initFakeRepo(); const res = await gitea.createPr({ sourceBranch: mockNewPR.head.label, targetBranch: 'devel', @@ -994,23 +1341,20 @@ describe('modules/platform/gitea/index', () => { prBody: mockNewPR.body, }); - expect(res).toHaveProperty('number', mockNewPR.number); - expect(res).toHaveProperty('targetBranch', 'devel'); - expect(res).toMatchSnapshot(); - expect(helper.createPR).toHaveBeenCalledTimes(1); - expect(helper.createPR).toHaveBeenCalledWith(mockRepo.full_name, { - base: 'devel', - head: mockNewPR.head.label, - title: mockNewPR.title, - body: mockNewPR.body, - labels: [], + expect(res).toMatchObject({ + number: 42, + title: 'pr-title', }); }); it('should use default branch if requested', async () => { - helper.createPR.mockResolvedValueOnce(mockNewPR); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .post('/repos/some/repo/pulls') + .reply(200, mockNewPR); + await initFakePlatform(scope); + await initFakeRepo(scope); - await initFakeRepo(); const res = await gitea.createPr({ sourceBranch: mockNewPR.head.label, targetBranch: 'master', @@ -1019,50 +1363,49 @@ describe('modules/platform/gitea/index', () => { draftPR: true, }); - expect(res).toHaveProperty('number', mockNewPR.number); - expect(res).toHaveProperty('targetBranch', mockNewPR.base.ref); - expect(res).toMatchSnapshot(); - expect(helper.createPR).toHaveBeenCalledTimes(1); - expect(helper.createPR).toHaveBeenCalledWith(mockRepo.full_name, { - base: mockNewPR.base.ref, - head: mockNewPR.head.label, - title: `WIP: ${mockNewPR.title}`, - body: mockNewPR.body, - labels: [], + expect(res).toMatchObject({ + number: 42, + title: 'pr-title', }); }); it('should resolve and apply optional labels to pull request', async () => { - helper.createPR.mockResolvedValueOnce(mockNewPR); - helper.getRepoLabels.mockResolvedValueOnce(mockRepoLabels); - helper.getOrgLabels.mockResolvedValueOnce(mockOrgLabels); - - const mockLabels = mockRepoLabels.concat(mockOrgLabels); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .post('/repos/some/repo/pulls') + .reply(200, mockNewPR) + .get('/repos/some/repo/labels') + .reply(200, mockRepoLabels) + .get('/orgs/some/labels') + .reply(200, mockOrgLabels); + await initFakePlatform(scope); + await initFakeRepo(scope); - await initFakeRepo(); - await gitea.createPr({ + const res = await gitea.createPr({ sourceBranch: mockNewPR.head.label, targetBranch: 'master', prTitle: mockNewPR.title, prBody: mockNewPR.body, - labels: mockLabels.map((l) => l.name), + labels: [...mockRepoLabels, ...mockOrgLabels].map(({ name }) => name), }); - expect(helper.createPR).toHaveBeenCalledTimes(1); - expect(helper.createPR).toHaveBeenCalledWith(mockRepo.full_name, { - base: mockNewPR.base.ref, - head: mockNewPR.head.label, - title: mockNewPR.title, - body: mockNewPR.body, - labels: mockLabels.map((l) => l.id), + expect(res).toMatchObject({ + number: 42, + title: 'pr-title', }); }); it('should ensure new pull request gets added to cached pull requests', async () => { - helper.searchPRs.mockResolvedValueOnce(mockPRs); - helper.createPR.mockResolvedValueOnce(mockNewPR); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get('/repos/some/repo/pulls') + .query({ state: 'all' }) + .reply(200, mockPRs) + .post('/repos/some/repo/pulls') + .reply(200, mockNewPR); + await initFakePlatform(scope); + await initFakeRepo(scope); - await initFakeRepo(); await gitea.getPrList(); await gitea.createPr({ sourceBranch: mockNewPR.head.label, @@ -1070,17 +1413,25 @@ describe('modules/platform/gitea/index', () => { prTitle: mockNewPR.title, prBody: mockNewPR.body, }); - const res = gitea.getPr(mockNewPR.number); + const res = await gitea.getPr(mockNewPR.number); - expect(res).not.toBeNull(); - expect(helper.searchPRs).toHaveBeenCalledTimes(1); + expect(res).toMatchObject({ + number: 42, + title: 'pr-title', + }); }); it('should attempt to resolve 409 conflict error (w/o update)', async () => { - helper.createPR.mockRejectedValueOnce({ statusCode: 409 }); - helper.searchPRs.mockResolvedValueOnce([mockNewPR]); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .post('/repos/some/repo/pulls') + .reply(409) + .get('/repos/some/repo/pulls') + .query({ state: 'all' }) + .reply(200, [mockNewPR]); + await initFakePlatform(scope); + await initFakeRepo(scope); - await initFakeRepo(); const res = await gitea.createPr({ sourceBranch: mockNewPR.head.label, targetBranch: 'master', @@ -1088,14 +1439,25 @@ describe('modules/platform/gitea/index', () => { prBody: mockNewPR.body, }); - expect(res).toHaveProperty('number', mockNewPR.number); + expect(res).toMatchObject({ + number: 42, + title: 'pr-title', + }); }); it('should attempt to resolve 409 conflict error (w/ update)', async () => { - helper.createPR.mockRejectedValueOnce({ statusCode: 409 }); - helper.searchPRs.mockResolvedValueOnce([mockNewPR]); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .post('/repos/some/repo/pulls') + .reply(409) + .get('/repos/some/repo/pulls') + .query({ state: 'all' }) + .reply(200, [mockNewPR]) + .patch('/repos/some/repo/pulls/42') + .reply(200); + await initFakePlatform(scope); + await initFakeRepo(scope); - await initFakeRepo(); const res = await gitea.createPr({ sourceBranch: mockNewPR.head.label, targetBranch: 'master', @@ -1103,19 +1465,20 @@ describe('modules/platform/gitea/index', () => { prBody: 'new-body', }); - expect(res).toHaveProperty('number', mockNewPR.number); - expect(helper.updatePR).toHaveBeenCalledTimes(1); - expect(helper.updatePR).toHaveBeenCalledWith( - mockRepo.full_name, - mockNewPR.number, - { title: 'new-title', body: 'new-body' }, - ); + expect(res).toMatchObject({ + number: 42, + title: 'new-title', + }); }); it('should abort when response for created pull request is invalid', async () => { - helper.createPR.mockResolvedValueOnce(partial()); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .post('/repos/some/repo/pulls') + .reply(200, {}); + await initFakePlatform(scope); + await initFakeRepo(scope); - await initFakeRepo(); await expect( gitea.createPr({ sourceBranch: mockNewPR.head.label, @@ -1127,9 +1490,15 @@ describe('modules/platform/gitea/index', () => { }); it('should use platform automerge', async () => { - helper.createPR.mockResolvedValueOnce(mockNewPR); - await initFakePlatform('1.17.0'); - await initFakeRepo(); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .post('/repos/some/repo/pulls') + .reply(200, mockNewPR) + .post('/repos/some/repo/pulls/42/merge') + .reply(200); + await initFakePlatform(scope, '1.17.0'); + await initFakeRepo(scope); + const res = await gitea.createPr({ sourceBranch: mockNewPR.head.label, targetBranch: 'master', @@ -1138,32 +1507,22 @@ describe('modules/platform/gitea/index', () => { platformOptions: { usePlatformAutomerge: true }, }); - expect(res).toHaveProperty('number', mockNewPR.number); - expect(res).toHaveProperty('targetBranch', mockNewPR.base.ref); - - expect(helper.createPR).toHaveBeenCalledTimes(1); - expect(helper.createPR).toHaveBeenCalledWith(mockRepo.full_name, { - base: mockNewPR.base.ref, - head: mockNewPR.head.label, - title: mockNewPR.title, - body: mockNewPR.body, - labels: [], + expect(res).toMatchObject({ + number: 42, + title: 'pr-title', }); - expect(helper.mergePR).toHaveBeenCalledWith( - mockRepo.full_name, - mockNewPR.number, - { - Do: 'rebase', - merge_when_checks_succeed: true, - }, - ); }); it('continues on platform automerge error', async () => { - helper.createPR.mockResolvedValueOnce(mockNewPR); - await initFakePlatform('1.17.0'); - await initFakeRepo(); - helper.mergePR.mockRejectedValueOnce(new Error('fake')); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .post('/repos/some/repo/pulls') + .reply(200, mockNewPR) + .post('/repos/some/repo/pulls/42/merge') + .replyWithError('unknown error'); + await initFakePlatform(scope, '1.17.0'); + await initFakeRepo(scope); + const res = await gitea.createPr({ sourceBranch: mockNewPR.head.label, targetBranch: 'master', @@ -1172,30 +1531,24 @@ describe('modules/platform/gitea/index', () => { platformOptions: { usePlatformAutomerge: true }, }); - expect(res).toHaveProperty('number', mockNewPR.number); - expect(res).toHaveProperty('targetBranch', mockNewPR.base.ref); - - expect(helper.createPR).toHaveBeenCalledTimes(1); - expect(helper.createPR).toHaveBeenCalledWith(mockRepo.full_name, { - base: mockNewPR.base.ref, - head: mockNewPR.head.label, - title: mockNewPR.title, - body: mockNewPR.body, - labels: [], + expect(res).toMatchObject({ + number: 42, + title: 'pr-title', }); - expect(helper.mergePR).toHaveBeenCalledWith( - mockRepo.full_name, - mockNewPR.number, - { - Do: 'rebase', - merge_when_checks_succeed: true, - }, + expect(logger.warn).toHaveBeenCalledWith( + expect.objectContaining({ prNumber: 42 }), + 'Gitea-native automerge: fail', ); }); it('continues if platform automerge is not supported', async () => { - helper.createPR.mockResolvedValueOnce(mockNewPR); - await initFakeRepo(); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .post('/repos/some/repo/pulls') + .reply(200, mockNewPR); + await initFakePlatform(scope, '1.10.0'); + await initFakeRepo(scope); + const res = await gitea.createPr({ sourceBranch: mockNewPR.head.label, targetBranch: 'master', @@ -1204,25 +1557,27 @@ describe('modules/platform/gitea/index', () => { platformOptions: { usePlatformAutomerge: true }, }); - expect(res).toHaveProperty('number', mockNewPR.number); - expect(res).toHaveProperty('targetBranch', mockNewPR.base.ref); - - expect(helper.createPR).toHaveBeenCalledTimes(1); - expect(helper.createPR).toHaveBeenCalledWith(mockRepo.full_name, { - base: mockNewPR.base.ref, - head: mockNewPR.head.label, - title: mockNewPR.title, - body: mockNewPR.body, - labels: [], + expect(res).toMatchObject({ + number: 42, + title: 'pr-title', }); - expect(helper.mergePR).not.toHaveBeenCalled(); + expect(logger.debug).toHaveBeenCalledWith( + expect.objectContaining({ prNumber: 42 }), + 'Gitea-native automerge: not supported on this version of Gitea. Use 1.17.0 or newer.', + ); }); it('should create PR with repository merge method when automergeStrategy is auto', async () => { - helper.createPR.mockResolvedValueOnce(mockNewPR); - await initFakePlatform('1.17.0'); - await initFakeRepo(); - await gitea.createPr({ + const scope = httpMock + .scope('https://gitea.com/api/v1') + .post('/repos/some/repo/pulls') + .reply(200, mockNewPR) + .post('/repos/some/repo/pulls/42/merge') + .reply(200); + await initFakePlatform(scope, '1.17.0'); + await initFakeRepo(scope); + + const res = await gitea.createPr({ sourceBranch: mockNewPR.head.label, targetBranch: 'master', prTitle: mockNewPR.title, @@ -1233,22 +1588,10 @@ describe('modules/platform/gitea/index', () => { }, }); - expect(helper.createPR).toHaveBeenCalledTimes(1); - expect(helper.createPR).toHaveBeenCalledWith(mockRepo.full_name, { - base: mockNewPR.base.ref, - head: mockNewPR.head.label, - title: mockNewPR.title, - body: mockNewPR.body, - labels: [], + expect(res).toMatchObject({ + number: 42, + title: 'pr-title', }); - expect(helper.mergePR).toHaveBeenCalledWith( - mockRepo.full_name, - mockNewPR.number, - { - Do: 'rebase', - merge_when_checks_succeed: true, - }, - ); }); it.each` @@ -1260,10 +1603,19 @@ describe('modules/platform/gitea/index', () => { `( 'should create PR with mergeStrategy $prMergeStrategy', async ({ automergeStrategy, prMergeStrategy }) => { - helper.createPR.mockResolvedValueOnce(mockNewPR); - await initFakePlatform('1.17.0'); - await initFakeRepo(); - await gitea.createPr({ + const scope = httpMock + .scope('https://gitea.com/api/v1') + .post('/repos/some/repo/pulls') + .reply(200, mockNewPR) + .post('/repos/some/repo/pulls/42/merge') + .reply(200, { + Do: prMergeStrategy, + merge_when_checks_succeed: true, + }); + await initFakePlatform(scope, '1.17.0'); + await initFakeRepo(scope); + + const res = await gitea.createPr({ sourceBranch: mockNewPR.head.label, targetBranch: 'master', prTitle: mockNewPR.title, @@ -1274,185 +1626,256 @@ describe('modules/platform/gitea/index', () => { }, }); - expect(helper.createPR).toHaveBeenCalledTimes(1); - expect(helper.createPR).toHaveBeenCalledWith(mockRepo.full_name, { - base: mockNewPR.base.ref, - head: mockNewPR.head.label, - title: mockNewPR.title, - body: mockNewPR.body, - labels: [], + expect(res).toMatchObject({ + number: 42, + title: 'pr-title', }); - expect(helper.mergePR).toHaveBeenCalledWith( - mockRepo.full_name, - mockNewPR.number, - { - Do: prMergeStrategy, - merge_when_checks_succeed: true, - }, - ); }, ); }); describe('updatePr', () => { it('should update pull request with title', async () => { - helper.searchPRs.mockResolvedValueOnce(mockPRs); - await initFakeRepo(); - await gitea.updatePr({ number: 1, prTitle: 'New Title' }); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get('/repos/some/repo/pulls') + .query({ state: 'all' }) + .reply(200, mockPRs) + .patch('/repos/some/repo/pulls/1', { title: 'New Title' }) + .reply(200); + await initFakePlatform(scope); + await initFakeRepo(scope); - expect(helper.updatePR).toHaveBeenCalledTimes(1); - expect(helper.updatePR).toHaveBeenCalledWith(mockRepo.full_name, 1, { - title: 'New Title', - }); + await expect( + gitea.updatePr({ number: 1, prTitle: 'New Title' }), + ).toResolve(); }); it('should update pull target branch', async () => { - helper.searchPRs.mockResolvedValueOnce(mockPRs); - await initFakeRepo(); - await gitea.updatePr({ - number: 1, - prTitle: 'New Title', - targetBranch: 'New Base', - }); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get('/repos/some/repo/pulls') + .query({ state: 'all' }) + .reply(200, mockPRs) + .patch('/repos/some/repo/pulls/1', { + title: 'New Title', + base: 'New Base', + }) + .reply(200); + await initFakePlatform(scope); + await initFakeRepo(scope); - expect(helper.updatePR).toHaveBeenCalledTimes(1); - expect(helper.updatePR).toHaveBeenCalledWith(mockRepo.full_name, 1, { - title: 'New Title', - base: 'New Base', - }); + await expect( + gitea.updatePr({ + number: 1, + prTitle: 'New Title', + targetBranch: 'New Base', + }), + ).toResolve(); }); it('should update pull request with title and body', async () => { - helper.searchPRs.mockResolvedValueOnce(mockPRs); - await initFakeRepo(); - await gitea.updatePr({ - number: 1, - prTitle: 'New Title', - prBody: 'New Body', - }); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get('/repos/some/repo/pulls') + .query({ state: 'all' }) + .reply(200, mockPRs) + .patch('/repos/some/repo/pulls/1', { + title: 'New Title', + body: 'New Body', + }) + .reply(200); + await initFakePlatform(scope); + await initFakeRepo(scope); - expect(helper.updatePR).toHaveBeenCalledTimes(1); - expect(helper.updatePR).toHaveBeenCalledWith(mockRepo.full_name, 1, { - title: 'New Title', - body: 'New Body', - }); + await expect( + gitea.updatePr({ + number: 1, + prTitle: 'New Title', + prBody: 'New Body', + }), + ).toResolve(); }); it('should update pull request with draft', async () => { - helper.searchPRs.mockResolvedValueOnce(mockPRs); - await initFakeRepo(); - await gitea.updatePr({ - number: 3, - prTitle: 'New Title', - prBody: 'New Body', - }); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get('/repos/some/repo/pulls') + .query({ state: 'all' }) + .reply(200, mockPRs) + .patch('/repos/some/repo/pulls/3', { + title: 'WIP: New Title', + body: 'New Body', + }) + .reply(200); + await initFakePlatform(scope); + await initFakeRepo(scope); - expect(helper.updatePR).toHaveBeenCalledTimes(1); - expect(helper.updatePR).toHaveBeenCalledWith(mockRepo.full_name, 3, { - title: 'WIP: New Title', - body: 'New Body', - }); + await expect( + gitea.updatePr({ + number: 3, + prTitle: 'New Title', + prBody: 'New Body', + }), + ).toResolve(); }); it('should close pull request', async () => { - helper.searchPRs.mockResolvedValueOnce(mockPRs); - await initFakeRepo(); - await gitea.updatePr({ - number: 1, - prTitle: 'New Title', - prBody: 'New Body', - state: 'closed', - }); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get('/repos/some/repo/pulls') + .query({ state: 'all' }) + .reply(200, mockPRs) + .patch('/repos/some/repo/pulls/1', { + title: 'New Title', + body: 'New Body', + state: 'closed', + }) + .reply(200); + await initFakePlatform(scope); + await initFakeRepo(scope); - expect(helper.updatePR).toHaveBeenCalledWith(mockRepo.full_name, 1, { - title: 'New Title', - body: 'New Body', - state: 'closed', - }); + await expect( + gitea.updatePr({ + number: 1, + prTitle: 'New Title', + prBody: 'New Body', + state: 'closed', + }), + ).toResolve(); }); }); describe('mergePr', () => { it('should return true when merging succeeds', async () => { - await initFakeRepo(); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .post('/repos/some/repo/pulls/1/merge', { + Do: 'rebase', + }) + .reply(200); + await initFakePlatform(scope); + await initFakeRepo(scope); - expect( - await gitea.mergePr({ - branchName: 'some-branch', - id: 1, - }), - ).toBe(true); - expect(helper.mergePR).toHaveBeenCalledTimes(1); - expect(helper.mergePR).toHaveBeenCalledWith(mockRepo.full_name, 1, { - Do: 'rebase', + const res = await gitea.mergePr({ + branchName: 'some-branch', + id: 1, }); + + expect(res).toBe(true); }); it('should return false when merging fails', async () => { - helper.mergePR.mockRejectedValueOnce(new Error()); - await initFakeRepo(); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .post('/repos/some/repo/pulls/1/merge', { + Do: 'squash', + }) + .replyWithError('unknown'); + await initFakePlatform(scope); + await initFakeRepo(scope); + + const res = await gitea.mergePr({ + branchName: 'some-branch', + id: 1, + strategy: 'squash', + }); - expect( - await gitea.mergePr({ - branchName: 'some-branch', - id: 1, - strategy: 'squash', - }), - ).toBe(false); + expect(res).toBe(false); }); }); describe('getIssueList', () => { it('should return empty for disabled issues', async () => { - await initFakeRepo({ has_issues: false }); - expect(await gitea.getIssueList()).toBeEmptyArray(); + const scope = httpMock.scope('https://gitea.com/api/v1'); + await initFakePlatform(scope); + await initFakeRepo(scope, { has_issues: false }); + + const res = await gitea.getIssueList(); + + expect(res).toBeEmptyArray(); }); }); describe('getIssue', () => { it('should return the issue', async () => { const mockIssue = mockIssues.find((i) => i.number === 1)!; - helper.getIssue.mockResolvedValueOnce(mockIssue); - await initFakeRepo(); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get('/repos/some/repo/issues/1') + .reply(200, mockIssue); + await initFakePlatform(scope); + await initFakeRepo(scope); - expect(await gitea.getIssue?.(mockIssue.number)).toHaveProperty( - 'number', - mockIssue.number, - ); + const res = await gitea.getIssue?.(mockIssue.number); + + expect(res).toEqual({ + body: 'some-content', + number: 1, + }); }); it('should return null for disabled issues', async () => { - await initFakeRepo({ has_issues: false }); - expect(await gitea.getIssue!(1)).toBeNull(); + const scope = httpMock.scope('https://gitea.com/api/v1'); + await initFakePlatform(scope); + await initFakeRepo(scope, { has_issues: false }); + + const res = await gitea.getIssue!(1); + + expect(res).toBeNull(); }); }); describe('findIssue', () => { it('should return existing open issue', async () => { - const mockIssue = mockIssues.find((i) => i.title === 'open-issue')!; - helper.searchIssues.mockResolvedValueOnce(mockIssues); - helper.getIssue.mockResolvedValueOnce(mockIssue); - await initFakeRepo(); - - expect(await gitea.findIssue(mockIssue.title)).toHaveProperty( - 'number', - mockIssue.number, - ); + const mockIssue = mockIssues.find(({ title }) => title === 'open-issue')!; + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get('/repos/some/repo/issues') + .query({ state: 'all', type: 'issues' }) + .reply(200, mockIssues) + .get('/repos/some/repo/issues/1') + .reply(200, mockIssue); + await initFakePlatform(scope); + await initFakeRepo(scope); + + const res = await gitea.findIssue(mockIssue.title); + + expect(res).toMatchObject({ + body: 'some-content', + number: 1, + }); }); it('should not return existing closed issue', async () => { - const mockIssue = mockIssues.find((i) => i.title === 'closed-issue')!; - helper.searchIssues.mockResolvedValueOnce(mockIssues); - await initFakeRepo(); + const mockIssue = mockIssues.find( + ({ title }) => title === 'closed-issue', + )!; + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get('/repos/some/repo/issues') + .query({ state: 'all', type: 'issues' }) + .reply(200, mockIssues); + await initFakePlatform(scope); + await initFakeRepo(scope); + + const res = await gitea.findIssue(mockIssue.title); - expect(await gitea.findIssue(mockIssue.title)).toBeNull(); + expect(res).toBeNull(); }); it('should return null for missing issue', async () => { - helper.searchIssues.mockResolvedValueOnce(mockIssues); - await initFakeRepo(); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get('/repos/some/repo/issues') + .query({ state: 'all', type: 'issues' }) + .reply(200, mockIssues); + await initFakePlatform(scope); + await initFakeRepo(scope); - expect(await gitea.findIssue('missing')).toBeNull(); + const res = await gitea.findIssue('missing'); + + expect(res).toBeNull(); }); }); @@ -1465,18 +1888,22 @@ describe('modules/platform/gitea/index', () => { once: false, }; - helper.searchIssues.mockResolvedValueOnce(mockIssues); - helper.createIssue.mockResolvedValueOnce(partial({ number: 42 })); + const scope = httpMock + .scope('https://gitea.com/api/v1') + .get('/repos/some/repo/issues') + .query({ state: 'all', type: 'issues' }) + .reply(200, mockIssues) + .post('/repos/some/repo/issues', { + body: mockIssue.body, + title: mockIssue.title, + }) + .reply(200, { number: 42 }); + await initFakePlatform(scope); + await initFakeRepo(scope); - await initFakeRepo(); const res = await gitea.ensureIssue(mockIssue); expect(res).toBe('created'); - expect(helper.createIssue).toHaveBeenCalledTimes(1); - expect(helper.createIssue).toHaveBeenCalledWith(mockRepo.full_name, { - body: mockIssue.body, - title: mockIssue.title, - }); }); it('should create issue with the correct labels', async () => { @@ -1487,35 +1914,49 @@ describe('modules/platform/gitea/index', () => { once: false, labels: ['Renovate', 'Maintenance'], }; - const mockLabels: Label[] = [ - partial