Skip to content

Commit

Permalink
Merge pull request #26616 from storybookjs/yann/improve-yarn2-error-m…
Browse files Browse the repository at this point in the history
…essages

CLI: Improve Yarn berry error parsing
(cherry picked from commit ee7c4d9)
  • Loading branch information
yannbf authored and storybook-bot committed Mar 25, 2024
1 parent eb8f745 commit 49db7b2
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 50 deletions.
54 changes: 42 additions & 12 deletions code/lib/core-common/src/js-package-manager/Yarn2Proxy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -276,35 +276,65 @@ describe('Yarn 2 Proxy', () => {
});

describe('parseErrors', () => {
it('should parse yarn2 errors', () => {
it('should single yarn2 error message', () => {
const YARN2_ERROR_SAMPLE = `
➤ YN0000: ┌ Resolution step
➤ YN0001: │ Error: react@npm:28.2.0: No candidates found
at ge (/Users/yannbraga/.cache/node/corepack/yarn/3.5.1/yarn.js:439:8124)
at ge (/Users/xyz/.cache/node/corepack/yarn/3.5.1/yarn.js:439:8124)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async Promise.allSettled (index 8)
at async io (/Users/yannbraga/.cache/node/corepack/yarn/3.5.1/yarn.js:390:10398)
at async io (/Users/xyz/.cache/node/corepack/yarn/3.5.1/yarn.js:390:10398)
➤ YN0000: └ Completed in 2s 369ms
➤ YN0000: Failed with errors in 2s 372ms
➤ YN0032: fsevents@npm:2.3.2: Implicit dependencies on node-gyp are discouraged
➤ YN0061: @npmcli/move-file@npm:2.0.1 is deprecated: This functionality has been moved to @npmcli/fs
`;

expect(yarn2Proxy.parseErrorFromLogs(YARN2_ERROR_SAMPLE)).toEqual(
'YARN2 error YN0001 - EXCEPTION: react@npm:28.2.0: No candidates found'
expect(yarn2Proxy.parseErrorFromLogs(YARN2_ERROR_SAMPLE)).toMatchInlineSnapshot(
`
"YARN2 error
YN0001: EXCEPTION
-> Error: react@npm:28.2.0: No candidates found
"
`
);
});

it('should show unknown yarn2 error', () => {
const YARN2_ERROR_SAMPLE = dedent`
it('shows multiple yarn2 error messages', () => {
const YARN2_ERROR_SAMPLE = `
➤ YN0000: · Yarn 4.1.1
➤ YN0000: ┌ Resolution step
➤ YN0000: └ Completed in 2s 369ms
➤ YN0000: Failed with errors in 2s 372ms
➤ YN0032: fsevents@npm:2.3.2: Implicit dependencies on node-gyp are discouraged
➤ YN0061: @npmcli/move-file@npm:2.0.1 is deprecated: This functionality has been moved to @npmcli/fs
➤ YN0085: │ + @chromatic-com/storybook@npm:1.2.25, and 300 more.
➤ YN0000: └ Completed in 0s 763ms
➤ YN0000: ┌ Post-resolution validation
➤ YN0002: │ before-storybook@workspace:. doesn't provide @testing-library/dom (p1ac37), requested by @testing-library/user-event.
➤ YN0002: │ before-storybook@workspace:. doesn't provide eslint (p1f657), requested by eslint-plugin-storybook.
➤ YN0086: │ Some peer dependencies are incorrectly met; run yarn explain peer-requirements <hash> for details, where <hash> is the six-letter p-prefixed code.
➤ YN0000: └ Completed
➤ YN0000: ┌ Fetch step
➤ YN0000: └ Completed
➤ YN0000: ┌ Link step
➤ YN0014: │ Failed to import certain dependencies
➤ YN0071: │ Cannot link @storybook/test into before-storybook@workspace:. dependency @testing-library/jest-dom@npm:6.4.2 [ae73b] conflicts with parent dependency @testing-library/jest-dom@npm:5.17.0
➤ YN0071: │ Cannot link @storybook/test into before-storybook@workspace:. dependency @testing-library/user-event@npm:14.5.2 [ae73b] conflicts with parent dependency @testing-library/user-event@npm:13.5.0 [1b0ac]
➤ YN0000: └ Completed in 0s 262ms
➤ YN0000: · Failed with errors in 1s 301ms
`;

expect(yarn2Proxy.parseErrorFromLogs(YARN2_ERROR_SAMPLE)).toEqual(`YARN2 error`);
expect(yarn2Proxy.parseErrorFromLogs(YARN2_ERROR_SAMPLE)).toMatchInlineSnapshot(
`
"YARN2 error
YN0014: YARN_IMPORT_FAILED
-> Failed to import certain dependencies
YN0071: NM_CANT_INSTALL_EXTERNAL_SOFT_LINK
-> Cannot link @storybook/test into before-storybook@workspace:. dependency @testing-library/jest-dom@npm:6.4.2 [ae73b] conflicts with parent dependency @testing-library/jest-dom@npm:5.17.0
YN0071: NM_CANT_INSTALL_EXTERNAL_SOFT_LINK
-> Cannot link @storybook/test into before-storybook@workspace:. dependency @testing-library/user-event@npm:14.5.2 [ae73b] conflicts with parent dependency @testing-library/user-event@npm:13.5.0 [1b0ac]
"
`
);
});
});
});
89 changes: 51 additions & 38 deletions code/lib/core-common/src/js-package-manager/Yarn2Proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,59 +10,73 @@ import type { PackageJson } from './PackageJson';
import type { InstallationMetadata, PackageMetadata } from './types';
import { parsePackageData } from './util';

const YARN2_ERROR_REGEX = /(YN\d{4}):.*?Error:\s+(.*)/i;
const CRITICAL_YARN2_ERROR_CODES = {
YN0001: 'EXCEPTION',
YN0009: 'BUILD_FAILED',
YN0010: 'RESOLVER_NOT_FOUND',
YN0011: 'FETCHER_NOT_FOUND',
YN0012: 'LINKER_NOT_FOUND',
YN0014: 'YARN_IMPORT_FAILED',
YN0015: 'REMOTE_INVALID',
YN0016: 'REMOTE_NOT_FOUND',
YN0020: 'MISSING_LOCKFILE_ENTRY',
YN0021: 'WORKSPACE_NOT_FOUND',
YN0028: 'FROZEN_LOCKFILE_EXCEPTION',
YN0030: 'FETCH_FAILED',
YN0046: 'AUTOMERGE_FAILED_TO_PARSE',
YN0062: 'INCOMPATIBLE_OS',
YN0063: 'INCOMPATIBLE_CPU',
YN0071: 'NM_CANT_INSTALL_EXTERNAL_SOFT_LINK',
YN0072: 'NM_PRESERVE_SYMLINKS_REQUIRED',
YN0075: 'PROLOG_INSTANTIATION_ERROR',
YN0076: 'INCOMPATIBLE_ARCHITECTURE',
YN0078: 'RESOLUTION_MISMATCH',
YN0081: 'NETWORK_UNSAFE_HTTP',
YN0082: 'RESOLUTION_FAILED',
YN0083: 'AUTOMERGE_GIT_ERROR',
};

const YARN2_ERROR_CODES = {
...CRITICAL_YARN2_ERROR_CODES,
YN0000: 'UNNAMED',
YN0001: 'EXCEPTION',
YN0002: 'MISSING_PEER_DEPENDENCY',
YN0003: 'CYCLIC_DEPENDENCIES',
YN0004: 'DISABLED_BUILD_SCRIPTS',
YN0005: 'BUILD_DISABLED',
YN0006: 'SOFT_LINK_BUILD',
YN0007: 'MUST_BUILD',
YN0008: 'MUST_REBUILD',
YN0009: 'BUILD_FAILED',
YN0010: 'RESOLVER_NOT_FOUND',
YN0011: 'FETCHER_NOT_FOUND',
YN0012: 'LINKER_NOT_FOUND',
YN0013: 'FETCH_NOT_CACHED',
YN0014: 'YARN_IMPORT_FAILED',
YN0015: 'REMOTE_INVALID',
YN0016: 'REMOTE_NOT_FOUND',
YN0017: 'RESOLUTION_PACK',
YN0018: 'CACHE_CHECKSUM_MISMATCH',
YN0019: 'UNUSED_CACHE_ENTRY',
YN0020: 'MISSING_LOCKFILE_ENTRY',
YN0021: 'WORKSPACE_NOT_FOUND',
YN0022: 'TOO_MANY_MATCHING_WORKSPACES',
YN0023: 'CONSTRAINTS_MISSING_DEPENDENCY',
YN0024: 'CONSTRAINTS_INCOMPATIBLE_DEPENDENCY',
YN0025: 'CONSTRAINTS_EXTRANEOUS_DEPENDENCY',
YN0026: 'CONSTRAINTS_INVALID_DEPENDENCY',
YN0027: 'CANT_SUGGEST_RESOLUTIONS',
YN0028: 'FROZEN_LOCKFILE_EXCEPTION',
YN0029: 'CROSS_DRIVE_VIRTUAL_LOCAL',
YN0030: 'FETCH_FAILED',
YN0031: 'DANGEROUS_NODE_MODULES',
YN0032: 'NODE_GYP_INJECTED',
YN0046: 'AUTOMERGE_FAILED_TO_PARSE',
YN0047: 'AUTOMERGE_IMMUTABLE',
YN0048: 'AUTOMERGE_SUCCESS',
YN0049: 'AUTOMERGE_REQUIRED',
YN0050: 'DEPRECATED_CLI_SETTINGS',
YN0059: 'INVALID_RANGE_PEER_DEPENDENCY',
YN0060: 'INCOMPATIBLE_PEER_DEPENDENCY',
YN0061: 'DEPRECATED_PACKAGE',
YN0062: 'INCOMPATIBLE_OS',
YN0063: 'INCOMPATIBLE_CPU',
YN0068: 'UNUSED_PACKAGE_EXTENSION',
YN0069: 'REDUNDANT_PACKAGE_EXTENSION',
YN0071: 'NM_CANT_INSTALL_EXTERNAL_SOFT_LINK',
YN0072: 'NM_PRESERVE_SYMLINKS_REQUIRED',
YN0074: 'NM_HARDLINKS_MODE_DOWNGRADED',
YN0075: 'PROLOG_INSTANTIATION_ERROR',
YN0076: 'INCOMPATIBLE_ARCHITECTURE',
YN0077: 'GHOST_ARCHITECTURE',
YN0080: 'NETWORK_DISABLED',
YN0085: 'UPDATED_RESOLUTION_RECORD',
YN0086: 'EXPLAIN_PEER_DEPENDENCIES_CTA',
YN0087: 'MIGRATION_SUCCESS',
YN0088: 'VERSION_NOTICE',
YN0089: 'TIPS_NOTICE',
YN0090: 'OFFLINE_MODE_ENABLED',
};

// This encompasses both yarn 2 and yarn 3
Expand Down Expand Up @@ -284,26 +298,25 @@ export class Yarn2Proxy extends JsPackageManager {
}

public parseErrorFromLogs(logs: string): string {
let finalMessage = 'YARN2 error';
const match = logs.match(YARN2_ERROR_REGEX);

if (match) {
const errorCode = match[1] as keyof typeof YARN2_ERROR_CODES;
if (errorCode) {
finalMessage = `${finalMessage} ${errorCode}`;
}

const errorType = YARN2_ERROR_CODES[errorCode];
if (errorType) {
finalMessage = `${finalMessage} - ${errorType}`;
}

const errorMessage = match[2];
if (errorMessage) {
finalMessage = `${finalMessage}: ${errorMessage}`;
const finalMessage = 'YARN2 error';
const errorCodesWithMessages: { code: string; message: string }[] = [];
const regex = /(YN\d{4}): (.+)/g;
let match: RegExpExecArray | null;

while ((match = regex.exec(logs)) !== null) {
const code = match[1];
const message = match[2].replace(/[┌│└]/g, '').trim();
if (CRITICAL_YARN2_ERROR_CODES[code]) {
errorCodesWithMessages.push({
code,
message: `${CRITICAL_YARN2_ERROR_CODES[code]}\n-> ${message}\n`,
});
}
}

return finalMessage.trim();
return [
finalMessage,
errorCodesWithMessages.map(({ code, message }) => `${code}: ${message}`).join('\n'),
].join('\n');
}
}

0 comments on commit 49db7b2

Please sign in to comment.