bun-workspaces 1.0.0-alpha.7 → 1.0.0-alpha.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +21 -0
- package/README.md +11 -89
- package/package.json +2 -1
- package/src/cli/{cli.d.ts → createCli.d.ts} +1 -1
- package/src/cli/{cli.mjs → createCli.mjs} +4 -4
- package/src/cli/globalOptions/globalOptions.d.ts +4 -0
- package/src/cli/{globalOptions.mjs → globalOptions/globalOptions.mjs} +12 -21
- package/src/cli/globalOptions/globalOptionsConfig.d.ts +37 -0
- package/src/cli/globalOptions/globalOptionsConfig.mjs +32 -0
- package/src/cli/globalOptions/index.d.ts +2 -0
- package/src/cli/globalOptions/index.mjs +2 -0
- package/src/cli/index.d.ts +1 -1
- package/src/cli/index.mjs +2 -2
- package/src/cli/projectCommands/index.d.ts +2 -0
- package/src/cli/projectCommands/index.mjs +2 -0
- package/src/cli/projectCommands/projectCommandHandlers.d.ts +8 -0
- package/src/cli/projectCommands/projectCommandHandlers.mjs +180 -0
- package/src/cli/projectCommands/projectCommandsConfig.d.ts +191 -0
- package/src/cli/projectCommands/projectCommandsConfig.mjs +100 -0
- package/src/config/configFile.d.ts +1 -1
- package/src/internal/bunVersion.d.ts +3 -3
- package/src/internal/env.mjs +4 -1
- package/src/workspaces/errors.d.ts +1 -1
- package/src/workspaces/findWorkspaces.d.ts +2 -2
- package/src/workspaces/packageJson.d.ts +1 -1
- package/src/cli/globalOptions.d.ts +0 -11
- package/src/cli/projectCommands.d.ts +0 -8
- package/src/cli/projectCommands.mjs +0 -179
package/LICENSE.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Scott Morse
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
|
+
<img src="./packages/doc-website/src/docs/public/bw-eye.png" alt="bun-workspaces" width="50" />
|
|
2
|
+
|
|
1
3
|
# bun-workspaces
|
|
2
4
|
|
|
3
|
-
This is a CLI
|
|
5
|
+
This is a CLI that works on top of native [Bun workspaces](https://bun.sh/docs/install/workspaces) with no additional setup required. Get metadata about your workspaces and scripts, and run scripts across your workspaces.
|
|
6
|
+
|
|
7
|
+
### **[See Full Documentation Here](https://bunworkspaces.com)**
|
|
4
8
|
|
|
5
|
-
##
|
|
9
|
+
## Quick Start
|
|
6
10
|
|
|
7
11
|
You can install the CLI in your project or simply use `bunx bun-workspaces`.
|
|
8
12
|
|
|
@@ -11,107 +15,25 @@ $ bun add --dev bun-workspaces
|
|
|
11
15
|
$ bunx bun-workspaces --help
|
|
12
16
|
```
|
|
13
17
|
|
|
14
|
-
### Config file
|
|
15
|
-
|
|
16
|
-
You can create a config file at `bw.json` in your project root, or you can pass a config file to the CLI with the `--configFile` (or `-c`) option.
|
|
17
|
-
|
|
18
|
-
#### Example config
|
|
19
|
-
|
|
20
|
-
In this config, "app-a" is an alias for package "@my-org/application-a" and "app-b" is an alias for package "@my-org/application-b".
|
|
21
|
-
|
|
22
|
-
CLI log levels are `debug`, `info`, `warn`, and `error` or `silent`. The default log level is `info`. Commands that are intended to print specific output will still print at `silent`, such as `list-workspaces`, `list-scripts`, `workspace-info`, `script-info`, etc., but other logs will be suppressed.
|
|
23
|
-
|
|
24
|
-
```json
|
|
25
|
-
{
|
|
26
|
-
"workspaceAliases": {
|
|
27
|
-
"app-a": "@my-org/application-a",
|
|
28
|
-
"app-b": "@my-org/application-b"
|
|
29
|
-
},
|
|
30
|
-
"cli": {
|
|
31
|
-
"logLevel": "warn"
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
You can also pass a config file to the CLI with the `-c` or `--configFile` option.
|
|
37
|
-
|
|
38
|
-
### Examples
|
|
39
|
-
|
|
40
|
-
You might consider making a shorter alias in your `.bashrc`, `.zshrc`, or similar shell configuration file, such as `alias bw="bunx bun-workspaces"`, for convenience.
|
|
41
|
-
|
|
42
18
|
```bash
|
|
43
19
|
alias bw="bunx bun-workspaces"
|
|
44
20
|
|
|
45
|
-
#
|
|
46
|
-
bw
|
|
47
|
-
bw
|
|
48
|
-
|
|
49
|
-
# List workspace names only
|
|
50
|
-
bw list-workspaces --name-only
|
|
51
|
-
|
|
52
|
-
# Filter list of workspaces with wildcard
|
|
53
|
-
bw list-workspaces "my-*"
|
|
54
|
-
|
|
55
|
-
# List all workspace scripts
|
|
56
|
-
bw list-scripts
|
|
57
|
-
|
|
58
|
-
# List script names only
|
|
59
|
-
bw list-scripts --name-only
|
|
60
|
-
|
|
61
|
-
# Get info about a workspace
|
|
62
|
-
bw workspace-info my-workspace
|
|
63
|
-
bw info my-workspace
|
|
64
|
-
|
|
65
|
-
# Get info about a script
|
|
66
|
-
bw script-info my-script
|
|
67
|
-
|
|
68
|
-
# Only print list of workspace names that have the script
|
|
69
|
-
bw script-info my-script --workspaces-only
|
|
21
|
+
# Usage (--help can also be passed to any command)
|
|
22
|
+
bw help
|
|
23
|
+
bw --help
|
|
70
24
|
|
|
71
|
-
# Get JSON
|
|
25
|
+
# Get JSON metadata
|
|
72
26
|
bw list-workspaces --json --pretty # optionally pretty print JSON
|
|
73
27
|
bw list-scripts --json
|
|
74
28
|
bw workspace-info my-workspace --json
|
|
75
29
|
bw script-info my-script --json
|
|
76
30
|
|
|
77
|
-
# Run
|
|
78
|
-
# workspaces that have it
|
|
79
|
-
# in their `scripts` field
|
|
31
|
+
# Run scripts across workspaces
|
|
80
32
|
bw run my-script
|
|
81
|
-
|
|
82
|
-
# By default, a prefix is added to the script output with the workspace name
|
|
83
|
-
# This can be disabled with the --noPrefix option
|
|
84
|
-
bw run my-script --noPrefix
|
|
85
|
-
|
|
86
|
-
# Run a script for a specific workspace by its package.json name or alias from the config
|
|
87
33
|
bw run my-script my-workspace
|
|
88
|
-
|
|
89
|
-
# Run a script for multiple workspaces
|
|
90
34
|
bw run my-script workspace-a workspace-b
|
|
91
|
-
|
|
92
|
-
# Run a script for workspaces using wildcard (does not take into account workspace aliases)
|
|
93
35
|
bw run my-script "my-workspace-*"
|
|
94
|
-
|
|
95
|
-
# Run script in parallel for all workspaces
|
|
96
36
|
bw run my-script --parallel
|
|
97
|
-
|
|
98
|
-
# Append args to each script call
|
|
99
37
|
bw run my-script --args "--my --args"
|
|
100
|
-
|
|
101
|
-
# Use the workspace name in args
|
|
102
38
|
bw run my-script --args "--my --args=<workspace>"
|
|
103
|
-
|
|
104
|
-
# Help (--help can also be passed to any command)
|
|
105
|
-
bw help
|
|
106
|
-
bw --help
|
|
107
|
-
|
|
108
|
-
# Pass --cwd to any command
|
|
109
|
-
bw --cwd /path/to/your/project ls
|
|
110
|
-
bw --cwd /path/to/your/project run-script my-script
|
|
111
|
-
|
|
112
|
-
# Pass --configFile to any command
|
|
113
|
-
bw --configFile /path/to/your/config.json ls
|
|
114
|
-
|
|
115
|
-
# Pass --logLevel to any command (debug, info, warn, error, or silent)
|
|
116
|
-
bw --logLevel silent run my-script
|
|
117
39
|
```
|
package/package.json
CHANGED
|
@@ -10,4 +10,4 @@ export interface CreateCliProgramOptions {
|
|
|
10
10
|
postInit?: (program: Command) => unknown;
|
|
11
11
|
defaultCwd?: string;
|
|
12
12
|
}
|
|
13
|
-
export declare const
|
|
13
|
+
export declare const createCli: ({ handleError, postInit, defaultCwd, }?: CreateCliProgramOptions) => CliProgram;
|
|
@@ -2,9 +2,9 @@ import { createCommand } from "commander";
|
|
|
2
2
|
import package_0 from "../../package.json";
|
|
3
3
|
import { getRequiredBunVersion, validateCurrentBunVersion } from "../internal/bunVersion.mjs";
|
|
4
4
|
import { logger } from "../internal/logger.mjs";
|
|
5
|
-
import { initializeWithGlobalOptions } from "./globalOptions.mjs";
|
|
6
|
-
import { defineProjectCommands } from "./projectCommands.mjs";
|
|
7
|
-
const
|
|
5
|
+
import { initializeWithGlobalOptions } from "./globalOptions/index.mjs";
|
|
6
|
+
import { defineProjectCommands } from "./projectCommands/index.mjs";
|
|
7
|
+
const createCli = ({ handleError, postInit, defaultCwd = process.cwd() } = {})=>{
|
|
8
8
|
const run = async ({ argv = process.argv } = {})=>{
|
|
9
9
|
const errorListener = handleError ?? ((error)=>{
|
|
10
10
|
logger.error(error);
|
|
@@ -40,4 +40,4 @@ const createCliProgram = ({ handleError, postInit, defaultCwd = process.cwd() }
|
|
|
40
40
|
run
|
|
41
41
|
};
|
|
42
42
|
};
|
|
43
|
-
export {
|
|
43
|
+
export { createCli };
|
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
import path from "path";
|
|
2
2
|
import { Option } from "commander";
|
|
3
|
-
import { loadConfigFile } from "
|
|
4
|
-
import {
|
|
5
|
-
import { createProject } from "
|
|
3
|
+
import { loadConfigFile } from "../../config/index.mjs";
|
|
4
|
+
import { logger } from "../../internal/logger.mjs";
|
|
5
|
+
import { createProject } from "../../project/index.mjs";
|
|
6
|
+
import { getCliGlobalOptionConfig } from "./globalOptionsConfig.mjs";
|
|
7
|
+
const addGlobalOption = (program, optionName, defaultOverride)=>{
|
|
8
|
+
const { mainOption, shortOption, description, param, values, defaultValue } = getCliGlobalOptionConfig(optionName);
|
|
9
|
+
const option = new Option(`${shortOption} ${mainOption}${param ? ` <${param}>` : ""}`, description).default(defaultOverride ?? defaultValue);
|
|
10
|
+
program.addOption(values?.length ? option.choices(values) : option);
|
|
11
|
+
};
|
|
6
12
|
const getWorkingDirectory = (program, args, defaultCwd)=>{
|
|
7
|
-
program
|
|
13
|
+
addGlobalOption(program, "cwd", defaultCwd);
|
|
8
14
|
program.parseOptions(args);
|
|
9
15
|
return program.opts().cwd;
|
|
10
16
|
};
|
|
11
17
|
const getConfig = (program, args)=>{
|
|
12
|
-
program
|
|
18
|
+
addGlobalOption(program, "configFile");
|
|
13
19
|
program.parseOptions(args);
|
|
14
20
|
return program.opts().configFile;
|
|
15
21
|
};
|
|
@@ -17,22 +23,7 @@ const defineGlobalOptions = (program, args, defaultCwd)=>{
|
|
|
17
23
|
const cwd = getWorkingDirectory(program, args, defaultCwd);
|
|
18
24
|
const configFilePath = getConfig(program, args);
|
|
19
25
|
const config = loadConfigFile(configFilePath, cwd);
|
|
20
|
-
|
|
21
|
-
logLevel: {
|
|
22
|
-
shortName: "l",
|
|
23
|
-
description: "Log levels",
|
|
24
|
-
defaultValue: config?.cli?.logLevel ?? logger.printLevel,
|
|
25
|
-
values: [
|
|
26
|
-
...LOG_LEVELS,
|
|
27
|
-
"silent"
|
|
28
|
-
],
|
|
29
|
-
param: "level"
|
|
30
|
-
}
|
|
31
|
-
};
|
|
32
|
-
Object.entries(globalOptions).forEach(([name, { shortName, description, param, values, defaultValue }])=>{
|
|
33
|
-
const option = new Option(`-${shortName} --${name}${param ? ` <${param}>` : ""}`, description).default(defaultValue);
|
|
34
|
-
program.addOption(values?.length ? option.choices(values) : option);
|
|
35
|
-
});
|
|
26
|
+
addGlobalOption(program, "logLevel");
|
|
36
27
|
return {
|
|
37
28
|
cwd,
|
|
38
29
|
config
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { type LogLevelSetting } from "../../internal/logger";
|
|
2
|
+
export interface CliGlobalOptions {
|
|
3
|
+
logLevel: LogLevelSetting;
|
|
4
|
+
cwd: string;
|
|
5
|
+
configFile?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface CliGlobalOptionConfig {
|
|
8
|
+
mainOption: string;
|
|
9
|
+
shortOption: string;
|
|
10
|
+
description: string;
|
|
11
|
+
defaultValue: string;
|
|
12
|
+
values: LogLevelSetting[] | null;
|
|
13
|
+
param: string;
|
|
14
|
+
}
|
|
15
|
+
export type CliGlobalOptionName = keyof CliGlobalOptions;
|
|
16
|
+
export declare const getCliGlobalOptionConfig: (optionName: CliGlobalOptionName) => {
|
|
17
|
+
readonly mainOption: "--logLevel";
|
|
18
|
+
readonly shortOption: "-l";
|
|
19
|
+
readonly description: "Log levels";
|
|
20
|
+
readonly defaultValue: "info";
|
|
21
|
+
readonly values: ["debug", "info", "warn", "error", "silent"];
|
|
22
|
+
readonly param: "level";
|
|
23
|
+
} | {
|
|
24
|
+
readonly mainOption: "--cwd";
|
|
25
|
+
readonly shortOption: "-d";
|
|
26
|
+
readonly description: "Working directory";
|
|
27
|
+
readonly defaultValue: ".";
|
|
28
|
+
readonly values: null;
|
|
29
|
+
readonly param: "path";
|
|
30
|
+
} | {
|
|
31
|
+
readonly mainOption: "--configFile";
|
|
32
|
+
readonly shortOption: "-c";
|
|
33
|
+
readonly description: "Config file";
|
|
34
|
+
readonly defaultValue: "";
|
|
35
|
+
readonly values: null;
|
|
36
|
+
readonly param: "path";
|
|
37
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { LOG_LEVELS } from "../../internal/logger.mjs";
|
|
2
|
+
const CLI_GLOBAL_OPTIONS_CONFIG = {
|
|
3
|
+
logLevel: {
|
|
4
|
+
mainOption: "--logLevel",
|
|
5
|
+
shortOption: "-l",
|
|
6
|
+
description: "Log levels",
|
|
7
|
+
defaultValue: "info",
|
|
8
|
+
values: [
|
|
9
|
+
...LOG_LEVELS,
|
|
10
|
+
"silent"
|
|
11
|
+
],
|
|
12
|
+
param: "level"
|
|
13
|
+
},
|
|
14
|
+
cwd: {
|
|
15
|
+
mainOption: "--cwd",
|
|
16
|
+
shortOption: "-d",
|
|
17
|
+
description: "Working directory",
|
|
18
|
+
defaultValue: ".",
|
|
19
|
+
values: null,
|
|
20
|
+
param: "path"
|
|
21
|
+
},
|
|
22
|
+
configFile: {
|
|
23
|
+
mainOption: "--configFile",
|
|
24
|
+
shortOption: "-c",
|
|
25
|
+
description: "Config file",
|
|
26
|
+
defaultValue: "",
|
|
27
|
+
values: null,
|
|
28
|
+
param: "path"
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
const getCliGlobalOptionConfig = (optionName)=>CLI_GLOBAL_OPTIONS_CONFIG[optionName];
|
|
32
|
+
export { getCliGlobalOptionConfig };
|
package/src/cli/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { createCli } from "./createCli";
|
package/src/cli/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export {
|
|
1
|
+
import { createCli } from "./createCli.mjs";
|
|
2
|
+
export { createCli };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type Command } from "commander";
|
|
2
|
+
import type { Project } from "../../project";
|
|
3
|
+
export interface ProjectCommandContext {
|
|
4
|
+
project: Project;
|
|
5
|
+
program: Command;
|
|
6
|
+
}
|
|
7
|
+
export declare const commandOutputLogger: import("../../internal/logger").Logger;
|
|
8
|
+
export declare const defineProjectCommands: (context: ProjectCommandContext) => void;
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { BunWorkspacesError } from "../../internal/error.mjs";
|
|
2
|
+
import { createLogger, logger } from "../../internal/logger.mjs";
|
|
3
|
+
import { getProjectCommandConfig } from "./projectCommandsConfig.mjs";
|
|
4
|
+
const createWorkspaceInfoLines = (workspace)=>[
|
|
5
|
+
`Workspace: ${workspace.name}`,
|
|
6
|
+
` - Aliases: ${workspace.aliases.join(", ")}`,
|
|
7
|
+
` - Path: ${workspace.path}`,
|
|
8
|
+
` - Glob Match: ${workspace.matchPattern}`,
|
|
9
|
+
` - Scripts: ${Object.keys(workspace.packageJson.scripts).sort().join(", ")}`
|
|
10
|
+
];
|
|
11
|
+
const createScriptInfoLines = (script, workspaces)=>[
|
|
12
|
+
`Script: ${script}`,
|
|
13
|
+
...workspaces.map((workspace)=>` - ${workspace.name}`)
|
|
14
|
+
];
|
|
15
|
+
const createJsonLines = (data, options)=>JSON.stringify(data, null, options.pretty ? 2 : void 0).split("\n");
|
|
16
|
+
const commandOutputLogger = createLogger("");
|
|
17
|
+
commandOutputLogger.printLevel = "info";
|
|
18
|
+
const handleCommand = (commandName, handler)=>{
|
|
19
|
+
const config = getProjectCommandConfig(commandName);
|
|
20
|
+
return ({ program, project })=>{
|
|
21
|
+
program = program.command(config.command).aliases(config.aliases).description(config.description);
|
|
22
|
+
for (const option of Object.values(config.options))program.option(option.flags, option.description);
|
|
23
|
+
program = program.action((...actionArgs)=>handler({
|
|
24
|
+
program,
|
|
25
|
+
project
|
|
26
|
+
}, ...actionArgs));
|
|
27
|
+
return program;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
const listWorkspaces = handleCommand("listWorkspaces", ({ project }, pattern, options)=>{
|
|
31
|
+
logger.debug(`Command: List workspaces (options: ${JSON.stringify(options)})`);
|
|
32
|
+
const lines = [];
|
|
33
|
+
const workspaces = pattern ? project.findWorkspacesByPattern(pattern) : project.workspaces;
|
|
34
|
+
if (options.json) lines.push(...createJsonLines(options.nameOnly ? workspaces.map(({ name })=>name) : workspaces, options));
|
|
35
|
+
else workspaces.forEach((workspace)=>{
|
|
36
|
+
if (options.nameOnly) lines.push(workspace.name);
|
|
37
|
+
else lines.push(...createWorkspaceInfoLines(workspace));
|
|
38
|
+
});
|
|
39
|
+
if (!lines.length) logger.info("No workspaces found");
|
|
40
|
+
if (lines.length) commandOutputLogger.info(lines.join("\n"));
|
|
41
|
+
});
|
|
42
|
+
const listScripts = handleCommand("listScripts", ({ project }, options)=>{
|
|
43
|
+
logger.debug(`Command: List scripts (options: ${JSON.stringify(options)})`);
|
|
44
|
+
const scripts = project.listScriptsWithWorkspaces();
|
|
45
|
+
const lines = [];
|
|
46
|
+
if (options.json) lines.push(...createJsonLines(options.nameOnly ? Object.keys(scripts) : Object.values(scripts).map(({ workspaces, ...rest })=>({
|
|
47
|
+
...rest,
|
|
48
|
+
workspaces: workspaces.map(({ name })=>name)
|
|
49
|
+
})), options));
|
|
50
|
+
else {
|
|
51
|
+
Object.values(scripts).sort(({ name: nameA }, { name: nameB })=>nameA.localeCompare(nameB)).forEach(({ name, workspaces })=>{
|
|
52
|
+
if (options.nameOnly) lines.push(name);
|
|
53
|
+
else lines.push(...createScriptInfoLines(name, workspaces));
|
|
54
|
+
});
|
|
55
|
+
if (!lines.length) logger.info("No scripts found");
|
|
56
|
+
}
|
|
57
|
+
if (lines.length) commandOutputLogger.info(lines.join("\n"));
|
|
58
|
+
});
|
|
59
|
+
const workspaceInfo = handleCommand("workspaceInfo", ({ project }, workspaceName, options)=>{
|
|
60
|
+
logger.debug(`Command: Workspace info for ${workspaceName} (options: ${JSON.stringify(options)})`);
|
|
61
|
+
const workspace = project.findWorkspaceByNameOrAlias(workspaceName);
|
|
62
|
+
if (!workspace) return void logger.error(`Workspace not found: (options: ${JSON.stringify(workspaceName)})`);
|
|
63
|
+
commandOutputLogger.info((options.json ? createJsonLines(workspace, options) : createWorkspaceInfoLines(workspace)).join("\n"));
|
|
64
|
+
});
|
|
65
|
+
const scriptInfo = handleCommand("scriptInfo", ({ project }, script, options)=>{
|
|
66
|
+
logger.debug(`Command: Script info for ${script} (options: ${JSON.stringify(options)})`);
|
|
67
|
+
const scripts = project.listScriptsWithWorkspaces();
|
|
68
|
+
const scriptMetadata = scripts[script];
|
|
69
|
+
if (!scriptMetadata) return void logger.error(`Script not found: ${JSON.stringify(script)} (available: ${Object.keys(scripts).join(", ")})`);
|
|
70
|
+
commandOutputLogger.info((options.json ? createJsonLines(options.workspacesOnly ? scriptMetadata.workspaces.map(({ name })=>name) : {
|
|
71
|
+
name: scriptMetadata.name,
|
|
72
|
+
workspaces: scriptMetadata.workspaces.map(({ name })=>name)
|
|
73
|
+
}, options) : options.workspacesOnly ? scriptMetadata.workspaces.map(({ name })=>name) : createScriptInfoLines(script, scriptMetadata.workspaces)).join("\n"));
|
|
74
|
+
});
|
|
75
|
+
const runScript = handleCommand("runScript", async ({ project }, script, _workspaces, options)=>{
|
|
76
|
+
logger.debug(`Command: Run script ${JSON.stringify(script)} for ${_workspaces.length ? "workspaces " + _workspaces.join(", ") : "all workspaces"} (parallel: ${!!options.parallel}, args: ${JSON.stringify(options.args)})`);
|
|
77
|
+
const workspaces = _workspaces.length ? _workspaces.flatMap((workspacePattern)=>{
|
|
78
|
+
if (workspacePattern.includes("*")) return project.findWorkspacesByPattern(workspacePattern).filter(({ packageJson: { scripts } })=>scripts?.[script]).map(({ name })=>name);
|
|
79
|
+
return [
|
|
80
|
+
workspacePattern
|
|
81
|
+
];
|
|
82
|
+
}).filter((workspace)=>project.workspaces.some(({ name })=>name === workspace)) : project.listWorkspacesWithScript(script).map(({ name })=>name);
|
|
83
|
+
if (!workspaces.length) {
|
|
84
|
+
if (1 === _workspaces.length && !_workspaces[0].includes("*")) {
|
|
85
|
+
const message = `Workspace not found: ${JSON.stringify(_workspaces[0])}`;
|
|
86
|
+
logger.error(message);
|
|
87
|
+
throw new Error(message);
|
|
88
|
+
}
|
|
89
|
+
const message = `No ${_workspaces.length ? "matching " : ""}workspaces found for script ${JSON.stringify(script)}`;
|
|
90
|
+
logger.error(message);
|
|
91
|
+
throw new Error(message);
|
|
92
|
+
}
|
|
93
|
+
const scriptCommands = workspaces.map((workspaceName)=>project.createScriptCommand({
|
|
94
|
+
scriptName: script,
|
|
95
|
+
workspaceName,
|
|
96
|
+
method: "cd",
|
|
97
|
+
args: options.args?.replace(/<workspace>/g, workspaceName) ?? ""
|
|
98
|
+
}));
|
|
99
|
+
const runCommand = async ({ command, scriptName, workspace })=>{
|
|
100
|
+
const commandLogger = createLogger(`${workspace.name}:${scriptName}`);
|
|
101
|
+
const splitCommand = command.command.split(/\s+/g);
|
|
102
|
+
commandLogger.debug(`Running script ${scriptName} in workspace ${workspace.name} (cwd: ${command.cwd}): ${splitCommand.join(" ")}`);
|
|
103
|
+
const isSilent = "silent" === logger.printLevel;
|
|
104
|
+
const proc = Bun.spawn(command.command.split(/\s+/g), {
|
|
105
|
+
cwd: command.cwd,
|
|
106
|
+
env: {
|
|
107
|
+
...process.env,
|
|
108
|
+
FORCE_COLOR: "1"
|
|
109
|
+
},
|
|
110
|
+
stdout: isSilent ? "ignore" : "pipe",
|
|
111
|
+
stderr: isSilent ? "ignore" : "pipe"
|
|
112
|
+
});
|
|
113
|
+
const linePrefix = options.noPrefix ? "" : `[${workspace.name}:${scriptName}] `;
|
|
114
|
+
if (proc.stdout) for await (const chunk of proc.stdout)commandLogger.logOutput(chunk, "info", process.stdout, linePrefix);
|
|
115
|
+
if (proc.stderr) for await (const chunk of proc.stderr)commandLogger.logOutput(chunk, "error", process.stderr, linePrefix);
|
|
116
|
+
await proc.exited;
|
|
117
|
+
return {
|
|
118
|
+
scriptName,
|
|
119
|
+
workspace,
|
|
120
|
+
command,
|
|
121
|
+
success: 0 === proc.exitCode,
|
|
122
|
+
error: 0 === proc.exitCode ? null : new BunWorkspacesError(`Script exited with code ${proc.exitCode}`)
|
|
123
|
+
};
|
|
124
|
+
};
|
|
125
|
+
const results = [];
|
|
126
|
+
if (options.parallel) {
|
|
127
|
+
let i = 0;
|
|
128
|
+
for await (const result of (await Promise.allSettled(scriptCommands.map(runCommand)))){
|
|
129
|
+
if ("rejected" === result.status) results.push({
|
|
130
|
+
success: false,
|
|
131
|
+
workspaceName: workspaces[i],
|
|
132
|
+
error: result.reason
|
|
133
|
+
});
|
|
134
|
+
else results.push({
|
|
135
|
+
success: result.value.success,
|
|
136
|
+
workspaceName: workspaces[i],
|
|
137
|
+
error: result.value.error
|
|
138
|
+
});
|
|
139
|
+
i++;
|
|
140
|
+
}
|
|
141
|
+
} else {
|
|
142
|
+
let i = 0;
|
|
143
|
+
for (const command of scriptCommands){
|
|
144
|
+
try {
|
|
145
|
+
const result = await runCommand(command);
|
|
146
|
+
results.push({
|
|
147
|
+
success: result.success,
|
|
148
|
+
workspaceName: workspaces[i],
|
|
149
|
+
error: result.error
|
|
150
|
+
});
|
|
151
|
+
} catch (error) {
|
|
152
|
+
results.push({
|
|
153
|
+
success: false,
|
|
154
|
+
workspaceName: workspaces[i],
|
|
155
|
+
error: error
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
i++;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
let failCount = 0;
|
|
162
|
+
results.forEach(({ success, workspaceName })=>{
|
|
163
|
+
if (!success) failCount++;
|
|
164
|
+
logger.info(`${success ? "✅" : "❌"} ${workspaceName}: ${script}`);
|
|
165
|
+
});
|
|
166
|
+
const s = 1 === results.length ? "" : "s";
|
|
167
|
+
if (failCount) {
|
|
168
|
+
const message = `${failCount} of ${results.length} script${s} failed`;
|
|
169
|
+
logger.error(message);
|
|
170
|
+
process.exit(1);
|
|
171
|
+
} else logger.info(`${results.length} script${s} ran successfully`);
|
|
172
|
+
});
|
|
173
|
+
const defineProjectCommands = (context)=>{
|
|
174
|
+
listWorkspaces(context);
|
|
175
|
+
listScripts(context);
|
|
176
|
+
workspaceInfo(context);
|
|
177
|
+
scriptInfo(context);
|
|
178
|
+
runScript(context);
|
|
179
|
+
};
|
|
180
|
+
export { commandOutputLogger, defineProjectCommands };
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
export interface ProjectCommandConfig {
|
|
2
|
+
command: string;
|
|
3
|
+
aliases: string[];
|
|
4
|
+
description: string;
|
|
5
|
+
options: Record<string, {
|
|
6
|
+
flags: string;
|
|
7
|
+
description: string;
|
|
8
|
+
}>;
|
|
9
|
+
}
|
|
10
|
+
export type ProjectCommandName = keyof typeof PROJECT_COMMANDS_CONFIG;
|
|
11
|
+
declare const PROJECT_COMMANDS_CONFIG: {
|
|
12
|
+
readonly listWorkspaces: {
|
|
13
|
+
readonly command: "list-workspaces [pattern]";
|
|
14
|
+
readonly aliases: ["ls", "list"];
|
|
15
|
+
readonly description: "List all workspaces";
|
|
16
|
+
readonly options: {
|
|
17
|
+
readonly nameOnly: {
|
|
18
|
+
readonly flags: "--name-only";
|
|
19
|
+
readonly description: "Only show workspace names";
|
|
20
|
+
};
|
|
21
|
+
readonly json: {
|
|
22
|
+
readonly flags: "--json";
|
|
23
|
+
readonly description: "Output as JSON";
|
|
24
|
+
};
|
|
25
|
+
readonly pretty: {
|
|
26
|
+
readonly flags: "--pretty";
|
|
27
|
+
readonly description: "Pretty print JSON";
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
readonly listScripts: {
|
|
32
|
+
readonly command: "list-scripts";
|
|
33
|
+
readonly aliases: [];
|
|
34
|
+
readonly description: "List all scripts available with their workspaces";
|
|
35
|
+
readonly options: {
|
|
36
|
+
readonly nameOnly: {
|
|
37
|
+
readonly flags: "--name-only";
|
|
38
|
+
readonly description: "Only show script names";
|
|
39
|
+
};
|
|
40
|
+
readonly json: {
|
|
41
|
+
readonly flags: "--json";
|
|
42
|
+
readonly description: "Output as JSON";
|
|
43
|
+
};
|
|
44
|
+
readonly pretty: {
|
|
45
|
+
readonly flags: "--pretty";
|
|
46
|
+
readonly description: "Pretty print JSON";
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
readonly workspaceInfo: {
|
|
51
|
+
readonly command: "workspace-info <workspace>";
|
|
52
|
+
readonly aliases: ["info"];
|
|
53
|
+
readonly description: "Show information about a workspace";
|
|
54
|
+
readonly options: {
|
|
55
|
+
readonly json: {
|
|
56
|
+
readonly flags: "--json";
|
|
57
|
+
readonly description: "Output as JSON";
|
|
58
|
+
};
|
|
59
|
+
readonly pretty: {
|
|
60
|
+
readonly flags: "--pretty";
|
|
61
|
+
readonly description: "Pretty print JSON";
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
readonly scriptInfo: {
|
|
66
|
+
readonly command: "script-info <script>";
|
|
67
|
+
readonly aliases: [];
|
|
68
|
+
readonly description: "Show information about a script";
|
|
69
|
+
readonly options: {
|
|
70
|
+
readonly workspacesOnly: {
|
|
71
|
+
readonly flags: "--workspaces-only";
|
|
72
|
+
readonly description: "Only show script's workspace names";
|
|
73
|
+
};
|
|
74
|
+
readonly json: {
|
|
75
|
+
readonly flags: "--json";
|
|
76
|
+
readonly description: "Output as JSON";
|
|
77
|
+
};
|
|
78
|
+
readonly pretty: {
|
|
79
|
+
readonly flags: "--pretty";
|
|
80
|
+
readonly description: "Pretty print JSON";
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
};
|
|
84
|
+
readonly runScript: {
|
|
85
|
+
readonly command: "run <script> [workspaces...]";
|
|
86
|
+
readonly aliases: [];
|
|
87
|
+
readonly description: "Run a script in all workspaces that have it in their \"scripts\" field in package.json";
|
|
88
|
+
readonly options: {
|
|
89
|
+
readonly parallel: {
|
|
90
|
+
readonly flags: "--parallel";
|
|
91
|
+
readonly description: "Run the scripts in parallel";
|
|
92
|
+
};
|
|
93
|
+
readonly args: {
|
|
94
|
+
readonly flags: "--args <args>";
|
|
95
|
+
readonly description: "Args to append to the script command";
|
|
96
|
+
};
|
|
97
|
+
readonly noPrefix: {
|
|
98
|
+
readonly flags: "--noPrefix";
|
|
99
|
+
readonly description: "Do not prefix the workspace name to the script output";
|
|
100
|
+
};
|
|
101
|
+
};
|
|
102
|
+
};
|
|
103
|
+
};
|
|
104
|
+
export declare const getProjectCommandConfig: (commandName: ProjectCommandName) => {
|
|
105
|
+
readonly command: "list-workspaces [pattern]";
|
|
106
|
+
readonly aliases: ["ls", "list"];
|
|
107
|
+
readonly description: "List all workspaces";
|
|
108
|
+
readonly options: {
|
|
109
|
+
readonly nameOnly: {
|
|
110
|
+
readonly flags: "--name-only";
|
|
111
|
+
readonly description: "Only show workspace names";
|
|
112
|
+
};
|
|
113
|
+
readonly json: {
|
|
114
|
+
readonly flags: "--json";
|
|
115
|
+
readonly description: "Output as JSON";
|
|
116
|
+
};
|
|
117
|
+
readonly pretty: {
|
|
118
|
+
readonly flags: "--pretty";
|
|
119
|
+
readonly description: "Pretty print JSON";
|
|
120
|
+
};
|
|
121
|
+
};
|
|
122
|
+
} | {
|
|
123
|
+
readonly command: "list-scripts";
|
|
124
|
+
readonly aliases: [];
|
|
125
|
+
readonly description: "List all scripts available with their workspaces";
|
|
126
|
+
readonly options: {
|
|
127
|
+
readonly nameOnly: {
|
|
128
|
+
readonly flags: "--name-only";
|
|
129
|
+
readonly description: "Only show script names";
|
|
130
|
+
};
|
|
131
|
+
readonly json: {
|
|
132
|
+
readonly flags: "--json";
|
|
133
|
+
readonly description: "Output as JSON";
|
|
134
|
+
};
|
|
135
|
+
readonly pretty: {
|
|
136
|
+
readonly flags: "--pretty";
|
|
137
|
+
readonly description: "Pretty print JSON";
|
|
138
|
+
};
|
|
139
|
+
};
|
|
140
|
+
} | {
|
|
141
|
+
readonly command: "workspace-info <workspace>";
|
|
142
|
+
readonly aliases: ["info"];
|
|
143
|
+
readonly description: "Show information about a workspace";
|
|
144
|
+
readonly options: {
|
|
145
|
+
readonly json: {
|
|
146
|
+
readonly flags: "--json";
|
|
147
|
+
readonly description: "Output as JSON";
|
|
148
|
+
};
|
|
149
|
+
readonly pretty: {
|
|
150
|
+
readonly flags: "--pretty";
|
|
151
|
+
readonly description: "Pretty print JSON";
|
|
152
|
+
};
|
|
153
|
+
};
|
|
154
|
+
} | {
|
|
155
|
+
readonly command: "script-info <script>";
|
|
156
|
+
readonly aliases: [];
|
|
157
|
+
readonly description: "Show information about a script";
|
|
158
|
+
readonly options: {
|
|
159
|
+
readonly workspacesOnly: {
|
|
160
|
+
readonly flags: "--workspaces-only";
|
|
161
|
+
readonly description: "Only show script's workspace names";
|
|
162
|
+
};
|
|
163
|
+
readonly json: {
|
|
164
|
+
readonly flags: "--json";
|
|
165
|
+
readonly description: "Output as JSON";
|
|
166
|
+
};
|
|
167
|
+
readonly pretty: {
|
|
168
|
+
readonly flags: "--pretty";
|
|
169
|
+
readonly description: "Pretty print JSON";
|
|
170
|
+
};
|
|
171
|
+
};
|
|
172
|
+
} | {
|
|
173
|
+
readonly command: "run <script> [workspaces...]";
|
|
174
|
+
readonly aliases: [];
|
|
175
|
+
readonly description: "Run a script in all workspaces that have it in their \"scripts\" field in package.json";
|
|
176
|
+
readonly options: {
|
|
177
|
+
readonly parallel: {
|
|
178
|
+
readonly flags: "--parallel";
|
|
179
|
+
readonly description: "Run the scripts in parallel";
|
|
180
|
+
};
|
|
181
|
+
readonly args: {
|
|
182
|
+
readonly flags: "--args <args>";
|
|
183
|
+
readonly description: "Args to append to the script command";
|
|
184
|
+
};
|
|
185
|
+
readonly noPrefix: {
|
|
186
|
+
readonly flags: "--noPrefix";
|
|
187
|
+
readonly description: "Do not prefix the workspace name to the script output";
|
|
188
|
+
};
|
|
189
|
+
};
|
|
190
|
+
};
|
|
191
|
+
export {};
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
const PROJECT_COMMANDS_CONFIG = {
|
|
2
|
+
listWorkspaces: {
|
|
3
|
+
command: "list-workspaces [pattern]",
|
|
4
|
+
aliases: [
|
|
5
|
+
"ls",
|
|
6
|
+
"list"
|
|
7
|
+
],
|
|
8
|
+
description: "List all workspaces",
|
|
9
|
+
options: {
|
|
10
|
+
nameOnly: {
|
|
11
|
+
flags: "--name-only",
|
|
12
|
+
description: "Only show workspace names"
|
|
13
|
+
},
|
|
14
|
+
json: {
|
|
15
|
+
flags: "--json",
|
|
16
|
+
description: "Output as JSON"
|
|
17
|
+
},
|
|
18
|
+
pretty: {
|
|
19
|
+
flags: "--pretty",
|
|
20
|
+
description: "Pretty print JSON"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
listScripts: {
|
|
25
|
+
command: "list-scripts",
|
|
26
|
+
aliases: [],
|
|
27
|
+
description: "List all scripts available with their workspaces",
|
|
28
|
+
options: {
|
|
29
|
+
nameOnly: {
|
|
30
|
+
flags: "--name-only",
|
|
31
|
+
description: "Only show script names"
|
|
32
|
+
},
|
|
33
|
+
json: {
|
|
34
|
+
flags: "--json",
|
|
35
|
+
description: "Output as JSON"
|
|
36
|
+
},
|
|
37
|
+
pretty: {
|
|
38
|
+
flags: "--pretty",
|
|
39
|
+
description: "Pretty print JSON"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
workspaceInfo: {
|
|
44
|
+
command: "workspace-info <workspace>",
|
|
45
|
+
aliases: [
|
|
46
|
+
"info"
|
|
47
|
+
],
|
|
48
|
+
description: "Show information about a workspace",
|
|
49
|
+
options: {
|
|
50
|
+
json: {
|
|
51
|
+
flags: "--json",
|
|
52
|
+
description: "Output as JSON"
|
|
53
|
+
},
|
|
54
|
+
pretty: {
|
|
55
|
+
flags: "--pretty",
|
|
56
|
+
description: "Pretty print JSON"
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
scriptInfo: {
|
|
61
|
+
command: "script-info <script>",
|
|
62
|
+
aliases: [],
|
|
63
|
+
description: "Show information about a script",
|
|
64
|
+
options: {
|
|
65
|
+
workspacesOnly: {
|
|
66
|
+
flags: "--workspaces-only",
|
|
67
|
+
description: "Only show script's workspace names"
|
|
68
|
+
},
|
|
69
|
+
json: {
|
|
70
|
+
flags: "--json",
|
|
71
|
+
description: "Output as JSON"
|
|
72
|
+
},
|
|
73
|
+
pretty: {
|
|
74
|
+
flags: "--pretty",
|
|
75
|
+
description: "Pretty print JSON"
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
runScript: {
|
|
80
|
+
command: "run <script> [workspaces...]",
|
|
81
|
+
aliases: [],
|
|
82
|
+
description: 'Run a script in all workspaces that have it in their "scripts" field in package.json',
|
|
83
|
+
options: {
|
|
84
|
+
parallel: {
|
|
85
|
+
flags: "--parallel",
|
|
86
|
+
description: "Run the scripts in parallel"
|
|
87
|
+
},
|
|
88
|
+
args: {
|
|
89
|
+
flags: "--args <args>",
|
|
90
|
+
description: "Args to append to the script command"
|
|
91
|
+
},
|
|
92
|
+
noPrefix: {
|
|
93
|
+
flags: "--noPrefix",
|
|
94
|
+
description: "Do not prefix the workspace name to the script output"
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
const getProjectCommandConfig = (commandName)=>PROJECT_COMMANDS_CONFIG[commandName];
|
|
100
|
+
export { getProjectCommandConfig };
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { type BunWorkspacesConfig } from "./bunWorkspacesConfig";
|
|
2
2
|
export declare const DEFAULT_CONFIG_FILE_PATH = "bw.json";
|
|
3
|
-
export declare const loadConfigFile: (filePath?: string
|
|
3
|
+
export declare const loadConfigFile: (filePath?: string, rootDir?: string) => BunWorkspacesConfig | null;
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
export declare const LIBRARY_CONSUMER_BUN_VERSION: string;
|
|
2
2
|
export declare const BUILD_BUN_VERSION: string;
|
|
3
|
-
export declare const getRequiredBunVersion: (build?: boolean
|
|
3
|
+
export declare const getRequiredBunVersion: (build?: boolean) => string;
|
|
4
4
|
/**
|
|
5
5
|
* Validates that the provided version satisfies the required Bun version
|
|
6
6
|
* specified in the root `package.json`.
|
|
7
7
|
*/
|
|
8
|
-
export declare const validateBunVersion: (version: string, build?: boolean
|
|
8
|
+
export declare const validateBunVersion: (version: string, build?: boolean) => boolean;
|
|
9
9
|
/**
|
|
10
10
|
*
|
|
11
11
|
* Validates that the Bun version of the current script satisfies the
|
|
12
12
|
* required Bun version specified in the root `package.json`.
|
|
13
13
|
*/
|
|
14
|
-
export declare const validateCurrentBunVersion: (build?: boolean
|
|
14
|
+
export declare const validateCurrentBunVersion: (build?: boolean) => boolean;
|
package/src/internal/env.mjs
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
const _process = "undefined" == typeof process ? {
|
|
2
|
+
env: {}
|
|
3
|
+
} : process;
|
|
1
4
|
const RUNTIME_MODE_VALUES = [
|
|
2
5
|
"development",
|
|
3
6
|
"production",
|
|
4
7
|
"test"
|
|
5
8
|
];
|
|
6
|
-
const _RUNTIME_MODE =
|
|
9
|
+
const _RUNTIME_MODE = _process.env._BW_RUNTIME_MODE || (process.env.NODE_ENV?.match(/test(ing)?/) ? "test" : "development" === process.env.NODE_ENV ? "development" : "production");
|
|
7
10
|
const RUNTIME_MODE = RUNTIME_MODE_VALUES.includes(_RUNTIME_MODE) ? _RUNTIME_MODE : "production";
|
|
8
11
|
if (RUNTIME_MODE !== _RUNTIME_MODE) console.error(`Env var RUNTIME_MODE has an invalid value: "${_RUNTIME_MODE}". Defaulting to "${RUNTIME_MODE}". Accepted values: ${RUNTIME_MODE_VALUES.join(", ")}.`);
|
|
9
12
|
const IS_TEST = "test" === RUNTIME_MODE;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const ERRORS: import("../internal/error").DefinedErrors<"
|
|
1
|
+
export declare const ERRORS: import("../internal/error").DefinedErrors<"PackageNotFound" | "InvalidPackageJson" | "DuplicateWorkspaceName" | "InvalidWorkspaceName" | "NoWorkspaceName" | "InvalidScripts" | "InvalidWorkspaces" | "InvalidWorkspacePattern" | "AliasConflict" | "AliasedWorkspaceNotFound">;
|
|
@@ -8,10 +8,10 @@ export interface FindWorkspacesOptions {
|
|
|
8
8
|
export declare const findWorkspaces: ({ rootDir, workspaceGlobs, workspaceAliases, }: FindWorkspacesOptions) => {
|
|
9
9
|
workspaces: Workspace[];
|
|
10
10
|
};
|
|
11
|
-
export declare const validateWorkspaceAliases: (workspaces: Workspace[], workspaceAliases:
|
|
11
|
+
export declare const validateWorkspaceAliases: (workspaces: Workspace[], workspaceAliases: ProjectConfig["workspaceAliases"]) => void;
|
|
12
12
|
export declare const findWorkspacesFromPackage: ({ rootDir, workspaceAliases, }: ProjectConfig & {
|
|
13
13
|
rootDir: string;
|
|
14
14
|
}) => {
|
|
15
|
-
workspaces: Workspace[];
|
|
16
15
|
name: string;
|
|
16
|
+
workspaces: Workspace[];
|
|
17
17
|
};
|
|
@@ -5,4 +5,4 @@ export type ResolvedPackageJsonContent = {
|
|
|
5
5
|
scripts: Record<string, string>;
|
|
6
6
|
} & Record<string, unknown>;
|
|
7
7
|
export declare const scanWorkspaceGlob: (pattern: string, rootDir: string) => Generator<string, void, void>;
|
|
8
|
-
export declare const resolvePackageJsonContent: (packageJsonPath: string, rootDir: string, validations: ("
|
|
8
|
+
export declare const resolvePackageJsonContent: (packageJsonPath: string, rootDir: string, validations: ("workspaces" | "name" | "scripts")[]) => ResolvedPackageJsonContent;
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { type Command } from "commander";
|
|
2
|
-
import { type LogLevelSetting } from "../internal/logger";
|
|
3
|
-
export interface CliGlobalOptions {
|
|
4
|
-
logLevel: LogLevelSetting;
|
|
5
|
-
cwd: string;
|
|
6
|
-
configFile?: string;
|
|
7
|
-
}
|
|
8
|
-
export type CliGlobalOptionName = keyof CliGlobalOptions;
|
|
9
|
-
export declare const initializeWithGlobalOptions: (program: Command, args: string[], defaultCwd: string) => {
|
|
10
|
-
project: import("..").Project;
|
|
11
|
-
};
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { type Command } from "commander";
|
|
2
|
-
import type { Project } from "../project";
|
|
3
|
-
export interface ProjectCommandsContext {
|
|
4
|
-
project: Project;
|
|
5
|
-
program: Command;
|
|
6
|
-
}
|
|
7
|
-
export declare const commandOutputLogger: import("../internal/logger").Logger;
|
|
8
|
-
export declare const defineProjectCommands: (context: ProjectCommandsContext) => void;
|
|
@@ -1,179 +0,0 @@
|
|
|
1
|
-
import { BunWorkspacesError } from "../internal/error.mjs";
|
|
2
|
-
import { createLogger, logger } from "../internal/logger.mjs";
|
|
3
|
-
const createWorkspaceInfoLines = (workspace)=>[
|
|
4
|
-
`Workspace: ${workspace.name}`,
|
|
5
|
-
` - Aliases: ${workspace.aliases.join(", ")}`,
|
|
6
|
-
` - Path: ${workspace.path}`,
|
|
7
|
-
` - Glob Match: ${workspace.matchPattern}`,
|
|
8
|
-
` - Scripts: ${Object.keys(workspace.packageJson.scripts).sort().join(", ")}`
|
|
9
|
-
];
|
|
10
|
-
const createScriptInfoLines = (script, workspaces)=>[
|
|
11
|
-
`Script: ${script}`,
|
|
12
|
-
...workspaces.map((workspace)=>` - ${workspace.name}`)
|
|
13
|
-
];
|
|
14
|
-
const createJsonLines = (data, options)=>JSON.stringify(data, null, options.pretty ? 2 : void 0).split("\n");
|
|
15
|
-
const commandOutputLogger = createLogger("");
|
|
16
|
-
commandOutputLogger.printLevel = "info";
|
|
17
|
-
const listWorkspaces = ({ program, project })=>{
|
|
18
|
-
program.command("list-workspaces [pattern]").aliases([
|
|
19
|
-
"ls",
|
|
20
|
-
"list"
|
|
21
|
-
]).description("List all workspaces").option("--name-only", "Only show workspace names").option("--json", "Output as JSON").option("--pretty", "Pretty print JSON").action((pattern, options)=>{
|
|
22
|
-
logger.debug(`Command: List workspaces (options: ${JSON.stringify(options)})`);
|
|
23
|
-
const lines = [];
|
|
24
|
-
const workspaces = pattern ? project.findWorkspacesByPattern(pattern) : project.workspaces;
|
|
25
|
-
if (options.json) lines.push(...createJsonLines(options.nameOnly ? workspaces.map(({ name })=>name) : workspaces, options));
|
|
26
|
-
else workspaces.forEach((workspace)=>{
|
|
27
|
-
if (options.nameOnly) lines.push(workspace.name);
|
|
28
|
-
else lines.push(...createWorkspaceInfoLines(workspace));
|
|
29
|
-
});
|
|
30
|
-
if (!lines.length) logger.info("No workspaces found");
|
|
31
|
-
if (lines.length) commandOutputLogger.info(lines.join("\n"));
|
|
32
|
-
});
|
|
33
|
-
};
|
|
34
|
-
const listScripts = ({ program, project })=>{
|
|
35
|
-
program.command("list-scripts").description("List all scripts available with their workspaces").option("--name-only", "Only show script names").option("--json", "Output as JSON").option("--pretty", "Pretty print JSON").action((options)=>{
|
|
36
|
-
logger.debug(`Command: List scripts (options: ${JSON.stringify(options)})`);
|
|
37
|
-
const scripts = project.listScriptsWithWorkspaces();
|
|
38
|
-
const lines = [];
|
|
39
|
-
if (options.json) lines.push(...createJsonLines(options.nameOnly ? Object.keys(scripts) : Object.values(scripts).map(({ workspaces, ...rest })=>({
|
|
40
|
-
...rest,
|
|
41
|
-
workspaces: workspaces.map(({ name })=>name)
|
|
42
|
-
})), options));
|
|
43
|
-
else {
|
|
44
|
-
Object.values(scripts).sort(({ name: nameA }, { name: nameB })=>nameA.localeCompare(nameB)).forEach(({ name, workspaces })=>{
|
|
45
|
-
if (options.nameOnly) lines.push(name);
|
|
46
|
-
else lines.push(...createScriptInfoLines(name, workspaces));
|
|
47
|
-
});
|
|
48
|
-
if (!lines.length) logger.info("No scripts found");
|
|
49
|
-
}
|
|
50
|
-
if (lines.length) commandOutputLogger.info(lines.join("\n"));
|
|
51
|
-
});
|
|
52
|
-
};
|
|
53
|
-
const workspaceInfo = ({ program, project })=>{
|
|
54
|
-
program.command("workspace-info <workspace>").aliases([
|
|
55
|
-
"info"
|
|
56
|
-
]).description("Show information about a workspace").option("--json", "Output as JSON").option("--pretty", "Pretty print JSON").action((workspaceName, options)=>{
|
|
57
|
-
logger.debug(`Command: Workspace info for ${workspaceName} (options: ${JSON.stringify(options)})`);
|
|
58
|
-
const workspace = project.findWorkspaceByNameOrAlias(workspaceName);
|
|
59
|
-
if (!workspace) return void logger.error(`Workspace not found: (options: ${JSON.stringify(workspaceName)})`);
|
|
60
|
-
commandOutputLogger.info((options.json ? createJsonLines(workspace, options) : createWorkspaceInfoLines(workspace)).join("\n"));
|
|
61
|
-
});
|
|
62
|
-
};
|
|
63
|
-
const scriptInfo = ({ program, project })=>{
|
|
64
|
-
program.command("script-info <script>").description("Show information about a script").option("--workspaces-only", "Only show script's workspace names").option("--json", "Output as JSON").option("--pretty", "Pretty print JSON").action((script, options)=>{
|
|
65
|
-
logger.debug(`Command: Script info for ${script} (options: ${JSON.stringify(options)})`);
|
|
66
|
-
const scripts = project.listScriptsWithWorkspaces();
|
|
67
|
-
const scriptMetadata = scripts[script];
|
|
68
|
-
if (!scriptMetadata) return void logger.error(`Script not found: ${JSON.stringify(script)} (available: ${Object.keys(scripts).join(", ")})`);
|
|
69
|
-
commandOutputLogger.info((options.json ? createJsonLines(options.workspacesOnly ? scriptMetadata.workspaces.map(({ name })=>name) : {
|
|
70
|
-
name: scriptMetadata.name,
|
|
71
|
-
workspaces: scriptMetadata.workspaces.map(({ name })=>name)
|
|
72
|
-
}, options) : options.workspacesOnly ? scriptMetadata.workspaces.map(({ name })=>name) : createScriptInfoLines(script, scriptMetadata.workspaces)).join("\n"));
|
|
73
|
-
});
|
|
74
|
-
};
|
|
75
|
-
const runScript = ({ program, project })=>{
|
|
76
|
-
program.command("run <script> [workspaces...]").description("Run a script in all workspaces").option("--parallel", "Run the scripts in parallel").option("--args <args>", "Args to append to the script command", "").option("--noPrefix", "Do not prefix the workspace name to the script output", "").action(async (script, _workspaces, options)=>{
|
|
77
|
-
logger.debug(`Command: Run script ${JSON.stringify(script)} for ${_workspaces.length ? "workspaces " + _workspaces.join(", ") : "all workspaces"} (parallel: ${!!options.parallel}, method: ${JSON.stringify(options.method)}, args: ${JSON.stringify(options.args)})`);
|
|
78
|
-
const workspaces = _workspaces.length ? _workspaces.flatMap((workspacePattern)=>{
|
|
79
|
-
if (workspacePattern.includes("*")) return project.findWorkspacesByPattern(workspacePattern).filter(({ packageJson: { scripts } })=>scripts?.[script]).map(({ name })=>name);
|
|
80
|
-
return [
|
|
81
|
-
workspacePattern
|
|
82
|
-
];
|
|
83
|
-
}) : project.listWorkspacesWithScript(script).map(({ name })=>name);
|
|
84
|
-
if (!workspaces.length) program.error(`No ${_workspaces.length ? "matching " : ""}workspaces found for script ${JSON.stringify(script)}`);
|
|
85
|
-
let scriptCommands;
|
|
86
|
-
try {
|
|
87
|
-
scriptCommands = workspaces.map((workspaceName)=>project.createScriptCommand({
|
|
88
|
-
scriptName: script,
|
|
89
|
-
workspaceName,
|
|
90
|
-
method: "cd",
|
|
91
|
-
args: options.args.replace(/<workspace>/g, workspaceName)
|
|
92
|
-
}));
|
|
93
|
-
} catch (error) {
|
|
94
|
-
program.error(error.message);
|
|
95
|
-
throw error;
|
|
96
|
-
}
|
|
97
|
-
const runCommand = async ({ command, scriptName, workspace })=>{
|
|
98
|
-
const commandLogger = createLogger(`${workspace.name}:${scriptName}`);
|
|
99
|
-
const splitCommand = command.command.split(/\s+/g);
|
|
100
|
-
commandLogger.debug(`Running script ${scriptName} in workspace ${workspace.name} (cwd: ${command.cwd}): ${splitCommand.join(" ")}`);
|
|
101
|
-
const isSilent = "silent" === logger.printLevel;
|
|
102
|
-
const proc = Bun.spawn(command.command.split(/\s+/g), {
|
|
103
|
-
cwd: command.cwd,
|
|
104
|
-
env: {
|
|
105
|
-
...process.env,
|
|
106
|
-
FORCE_COLOR: "1"
|
|
107
|
-
},
|
|
108
|
-
stdout: isSilent ? "ignore" : "pipe",
|
|
109
|
-
stderr: isSilent ? "ignore" : "pipe"
|
|
110
|
-
});
|
|
111
|
-
const linePrefix = options.noPrefix ? "" : `[${workspace.name}:${scriptName}] `;
|
|
112
|
-
if (proc.stdout) for await (const chunk of proc.stdout)commandLogger.logOutput(chunk, "info", process.stdout, linePrefix);
|
|
113
|
-
if (proc.stderr) for await (const chunk of proc.stderr)commandLogger.logOutput(chunk, "error", process.stderr, linePrefix);
|
|
114
|
-
await proc.exited;
|
|
115
|
-
return {
|
|
116
|
-
scriptName,
|
|
117
|
-
workspace,
|
|
118
|
-
command,
|
|
119
|
-
success: 0 === proc.exitCode,
|
|
120
|
-
error: 0 === proc.exitCode ? null : new BunWorkspacesError(`Script exited with code ${proc.exitCode}`)
|
|
121
|
-
};
|
|
122
|
-
};
|
|
123
|
-
const results = [];
|
|
124
|
-
if (options.parallel) {
|
|
125
|
-
let i = 0;
|
|
126
|
-
for await (const result of (await Promise.allSettled(scriptCommands.map(runCommand)))){
|
|
127
|
-
if ("rejected" === result.status) results.push({
|
|
128
|
-
success: false,
|
|
129
|
-
workspaceName: workspaces[i],
|
|
130
|
-
error: result.reason
|
|
131
|
-
});
|
|
132
|
-
else results.push({
|
|
133
|
-
success: result.value.success,
|
|
134
|
-
workspaceName: workspaces[i],
|
|
135
|
-
error: result.value.error
|
|
136
|
-
});
|
|
137
|
-
i++;
|
|
138
|
-
}
|
|
139
|
-
} else {
|
|
140
|
-
let i = 0;
|
|
141
|
-
for (const command of scriptCommands){
|
|
142
|
-
try {
|
|
143
|
-
const result = await runCommand(command);
|
|
144
|
-
results.push({
|
|
145
|
-
success: result.success,
|
|
146
|
-
workspaceName: workspaces[i],
|
|
147
|
-
error: result.error
|
|
148
|
-
});
|
|
149
|
-
} catch (error) {
|
|
150
|
-
results.push({
|
|
151
|
-
success: false,
|
|
152
|
-
workspaceName: workspaces[i],
|
|
153
|
-
error: error
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
i++;
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
let failCount = 0;
|
|
160
|
-
results.forEach(({ success, workspaceName })=>{
|
|
161
|
-
if (!success) failCount++;
|
|
162
|
-
logger.info(`${success ? "✅" : "❌"} ${workspaceName}: ${script}`);
|
|
163
|
-
});
|
|
164
|
-
const s = 1 === results.length ? "" : "s";
|
|
165
|
-
if (failCount) {
|
|
166
|
-
const message = `${failCount} of ${results.length} script${s} failed`;
|
|
167
|
-
logger.error(message);
|
|
168
|
-
process.exit(1);
|
|
169
|
-
} else logger.info(`${results.length} script${s} ran successfully`);
|
|
170
|
-
});
|
|
171
|
-
};
|
|
172
|
-
const defineProjectCommands = (context)=>{
|
|
173
|
-
listWorkspaces(context);
|
|
174
|
-
listScripts(context);
|
|
175
|
-
workspaceInfo(context);
|
|
176
|
-
scriptInfo(context);
|
|
177
|
-
runScript(context);
|
|
178
|
-
};
|
|
179
|
-
export { commandOutputLogger, defineProjectCommands };
|