bun-workspaces 0.2.0 → 0.3.0
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/README.md +12 -0
- package/ignore-me-CHANGELOG_TEMPLATE.md +264 -0
- package/ignore-me-test-projects/no-fail/applications/applicationA/package.json +8 -0
- package/ignore-me-test-projects/no-fail/applications/applicationB/package.json +8 -0
- package/ignore-me-test-projects/no-fail/libraries/libraryA/package.json +8 -0
- package/ignore-me-test-projects/no-fail/libraries/libraryB/package.json +8 -0
- package/ignore-me-test-projects/no-fail/libraries/nested/libraryC/package.json +8 -0
- package/ignore-me-test-projects/no-fail/package.json +7 -0
- package/ignore-me-test-projects/one-fail/applications/applicationA/package.json +8 -0
- package/ignore-me-test-projects/one-fail/applications/applicationB/package.json +8 -0
- package/ignore-me-test-projects/one-fail/libraries/libraryA/package.json +8 -0
- package/ignore-me-test-projects/one-fail/libraries/libraryB/package.json +8 -0
- package/ignore-me-test-projects/one-fail/libraries/nested/libraryC/package.json +8 -0
- package/ignore-me-test-projects/one-fail/package.json +7 -0
- package/ignore-me-test-projects/two-fail/applications/applicationA/package.json +8 -0
- package/ignore-me-test-projects/two-fail/applications/applicationB/package.json +8 -0
- package/ignore-me-test-projects/two-fail/libraries/libraryA/package.json +8 -0
- package/ignore-me-test-projects/two-fail/libraries/libraryB/package.json +8 -0
- package/ignore-me-test-projects/two-fail/libraries/nested/libraryC/package.json +8 -0
- package/ignore-me-test-projects/two-fail/package.json +7 -0
- package/package.json +2 -1
- package/src/cli/cli.ts +1 -1
- package/src/cli/projectCommands.ts +207 -106
- package/src/internal/bunVersion.ts +4 -2
- package/src/internal/logger.ts +7 -3
- package/src/project/project.ts +1 -0
- package/src/workspaces/errors.ts +1 -0
- package/src/workspaces/findWorkspaces.ts +1 -3
- package/src/workspaces/packageJson.ts +15 -7
- package/tsconfig.json +1 -1
package/README.md
CHANGED
|
@@ -23,6 +23,7 @@ alias bw="bunx bun-workspaces"
|
|
|
23
23
|
# List all workspaces
|
|
24
24
|
bw list-workspaces
|
|
25
25
|
bw ls
|
|
26
|
+
|
|
26
27
|
# List workspace names only
|
|
27
28
|
bw list-workspaces --name-only
|
|
28
29
|
|
|
@@ -31,6 +32,7 @@ bw list-workspaces "my-*"
|
|
|
31
32
|
|
|
32
33
|
# List all workspace scripts
|
|
33
34
|
bw list-scripts
|
|
35
|
+
|
|
34
36
|
# List script names only
|
|
35
37
|
bw list-scripts --name-only
|
|
36
38
|
|
|
@@ -40,9 +42,16 @@ bw info my-workspace
|
|
|
40
42
|
|
|
41
43
|
# Get info about a script
|
|
42
44
|
bw script-info my-script
|
|
45
|
+
|
|
43
46
|
# Only print list of workspace names that have the script
|
|
44
47
|
bw script-info my-script --workspaces-only
|
|
45
48
|
|
|
49
|
+
# Get JSON output
|
|
50
|
+
bw list-workspaces --json --pretty # optionally pretty print JSON
|
|
51
|
+
bw list-scripts --json
|
|
52
|
+
bw workspace-info my-workspace --json
|
|
53
|
+
bw script-info my-script --json
|
|
54
|
+
|
|
46
55
|
# Run a script for all
|
|
47
56
|
# workspaces that have it
|
|
48
57
|
# in their `scripts` field
|
|
@@ -63,6 +72,9 @@ bw run my-script --parallel
|
|
|
63
72
|
# Append args to each script call
|
|
64
73
|
bw run my-script --args "--my --args"
|
|
65
74
|
|
|
75
|
+
# Use the workspace name in args
|
|
76
|
+
bw run my-script --args "--my --args=<workspace>"
|
|
77
|
+
|
|
66
78
|
# Help (--help can also be passed to any command)
|
|
67
79
|
bw help
|
|
68
80
|
bw --help
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- v1.1 Brazilian Portuguese translation.
|
|
13
|
+
- v1.1 German Translation
|
|
14
|
+
- v1.1 Spanish translation.
|
|
15
|
+
- v1.1 Italian translation.
|
|
16
|
+
- v1.1 Polish translation.
|
|
17
|
+
- v1.1 Ukrainian translation.
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- Use frontmatter title & description in each language version template
|
|
22
|
+
- Replace broken OpenGraph image with an appropriately-sized Keep a Changelog
|
|
23
|
+
image that will render properly (although in English for all languages)
|
|
24
|
+
- Fix OpenGraph title & description for all languages so the title and
|
|
25
|
+
description when links are shared are language-appropriate
|
|
26
|
+
|
|
27
|
+
### Removed
|
|
28
|
+
|
|
29
|
+
- Trademark sign previously shown after the project description in version
|
|
30
|
+
0.3.0
|
|
31
|
+
|
|
32
|
+
## [1.1.1] - 2023-03-05
|
|
33
|
+
|
|
34
|
+
### Added
|
|
35
|
+
|
|
36
|
+
- Arabic translation (#444).
|
|
37
|
+
- v1.1 French translation.
|
|
38
|
+
- v1.1 Dutch translation (#371).
|
|
39
|
+
- v1.1 Russian translation (#410).
|
|
40
|
+
- v1.1 Japanese translation (#363).
|
|
41
|
+
- v1.1 Norwegian Bokmål translation (#383).
|
|
42
|
+
- v1.1 "Inconsistent Changes" Turkish translation (#347).
|
|
43
|
+
- Default to most recent versions available for each languages.
|
|
44
|
+
- Display count of available translations (26 to date!).
|
|
45
|
+
- Centralize all links into `/data/links.json` so they can be updated easily.
|
|
46
|
+
|
|
47
|
+
### Fixed
|
|
48
|
+
|
|
49
|
+
- Improve French translation (#377).
|
|
50
|
+
- Improve id-ID translation (#416).
|
|
51
|
+
- Improve Persian translation (#457).
|
|
52
|
+
- Improve Russian translation (#408).
|
|
53
|
+
- Improve Swedish title (#419).
|
|
54
|
+
- Improve zh-CN translation (#359).
|
|
55
|
+
- Improve French translation (#357).
|
|
56
|
+
- Improve zh-TW translation (#360, #355).
|
|
57
|
+
- Improve Spanish (es-ES) transltion (#362).
|
|
58
|
+
- Foldout menu in Dutch translation (#371).
|
|
59
|
+
- Missing periods at the end of each change (#451).
|
|
60
|
+
- Fix missing logo in 1.1 pages.
|
|
61
|
+
- Display notice when translation isn't for most recent version.
|
|
62
|
+
- Various broken links, page versions, and indentations.
|
|
63
|
+
|
|
64
|
+
### Changed
|
|
65
|
+
|
|
66
|
+
- Upgrade dependencies: Ruby 3.2.1, Middleman, etc.
|
|
67
|
+
|
|
68
|
+
### Removed
|
|
69
|
+
|
|
70
|
+
- Unused normalize.css file.
|
|
71
|
+
- Identical links assigned in each translation file.
|
|
72
|
+
- Duplicate index file for the english version.
|
|
73
|
+
|
|
74
|
+
## [1.1.0] - 2019-02-15
|
|
75
|
+
|
|
76
|
+
### Added
|
|
77
|
+
|
|
78
|
+
- Danish translation (#297).
|
|
79
|
+
- Georgian translation from (#337).
|
|
80
|
+
- Changelog inconsistency section in Bad Practices.
|
|
81
|
+
|
|
82
|
+
### Fixed
|
|
83
|
+
|
|
84
|
+
- Italian translation (#332).
|
|
85
|
+
- Indonesian translation (#336).
|
|
86
|
+
|
|
87
|
+
## [1.0.0] - 2017-06-20
|
|
88
|
+
|
|
89
|
+
### Added
|
|
90
|
+
|
|
91
|
+
- New visual identity by [@tylerfortune8](https://github.com/tylerfortune8).
|
|
92
|
+
- Version navigation.
|
|
93
|
+
- Links to latest released version in previous versions.
|
|
94
|
+
- "Why keep a changelog?" section.
|
|
95
|
+
- "Who needs a changelog?" section.
|
|
96
|
+
- "How do I make a changelog?" section.
|
|
97
|
+
- "Frequently Asked Questions" section.
|
|
98
|
+
- New "Guiding Principles" sub-section to "How do I make a changelog?".
|
|
99
|
+
- Simplified and Traditional Chinese translations from [@tianshuo](https://github.com/tianshuo).
|
|
100
|
+
- German translation from [@mpbzh](https://github.com/mpbzh) & [@Art4](https://github.com/Art4).
|
|
101
|
+
- Italian translation from [@azkidenz](https://github.com/azkidenz).
|
|
102
|
+
- Swedish translation from [@magol](https://github.com/magol).
|
|
103
|
+
- Turkish translation from [@emreerkan](https://github.com/emreerkan).
|
|
104
|
+
- French translation from [@zapashcanon](https://github.com/zapashcanon).
|
|
105
|
+
- Brazilian Portuguese translation from [@Webysther](https://github.com/Webysther).
|
|
106
|
+
- Polish translation from [@amielucha](https://github.com/amielucha) & [@m-aciek](https://github.com/m-aciek).
|
|
107
|
+
- Russian translation from [@aishek](https://github.com/aishek).
|
|
108
|
+
- Czech translation from [@h4vry](https://github.com/h4vry).
|
|
109
|
+
- Slovak translation from [@jkostolansky](https://github.com/jkostolansky).
|
|
110
|
+
- Korean translation from [@pierceh89](https://github.com/pierceh89).
|
|
111
|
+
- Croatian translation from [@porx](https://github.com/porx).
|
|
112
|
+
- Persian translation from [@Hameds](https://github.com/Hameds).
|
|
113
|
+
- Ukrainian translation from [@osadchyi-s](https://github.com/osadchyi-s).
|
|
114
|
+
|
|
115
|
+
### Changed
|
|
116
|
+
|
|
117
|
+
- Start using "changelog" over "change log" since it's the common usage.
|
|
118
|
+
- Start versioning based on the current English version at 0.3.0 to help
|
|
119
|
+
translation authors keep things up-to-date.
|
|
120
|
+
- Rewrite "What makes unicorns cry?" section.
|
|
121
|
+
- Rewrite "Ignoring Deprecations" sub-section to clarify the ideal
|
|
122
|
+
scenario.
|
|
123
|
+
- Improve "Commit log diffs" sub-section to further argument against
|
|
124
|
+
them.
|
|
125
|
+
- Merge "Why can’t people just use a git log diff?" with "Commit log
|
|
126
|
+
diffs".
|
|
127
|
+
- Fix typos in Simplified Chinese and Traditional Chinese translations.
|
|
128
|
+
- Fix typos in Brazilian Portuguese translation.
|
|
129
|
+
- Fix typos in Turkish translation.
|
|
130
|
+
- Fix typos in Czech translation.
|
|
131
|
+
- Fix typos in Swedish translation.
|
|
132
|
+
- Improve phrasing in French translation.
|
|
133
|
+
- Fix phrasing and spelling in German translation.
|
|
134
|
+
|
|
135
|
+
### Removed
|
|
136
|
+
|
|
137
|
+
- Section about "changelog" vs "CHANGELOG".
|
|
138
|
+
|
|
139
|
+
## [0.3.0] - 2015-12-03
|
|
140
|
+
|
|
141
|
+
### Added
|
|
142
|
+
|
|
143
|
+
- RU translation from [@aishek](https://github.com/aishek).
|
|
144
|
+
- pt-BR translation from [@tallesl](https://github.com/tallesl).
|
|
145
|
+
- es-ES translation from [@ZeliosAriex](https://github.com/ZeliosAriex).
|
|
146
|
+
|
|
147
|
+
## [0.2.0] - 2015-10-06
|
|
148
|
+
|
|
149
|
+
### Changed
|
|
150
|
+
|
|
151
|
+
- Remove exclusionary mentions of "open source" since this project can
|
|
152
|
+
benefit both "open" and "closed" source projects equally.
|
|
153
|
+
|
|
154
|
+
## [0.1.0] - 2015-10-06
|
|
155
|
+
|
|
156
|
+
### Added
|
|
157
|
+
|
|
158
|
+
- Answer "Should you ever rewrite a change log?".
|
|
159
|
+
|
|
160
|
+
### Changed
|
|
161
|
+
|
|
162
|
+
- Improve argument against commit logs.
|
|
163
|
+
- Start following [SemVer](https://semver.org) properly.
|
|
164
|
+
|
|
165
|
+
## [0.0.8] - 2015-02-17
|
|
166
|
+
|
|
167
|
+
### Changed
|
|
168
|
+
|
|
169
|
+
- Update year to match in every README example.
|
|
170
|
+
- Reluctantly stop making fun of Brits only, since most of the world
|
|
171
|
+
writes dates in a strange way.
|
|
172
|
+
|
|
173
|
+
### Fixed
|
|
174
|
+
|
|
175
|
+
- Fix typos in recent README changes.
|
|
176
|
+
- Update outdated unreleased diff link.
|
|
177
|
+
|
|
178
|
+
## [0.0.7] - 2015-02-16
|
|
179
|
+
|
|
180
|
+
### Added
|
|
181
|
+
|
|
182
|
+
- Link, and make it obvious that date format is ISO 8601.
|
|
183
|
+
|
|
184
|
+
### Changed
|
|
185
|
+
|
|
186
|
+
- Clarified the section on "Is there a standard change log format?".
|
|
187
|
+
|
|
188
|
+
### Fixed
|
|
189
|
+
|
|
190
|
+
- Fix Markdown links to tag comparison URL with footnote-style links.
|
|
191
|
+
|
|
192
|
+
## [0.0.6] - 2014-12-12
|
|
193
|
+
|
|
194
|
+
### Added
|
|
195
|
+
|
|
196
|
+
- README section on "yanked" releases.
|
|
197
|
+
|
|
198
|
+
## [0.0.5] - 2014-08-09
|
|
199
|
+
|
|
200
|
+
### Added
|
|
201
|
+
|
|
202
|
+
- Markdown links to version tags on release headings.
|
|
203
|
+
- Unreleased section to gather unreleased changes and encourage note
|
|
204
|
+
keeping prior to releases.
|
|
205
|
+
|
|
206
|
+
## [0.0.4] - 2014-08-09
|
|
207
|
+
|
|
208
|
+
### Added
|
|
209
|
+
|
|
210
|
+
- Better explanation of the difference between the file ("CHANGELOG")
|
|
211
|
+
and its function "the change log".
|
|
212
|
+
|
|
213
|
+
### Changed
|
|
214
|
+
|
|
215
|
+
- Refer to a "change log" instead of a "CHANGELOG" throughout the site
|
|
216
|
+
to differentiate between the file and the purpose of the file — the
|
|
217
|
+
logging of changes.
|
|
218
|
+
|
|
219
|
+
### Removed
|
|
220
|
+
|
|
221
|
+
- Remove empty sections from CHANGELOG, they occupy too much space and
|
|
222
|
+
create too much noise in the file. People will have to assume that the
|
|
223
|
+
missing sections were intentionally left out because they contained no
|
|
224
|
+
notable changes.
|
|
225
|
+
|
|
226
|
+
## [0.0.3] - 2014-08-09
|
|
227
|
+
|
|
228
|
+
### Added
|
|
229
|
+
|
|
230
|
+
- "Why should I care?" section mentioning The Changelog podcast.
|
|
231
|
+
|
|
232
|
+
## [0.0.2] - 2014-07-10
|
|
233
|
+
|
|
234
|
+
### Added
|
|
235
|
+
|
|
236
|
+
- Explanation of the recommended reverse chronological release ordering.
|
|
237
|
+
|
|
238
|
+
## [0.0.1] - 2014-05-31
|
|
239
|
+
|
|
240
|
+
### Added
|
|
241
|
+
|
|
242
|
+
- This CHANGELOG file to hopefully serve as an evolving example of a
|
|
243
|
+
standardized open source project CHANGELOG.
|
|
244
|
+
- CNAME file to enable GitHub Pages custom domain.
|
|
245
|
+
- README now contains answers to common questions about CHANGELOGs.
|
|
246
|
+
- Good examples and basic guidelines, including proper date formatting.
|
|
247
|
+
- Counter-examples: "What makes unicorns cry?".
|
|
248
|
+
|
|
249
|
+
[unreleased]: https://github.com/olivierlacan/keep-a-changelog/compare/v1.1.1...HEAD
|
|
250
|
+
[1.1.1]: https://github.com/olivierlacan/keep-a-changelog/compare/v1.1.0...v1.1.1
|
|
251
|
+
[1.1.0]: https://github.com/olivierlacan/keep-a-changelog/compare/v1.0.0...v1.1.0
|
|
252
|
+
[1.0.0]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.3.0...v1.0.0
|
|
253
|
+
[0.3.0]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.2.0...v0.3.0
|
|
254
|
+
[0.2.0]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.1.0...v0.2.0
|
|
255
|
+
[0.1.0]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.8...v0.1.0
|
|
256
|
+
[0.0.8]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.7...v0.0.8
|
|
257
|
+
[0.0.7]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.6...v0.0.7
|
|
258
|
+
[0.0.6]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.5...v0.0.6
|
|
259
|
+
[0.0.5]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.4...v0.0.5
|
|
260
|
+
[0.0.4]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.3...v0.0.4
|
|
261
|
+
[0.0.3]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.2...v0.0.3
|
|
262
|
+
[0.0.2]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.1...v0.0.2
|
|
263
|
+
[0.0.1]: https://github.com/olivierlacan/keep-a-changelog/releases/tag/v0.0.1
|
|
264
|
+
Wh
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bun-workspaces",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"main": "src/index.ts",
|
|
5
5
|
"homepage": "https://github.com/ScottMorse/bun-workspaces#readme",
|
|
6
6
|
"bin": {
|
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"commander": "^12.1.0",
|
|
35
|
+
"glob": "^11.0.0",
|
|
35
36
|
"pino": "^9.5.0",
|
|
36
37
|
"pino-pretty": "^13.0.0"
|
|
37
38
|
},
|
package/src/cli/cli.ts
CHANGED
|
@@ -6,8 +6,8 @@ import {
|
|
|
6
6
|
} from "../internal/bunVersion";
|
|
7
7
|
import { logger } from "../internal/logger";
|
|
8
8
|
import { initializeWithGlobalOptions } from "./globalOptions";
|
|
9
|
-
import { defineProjectCommands } from "./projectCommands";
|
|
10
9
|
import { OUTPUT_CONFIG } from "./output";
|
|
10
|
+
import { defineProjectCommands } from "./projectCommands";
|
|
11
11
|
|
|
12
12
|
export interface RunCliOptions {
|
|
13
13
|
argv?: string | string[];
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type Command } from "commander";
|
|
2
|
-
import {
|
|
2
|
+
import { BunWorkspacesError } from "../internal/error";
|
|
3
|
+
import { logger, createLogger } from "../internal/logger";
|
|
3
4
|
import type { Project } from "../project";
|
|
4
5
|
import type { Workspace } from "../workspaces";
|
|
5
6
|
|
|
@@ -21,6 +22,9 @@ const createScriptInfoLines = (script: string, workspaces: Workspace[]) => [
|
|
|
21
22
|
...workspaces.map((workspace) => ` - ${workspace.name}`),
|
|
22
23
|
];
|
|
23
24
|
|
|
25
|
+
const createJsonLines = (data: unknown, options: { pretty: boolean }) =>
|
|
26
|
+
JSON.stringify(data, null, options.pretty ? 2 : undefined).split("\n");
|
|
27
|
+
|
|
24
28
|
const listWorkspaces = ({
|
|
25
29
|
program,
|
|
26
30
|
project,
|
|
@@ -31,31 +35,49 @@ const listWorkspaces = ({
|
|
|
31
35
|
.aliases(["ls", "list"])
|
|
32
36
|
.description("List all workspaces")
|
|
33
37
|
.option("--name-only", "Only show workspace names")
|
|
34
|
-
.
|
|
35
|
-
|
|
38
|
+
.option("--json", "Output as JSON")
|
|
39
|
+
.option("--pretty", "Pretty print JSON")
|
|
40
|
+
.action(
|
|
41
|
+
(
|
|
42
|
+
pattern,
|
|
43
|
+
options: { nameOnly: boolean; json: boolean; pretty: boolean },
|
|
44
|
+
) => {
|
|
45
|
+
logger.debug(
|
|
46
|
+
`Command: List workspaces (options: ${JSON.stringify(options)})`,
|
|
47
|
+
);
|
|
36
48
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
49
|
+
const lines: string[] = [];
|
|
50
|
+
|
|
51
|
+
const workspaces = pattern
|
|
52
|
+
? project.findWorkspacesByPattern(pattern)
|
|
53
|
+
: project.workspaces;
|
|
40
54
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
55
|
+
if (options.json) {
|
|
56
|
+
lines.push(
|
|
57
|
+
...createJsonLines(
|
|
58
|
+
options.nameOnly
|
|
59
|
+
? workspaces.map(({ name }) => name)
|
|
60
|
+
: workspaces,
|
|
61
|
+
options,
|
|
62
|
+
),
|
|
63
|
+
);
|
|
48
64
|
} else {
|
|
49
|
-
|
|
65
|
+
workspaces.forEach((workspace) => {
|
|
66
|
+
if (options.nameOnly) {
|
|
67
|
+
lines.push(workspace.name);
|
|
68
|
+
} else {
|
|
69
|
+
lines.push(...createWorkspaceInfoLines(workspace));
|
|
70
|
+
}
|
|
71
|
+
});
|
|
50
72
|
}
|
|
51
|
-
});
|
|
52
73
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
74
|
+
if (!lines.length) {
|
|
75
|
+
lines.push("No workspaces found");
|
|
76
|
+
}
|
|
56
77
|
|
|
57
|
-
|
|
58
|
-
|
|
78
|
+
printLines(...lines);
|
|
79
|
+
},
|
|
80
|
+
);
|
|
59
81
|
};
|
|
60
82
|
|
|
61
83
|
const listScripts = ({
|
|
@@ -67,27 +89,50 @@ const listScripts = ({
|
|
|
67
89
|
.command("list-scripts")
|
|
68
90
|
.description("List all scripts available with their workspaces")
|
|
69
91
|
.option("--name-only", "Only show script names")
|
|
70
|
-
.
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
.forEach(({ name, workspaces }) => {
|
|
78
|
-
if (options.nameOnly) {
|
|
79
|
-
lines.push(name);
|
|
80
|
-
} else {
|
|
81
|
-
lines.push(...createScriptInfoLines(name, workspaces));
|
|
82
|
-
}
|
|
83
|
-
});
|
|
92
|
+
.option("--json", "Output as JSON")
|
|
93
|
+
.option("--pretty", "Pretty print JSON")
|
|
94
|
+
.action(
|
|
95
|
+
(options: { nameOnly: boolean; json: boolean; pretty: boolean }) => {
|
|
96
|
+
logger.debug(
|
|
97
|
+
`Command: List scripts (options: ${JSON.stringify(options)})`,
|
|
98
|
+
);
|
|
84
99
|
|
|
85
|
-
|
|
86
|
-
lines
|
|
87
|
-
|
|
100
|
+
const scripts = project.listScriptsWithWorkspaces();
|
|
101
|
+
const lines: string[] = [];
|
|
102
|
+
|
|
103
|
+
if (options.json) {
|
|
104
|
+
lines.push(
|
|
105
|
+
...createJsonLines(
|
|
106
|
+
options.nameOnly
|
|
107
|
+
? Object.keys(scripts)
|
|
108
|
+
: Object.values(scripts).map(({ workspaces, ...rest }) => ({
|
|
109
|
+
...rest,
|
|
110
|
+
workspaces: workspaces.map(({ name }) => name),
|
|
111
|
+
})),
|
|
112
|
+
options,
|
|
113
|
+
),
|
|
114
|
+
);
|
|
115
|
+
} else {
|
|
116
|
+
Object.values(scripts)
|
|
117
|
+
.sort(({ name: nameA }, { name: nameB }) =>
|
|
118
|
+
nameA.localeCompare(nameB),
|
|
119
|
+
)
|
|
120
|
+
.forEach(({ name, workspaces }) => {
|
|
121
|
+
if (options.nameOnly) {
|
|
122
|
+
lines.push(name);
|
|
123
|
+
} else {
|
|
124
|
+
lines.push(...createScriptInfoLines(name, workspaces));
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
if (!lines.length) {
|
|
129
|
+
lines.push("No scripts found");
|
|
130
|
+
}
|
|
131
|
+
}
|
|
88
132
|
|
|
89
|
-
|
|
90
|
-
|
|
133
|
+
printLines(...lines);
|
|
134
|
+
},
|
|
135
|
+
);
|
|
91
136
|
};
|
|
92
137
|
|
|
93
138
|
const workspaceInfo = ({
|
|
@@ -99,17 +144,29 @@ const workspaceInfo = ({
|
|
|
99
144
|
.command("workspace-info <workspace>")
|
|
100
145
|
.aliases(["info"])
|
|
101
146
|
.description("Show information about a workspace")
|
|
102
|
-
.
|
|
103
|
-
|
|
147
|
+
.option("--json", "Output as JSON")
|
|
148
|
+
.option("--pretty", "Pretty print JSON")
|
|
149
|
+
.action(
|
|
150
|
+
(workspaceName: string, options: { json: boolean; pretty: boolean }) => {
|
|
151
|
+
logger.debug(
|
|
152
|
+
`Command: Workspace info for ${workspaceName} (options: ${JSON.stringify(options)})`,
|
|
153
|
+
);
|
|
104
154
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
155
|
+
const workspace = project.findWorkspaceByName(workspaceName);
|
|
156
|
+
if (!workspace) {
|
|
157
|
+
logger.error(
|
|
158
|
+
`Workspace not found: (options: ${JSON.stringify(workspaceName)})`,
|
|
159
|
+
);
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
110
162
|
|
|
111
|
-
|
|
112
|
-
|
|
163
|
+
printLines(
|
|
164
|
+
...(options.json
|
|
165
|
+
? createJsonLines(workspace, options)
|
|
166
|
+
: createWorkspaceInfoLines(workspace)),
|
|
167
|
+
);
|
|
168
|
+
},
|
|
169
|
+
);
|
|
113
170
|
};
|
|
114
171
|
|
|
115
172
|
const scriptInfo = ({
|
|
@@ -121,32 +178,49 @@ const scriptInfo = ({
|
|
|
121
178
|
.command("script-info <script>")
|
|
122
179
|
.description("Show information about a script")
|
|
123
180
|
.option("--workspaces-only", "Only show script's workspace names")
|
|
124
|
-
.
|
|
125
|
-
|
|
181
|
+
.option("--json", "Output as JSON")
|
|
182
|
+
.option("--pretty", "Pretty print JSON")
|
|
183
|
+
.action(
|
|
184
|
+
(
|
|
185
|
+
script,
|
|
186
|
+
options: { workspacesOnly: boolean; json: boolean; pretty: boolean },
|
|
187
|
+
) => {
|
|
188
|
+
logger.debug(
|
|
189
|
+
`Command: Script info for ${script} (options: ${JSON.stringify(options)})`,
|
|
190
|
+
);
|
|
126
191
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
192
|
+
const scripts = project.listScriptsWithWorkspaces();
|
|
193
|
+
const scriptMetadata = scripts[script];
|
|
194
|
+
if (!scriptMetadata) {
|
|
195
|
+
printLines(
|
|
196
|
+
`Script not found: ${JSON.stringify(
|
|
197
|
+
script,
|
|
198
|
+
)} (available: ${Object.keys(scripts).join(", ")})`,
|
|
199
|
+
);
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
130
202
|
printLines(
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
203
|
+
...(options.json
|
|
204
|
+
? createJsonLines(
|
|
205
|
+
options.workspacesOnly
|
|
206
|
+
? scriptMetadata.workspaces.map(({ name }) => name)
|
|
207
|
+
: {
|
|
208
|
+
name: scriptMetadata.name,
|
|
209
|
+
workspaces: scriptMetadata.workspaces.map(
|
|
210
|
+
({ name }) => name,
|
|
211
|
+
),
|
|
212
|
+
},
|
|
213
|
+
options,
|
|
214
|
+
)
|
|
215
|
+
: options.workspacesOnly
|
|
216
|
+
? scriptMetadata.workspaces.map(({ name }) => name)
|
|
217
|
+
: createScriptInfoLines(script, scriptMetadata.workspaces)),
|
|
134
218
|
);
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
printLines(
|
|
138
|
-
...(options.workspacesOnly
|
|
139
|
-
? scriptMetadata.workspaces.map(({ name }) => name)
|
|
140
|
-
: createScriptInfoLines(script, scriptMetadata.workspaces)),
|
|
141
|
-
);
|
|
142
|
-
});
|
|
219
|
+
},
|
|
220
|
+
);
|
|
143
221
|
};
|
|
144
222
|
|
|
145
|
-
const runScript = ({
|
|
146
|
-
program,
|
|
147
|
-
project,
|
|
148
|
-
printLines,
|
|
149
|
-
}: ProjectCommandsContext) => {
|
|
223
|
+
const runScript = ({ program, project }: ProjectCommandsContext) => {
|
|
150
224
|
program
|
|
151
225
|
.command("run <script> [workspaces...]")
|
|
152
226
|
.description("Run a script in all workspaces")
|
|
@@ -201,9 +275,11 @@ const runScript = ({
|
|
|
201
275
|
scriptName,
|
|
202
276
|
workspace,
|
|
203
277
|
}: (typeof scriptCommands)[number]) => {
|
|
278
|
+
const commandLogger = createLogger(`${workspace.name}:${scriptName}`);
|
|
279
|
+
|
|
204
280
|
const splitCommand = command.command.split(/\s+/g);
|
|
205
281
|
|
|
206
|
-
|
|
282
|
+
commandLogger.debug(
|
|
207
283
|
`Running script ${scriptName} in workspace ${workspace.name} (cwd: ${
|
|
208
284
|
command.cwd
|
|
209
285
|
}): ${splitCommand.join(" ")}`,
|
|
@@ -211,21 +287,25 @@ const runScript = ({
|
|
|
211
287
|
|
|
212
288
|
const silent = logger.level === "silent";
|
|
213
289
|
|
|
214
|
-
if (!silent) {
|
|
215
|
-
printLines(
|
|
216
|
-
`Running script ${JSON.stringify(
|
|
217
|
-
scriptName,
|
|
218
|
-
)} in workspace ${JSON.stringify(workspace.name)}`,
|
|
219
|
-
);
|
|
220
|
-
}
|
|
221
|
-
|
|
222
290
|
const proc = Bun.spawn(command.command.split(/\s+/g), {
|
|
223
291
|
cwd: command.cwd,
|
|
224
292
|
env: process.env,
|
|
225
|
-
stdout: silent ? "ignore" : "
|
|
226
|
-
stderr: silent ? "ignore" : "
|
|
293
|
+
stdout: silent ? "ignore" : "pipe",
|
|
294
|
+
stderr: silent ? "ignore" : "pipe",
|
|
227
295
|
});
|
|
228
296
|
|
|
297
|
+
if (proc.stdout) {
|
|
298
|
+
for await (const chunk of proc.stdout) {
|
|
299
|
+
commandLogger.info(new TextDecoder().decode(chunk).trim());
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
if (proc.stderr) {
|
|
304
|
+
for await (const chunk of proc.stderr) {
|
|
305
|
+
commandLogger.error(new TextDecoder().decode(chunk).trim());
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
229
309
|
await proc.exited;
|
|
230
310
|
|
|
231
311
|
return {
|
|
@@ -233,30 +313,20 @@ const runScript = ({
|
|
|
233
313
|
workspace,
|
|
234
314
|
command,
|
|
235
315
|
success: proc.exitCode === 0,
|
|
316
|
+
error:
|
|
317
|
+
proc.exitCode === 0
|
|
318
|
+
? null
|
|
319
|
+
: new BunWorkspacesError(
|
|
320
|
+
`Script exited with code ${proc.exitCode}`,
|
|
321
|
+
),
|
|
236
322
|
};
|
|
237
323
|
};
|
|
238
324
|
|
|
239
|
-
const
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
};
|
|
245
|
-
|
|
246
|
-
const handleResult = ({
|
|
247
|
-
scriptName,
|
|
248
|
-
workspace,
|
|
249
|
-
success,
|
|
250
|
-
}: (typeof scriptCommands)[number] & { success: boolean }) => {
|
|
251
|
-
logger.info(
|
|
252
|
-
`${success ? "✅" : "❌"} ${workspace.name}: ${scriptName}`,
|
|
253
|
-
);
|
|
254
|
-
if (!success) {
|
|
255
|
-
program.error(
|
|
256
|
-
`Script ${scriptName} failed in workspace ${workspace.name}`,
|
|
257
|
-
);
|
|
258
|
-
}
|
|
259
|
-
};
|
|
325
|
+
const results = [] as {
|
|
326
|
+
success: boolean;
|
|
327
|
+
workspaceName: string;
|
|
328
|
+
error: Error | null;
|
|
329
|
+
}[];
|
|
260
330
|
|
|
261
331
|
if (options.parallel) {
|
|
262
332
|
let i = 0;
|
|
@@ -264,9 +334,17 @@ const runScript = ({
|
|
|
264
334
|
scriptCommands.map(runCommand),
|
|
265
335
|
)) {
|
|
266
336
|
if (result.status === "rejected") {
|
|
267
|
-
|
|
337
|
+
results.push({
|
|
338
|
+
success: false,
|
|
339
|
+
workspaceName: workspaces[i],
|
|
340
|
+
error: result.reason,
|
|
341
|
+
});
|
|
268
342
|
} else {
|
|
269
|
-
|
|
343
|
+
results.push({
|
|
344
|
+
success: result.value.success,
|
|
345
|
+
workspaceName: workspaces[i],
|
|
346
|
+
error: result.value.error,
|
|
347
|
+
});
|
|
270
348
|
}
|
|
271
349
|
i++;
|
|
272
350
|
}
|
|
@@ -275,12 +353,35 @@ const runScript = ({
|
|
|
275
353
|
for (const command of scriptCommands) {
|
|
276
354
|
try {
|
|
277
355
|
const result = await runCommand(command);
|
|
278
|
-
|
|
356
|
+
results.push({
|
|
357
|
+
success: result.success,
|
|
358
|
+
workspaceName: workspaces[i],
|
|
359
|
+
error: result.error,
|
|
360
|
+
});
|
|
279
361
|
} catch (error) {
|
|
280
|
-
|
|
362
|
+
results.push({
|
|
363
|
+
success: false,
|
|
364
|
+
workspaceName: workspaces[i],
|
|
365
|
+
error: error as Error,
|
|
366
|
+
});
|
|
281
367
|
}
|
|
368
|
+
i++;
|
|
282
369
|
}
|
|
283
|
-
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
let failCount = 0;
|
|
373
|
+
results.forEach(({ success, workspaceName }) => {
|
|
374
|
+
if (!success) failCount++;
|
|
375
|
+
logger.info(`${success ? "✅" : "❌"} ${workspaceName}: ${script}`);
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
const s = results.length === 1 ? "" : "s";
|
|
379
|
+
if (failCount) {
|
|
380
|
+
const message = `${failCount} of ${results.length} script${s} failed`;
|
|
381
|
+
logger.info(message);
|
|
382
|
+
process.exit(1);
|
|
383
|
+
} else {
|
|
384
|
+
logger.info(`${results.length} script${s} ran successfully`);
|
|
284
385
|
}
|
|
285
386
|
});
|
|
286
387
|
};
|
|
@@ -8,12 +8,14 @@ export const BUILD_BUN_VERSION = rootPackageJson.custom.bunVersion.build;
|
|
|
8
8
|
export const getRequiredBunVersion = (build?: boolean) =>
|
|
9
9
|
build ? BUILD_BUN_VERSION : LIBRARY_CONSUMER_BUN_VERSION;
|
|
10
10
|
|
|
11
|
+
const _Bun = typeof Bun === "undefined" ? ({} as typeof Bun) : Bun;
|
|
12
|
+
|
|
11
13
|
/**
|
|
12
14
|
* Validates that the provided version satisfies the required Bun version
|
|
13
15
|
* specified in the root `package.json`.
|
|
14
16
|
*/
|
|
15
17
|
export const validateBunVersion = (version: string, build?: boolean) =>
|
|
16
|
-
|
|
18
|
+
_Bun ? _Bun.semver.satisfies(version, getRequiredBunVersion(build)) : true;
|
|
17
19
|
|
|
18
20
|
/**
|
|
19
21
|
*
|
|
@@ -21,4 +23,4 @@ export const validateBunVersion = (version: string, build?: boolean) =>
|
|
|
21
23
|
* required Bun version specified in the root `package.json`.
|
|
22
24
|
*/
|
|
23
25
|
export const validateCurrentBunVersion = (build?: boolean) =>
|
|
24
|
-
validateBunVersion(
|
|
26
|
+
validateBunVersion(_Bun?.version, build);
|
package/src/internal/logger.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import
|
|
1
|
+
import createPinoLogger from "pino";
|
|
2
2
|
|
|
3
|
-
export const logger =
|
|
4
|
-
msgPrefix:
|
|
3
|
+
export const logger = createPinoLogger({
|
|
4
|
+
msgPrefix: `[bw] `,
|
|
5
5
|
level:
|
|
6
6
|
process.env.NODE_ENV === "test"
|
|
7
7
|
? "silent"
|
|
@@ -12,6 +12,10 @@ export const logger = createLogger({
|
|
|
12
12
|
target: "pino-pretty",
|
|
13
13
|
options: {
|
|
14
14
|
color: true,
|
|
15
|
+
ignore: "hostname,pid,time",
|
|
15
16
|
},
|
|
16
17
|
},
|
|
17
18
|
});
|
|
19
|
+
|
|
20
|
+
export const createLogger = (prefixContent: string) =>
|
|
21
|
+
logger.child({}, { msgPrefix: `[${prefixContent}] ` });
|
package/src/project/project.ts
CHANGED
package/src/workspaces/errors.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import fs from "fs";
|
|
2
2
|
import path from "path";
|
|
3
|
-
import { Glob } from "bun";
|
|
4
3
|
import { logger } from "../internal/logger";
|
|
5
4
|
import { ERRORS } from "./errors";
|
|
6
5
|
import {
|
|
@@ -52,8 +51,7 @@ export const findWorkspaces = ({
|
|
|
52
51
|
for (const pattern of workspaceGlobs) {
|
|
53
52
|
if (!validatePattern(pattern)) continue;
|
|
54
53
|
|
|
55
|
-
const
|
|
56
|
-
for (const item of scanWorkspaceGlob(glob, rootDir)) {
|
|
54
|
+
for (const item of scanWorkspaceGlob(pattern, rootDir)) {
|
|
57
55
|
const packageJsonPath = resolvePackageJsonPath(item);
|
|
58
56
|
if (packageJsonPath) {
|
|
59
57
|
const packageJsonContent = resolvePackageJsonContent(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import fs from "fs";
|
|
2
2
|
import path from "path";
|
|
3
|
-
import { Glob } from "
|
|
3
|
+
import { Glob } from "glob";
|
|
4
4
|
import { logger } from "../internal/logger";
|
|
5
5
|
import { ERRORS } from "./errors";
|
|
6
6
|
|
|
@@ -22,12 +22,8 @@ export type ResolvedPackageJsonContent = {
|
|
|
22
22
|
|
|
23
23
|
type UnknownPackageJson = Record<string, unknown>;
|
|
24
24
|
|
|
25
|
-
export const scanWorkspaceGlob = (
|
|
26
|
-
|
|
27
|
-
cwd: rootDir,
|
|
28
|
-
onlyFiles: false,
|
|
29
|
-
absolute: true,
|
|
30
|
-
});
|
|
25
|
+
export const scanWorkspaceGlob = (pattern: string, rootDir: string) =>
|
|
26
|
+
new Glob(pattern, { absolute: true, cwd: rootDir }).iterateSync();
|
|
31
27
|
|
|
32
28
|
const validateJsonRoot = (json: UnknownPackageJson) => {
|
|
33
29
|
if (!json || typeof json !== "object" || Array.isArray(json)) {
|
|
@@ -46,6 +42,18 @@ const validateName = (json: UnknownPackageJson) => {
|
|
|
46
42
|
);
|
|
47
43
|
}
|
|
48
44
|
|
|
45
|
+
if (!json.name.trim()) {
|
|
46
|
+
throw new ERRORS.NoWorkspaceName(
|
|
47
|
+
`Expected package.json to have a non-empty "name" field`,
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (json.name.includes("*")) {
|
|
52
|
+
throw new ERRORS.InvalidWorkspaceName(
|
|
53
|
+
`Package name cannot contain the character '*' (workspace: "${json.name}")`,
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
49
57
|
return json.name;
|
|
50
58
|
};
|
|
51
59
|
|