Skip to content

Commit 874b822

Browse files
authored
Include workspace and catalog bumps in the changelog (#1216)
1 parent 4cf68d2 commit 874b822

13 files changed

Lines changed: 183 additions & 77 deletions
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"changes": [
3+
{
4+
"type": "patch",
5+
"comment": "Include dependent bumps for `workspace:` and `catalog:` dependencies in the changelog",
6+
"packageName": "beachball",
7+
"email": "elcraig@microsoft.com",
8+
"dependentChangeType": "patch"
9+
}
10+
]
11+
}

packages/beachball/src/__e2e__/bump.test.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -485,10 +485,9 @@ describe('bump command', () => {
485485
// this gets a changelog entry since the workspace:^1.0.0 dep was updated
486486
// (a little debatable whether the current text is correct)
487487
expect(pkg3Changelog!.entries[0].comments.patch![0].comment).toBe('Bump pkg-2 to v1.0.1');
488-
// Current behavior: dependentChangedBy misses deps like workspace:~ that don't change,
489-
// so the bump of pkg-1 will be missing from pkg-2's changelog.
490-
// https://github.com/microsoft/beachball/issues/981
491-
expect(readChangelogJson(repo.pathTo('packages/pkg-2'))).toBeNull();
488+
// pkg-2 also gets a changelog entry even though its workspace:~ range string is unchanged.
489+
const pkg2Changelog = readChangelogJson(repo.pathTo('packages/pkg-2'));
490+
expect(pkg2Changelog!.entries[0].comments.patch![0].comment).toBe('Bump pkg-1 to v1.1.0');
492491
});
493492

494493
it('bumps dependents with catalog: deps', async () => {
@@ -527,10 +526,11 @@ describe('bump command', () => {
527526
expect(packageInfos['pkg-3']).toEqual({ ...originalPackageInfos['pkg-3'], version: '1.0.1' });
528527

529528
expect(readChangelogJson(repo.pathTo('packages/pkg-1'))).not.toBeNull();
530-
// Current behavior: dependentChangedBy misses catalog: deps, so there are no changelog entries
531-
// https://github.com/microsoft/beachball/issues/981
532-
expect(readChangelogJson(repo.pathTo('packages/pkg-2'))).toBeNull();
533-
expect(readChangelogJson(repo.pathTo('packages/pkg-3'))).toBeNull();
529+
// catalog: deps don't change the dep range string, but dependents still get changelog entries.
530+
const pkg2Changelog = readChangelogJson(repo.pathTo('packages/pkg-2'));
531+
expect(pkg2Changelog!.entries[0].comments.patch![0].comment).toBe('Bump pkg-1 to v1.1.0');
532+
const pkg3Changelog = readChangelogJson(repo.pathTo('packages/pkg-3'));
533+
expect(pkg3Changelog!.entries[0].comments.patch![0].comment).toBe('Bump pkg-2 to v1.0.1');
534534
});
535535

536536
// Explicit tests for sync/async hooks aren't necessary, especially since these are slow tests.

packages/beachball/src/__tests__/bump/bumpInMemory.test.ts

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -260,8 +260,7 @@ describe('bumpInMemory', () => {
260260
const { packageInfos, modifiedPackages, calculatedChangeTypes, dependentChangedBy } = bumpInfo;
261261
expect(modifiedPackages).toEqual(new Set(['pkg-1', 'pkg-2', 'pkg-3']));
262262
expect(calculatedChangeTypes).toEqual({ 'pkg-1': 'minor', 'pkg-2': 'patch', 'pkg-3': 'patch' });
263-
// Current behavior: dependentChangedBy misses file: deps, so the packages won't be in the changelog.
264-
// https://github.com/microsoft/beachball/issues/981
263+
// file: deps don't produce changelog entries — currently this is intentional, per https://github.com/microsoft/beachball/pull/1080
265264
expect(dependentChangedBy).toEqual({});
266265

267266
// All the packages are bumped despite the file: dep specs.
@@ -287,11 +286,8 @@ describe('bumpInMemory', () => {
287286
expect(modifiedPackages).toEqual(new Set(['pkg-1', 'pkg-2', 'pkg-3']));
288287
expect(calculatedChangeTypes).toEqual({ 'pkg-1': 'minor', 'pkg-2': 'patch', 'pkg-3': 'patch' });
289288
expect(dependentChangedBy).toEqual({
289+
'pkg-2': new Set(['pkg-1']),
290290
'pkg-3': new Set(['pkg-2']),
291-
// Current behavior: dependentChangedBy misses deps like workspace:~ that don't change,
292-
// so the bump of pkg-1 will be missing from pkg-2's changelog.
293-
// https://github.com/microsoft/beachball/issues/981
294-
// 'pkg-2': new Set(['pkg-1']),
295291
});
296292

297293
// All the dependent packages are bumped despite the workspace: dep specs
@@ -310,7 +306,6 @@ describe('bumpInMemory', () => {
310306
// pkg-2: workspace:^1.0.0
311307
packageFolders: {
312308
'pkg-1': { version: '1.0.0' },
313-
// both of these are detected as dependent bumps but currently missed from changelog
314309
'pkg-2': { version: '1.0.0', dependencies: { 'pkg-1': 'catalog:' } },
315310
'pkg-3': { version: '1.0.0', dependencies: { 'pkg-2': 'catalog:' } },
316311
},
@@ -322,10 +317,8 @@ describe('bumpInMemory', () => {
322317
expect(modifiedPackages).toEqual(new Set(['pkg-1', 'pkg-2', 'pkg-3']));
323318
expect(calculatedChangeTypes).toEqual({ 'pkg-1': 'minor', 'pkg-2': 'patch', 'pkg-3': 'patch' });
324319
expect(dependentChangedBy).toEqual({
325-
// Current behavior: dependentChangedBy misses all catalog: deps pointing to workspace: versions
326-
// https://github.com/microsoft/beachball/issues/981
327-
// 'pkg-2': new Set(['pkg-1']),
328-
// 'pkg-3': new Set(['pkg-2']),
320+
'pkg-2': new Set(['pkg-1']),
321+
'pkg-3': new Set(['pkg-2']),
329322
});
330323

331324
// All the dependent packages are bumped despite the catalog: dep specs

packages/beachball/src/__tests__/bump/bumpMinSemverRange.test.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,24 @@ import { bumpMinSemverRange } from '../../bump/bumpMinSemverRange';
44
describe('bumpMinSemverRange', () => {
55
it('preserves *', () => {
66
const result = bumpMinSemverRange({ newVersion: '1.0.0', currentRange: '*' });
7-
expect(result).toBe('*');
7+
expect(result).toBeUndefined();
88
});
99

1010
it('preserves file: protocol with relative path', () => {
1111
const result = bumpMinSemverRange({ newVersion: '1.0.0', currentRange: 'file:../local-package' });
12-
expect(result).toBe('file:../local-package');
12+
expect(result).toBeUndefined();
1313
});
1414

1515
it('preserves file: protocol with absolute path', () => {
1616
const result = bumpMinSemverRange({ newVersion: '1.0.0', currentRange: 'file:/absolute/path/to/package' });
17-
expect(result).toBe('file:/absolute/path/to/package');
17+
expect(result).toBeUndefined();
1818
});
1919

2020
it('preserves catalog: protocol', () => {
2121
let result = bumpMinSemverRange({ newVersion: '1.0.0', currentRange: 'catalog:' });
22-
expect(result).toBe('catalog:');
22+
expect(result).toBe(true);
2323
result = bumpMinSemverRange({ newVersion: '1.0.0', currentRange: 'catalog:foo' });
24-
expect(result).toBe('catalog:foo');
24+
expect(result).toBe(true);
2525
});
2626

2727
it.each(['~', '^'])('preserves %s and bumps to new version', prefix => {
@@ -46,7 +46,7 @@ describe('bumpMinSemverRange', () => {
4646

4747
it.each(['workspace:*', 'workspace:~', 'workspace:^'])('preserves %s', workspaceVersion => {
4848
const result = bumpMinSemverRange({ newVersion: '1.3.0', currentRange: workspaceVersion });
49-
expect(result).toBe(workspaceVersion);
49+
expect(result).toBe(true);
5050
});
5151

5252
it('bumps workspace:~x.y.z to workspace range with new version', () => {
@@ -71,6 +71,6 @@ describe('bumpMinSemverRange', () => {
7171

7272
it('preserves unrecognized range if new version satisfies it', () => {
7373
const result = bumpMinSemverRange({ newVersion: '1.3.0', currentRange: '1' });
74-
expect(result).toBe('1');
74+
expect(result).toBeUndefined();
7575
});
7676
});

packages/beachball/src/__tests__/bump/setDependentVersions.test.ts

Lines changed: 70 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { makePackageInfos, type PartialPackageInfos } from '../../__fixtures__/p
44
import { consideredDependencies } from '../../types/PackageInfo';
55
import { initMockLogs } from '../../__fixtures__/mockLogs';
66

7-
type PartialBumpInfo = Parameters<typeof setDependentVersions>[0];
7+
type PartialBumpInfo = Parameters<typeof setDependentVersions>[0]['bumpInfo'];
88

99
describe('setDependentVersions', () => {
1010
const logs = initMockLogs({ alsoLog: ['warn', 'error'] });
@@ -35,7 +35,7 @@ describe('setDependentVersions', () => {
3535
modifiedPackages: new Set(['pkg-a']),
3636
});
3737

38-
const result = setDependentVersions(bumpInfo, {});
38+
const result = setDependentVersions({ bumpInfo, options: {} });
3939

4040
expect(result).toEqual({});
4141
});
@@ -46,7 +46,7 @@ describe('setDependentVersions', () => {
4646
modifiedPackages: new Set(),
4747
});
4848

49-
const result = setDependentVersions(bumpInfo, {});
49+
const result = setDependentVersions({ bumpInfo, options: {} });
5050

5151
expect(result).toEqual({});
5252
});
@@ -61,7 +61,7 @@ describe('setDependentVersions', () => {
6161
},
6262
});
6363

64-
const result = setDependentVersions(bumpInfo, {});
64+
const result = setDependentVersions({ bumpInfo, options: {} });
6565

6666
expect(bumpInfo.packageInfos['pkg-b'].dependencies!['pkg-a']).toBe('^2.0.0');
6767
expect(result).toEqual({ 'pkg-b': new Set(['pkg-a']) });
@@ -78,7 +78,7 @@ describe('setDependentVersions', () => {
7878
},
7979
});
8080

81-
const result = setDependentVersions(bumpInfo, {});
81+
const result = setDependentVersions({ bumpInfo, options: {} });
8282

8383
expect(bumpInfo.packageInfos['pkg-b'].dependencies!['pkg-a']).toBe('^1.1.0');
8484
expect(bumpInfo.packageInfos['pkg-c'].dependencies!['pkg-a']).toBe('~1.1.0');
@@ -93,7 +93,7 @@ describe('setDependentVersions', () => {
9393
},
9494
});
9595

96-
const result = setDependentVersions(bumpInfo, {});
96+
const result = setDependentVersions({ bumpInfo, options: {} });
9797

9898
expect(bumpInfo.packageInfos['pkg-b'][depType]!['pkg-a']).toBe('^1.1.0');
9999
expect(result).toEqual({ 'pkg-b': new Set(['pkg-a']) });
@@ -109,7 +109,7 @@ describe('setDependentVersions', () => {
109109
},
110110
});
111111

112-
const result = setDependentVersions(bumpInfo, {});
112+
const result = setDependentVersions({ bumpInfo, options: {} });
113113

114114
expect(bumpInfo.packageInfos['pkg-a'].dependencies!['external']).toBe('^1.0.0');
115115
expect(result).toEqual({});
@@ -124,7 +124,7 @@ describe('setDependentVersions', () => {
124124
},
125125
});
126126

127-
const result = setDependentVersions(bumpInfo, {});
127+
const result = setDependentVersions({ bumpInfo, options: {} });
128128

129129
expect(bumpInfo.packageInfos['pkg-c'].dependencies!['pkg-a']).toBe('^1.0.1');
130130
expect(bumpInfo.packageInfos['pkg-c'].peerDependencies!['pkg-b']).toBe('^1.1.0');
@@ -139,44 +139,90 @@ describe('setDependentVersions', () => {
139139
},
140140
});
141141

142-
setDependentVersions(bumpInfo, { verbose: true });
142+
setDependentVersions({ bumpInfo, options: { verbose: true } });
143143

144144
expect(logs.mocks.log).toHaveBeenCalledWith('pkg-b needs to be bumped because pkg-a ^1.0.0 -> ^2.0.0');
145145
});
146146

147-
// Documenting this issue
148147
// https://github.com/microsoft/beachball/issues/981
149-
it('currently misses bumps of workspace: ranges', () => {
148+
it.each(['workspace:*', 'workspace:^', 'workspace:~'])(
149+
'records dependent bumps for %s ranges (range string unchanged)',
150+
workspaceVersion => {
151+
const bumpInfo = makeBumpInfo({
152+
packageInfos: {
153+
'pkg-a': { version: '1.1.0' },
154+
'pkg-b': { version: '1.0.1', dependencies: { 'pkg-a': workspaceVersion } },
155+
},
156+
});
157+
158+
const result = setDependentVersions({ bumpInfo, options: {} });
159+
160+
expect(bumpInfo.packageInfos['pkg-b'].dependencies!['pkg-a']).toBe(workspaceVersion);
161+
expect(result).toEqual({ 'pkg-b': new Set(['pkg-a']) });
162+
}
163+
);
164+
165+
// https://github.com/microsoft/beachball/issues/981
166+
it.each(['catalog:', 'catalog:foo'])(
167+
'records dependent bumps for %s ranges (range string unchanged)',
168+
catalogVersion => {
169+
const bumpInfo = makeBumpInfo({
170+
packageInfos: {
171+
'pkg-a': { version: '1.1.0' },
172+
'pkg-b': { version: '1.0.1', dependencies: { 'pkg-a': catalogVersion } },
173+
},
174+
});
175+
176+
const result = setDependentVersions({ bumpInfo, options: {} });
177+
178+
expect(bumpInfo.packageInfos['pkg-b'].dependencies!['pkg-a']).toBe(catalogVersion);
179+
expect(result).toEqual({ 'pkg-b': new Set(['pkg-a']) });
180+
}
181+
);
182+
183+
// file: deps are intentionally excluded — see #1080
184+
it('does not record dependent bumps for file: ranges', () => {
185+
const bumpInfo = makeBumpInfo({
186+
packageInfos: {
187+
'pkg-a': { version: '1.1.0' },
188+
'pkg-b': { version: '1.0.1', dependencies: { 'pkg-a': 'file:../pkg-a' } },
189+
},
190+
});
191+
192+
const result = setDependentVersions({ bumpInfo, options: {} });
193+
194+
expect(bumpInfo.packageInfos['pkg-b'].dependencies!['pkg-a']).toBe('file:../pkg-a');
195+
expect(result).toEqual({});
196+
});
197+
198+
it('does not record dependent bumps for workspace:/catalog: with skipImplicitBumps: true', () => {
150199
const bumpInfo = makeBumpInfo({
151200
packageInfos: {
152201
'pkg-a': { version: '1.1.0' },
153-
// * means an exact dependency and should definitely cause a bump
154202
'pkg-b': { version: '1.0.1', dependencies: { 'pkg-a': 'workspace:*' } },
203+
'pkg-c': { version: '1.0.1', dependencies: { 'pkg-a': 'catalog:foo' } },
155204
},
156205
});
157206

158-
const result = setDependentVersions(bumpInfo, {});
207+
const result = setDependentVersions({ bumpInfo, options: {}, skipImplicitBumps: true });
159208

160209
expect(bumpInfo.packageInfos['pkg-b'].dependencies!['pkg-a']).toBe('workspace:*');
161-
expect(result).toEqual({}); // should have pkg-b depending on pkg-a
210+
expect(bumpInfo.packageInfos['pkg-c'].dependencies!['pkg-a']).toBe('catalog:foo');
211+
expect(result).toEqual({});
162212
});
163213

164-
// Documenting this issue
165-
// https://github.com/microsoft/beachball/issues/981
166-
it('currently misses bumps of catalog: ranges', () => {
214+
it('logs a different verbose message when the range is unchanged', () => {
167215
const bumpInfo = makeBumpInfo({
168216
packageInfos: {
169217
'pkg-a': { version: '1.1.0' },
170-
// Assume there's a catalog like this:
171-
// catalog:
172-
// pkg-a: ^1.1.0
173-
'pkg-b': { version: '1.0.1', dependencies: { 'pkg-a': 'catalog:' } },
218+
'pkg-b': { version: '1.0.1', dependencies: { 'pkg-a': 'workspace:*' } },
174219
},
175220
});
176221

177-
const result = setDependentVersions(bumpInfo, {});
222+
setDependentVersions({ bumpInfo, options: { verbose: true } });
178223

179-
expect(bumpInfo.packageInfos['pkg-b'].dependencies!['pkg-a']).toBe('catalog:');
180-
expect(result).toEqual({}); // should have pkg-b depending on pkg-a
224+
expect(logs.mocks.log).toHaveBeenCalledWith(
225+
'pkg-b needs a changelog entry because pkg-a was bumped to 1.1.0 (range workspace:* unchanged)'
226+
);
181227
});
182228
});

packages/beachball/src/__tests__/changelog/__snapshots__/renderChangelog.test.ts.snap

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,34 @@ Thu, 22 Aug 2019 21:20:40 GMT
143143
"
144144
`;
145145

146+
exports[`renderChangelog renders grouped changelog 1`] = `
147+
"# Change Log - group
148+
149+
<!-- This log was last generated on Thu, 22 Aug 2019 21:20:40 GMT and should not be manually modified. -->
150+
151+
<!-- Start content -->
152+
153+
## 1.2.3
154+
155+
Thu, 22 Aug 2019 21:20:40 GMT
156+
157+
### Minor changes
158+
159+
- \`bar\`
160+
- Awesome change (user1@example.com)
161+
- \`foo\`
162+
- Boring change (user2@example.com)
163+
164+
### Patches
165+
166+
- \`baz\`
167+
- Fix (user1@example.com)
168+
- stuff (a@example.com)
169+
- \`foo\`
170+
- stuff (user2@example.com)
171+
"
172+
`;
173+
146174
exports[`renderChangelog trims previous versions if over maxVersions 1`] = `
147175
"# Change Log - foo
148176

packages/beachball/src/__tests__/changelog/renderChangelog.test.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,18 @@ describe('renderChangelog', () => {
8585
expect(result).toMatchSnapshot();
8686
});
8787

88+
it('renders grouped changelog', async () => {
89+
const options = getOptions();
90+
options.previousContent = '';
91+
options.isGrouped = true;
92+
options.newVersionChangelog.name = 'group';
93+
// Distribute entries across packages so the grouped renderer has something to group
94+
options.newVersionChangelog.comments.minor![0].package = 'bar';
95+
options.newVersionChangelog.comments.patch![0].package = 'baz';
96+
options.newVersionChangelog.comments.patch!.push({ package: 'baz', comment: 'stuff', author: 'a@example.com' });
97+
expect(await renderChangelog(options)).toMatchSnapshot();
98+
});
99+
88100
it('trims previous versions if over maxVersions', async () => {
89101
const options = getOptions();
90102
options.previousContent += '\n\n' + changelogFromVersions(['1.1.9', '1.1.8', '1.1.7']);

packages/beachball/src/bump/bumpInMemory.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ export function bumpInMemory(options: BeachballOptions, context: Omit<CommandCon
7070
}
7171

7272
// step 5: Bump all the dependency version ranges and collect dependentChangedBy for the changelog.
73-
const dependentChangedBy = setDependentVersions(bumpInfo, options);
73+
const dependentChangedBy = setDependentVersions({ bumpInfo, options });
7474
// For now, add any modifiedPackages not previously detected (due to bumpDeps: false or scopes).
7575
// TODO: Rethink all of this... https://github.com/microsoft/beachball/issues/1123
7676
Object.keys(dependentChangedBy).forEach(pkg => bumpInfo.modifiedPackages.add(pkg));

0 commit comments

Comments
 (0)