Skip to content

Commit 13d1843

Browse files
authored
Update logic for getting package infos and options (#1022)
1 parent d0010ae commit 13d1843

16 files changed

+225
-254
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"type": "patch",
3+
"comment": "getPackageInfos should only get repo and CLI options once. Also clarify in types and logic that changeFilePrompt can't be specified at package level.",
4+
"packageName": "beachball",
5+
"email": "[email protected]",
6+
"dependentChangeType": "patch"
7+
}

docs/overview/configuration.md

+23-12
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ There are two types of configurations:
1313
1. repository config
1414
2. package config
1515

16-
## Configuration files
16+
## Repository config
1717

1818
`beachball` uses [`cosmiconfig`](https://github.com/davidtheclark/cosmiconfig) to read its configuration, so you can specify configuration in several ways (in addition to CLI arguments).
1919

@@ -22,37 +22,48 @@ There are two types of configurations:
2222
- `.beachballrc.json`
2323
- `beachball.config.js` (CJS or ESM depending on your project setup; explicit `.cjs` or `.mjs` is also supported)
2424

25-
### `beachball.config.js`
25+
It's most common to use a JavaScript file for the repo-level config, since it's the most flexible and allows comments. Usually this file is at the repo root.
2626

27-
In many cases, you'll want to use a JavaScript config file, since this is the most flexible and allows comments. The example below uses JSDoc type annotations to enable intellisense in some editors (these are optional).
27+
The `beachball.config.js` example below uses JSDoc type annotations to enable intellisense in some editors (these are optional).
2828

2929
```js
3030
// @ts-check
3131
/** @type {import('beachball').BeachallConfig} */
3232
const config = {
33-
key: value,
34-
key2: value2
35-
key3: value3
33+
disallowedChangeTypes: ['major'],
34+
changehint: 'Run "yarn change" to generate a change file',
35+
groupChanges: true,
3636
};
3737
module.exports = config;
3838
```
3939

40-
Config files can be placed in either the root of a repo and/or within individual packages (package config overrides the repo config where applicable). For example:
40+
## Package config
41+
42+
Package-level configuration is currently only supported under the `beachball` key in `package.json`.
43+
44+
For example, suppose the repo config above is at `beachball.config.js` at the repo root, and there are these other files:
4145

4246
```
4347
packages/
4448
foo/
45-
src/
4649
package.json
47-
beachball.config.js
4850
bar/
49-
src/
5051
package.json
51-
package.json
5252
beachball.config.js
53+
package.json
5354
```
5455

55-
It's also common to have a repo-level `beachball.config.js` and any individual package overrides (if they're simple) in the `"beachball"` key in the package's `package.json`.
56+
To change the `disallowedChangeTypes` for package `foo`, you could add the following to `packages/foo/package.json`:
57+
58+
```json
59+
{
60+
"name": "foo",
61+
"version": "1.0.0",
62+
"beachball": {
63+
"disallowedChangeTypes": null
64+
}
65+
}
66+
```
5667

5768
## Options
5869

src/__e2e__/publishE2E.test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -483,7 +483,7 @@ describe('publish command (e2e)', () => {
483483
// All git results should still have previous information
484484
expect(repo.getCurrentTags()).toEqual(['foo_v1.1.0']);
485485
const manifestJson = fs.readFileSync(repo.pathTo('foo.txt'));
486-
expect(manifestJson.toString()).toMatchInlineSnapshot(`"foo"`);
486+
expect(manifestJson.toString()).toEqual('foo');
487487
});
488488

489489
it('publishes multiple packages concurrently respecting the concurrency limit', async () => {

src/__fixtures__/registry.ts

+3-8
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import execa from 'execa';
44
import fs from 'fs-extra';
55
import getPort from 'get-port';
66
import path from 'path';
7-
import { tmpdir } from './tmpdir';
7+
import { removeTempDir, tmpdir } from './tmpdir';
88

99
const verdaccioUser = {
1010
username: 'fake',
@@ -86,13 +86,8 @@ export class Registry {
8686

8787
/** Delete the temp directory used for the config file. */
8888
public cleanUp(): void {
89-
try {
90-
this.tempRoot && fs.removeSync(this.tempRoot);
91-
this.tempRoot = undefined;
92-
} catch {
93-
// This can fail on Windows with EBUSY (likely due to the server not being fully shut down
94-
// or all handles released or something). Just ignore it.
95-
}
89+
this.tempRoot && removeTempDir(this.tempRoot);
90+
this.tempRoot = undefined;
9691
}
9792

9893
private async startWithPort(port: number): Promise<void> {

src/__functional__/monorepo/getPackageInfos.test.ts

+98-114
Original file line numberDiff line numberDiff line change
@@ -92,67 +92,63 @@ describe('getPackageInfos', () => {
9292
const repo = singleFactory.cloneRepository();
9393
let packageInfos = getPackageInfos(repo.rootPath);
9494
packageInfos = cleanPackageInfos(repo.rootPath, packageInfos);
95-
expect(packageInfos).toMatchInlineSnapshot(`
96-
{
97-
"foo": {
98-
"dependencies": {
99-
"bar": "1.0.0",
100-
"baz": "1.0.0",
101-
},
102-
"name": "foo",
103-
"packageJsonPath": "package.json",
104-
"private": false,
105-
"version": "1.0.0",
95+
expect(packageInfos).toEqual({
96+
foo: {
97+
dependencies: {
98+
bar: '1.0.0',
99+
baz: '1.0.0',
106100
},
107-
}
108-
`);
101+
name: 'foo',
102+
packageJsonPath: 'package.json',
103+
private: false,
104+
version: '1.0.0',
105+
},
106+
});
109107
});
110108

111109
// both yarn and npm define "workspaces" in package.json
112110
it('works in yarn/npm monorepo', () => {
113111
const repo = monorepoFactory.cloneRepository();
114112
let packageInfos = getPackageInfos(repo.rootPath);
115113
packageInfos = cleanPackageInfos(repo.rootPath, packageInfos);
116-
expect(packageInfos).toMatchInlineSnapshot(`
117-
{
118-
"a": {
119-
"name": "a",
120-
"packageJsonPath": "packages/grouped/a/package.json",
121-
"private": false,
122-
"version": "3.1.2",
123-
},
124-
"b": {
125-
"name": "b",
126-
"packageJsonPath": "packages/grouped/b/package.json",
127-
"private": false,
128-
"version": "3.1.2",
114+
expect(packageInfos).toEqual({
115+
a: {
116+
name: 'a',
117+
packageJsonPath: 'packages/grouped/a/package.json',
118+
private: false,
119+
version: '3.1.2',
120+
},
121+
b: {
122+
name: 'b',
123+
packageJsonPath: 'packages/grouped/b/package.json',
124+
private: false,
125+
version: '3.1.2',
126+
},
127+
bar: {
128+
dependencies: {
129+
baz: '^1.3.4',
129130
},
130-
"bar": {
131-
"dependencies": {
132-
"baz": "^1.3.4",
133-
},
134-
"name": "bar",
135-
"packageJsonPath": "packages/bar/package.json",
136-
"private": false,
137-
"version": "1.3.4",
131+
name: 'bar',
132+
packageJsonPath: 'packages/bar/package.json',
133+
private: false,
134+
version: '1.3.4',
135+
},
136+
baz: {
137+
name: 'baz',
138+
packageJsonPath: 'packages/baz/package.json',
139+
private: false,
140+
version: '1.3.4',
141+
},
142+
foo: {
143+
dependencies: {
144+
bar: '^1.3.4',
138145
},
139-
"baz": {
140-
"name": "baz",
141-
"packageJsonPath": "packages/baz/package.json",
142-
"private": false,
143-
"version": "1.3.4",
144-
},
145-
"foo": {
146-
"dependencies": {
147-
"bar": "^1.3.4",
148-
},
149-
"name": "foo",
150-
"packageJsonPath": "packages/foo/package.json",
151-
"private": false,
152-
"version": "1.0.0",
153-
},
154-
}
155-
`);
146+
name: 'foo',
147+
packageJsonPath: 'packages/foo/package.json',
148+
private: false,
149+
version: '1.0.0',
150+
},
151+
});
156152
});
157153

158154
it('works in pnpm monorepo', () => {
@@ -162,16 +158,14 @@ describe('getPackageInfos', () => {
162158
fs.writeFileSync(repo.pathTo('pnpm-workspace.yaml'), 'packages: ["packages/*", "packages/grouped/*"]');
163159

164160
const rootPackageInfos = getPackageInfos(repo.rootPath);
165-
expect(getPackageNamesAndPaths(repo.rootPath, rootPackageInfos)).toMatchInlineSnapshot(`
166-
{
167-
"a": "packages/grouped/a/package.json",
168-
"b": "packages/grouped/b/package.json",
169-
"bar": "packages/bar/package.json",
170-
"baz": "packages/baz/package.json",
171-
"foo": "packages/foo/package.json",
172-
"pnpm-monorepo": "package.json",
173-
}
174-
`);
161+
expect(getPackageNamesAndPaths(repo.rootPath, rootPackageInfos)).toEqual({
162+
a: 'packages/grouped/a/package.json',
163+
b: 'packages/grouped/b/package.json',
164+
bar: 'packages/bar/package.json',
165+
baz: 'packages/baz/package.json',
166+
foo: 'packages/foo/package.json',
167+
'pnpm-monorepo': 'package.json',
168+
});
175169
});
176170

177171
it('works in rush monorepo', () => {
@@ -182,16 +176,14 @@ describe('getPackageInfos', () => {
182176
});
183177

184178
const rootPackageInfos = getPackageInfos(repo.rootPath);
185-
expect(getPackageNamesAndPaths(repo.rootPath, rootPackageInfos)).toMatchInlineSnapshot(`
186-
{
187-
"a": "packages/grouped/a/package.json",
188-
"b": "packages/grouped/b/package.json",
189-
"bar": "packages/bar/package.json",
190-
"baz": "packages/baz/package.json",
191-
"foo": "packages/foo/package.json",
192-
"rush-monorepo": "package.json",
193-
}
194-
`);
179+
expect(getPackageNamesAndPaths(repo.rootPath, rootPackageInfos)).toEqual({
180+
a: 'packages/grouped/a/package.json',
181+
b: 'packages/grouped/b/package.json',
182+
bar: 'packages/bar/package.json',
183+
baz: 'packages/baz/package.json',
184+
foo: 'packages/foo/package.json',
185+
'rush-monorepo': 'package.json',
186+
});
195187
});
196188

197189
it('works in lerna monorepo', () => {
@@ -200,62 +192,54 @@ describe('getPackageInfos', () => {
200192
fs.writeJSONSync(repo.pathTo('lerna.json'), { packages: ['packages/*', 'packages/grouped/*'] });
201193

202194
const rootPackageInfos = getPackageInfos(repo.rootPath);
203-
expect(getPackageNamesAndPaths(repo.rootPath, rootPackageInfos)).toMatchInlineSnapshot(`
204-
{
205-
"a": "packages/grouped/a/package.json",
206-
"b": "packages/grouped/b/package.json",
207-
"bar": "packages/bar/package.json",
208-
"baz": "packages/baz/package.json",
209-
"foo": "packages/foo/package.json",
210-
}
211-
`);
195+
expect(getPackageNamesAndPaths(repo.rootPath, rootPackageInfos)).toEqual({
196+
a: 'packages/grouped/a/package.json',
197+
b: 'packages/grouped/b/package.json',
198+
bar: 'packages/bar/package.json',
199+
baz: 'packages/baz/package.json',
200+
foo: 'packages/foo/package.json',
201+
});
212202
});
213203

214204
it('works multi-workspace monorepo', () => {
215205
const repo = multiWorkspaceFactory.cloneRepository();
216206

217207
// For this test, only snapshot the package names and paths
218208
const rootPackageInfos = getPackageInfos(repo.rootPath);
219-
expect(getPackageNamesAndPaths(repo.rootPath, rootPackageInfos)).toMatchInlineSnapshot(`
220-
{
221-
"@workspace-a/a": "workspace-a/packages/grouped/a/package.json",
222-
"@workspace-a/b": "workspace-a/packages/grouped/b/package.json",
223-
"@workspace-a/bar": "workspace-a/packages/bar/package.json",
224-
"@workspace-a/baz": "workspace-a/packages/baz/package.json",
225-
"@workspace-a/foo": "workspace-a/packages/foo/package.json",
226-
"@workspace-a/monorepo-fixture": "workspace-a/package.json",
227-
"@workspace-b/a": "workspace-b/packages/grouped/a/package.json",
228-
"@workspace-b/b": "workspace-b/packages/grouped/b/package.json",
229-
"@workspace-b/bar": "workspace-b/packages/bar/package.json",
230-
"@workspace-b/baz": "workspace-b/packages/baz/package.json",
231-
"@workspace-b/foo": "workspace-b/packages/foo/package.json",
232-
"@workspace-b/monorepo-fixture": "workspace-b/package.json",
233-
}
234-
`);
209+
expect(getPackageNamesAndPaths(repo.rootPath, rootPackageInfos)).toEqual({
210+
'@workspace-a/a': 'workspace-a/packages/grouped/a/package.json',
211+
'@workspace-a/b': 'workspace-a/packages/grouped/b/package.json',
212+
'@workspace-a/bar': 'workspace-a/packages/bar/package.json',
213+
'@workspace-a/baz': 'workspace-a/packages/baz/package.json',
214+
'@workspace-a/foo': 'workspace-a/packages/foo/package.json',
215+
'@workspace-a/monorepo-fixture': 'workspace-a/package.json',
216+
'@workspace-b/a': 'workspace-b/packages/grouped/a/package.json',
217+
'@workspace-b/b': 'workspace-b/packages/grouped/b/package.json',
218+
'@workspace-b/bar': 'workspace-b/packages/bar/package.json',
219+
'@workspace-b/baz': 'workspace-b/packages/baz/package.json',
220+
'@workspace-b/foo': 'workspace-b/packages/foo/package.json',
221+
'@workspace-b/monorepo-fixture': 'workspace-b/package.json',
222+
});
235223

236224
const workspaceARoot = repo.pathTo('workspace-a');
237225
const packageInfosA = getPackageInfos(workspaceARoot);
238-
expect(getPackageNamesAndPaths(workspaceARoot, packageInfosA)).toMatchInlineSnapshot(`
239-
{
240-
"@workspace-a/a": "packages/grouped/a/package.json",
241-
"@workspace-a/b": "packages/grouped/b/package.json",
242-
"@workspace-a/bar": "packages/bar/package.json",
243-
"@workspace-a/baz": "packages/baz/package.json",
244-
"@workspace-a/foo": "packages/foo/package.json",
245-
}
246-
`);
226+
expect(getPackageNamesAndPaths(workspaceARoot, packageInfosA)).toEqual({
227+
'@workspace-a/a': 'packages/grouped/a/package.json',
228+
'@workspace-a/b': 'packages/grouped/b/package.json',
229+
'@workspace-a/bar': 'packages/bar/package.json',
230+
'@workspace-a/baz': 'packages/baz/package.json',
231+
'@workspace-a/foo': 'packages/foo/package.json',
232+
});
247233

248234
const workspaceBRoot = repo.pathTo('workspace-b');
249235
const packageInfosB = getPackageInfos(workspaceBRoot);
250-
expect(getPackageNamesAndPaths(workspaceBRoot, packageInfosB)).toMatchInlineSnapshot(`
251-
{
252-
"@workspace-b/a": "packages/grouped/a/package.json",
253-
"@workspace-b/b": "packages/grouped/b/package.json",
254-
"@workspace-b/bar": "packages/bar/package.json",
255-
"@workspace-b/baz": "packages/baz/package.json",
256-
"@workspace-b/foo": "packages/foo/package.json",
257-
}
258-
`);
236+
expect(getPackageNamesAndPaths(workspaceBRoot, packageInfosB)).toEqual({
237+
'@workspace-b/a': 'packages/grouped/a/package.json',
238+
'@workspace-b/b': 'packages/grouped/b/package.json',
239+
'@workspace-b/bar': 'packages/bar/package.json',
240+
'@workspace-b/baz': 'packages/baz/package.json',
241+
'@workspace-b/foo': 'packages/foo/package.json',
242+
});
259243
});
260244

261245
it('throws if multiple packages have the same name in multi-workspace monorepo', () => {

src/__tests__/changefile/getQuestionsForPackage.test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ describe('getQuestionsForPackage', () => {
150150

151151
const questions = getQuestionsForPackage({
152152
...defaultQuestionsParams,
153-
packageInfos: makePackageInfos({ [pkg]: { combinedOptions: { changeFilePrompt: { changePrompt } } } }),
153+
options: { ...defaultQuestionsParams.options, changeFilePrompt: { changePrompt } },
154154
});
155155

156156
expect(questions).toEqual(customQuestions);

src/__tests__/changefile/promptForChange.test.ts

+1-4
Original file line numberDiff line numberDiff line change
@@ -135,11 +135,8 @@ describe('promptForChange', () => {
135135
};
136136
const changeFilesPromise = promptForChange({
137137
...defaultParams(),
138+
options: { message: 'message', changeFilePrompt },
138139
changedPackages: ['foo', 'bar'],
139-
packageInfos: makePackageInfos({
140-
foo: { combinedOptions: { changeFilePrompt } },
141-
bar: { combinedOptions: { changeFilePrompt } },
142-
}),
143140
});
144141
await waitForPrompt();
145142

0 commit comments

Comments
 (0)