-
-
Notifications
You must be signed in to change notification settings - Fork 9.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Release: Prerelease 8.5.0-alpha.2 #29508
Merged
+773
−167
Merged
Changes from 6 commits
Commits
Show all changes
58 commits
Select commit
Hold shift + click to select a range
96af77f
Chore: Fix path to sandbox template file
tobiasdiez d782224
Chore: Fix moving sandbox from temporary dir to another partition
tobiasdiez da4975b
Chore: Add output of errors during yarn setup in sandbox
tobiasdiez 9e1084d
Chore: Yarn setup in sandbox works on Windows now
tobiasdiez fd4b309
Merge branch 'next' into sandbox-improv
tobiasdiez 71c29c6
Merge branch 'next' into sandbox-improv
tobiasdiez 987feb4
SvelteKIT: Support ESM for Vitest test runs
valentinpalkovic 395173f
Next.js: Update dependencies
d0fb8a5
Merge remote-tracking branch 'origin/next' into next
ef6e2ce
feat: bun support with npm fallback
stephenjason89 9af7980
Merge branch 'next' into next
HoncharenkoZhenya 5ec554a
Merge branch 'next' into sandbox-improv
tobiasdiez 7937702
Merge branch 'next' into next
HoncharenkoZhenya 55d22d6
Chore: gracefully handle empty folders on dev machines
tobiasdiez f3a2521
Merge branch 'next' into next
HoncharenkoZhenya 5a4d779
Merge branch 'next' into next
HoncharenkoZhenya 7bf0947
Merge branch 'next' into next
HoncharenkoZhenya 11e4cb9
Merge branch 'next' into next
HoncharenkoZhenya 05a44c8
Merge branch 'next' into next
HoncharenkoZhenya dd72ea8
Merge branch 'next' into next
HoncharenkoZhenya c0003af
Merge branch 'next' into next
HoncharenkoZhenya 984d118
Merge branch 'next' into next
HoncharenkoZhenya c34b32f
Merge branch 'next' into next
HoncharenkoZhenya 9b6a437
Merge branch 'next' into next
HoncharenkoZhenya 35ca913
Merge branch 'next' into next
HoncharenkoZhenya bebaa3b
Ensure consistent absolute path for Next.js-bundled react and react-dom
sentience 6d78a22
Merge branch 'next' into next
HoncharenkoZhenya 3095d0c
Merge remote-tracking branch 'origin/next' into pr/tobiasdiez/28965
valentinpalkovic ee5a4f6
Refactor sandbox generate script to remove temporary directory
valentinpalkovic c9350ee
Merge remote-tracking branch 'origin/next' into pr/stephenjason89/29267
valentinpalkovic 8773f66
Refactor: Remove unused getNpmVersion method from BUNProxy and NPMProxy
valentinpalkovic d499768
Refactor: Add support for BUN package manager
valentinpalkovic 1523974
Refactor: Update BUNProxy to support remote run command
valentinpalkovic c56ec94
Merge remote-tracking branch 'origin/next' into pr/tobiasdiez/29287
valentinpalkovic cb540e4
Fix spelling in comment
sentience e8a9166
Enable scopedResolve to accept script file references
sentience e9ee80d
Merge remote-tracking branch 'origin/next' into fix-nextjs-react-path…
sentience 0d6c4e0
Only render the TestingModule component in development mode
yannbf 4632519
Merge branch 'next' into yann/hide-testing-module-on-prod
yannbf e763421
refactor logic
yannbf 01c02bc
Merge branch 'yann/hide-testing-module-on-prod' of github.com:storybo…
yannbf 54c8712
refactor
yannbf 4b49438
Add capability for groups to TooltipLinkList, use it for main menu an…
ghengeveld 18b4710
Indent all groups together
ghengeveld 4c0ac6f
Merge pull request #29287 from tobiasdiez/oldDir
valentinpalkovic fb79a2b
Merge pull request #29267 from stephenjason89/feat/bun-compatibility
valentinpalkovic db6bb01
Merge pull request #28965 from tobiasdiez/sandbox-improv
valentinpalkovic 6c829c5
Merge pull request #29444 from sentience/fix-nextjs-react-paths-in-mo…
valentinpalkovic bc837ac
Merge pull request #29264 from HoncharenkoZhenya/next
valentinpalkovic f85d62c
Merge branch 'next' into valentin/fix-svelte-vite-plugin
valentinpalkovic 3b5851a
Merge pull request #29157 from storybookjs/valentin/fix-svelte-vite-p…
valentinpalkovic b02bc0a
Update TagsFilterPanel to use link groups
ghengeveld 6663c5e
Update CHANGELOG.md for v8.4.1 [skip ci]
storybook-bot 46e37f1
Merge pull request #29501 from storybookjs/yann/hide-testing-module-o…
yannbf 5a4322c
Merge pull request #29507 from storybookjs/dropdown-menu-groups
ghengeveld a10154e
CLI: Fix Solid init by installing `@storybook/test`
shilman d130f0c
Merge pull request #29514 from storybookjs/shilman/fix-solid-init
shilman 2a0de12
Write changelog for 8.5.0-alpha.2 [skip ci]
storybook-bot File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,332 @@ | ||
import { existsSync, readFileSync } from 'node:fs'; | ||
import { platform } from 'node:os'; | ||
import { join } from 'node:path'; | ||
|
||
import { logger } from '@storybook/core/node-logger'; | ||
import { FindPackageVersionsError } from '@storybook/core/server-errors'; | ||
|
||
import { findUp } from 'find-up'; | ||
import sort from 'semver/functions/sort.js'; | ||
import { dedent } from 'ts-dedent'; | ||
|
||
import { createLogStream } from '../utils/cli'; | ||
import { JsPackageManager } from './JsPackageManager'; | ||
import type { PackageJson } from './PackageJson'; | ||
import type { InstallationMetadata, PackageMetadata } from './types'; | ||
|
||
type NpmDependency = { | ||
version: string; | ||
resolved?: string; | ||
overridden?: boolean; | ||
dependencies?: NpmDependencies; | ||
}; | ||
|
||
type NpmDependencies = { | ||
[key: string]: NpmDependency; | ||
}; | ||
|
||
export type NpmListOutput = { | ||
dependencies: NpmDependencies; | ||
}; | ||
|
||
const NPM_ERROR_REGEX = /npm ERR! code (\w+)/; | ||
const NPM_ERROR_CODES = { | ||
E401: 'Authentication failed or is required.', | ||
E403: 'Access to the resource is forbidden.', | ||
E404: 'Requested resource not found.', | ||
EACCES: 'Permission issue.', | ||
EAI_FAIL: 'DNS lookup failed.', | ||
EBADENGINE: 'Engine compatibility check failed.', | ||
EBADPLATFORM: 'Platform not supported.', | ||
ECONNREFUSED: 'Connection refused.', | ||
ECONNRESET: 'Connection reset.', | ||
EEXIST: 'File or directory already exists.', | ||
EINVALIDTYPE: 'Invalid type encountered.', | ||
EISGIT: 'Git operation failed or conflicts with an existing file.', | ||
EJSONPARSE: 'Error parsing JSON data.', | ||
EMISSINGARG: 'Required argument missing.', | ||
ENEEDAUTH: 'Authentication needed.', | ||
ENOAUDIT: 'No audit available.', | ||
ENOENT: 'File or directory does not exist.', | ||
ENOGIT: 'Git not found or failed to run.', | ||
ENOLOCK: 'Lockfile missing.', | ||
ENOSPC: 'Insufficient disk space.', | ||
ENOTFOUND: 'Resource not found.', | ||
EOTP: 'One-time password required.', | ||
EPERM: 'Permission error.', | ||
EPUBLISHCONFLICT: 'Conflict during package publishing.', | ||
ERESOLVE: 'Dependency resolution error.', | ||
EROFS: 'File system is read-only.', | ||
ERR_SOCKET_TIMEOUT: 'Socket timed out.', | ||
ETARGET: 'Package target not found.', | ||
ETIMEDOUT: 'Operation timed out.', | ||
ETOOMANYARGS: 'Too many arguments provided.', | ||
EUNKNOWNTYPE: 'Unknown type encountered.', | ||
}; | ||
|
||
export class BUNProxy extends JsPackageManager { | ||
readonly type = 'bun'; | ||
|
||
installArgs: string[] | undefined; | ||
|
||
async initPackageJson() { | ||
await this.executeCommand({ command: 'bun', args: ['init'] }); | ||
} | ||
|
||
getRunStorybookCommand(): string { | ||
return 'bun run storybook'; | ||
} | ||
|
||
getRunCommand(command: string): string { | ||
return `bun run ${command}`; | ||
} | ||
|
||
getRemoteRunCommand(): string { | ||
return 'bunx'; | ||
} | ||
|
||
public async getPackageJSON( | ||
packageName: string, | ||
basePath = this.cwd | ||
): Promise<PackageJson | null> { | ||
const packageJsonPath = await findUp( | ||
(dir) => { | ||
const possiblePath = join(dir, 'node_modules', packageName, 'package.json'); | ||
return existsSync(possiblePath) ? possiblePath : undefined; | ||
}, | ||
{ cwd: basePath } | ||
); | ||
|
||
if (!packageJsonPath) { | ||
return null; | ||
} | ||
|
||
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8')); | ||
return packageJson; | ||
} | ||
|
||
getInstallArgs(): string[] { | ||
if (!this.installArgs) { | ||
this.installArgs = []; | ||
} | ||
return this.installArgs; | ||
} | ||
|
||
public runPackageCommandSync( | ||
command: string, | ||
args: string[], | ||
cwd?: string, | ||
stdio?: 'pipe' | 'inherit' | ||
): string { | ||
return this.executeCommandSync({ | ||
command: 'bun', | ||
args: ['run', command, ...args], | ||
cwd, | ||
stdio, | ||
}); | ||
} | ||
|
||
public async runPackageCommand(command: string, args: string[], cwd?: string): Promise<string> { | ||
return this.executeCommand({ | ||
command: 'bun', | ||
args: ['run', command, ...args], | ||
cwd, | ||
}); | ||
} | ||
|
||
public async findInstallations(pattern: string[], { depth = 99 }: { depth?: number } = {}) { | ||
const exec = async ({ packageDepth }: { packageDepth: number }) => { | ||
const pipeToNull = platform() === 'win32' ? '2>NUL' : '2>/dev/null'; | ||
return this.executeCommand({ | ||
command: 'npm', | ||
args: ['ls', '--json', `--depth=${packageDepth}`, pipeToNull], | ||
env: { | ||
FORCE_COLOR: 'false', | ||
}, | ||
}); | ||
}; | ||
|
||
try { | ||
const commandResult = await exec({ packageDepth: depth }); | ||
const parsedOutput = JSON.parse(commandResult); | ||
|
||
return this.mapDependencies(parsedOutput, pattern); | ||
} catch (e) { | ||
// when --depth is higher than 0, npm can return a non-zero exit code | ||
// in case the user's project has peer dependency issues. So we try again with no depth | ||
try { | ||
const commandResult = await exec({ packageDepth: 0 }); | ||
const parsedOutput = JSON.parse(commandResult); | ||
|
||
return this.mapDependencies(parsedOutput, pattern); | ||
} catch (err) { | ||
logger.warn(`An issue occurred while trying to find dependencies metadata using npm.`); | ||
return undefined; | ||
} | ||
} | ||
} | ||
|
||
protected getResolutions(packageJson: PackageJson, versions: Record<string, string>) { | ||
return { | ||
overrides: { | ||
...packageJson.overrides, | ||
...versions, | ||
}, | ||
}; | ||
} | ||
|
||
protected async runInstall() { | ||
await this.executeCommand({ | ||
command: 'bun', | ||
args: ['install', ...this.getInstallArgs()], | ||
stdio: 'inherit', | ||
}); | ||
} | ||
|
||
public async getRegistryURL() { | ||
const res = await this.executeCommand({ | ||
command: 'npm', | ||
// "npm config" commands are not allowed in workspaces per default | ||
// https://github.com/npm/cli/issues/6099#issuecomment-1847584792 | ||
args: ['config', 'get', 'registry', '-ws=false', '-iwr'], | ||
}); | ||
const url = res.trim(); | ||
return url === 'undefined' ? undefined : url; | ||
} | ||
|
||
protected async runAddDeps(dependencies: string[], installAsDevDependencies: boolean) { | ||
const { logStream, readLogFile, moveLogFile, removeLogFile } = await createLogStream(); | ||
let args = [...dependencies]; | ||
|
||
if (installAsDevDependencies) { | ||
args = ['-D', ...args]; | ||
} | ||
|
||
try { | ||
await this.executeCommand({ | ||
command: 'bun', | ||
args: ['add', ...args, ...this.getInstallArgs()], | ||
stdio: process.env.CI ? 'inherit' : ['ignore', logStream, logStream], | ||
}); | ||
} catch (err) { | ||
const stdout = await readLogFile(); | ||
|
||
const errorMessage = this.parseErrorFromLogs(stdout); | ||
|
||
await moveLogFile(); | ||
|
||
throw new Error( | ||
dedent`${errorMessage} | ||
|
||
Please check the logfile generated at ./storybook.log for troubleshooting and try again.` | ||
); | ||
} | ||
|
||
await removeLogFile(); | ||
} | ||
|
||
protected async runRemoveDeps(dependencies: string[]) { | ||
const args = [...dependencies]; | ||
|
||
await this.executeCommand({ | ||
command: 'bun', | ||
args: ['remove', ...args, ...this.getInstallArgs()], | ||
stdio: 'inherit', | ||
}); | ||
} | ||
|
||
protected async runGetVersions<T extends boolean>( | ||
packageName: string, | ||
fetchAllVersions: T | ||
): Promise<T extends true ? string[] : string> { | ||
const args = [fetchAllVersions ? 'versions' : 'version', '--json']; | ||
try { | ||
const commandResult = await this.executeCommand({ | ||
command: 'npm', | ||
args: ['info', packageName, ...args], | ||
}); | ||
|
||
const parsedOutput = JSON.parse(commandResult); | ||
|
||
if (parsedOutput.error?.summary) { | ||
// this will be handled in the catch block below | ||
throw parsedOutput.error.summary; | ||
} | ||
|
||
return parsedOutput; | ||
} catch (error) { | ||
throw new FindPackageVersionsError({ | ||
error, | ||
packageManager: 'NPM', | ||
packageName, | ||
}); | ||
} | ||
} | ||
|
||
/** | ||
* @param input The output of `npm ls --json` | ||
* @param pattern A list of package names to filter the result. * can be used as a placeholder | ||
*/ | ||
protected mapDependencies(input: NpmListOutput, pattern: string[]): InstallationMetadata { | ||
const acc: Record<string, PackageMetadata[]> = {}; | ||
const existingVersions: Record<string, string[]> = {}; | ||
const duplicatedDependencies: Record<string, string[]> = {}; | ||
|
||
const recurse = ([name, packageInfo]: [string, NpmDependency]): void => { | ||
// transform pattern into regex where `*` is replaced with `.*` | ||
if (!name || !pattern.some((p) => new RegExp(`^${p.replace(/\*/g, '.*')}$`).test(name))) { | ||
return; | ||
} | ||
|
||
const value = { | ||
version: packageInfo.version, | ||
location: '', | ||
}; | ||
|
||
if (!existingVersions[name]?.includes(value.version)) { | ||
if (acc[name]) { | ||
acc[name].push(value); | ||
} else { | ||
acc[name] = [value]; | ||
} | ||
existingVersions[name] = sort([...(existingVersions[name] || []), value.version]); | ||
|
||
if (existingVersions[name].length > 1) { | ||
duplicatedDependencies[name] = existingVersions[name]; | ||
} | ||
} | ||
|
||
if (packageInfo.dependencies) { | ||
Object.entries(packageInfo.dependencies).forEach(recurse); | ||
} | ||
}; | ||
|
||
Object.entries(input.dependencies).forEach(recurse); | ||
|
||
return { | ||
dependencies: acc, | ||
duplicatedDependencies, | ||
infoCommand: 'npm ls --depth=1', | ||
dedupeCommand: 'npm dedupe', | ||
Comment on lines
+309
to
+310
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. style: Info and dedupe commands show npm commands but should reflect Bun equivalents if they exist |
||
}; | ||
} | ||
|
||
public parseErrorFromLogs(logs: string): string { | ||
let finalMessage = 'NPM error'; | ||
const match = logs.match(NPM_ERROR_REGEX); | ||
|
||
if (match) { | ||
const errorCode = match[1] as keyof typeof NPM_ERROR_CODES; | ||
if (errorCode) { | ||
finalMessage = `${finalMessage} ${errorCode}`; | ||
} | ||
|
||
const errorMessage = NPM_ERROR_CODES[errorCode]; | ||
if (errorMessage) { | ||
finalMessage = `${finalMessage} - ${errorMessage}`; | ||
} | ||
} | ||
|
||
return finalMessage.trim(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logic: Error message shows NPM as package manager even though this is the Bun proxy. Should show Bun instead.