feat: add --report-summary option for pnpm exec and pnpm run (#6098)

close #6008
This commit is contained in:
await-ovo
2023-02-20 09:36:35 +08:00
committed by GitHub
parent 4ed825aa49
commit 0377d93678
11 changed files with 354 additions and 62 deletions

View File

@@ -0,0 +1,9 @@
---
"@pnpm/plugin-commands-installation": minor
"@pnpm/plugin-commands-script-runners": minor
"@pnpm/plugin-commands-rebuild": minor
"@pnpm/cli-utils": minor
"pnpm": minor
---
Add --report-summary for pnpm exec and pnpm run [#6008](https://github.com/pnpm/pnpm/issues/6008)

View File

@@ -1,30 +1,33 @@
import { PnpmError } from '@pnpm/error'
interface ActionFailure {
status: 'failure'
duration?: number
prefix: string
message: string
error: Error
}
export interface RecursiveSummary {
fails: ActionFailure[]
passes: number
}
export type RecursiveSummary = Record<string, {
status: 'passed' | 'queued' | 'running'
duration?: number
} | ActionFailure>
class RecursiveFailError extends PnpmError {
public readonly fails: ActionFailure[]
public readonly failures: ActionFailure[]
public readonly passes: number
constructor (command: string, recursiveSummary: RecursiveSummary) {
super('RECURSIVE_FAIL', `"${command}" failed in ${recursiveSummary.fails.length} packages`)
constructor (command: string, recursiveSummary: RecursiveSummary, failures: ActionFailure[]) {
super('RECURSIVE_FAIL', `"${command}" failed in ${failures.length} packages`)
this.fails = recursiveSummary.fails
this.passes = recursiveSummary.passes
this.failures = failures
this.passes = Object.values(recursiveSummary).filter(({ status }) => status === 'passed').length
}
}
export function throwOnCommandFail (command: string, recursiveSummary: RecursiveSummary) {
if (recursiveSummary.fails.length > 0) {
throw new RecursiveFailError(command, recursiveSummary)
const failures = Object.values(recursiveSummary).filter(({ status }) => status === 'failure') as ActionFailure[]
if (failures.length > 0) {
throw new RecursiveFailError(command, recursiveSummary, failures)
}
}

View File

@@ -70,10 +70,7 @@ export async function recursiveRebuild (
workspacePackages,
}) as RebuildOptions
const result = {
fails: [],
passes: 0,
} as RecursiveSummary
const result: RecursiveSummary = {}
const memReadLocalConfig = mem(readLocalConfig)
@@ -120,6 +117,7 @@ export async function recursiveRebuild (
if (opts.ignoredPackages?.has(rootDir)) {
return
}
result[rootDir] = { status: 'running' }
const localConfig = await memReadLocalConfig(rootDir)
await rebuild(
[
@@ -140,16 +138,17 @@ export async function recursiveRebuild (
},
}
)
result.passes++
result[rootDir].status = 'passed'
} catch (err: any) { // eslint-disable-line
logger.info(err)
if (!opts.bail) {
result.fails.push({
result[rootDir] = {
status: 'failure',
error: err,
message: err.message,
prefix: rootDir,
})
}
return
}

View File

@@ -64,7 +64,8 @@
"path-name": "^1.0.0",
"ramda": "npm:@pnpm/ramda@0.28.1",
"realpath-missing": "^1.1.0",
"render-help": "^1.0.3"
"render-help": "^1.0.3",
"write-json-file": "^4.3.0"
},
"peerDependencies": {
"@pnpm/logger": "^5.0.0"

View File

@@ -1,3 +1,4 @@
import path from 'path'
import { docsUrl, RecursiveSummary, throwOnCommandFail } from '@pnpm/cli-utils'
import { Config, types } from '@pnpm/config'
import { makeNodeRequireOption } from '@pnpm/lifecycle'
@@ -13,10 +14,12 @@ import { existsInDir } from './existsInDir'
import { makeEnv } from './makeEnv'
import {
PARALLEL_OPTION_HELP,
REPORT_SUMMARY_OPTION_HELP,
RESUME_FROM_OPTION_HELP,
shorthands as runShorthands,
} from './run'
import { PnpmError } from '@pnpm/error'
import writeJsonFile from 'write-json-file'
export const shorthands = {
parallel: runShorthands.parallel,
@@ -36,6 +39,7 @@ export function rcOptionsTypes () {
], types),
'shell-mode': Boolean,
'resume-from': String,
'report-summary': Boolean,
}
}
@@ -69,6 +73,7 @@ The shell should understand the -c switch on UNIX or /d /s /c on Windows.',
shortAlias: '-c',
},
RESUME_FROM_OPTION_HELP,
REPORT_SUMMARY_OPTION_HELP,
],
},
],
@@ -97,6 +102,24 @@ export function getResumedPackageChunks ({
return chunks.slice(chunkPosition)
}
export async function writeRecursiveSummary (opts: { dir: string, summary: RecursiveSummary }) {
await writeJsonFile(path.join(opts.dir, 'pnpm-exec-summary.json'), {
executionStatus: opts.summary,
})
}
export function createEmptyRecursiveSummary (chunks: string[][]) {
return chunks.flat().reduce<RecursiveSummary>((acc, prefix) => {
acc[prefix] = { status: 'queued' }
return acc
}, {})
}
export function getExecutionDuration (start: [number, number]) {
const end = process.hrtime(start)
return (end[0] * 1e9 + end[1]) / 1e6
}
export async function handler (
opts: Required<Pick<Config, 'selectedProjectsGraph'>> & {
bail?: boolean
@@ -107,6 +130,7 @@ export async function handler (
workspaceConcurrency?: number
shellMode?: boolean
resumeFrom?: string
reportSummary?: boolean
} & Pick<Config, 'extraBinPaths' | 'extraEnv' | 'lockfileDir' | 'dir' | 'userAgent' | 'recursive' | 'workspaceDir'>,
params: string[]
) {
@@ -116,11 +140,6 @@ export async function handler (
}
const limitRun = pLimit(opts.workspaceConcurrency ?? 4)
const result = {
fails: [],
passes: 0,
} as RecursiveSummary
let chunks!: string[][]
if (opts.recursive) {
chunks = opts.sort
@@ -153,6 +172,7 @@ export async function handler (
})
}
const result = createEmptyRecursiveSummary(chunks)
const existsPnp = existsInDir.bind(null, '.pnp.cjs')
const workspacePnpPath = opts.workspaceDir && await existsPnp(opts.workspaceDir)
@@ -160,6 +180,8 @@ export async function handler (
for (const chunk of chunks) {
await Promise.all(chunk.map(async (prefix: string) =>
limitRun(async () => {
result[prefix].status = 'running'
const startTime = process.hrtime()
try {
const pnpPath = workspacePnpPath ?? await existsPnp(prefix)
const extraEnv = {
@@ -183,7 +205,8 @@ export async function handler (
stdio: 'inherit',
shell: opts.shellMode ?? false,
})
result.passes++
result[prefix].status = 'passed'
result[prefix].duration = getExecutionDuration(startTime)
} catch (err: any) { // eslint-disable-line
if (!opts.recursive && typeof err.exitCode === 'number') {
exitCode = err.exitCode
@@ -191,12 +214,15 @@ export async function handler (
}
logger.info(err)
result[prefix] = {
status: 'failure',
duration: getExecutionDuration(startTime),
error: err,
message: err.message,
prefix,
}
if (!opts.bail) {
result.fails.push({
error: err,
message: err.message,
prefix,
})
return
}
@@ -204,6 +230,10 @@ export async function handler (
err['code'] = 'ERR_PNPM_RECURSIVE_EXEC_FIRST_FAIL'
}
err['prefix'] = prefix
opts.reportSummary && await writeRecursiveSummary({
dir: opts.lockfileDir ?? opts.dir,
summary: result,
})
/* eslint-enable @typescript-eslint/dot-notation */
throw err
}
@@ -211,6 +241,10 @@ export async function handler (
)))
}
opts.reportSummary && await writeRecursiveSummary({
dir: opts.lockfileDir ?? opts.dir,
summary: result,
})
throwOnCommandFail('pnpm recursive exec', result)
return { exitCode }
}

View File

@@ -49,6 +49,11 @@ export const SEQUENTIAL_OPTION_HELP = {
name: '--sequential',
}
export const REPORT_SUMMARY_OPTION_HELP = {
description: 'Save the execution results of every package to "pnpm-exec-summary.json". Useful to inspect the execution time and status of each package.',
name: '--report-summary',
}
export const shorthands = {
parallel: [
'--workspace-concurrency=Infinity',
@@ -84,6 +89,7 @@ export function cliOptionsTypes () {
recursive: Boolean,
reverse: Boolean,
'resume-from': String,
'report-summary': Boolean,
}
}
@@ -122,6 +128,7 @@ For options that may be used with `-r`, see "pnpm help recursive"',
RESUME_FROM_OPTION_HELP,
...UNIVERSAL_OPTIONS,
SEQUENTIAL_OPTION_HELP,
REPORT_SUMMARY_OPTION_HELP,
],
},
FILTERING,

View File

@@ -1,5 +1,5 @@
import path from 'path'
import { RecursiveSummary, throwOnCommandFail } from '@pnpm/cli-utils'
import { throwOnCommandFail } from '@pnpm/cli-utils'
import { Config } from '@pnpm/config'
import { PnpmError } from '@pnpm/error'
import {
@@ -11,7 +11,7 @@ import { sortPackages } from '@pnpm/sort-packages'
import pLimit from 'p-limit'
import realpathMissing from 'realpath-missing'
import { existsInDir } from './existsInDir'
import { getResumedPackageChunks } from './exec'
import { createEmptyRecursiveSummary, getExecutionDuration, getResumedPackageChunks, writeRecursiveSummary } from './exec'
import { runScript } from './run'
import { tryBuildRegExpFromCommand } from './regexpCommand'
import { PackageScripts } from '@pnpm/types'
@@ -25,11 +25,12 @@ export type RecursiveRunOpts = Pick<Config,
| 'scriptShell'
| 'shellEmulator'
| 'stream'
> & Required<Pick<Config, 'allProjects' | 'selectedProjectsGraph' | 'workspaceDir'>> &
> & Required<Pick<Config, 'allProjects' | 'selectedProjectsGraph' | 'workspaceDir' | 'dir'>> &
Partial<Pick<Config, 'extraBinPaths' | 'extraEnv' | 'bail' | 'reverse' | 'sort' | 'workspaceConcurrency'>> &
{
ifPresent?: boolean
resumeFrom?: string
reportSummary?: boolean
}
export async function runRecursive (
@@ -55,11 +56,6 @@ export async function runRecursive (
})
}
const result = {
fails: [],
passes: 0,
} as RecursiveSummary
const limitRun = pLimit(opts.workspaceConcurrency ?? 4)
const stdio =
!opts.stream &&
@@ -82,6 +78,8 @@ export async function runRecursive (
}
}
const result = createEmptyRecursiveSummary(packageChunks)
for (const chunk of packageChunks) {
const selectedScripts = chunk.map(prefix => {
const pkg = opts.selectedProjectsGraph[prefix]
@@ -100,6 +98,8 @@ export async function runRecursive (
) {
return
}
result[prefix].status = 'running'
const startTime = process.hrtime()
hasCommand++
try {
const lifecycleOpts: RunLifecycleHookOptions = {
@@ -125,21 +125,29 @@ export async function runRecursive (
const _runScript = runScript.bind(null, { manifest: pkg.package.manifest, lifecycleOpts, runScriptOptions: { enablePrePostScripts: opts.enablePrePostScripts ?? false }, passedThruArgs })
await _runScript(scriptName)
result.passes++
result[prefix].status = 'passed'
result[prefix].duration = getExecutionDuration(startTime)
} catch (err: any) { // eslint-disable-line
logger.info(err)
result[prefix] = {
status: 'failure',
duration: getExecutionDuration(startTime),
error: err,
message: err.message,
prefix,
}
if (!opts.bail) {
result.fails.push({
error: err,
message: err.message,
prefix,
})
return
}
err['code'] = 'ERR_PNPM_RECURSIVE_RUN_FIRST_FAIL'
err['prefix'] = prefix
opts.reportSummary && await writeRecursiveSummary({
dir: opts.workspaceDir ?? opts.dir,
summary: result,
})
/* eslint-enable @typescript-eslint/dot-notation */
throw err
}
@@ -158,7 +166,10 @@ export async function runRecursive (
})
}
}
opts.reportSummary && await writeRecursiveSummary({
dir: opts.workspaceDir ?? opts.dir,
summary: result,
})
throwOnCommandFail('pnpm recursive run', result)
}

View File

@@ -696,3 +696,118 @@ test('pnpm exec in directory with path delimiter', async () => {
}
expect(error).toBeUndefined()
})
test('pnpm recursive exec report summary', async () => {
preparePackages([
{
name: 'project-1',
version: '1.0.0',
scripts: {
build: 'node -e "setTimeout(() => console.log(\'project-1\'), 1000)"',
},
},
{
name: 'project-2',
version: '1.0.0',
scripts: {
build: 'exit 1',
},
},
{
name: 'project-3',
version: '1.0.0',
scripts: {
build: 'node -e "setTimeout(() => console.log(\'project-3\'), 1000)"',
},
},
{
name: 'project-4',
version: '1.0.0',
scripts: {
build: 'exit 1',
},
},
])
const { selectedProjectsGraph } = await readProjects(process.cwd(), [])
let error
try {
await exec.handler({
...DEFAULT_OPTS,
dir: process.cwd(),
selectedProjectsGraph,
recursive: true,
reportSummary: true,
workspaceConcurrency: 3,
}, ['npm', 'run', 'build'])
} catch (err: any) { // eslint-disable-line
error = err
}
expect(error.code).toBe('ERR_PNPM_RECURSIVE_FAIL')
const { default: { executionStatus } } = (await import(path.resolve('pnpm-exec-summary.json')))
expect(executionStatus[path.resolve('project-1')].status).toBe('passed')
expect(executionStatus[path.resolve('project-1')].duration).not.toBeFalsy()
expect(executionStatus[path.resolve('project-2')].status).toBe('failure')
expect(executionStatus[path.resolve('project-2')].duration).not.toBeFalsy()
expect(executionStatus[path.resolve('project-3')].status).toBe('passed')
expect(executionStatus[path.resolve('project-3')].duration).not.toBeFalsy()
expect(executionStatus[path.resolve('project-4')].status).toBe('failure')
expect(executionStatus[path.resolve('project-4')].duration).not.toBeFalsy()
})
test('pnpm recursive exec report summary with --bail', async () => {
preparePackages([
{
name: 'project-1',
version: '1.0.0',
scripts: {
build: 'node -e "setTimeout(() => console.log(\'project-1\'), 1000)"',
},
},
{
name: 'project-2',
version: '1.0.0',
scripts: {
build: 'exit 1',
},
},
{
name: 'project-3',
version: '1.0.0',
scripts: {
build: 'node -e "setTimeout(() => console.log(\'project-3\'), 1000)"',
},
},
{
name: 'project-4',
version: '1.0.0',
scripts: {
build: 'exit 1',
},
},
])
const { selectedProjectsGraph } = await readProjects(process.cwd(), [])
let error
try {
await exec.handler({
...DEFAULT_OPTS,
dir: process.cwd(),
selectedProjectsGraph,
recursive: true,
reportSummary: true,
bail: true,
workspaceConcurrency: 3,
}, ['npm', 'run', 'build'])
} catch (err: any) { // eslint-disable-line
error = err
}
expect(error.code).toBe('ERR_PNPM_RECURSIVE_EXEC_FIRST_FAIL')
const { default: { executionStatus } } = (await import(path.resolve('pnpm-exec-summary.json')))
expect(executionStatus[path.resolve('project-1')].status).toBe('running')
expect(executionStatus[path.resolve('project-2')].status).toBe('failure')
expect(executionStatus[path.resolve('project-2')].duration).not.toBeFalsy()
expect(executionStatus[path.resolve('project-3')].status).toBe('running')
expect(executionStatus[path.resolve('project-4')].status).toBe('queued')
})

View File

@@ -977,3 +977,117 @@ test('pnpm run with RegExp script selector should work on recursive', async () =
expect(await fs.readFile('output-lint-3-b.txt', { encoding: 'utf-8' })).toEqual('3-b')
expect(await fs.readFile('output-lint-3-c.txt', { encoding: 'utf-8' })).toEqual('3-c')
})
test('pnpm recursive run report summary', async () => {
preparePackages([
{
name: 'project-1',
version: '1.0.0',
scripts: {
build: 'node -e "setTimeout(() => console.log(\'project-1\'), 1000)"',
},
},
{
name: 'project-2',
version: '1.0.0',
scripts: {
build: 'exit 1',
},
},
{
name: 'project-3',
version: '1.0.0',
scripts: {
build: 'node -e "setTimeout(() => console.log(\'project-3\'), 1000)"',
},
},
{
name: 'project-4',
version: '1.0.0',
scripts: {
build: 'exit 1',
},
},
])
let error
try {
await run.handler({
...DEFAULT_OPTS,
...await readProjects(process.cwd(), [{ namePattern: '*' }]),
dir: process.cwd(),
recursive: true,
reportSummary: true,
workspaceDir: process.cwd(),
}, ['build'])
} catch (err: any) { // eslint-disable-line
error = err
}
expect(error.code).toBe('ERR_PNPM_RECURSIVE_FAIL')
const { default: { executionStatus } } = (await import(path.resolve('pnpm-exec-summary.json')))
expect(executionStatus[path.resolve('project-1')].status).toBe('passed')
expect(executionStatus[path.resolve('project-1')].duration).not.toBeFalsy()
expect(executionStatus[path.resolve('project-2')].status).toBe('failure')
expect(executionStatus[path.resolve('project-2')].duration).not.toBeFalsy()
expect(executionStatus[path.resolve('project-3')].status).toBe('passed')
expect(executionStatus[path.resolve('project-3')].duration).not.toBeFalsy()
expect(executionStatus[path.resolve('project-4')].status).toBe('failure')
expect(executionStatus[path.resolve('project-4')].duration).not.toBeFalsy()
})
test('pnpm recursive run report summary with --bail', async () => {
preparePackages([
{
name: 'project-1',
version: '1.0.0',
scripts: {
build: 'node -e "setTimeout(() => console.log(\'project-1\'), 1000)"',
},
},
{
name: 'project-2',
version: '1.0.0',
scripts: {
build: 'exit 1',
},
},
{
name: 'project-3',
version: '1.0.0',
scripts: {
build: 'node -e "setTimeout(() => console.log(\'project-3\'), 1000)"',
},
},
{
name: 'project-4',
version: '1.0.0',
scripts: {
build: 'exit 1',
},
},
])
let error
try {
await run.handler({
...DEFAULT_OPTS,
...await readProjects(process.cwd(), [{ namePattern: '*' }]),
dir: process.cwd(),
recursive: true,
reportSummary: true,
workspaceDir: process.cwd(),
bail: true,
workspaceConcurrency: 3,
}, ['build'])
} catch (err: any) { // eslint-disable-line
error = err
}
expect(error.code).toBe('ERR_PNPM_RECURSIVE_RUN_FIRST_FAIL')
const { default: { executionStatus } } = (await import(path.resolve('pnpm-exec-summary.json')))
expect(executionStatus[path.resolve('project-1')].status).toBe('running')
expect(executionStatus[path.resolve('project-2')].status).toBe('failure')
expect(executionStatus[path.resolve('project-2')].duration).not.toBeFalsy()
expect(executionStatus[path.resolve('project-3')].status).toBe('running')
expect(executionStatus[path.resolve('project-4')].status).toBe('queued')
})

View File

@@ -135,10 +135,7 @@ export async function recursive (
forceShamefullyHoist: typeof opts.rawLocalConfig?.['shamefully-hoist'] !== 'undefined',
}) as InstallOptions
const result = {
fails: [],
passes: 0,
} as RecursiveSummary
const result: RecursiveSummary = {}
const memReadLocalConfig = mem(readLocalConfig)
@@ -297,7 +294,7 @@ export async function recursive (
if (opts.ignoredPackages?.has(rootDir)) {
return
}
result[rootDir] = { status: 'running' }
const { manifest, writeProjectManifest } = manifestsByPath[rootDir]
let currentInput = [...params]
if (updateMatch != null) {
@@ -369,16 +366,17 @@ export async function recursive (
if (opts.save !== false) {
await writeProjectManifest(newManifest)
}
result.passes++
result[rootDir].status = 'passed'
} catch (err: any) { // eslint-disable-line
logger.info(err)
if (!opts.bail) {
result.fails.push({
result[rootDir] = {
status: 'failure',
error: err,
message: err.message,
prefix: rootDir,
})
}
return
}
@@ -404,7 +402,7 @@ export async function recursive (
throwOnFail(result)
if (!result.passes && cmdFullName === 'update' && opts.depth === 0) {
if (!Object.values(result).filter(({ status }) => status === 'passed').length && cmdFullName === 'update' && opts.depth === 0) {
throw new PnpmError('NO_PACKAGE_IN_DEPENDENCIES',
'None of the specified packages were found in the dependencies of any of the projects.')
}

17
pnpm-lock.yaml generated
View File

@@ -1194,6 +1194,9 @@ importers:
render-help:
specifier: ^1.0.3
version: 1.0.3
write-json-file:
specifier: ^4.3.0
version: 4.3.0
devDependencies:
'@pnpm/filter-workspace-packages':
specifier: workspace:*
@@ -7975,7 +7978,7 @@ packages:
'@pnpm/find-workspace-dir': 5.0.1
'@pnpm/find-workspace-packages': 5.0.33(@pnpm/logger@5.0.0)(@yarnpkg/core@4.0.0-rc.14)(typanion@3.12.1)
'@pnpm/logger': 5.0.0
'@pnpm/types': 8.10.0
'@pnpm/types': 8.9.0
'@yarnpkg/core': 4.0.0-rc.14(typanion@3.12.1)
load-json-file: 7.0.1
meow: 10.1.5
@@ -8524,7 +8527,6 @@ packages:
/@pnpm/types@8.9.0:
resolution: {integrity: sha512-3MYHYm8epnciApn6w5Fzx6sepawmsNU7l6lvIq+ER22/DPSrr83YMhU/EQWnf4lORn2YyiXFj0FJSyJzEtIGmw==}
engines: {node: '>=14.6'}
dev: false
/@pnpm/util.lex-comparator@1.0.0:
resolution: {integrity: sha512-3aBQPHntVgk5AweBWZn+1I/fqZ9krK/w01197aYVkAJQGftb+BVWgEepxY5GChjSW12j52XX+CmfynYZ/p0DFQ==}
@@ -8657,7 +8659,7 @@ packages:
/@types/byline@4.2.33:
resolution: {integrity: sha512-LJYez7wrWcJQQDknqZtrZuExMGP0IXmPl1rOOGDqLbu+H7UNNRfKNuSxCBcQMLH1EfjeWidLedC/hCc5dDfBog==}
dependencies:
'@types/node': 18.13.0
'@types/node': 14.18.36
dev: true
/@types/cacheable-request@6.0.3:
@@ -8665,7 +8667,7 @@ packages:
dependencies:
'@types/http-cache-semantics': 4.0.1
'@types/keyv': 3.1.4
'@types/node': 18.13.0
'@types/node': 14.18.36
'@types/responselike': 1.0.0
/@types/concat-stream@2.0.0:
@@ -8693,7 +8695,7 @@ packages:
resolution: {integrity: sha512-8bVUjXZvJacUFkJXHdyZ9iH1Eaj5V7I8c4NdH5sQJsdXkqT4CA5Dhb4yb4VE/3asyx4L9ayZr1NIhTsWHczmMw==}
dependencies:
'@types/minimatch': 5.1.2
'@types/node': 18.13.0
'@types/node': 14.18.36
dev: true
/@types/graceful-fs@4.1.6:
@@ -8767,7 +8769,7 @@ packages:
/@types/keyv@3.1.4:
resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==}
dependencies:
'@types/node': 18.13.0
'@types/node': 14.18.36
/@types/lodash@4.14.181:
resolution: {integrity: sha512-n3tyKthHJbkiWhDZs3DkhkCzt2MexYHXlX0td5iMplyfwketaOeKboEVBqzceH7juqvEg3q5oUoBFxSLu7zFag==}
@@ -8810,7 +8812,6 @@ packages:
/@types/node@14.18.36:
resolution: {integrity: sha512-FXKWbsJ6a1hIrRxv+FoukuHnGTgEzKYGi7kilfMae96AL9UNkPFNWJEEYWzdRI9ooIkbr4AKldyuSTLql06vLQ==}
dev: true
/@types/node@18.13.0:
resolution: {integrity: sha512-gC3TazRzGoOnoKAhUx+Q0t8S9Tzs74z7m0ipwGpSqQrleP14hKxP4/JUeEQcD3W1/aIpnWl8pHowI7WokuZpXg==}
@@ -8847,7 +8848,7 @@ packages:
/@types/responselike@1.0.0:
resolution: {integrity: sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==}
dependencies:
'@types/node': 18.13.0
'@types/node': 14.18.36
/@types/retry@0.12.2:
resolution: {integrity: sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==}