-
Notifications
You must be signed in to change notification settings - Fork 91
Expand file tree
/
Copy pathwriteChangelog.test.ts
More file actions
598 lines (501 loc) · 24.9 KB
/
writeChangelog.test.ts
File metadata and controls
598 lines (501 loc) · 24.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
import { describe, expect, it, beforeAll, afterAll, afterEach } from '@jest/globals';
import fs from 'fs';
import semver from 'semver';
import { generateChangeFiles, getChange, fakeEmail as author } from '../../__fixtures__/changeFiles';
import {
readChangelogJson,
readChangelogMd,
fakeCommit as commit,
trimChangelogMd,
} from '../../__fixtures__/changelog';
import { initMockLogs } from '../../__fixtures__/mockLogs';
import { RepositoryFactory } from '../../__fixtures__/repositoryFactory';
import { writeChangelog } from '../../changelog/writeChangelog';
import { getPackageInfos } from '../../monorepo/getPackageInfos';
import { readChangeFiles } from '../../changefile/readChangeFiles';
import type { BeachballOptions, RepoOptions } from '../../types/BeachballOptions';
import type { Repository } from '../../__fixtures__/repository';
import type { BumpInfo } from '../../types/BumpInfo';
import { getMaxChangeType } from '../../changefile/changeTypes';
import { getChangePath } from '../../paths';
import { trimmedVersionsNote } from '../../changelog/renderChangelog';
import { getParsedOptions } from '../../options/getOptions';
import { defaultRemoteBranchName } from '../../__fixtures__/gitDefaults';
import type { PackageInfos } from '../../types/PackageInfo';
import { writeJson } from '../../object/writeJson';
import { getScopedPackages } from '../../monorepo/getScopedPackages';
describe('writeChangelog', () => {
let repositoryFactory: RepositoryFactory;
let monoRepoFactory: RepositoryFactory;
let repo: Repository | undefined;
let sharedSingleRepo: Repository;
let sharedMonoRepo: Repository;
initMockLogs();
function getOptionsAndPackages(repoOptions?: Partial<RepoOptions>, cwd?: string) {
const parsedOptions = getParsedOptions({
cwd: cwd || repo?.rootPath || '',
argv: ['node', 'beachball', 'bump'],
testRepoOptions: { branch: defaultRemoteBranchName, ...repoOptions },
});
const packageInfos = getPackageInfos(parsedOptions);
return { packageInfos, options: parsedOptions.options, parsedOptions };
}
/**
* Read package infos and change files, fill in default options, bump versions in package info,
* and call `writeChangelog`.
*
* `calculatedChangeTypes` will be generated based on the max change type of each package's change files,
* and assuming every `dependentChangedBy` package has change type `patch`.
*
* The package info versions and package.json versions on disk (but not dependency ranges) will be
* bumped based on the `calculatedChangeTypes`, so that the changelog results are more realistic,
* and tests involving multiple bumps work more realistically.
*/
async function writeChangelogWrapper(
params: Partial<Pick<BumpInfo, 'dependentChangedBy'>> & {
packageInfos: PackageInfos;
options: BeachballOptions;
}
) {
const { options, dependentChangedBy = {}, packageInfos } = params;
const changeFileChangeInfos = readChangeFiles(options, packageInfos, getScopedPackages(options, packageInfos));
// Generate a basic best guess at calculatedChangeTypes
const calculatedChangeTypes: BumpInfo['calculatedChangeTypes'] = {};
for (const { change } of changeFileChangeInfos) {
const { packageName, type } = change;
calculatedChangeTypes[packageName] = getMaxChangeType([type, calculatedChangeTypes[packageName]]);
}
for (const pkgName of Object.keys(dependentChangedBy)) {
calculatedChangeTypes[pkgName] = getMaxChangeType(['patch', calculatedChangeTypes[pkgName]]);
}
// Bump versions in package info and package.json for more realistic changelogs.
// (This is a much more basic variant of the usual bump process.)
for (const [pkgName, changeType] of Object.entries(calculatedChangeTypes)) {
packageInfos[pkgName].version = semver.inc(packageInfos[pkgName].version, changeType as semver.ReleaseType)!;
const { packageJsonPath, ...packageJson } = packageInfos[pkgName];
writeJson(packageJsonPath, packageJson);
}
await writeChangelog({ dependentChangedBy, calculatedChangeTypes, changeFileChangeInfos, packageInfos }, options);
}
beforeAll(() => {
// These tests can share the same factories and repos because they don't push to the remote,
// and the repo used is reset after each test (which is faster than making new clones).
repositoryFactory = new RepositoryFactory('single');
monoRepoFactory = new RepositoryFactory('monorepo');
sharedSingleRepo = repositoryFactory.cloneRepository();
sharedMonoRepo = monoRepoFactory.cloneRepository();
});
afterEach(() => {
// Revert whichever shared repo was used to the original state
repo?.resetAndClean();
repo = undefined;
});
afterAll(() => {
repositoryFactory.cleanUp();
monoRepoFactory.cleanUp();
});
it('does not write changelogs if there are no changes', async () => {
repo = sharedSingleRepo;
const { options, packageInfos } = getOptionsAndPackages();
await writeChangelogWrapper({ options, packageInfos });
expect(readChangelogMd(repo.rootPath)).toBeNull();
expect(readChangelogJson(repo.rootPath)).toBeNull();
});
it('generates basic changelog', async () => {
repo = sharedSingleRepo;
const { options, packageInfos } = getOptionsAndPackages();
generateChangeFiles([getChange('foo', 'old minor comment')], options);
generateChangeFiles([getChange('foo', 'patch comment', 'patch')], options);
generateChangeFiles([getChange('foo', 'no comment', 'none')], options);
generateChangeFiles([getChange('foo', 'new minor comment', 'minor')], options);
await writeChangelogWrapper({ options, packageInfos });
const changelogMd = readChangelogMd(repo.rootPath);
// Do some explicit tests since snapshot changes are too easy to ignore
expect(changelogMd).toMatch(/^# Change Log - foo/);
expect(changelogMd).toMatch(/### Minor changes\n\n- new minor comment.*\n- old minor comment/);
expect(changelogMd).toContain('### Patches\n\n- patch comment');
expect(changelogMd).not.toContain('no comment');
expect(changelogMd).toMatchSnapshot('changelog md');
const changelogJson = readChangelogJson(repo.rootPath);
expect(changelogJson).toEqual({ name: 'foo', entries: [expect.anything()] });
expect(changelogJson!.entries[0]).toEqual({
version: '1.1.0',
date: '(date)',
tag: 'foo_v1.1.0',
comments: {
minor: [
{ comment: 'new minor comment', package: 'foo', author, commit },
{ comment: 'old minor comment', package: 'foo', author, commit },
],
patch: [{ comment: 'patch comment', package: 'foo', author, commit }],
none: [{ comment: 'no comment', package: 'foo', author, commit }],
},
});
// Every entry should have a different commit hash
const nonTransformedJson = readChangelogJson(repo.rootPath, undefined, true /* noTransform */);
const minorComments = nonTransformedJson!.entries[0].comments.minor!;
expect(minorComments).toBeTruthy();
const commits = minorComments.map(entry => entry.commit);
expect(new Set(commits).size).toEqual(minorComments.length);
// The first entry should be the newest
expect(minorComments[0].commit).toBe(repo.getCurrentHash());
});
it('generates changelog with custom changeDir', async () => {
repo = sharedSingleRepo;
const changeDir = 'myChangeDir';
const { options, packageInfos } = getOptionsAndPackages({ changeDir });
generateChangeFiles([{ packageName: 'foo', comment: 'comment 1' }], options);
// make sure the setup worked as expected
expect(fs.readdirSync(repo.pathTo(changeDir))).toEqual([expect.stringMatching(/^foo-.*\.json$/)]);
await writeChangelogWrapper({ options, packageInfos });
// Just check for a comment in the md to verify that the change file was found
expect(readChangelogMd(repo.rootPath)).toContain('### Minor changes\n\n- comment 1');
});
it('generates changelogs with dependent changes in monorepo', async () => {
repo = sharedMonoRepo;
const { options, packageInfos } = getOptionsAndPackages();
generateChangeFiles([{ packageName: 'foo', comment: 'foo comment' }], options);
generateChangeFiles([{ packageName: 'baz', comment: 'baz comment' }], options);
await writeChangelogWrapper({
options,
packageInfos,
// Per the fixture, bar depends on baz (and is bumped), and foo depends on bar.
// Note that the changelogs will only include dependent bump entries as specified here
// (which may be different than what would actually be calculated while bumping), and
// NO actual bumping will occur (so the versions will be the same as the fixture).
dependentChangedBy: { bar: new Set(['baz']), foo: new Set(['bar']) },
});
// check changelogs for foo, bar, and baz
const fooText = readChangelogMd(repo.pathTo('packages/foo'));
expect(fooText).toMatch(/### Minor changes\n\n- foo comment.*\n- Bump bar to/);
expect(fooText).not.toContain('baz comment');
expect(fooText).toMatchSnapshot('foo CHANGELOG.md');
const barText = readChangelogMd(repo.pathTo('packages/bar'));
expect(barText).toContain('### Patches\n\n- Bump baz to');
expect(barText).not.toMatch(/(foo|baz) comment/);
expect(barText).toMatchSnapshot('bar CHANGELOG.md');
const bazText = readChangelogMd(repo.pathTo('packages/baz'));
expect(bazText).toContain('baz comment');
expect(bazText).not.toContain('Bump');
expect(bazText).toMatchSnapshot('baz CHANGELOG.md');
const fooJson = readChangelogJson(repo.pathTo('packages/foo'));
expect(fooJson).toEqual({ name: 'foo', entries: [expect.anything()] });
expect(fooJson!.entries[0]).toEqual({
version: '1.1.0',
date: '(date)',
tag: 'foo_v1.1.0',
comments: {
minor: [
{ package: 'foo', comment: 'foo comment', author, commit },
{ package: 'foo', comment: 'Bump bar to v1.3.5', author: 'beachball', commit },
],
},
});
const barJson = readChangelogJson(repo.pathTo('packages/bar'));
expect(barJson).toEqual({ name: 'bar', entries: [expect.anything()] });
expect(barJson!.entries[0]).toEqual({
comments: {
patch: [{ package: 'bar', comment: 'Bump baz to v1.4.0', author: 'beachball', commit }],
},
date: '(date)',
tag: 'bar_v1.3.5',
version: '1.3.5',
});
const bazJson = readChangelogJson(repo.pathTo('packages/baz'));
expect(bazJson).toEqual({ name: 'baz', entries: [expect.anything()] });
expect(bazJson!.entries[0]).toEqual({
version: '1.4.0',
date: '(date)',
tag: 'baz_v1.4.0',
comments: {
minor: [{ package: 'baz', comment: 'baz comment', author, commit }],
},
});
});
it('generates changelog in monorepo with grouped change files (groupChanges)', async () => {
repo = sharedMonoRepo;
const { options, packageInfos } = getOptionsAndPackages({ groupChanges: true });
// these will be in one change file
generateChangeFiles([getChange('foo', 'comment 2'), getChange('bar', 'bar comment')], options);
// separate change file
generateChangeFiles([getChange('foo', 'comment 1')], options);
await writeChangelogWrapper({ options, packageInfos, dependentChangedBy: { foo: new Set(['bar']) } });
// check changelogs for both foo and bar
const fooText = readChangelogMd(repo.pathTo('packages/foo'));
expect(fooText).toMatch(/- comment 1.*\n- comment 2/);
expect(fooText).not.toContain('bar comment');
const barText = readChangelogMd(repo.pathTo('packages/bar'));
expect(barText).toContain('bar comment');
expect(barText).not.toMatch(/comment (1|2)/);
const fooJson = readChangelogJson(repo.pathTo('packages/foo'));
expect(fooJson).toEqual({ name: 'foo', entries: [expect.anything()] });
expect(fooJson!.entries[0].comments).toEqual({
minor: [
expect.objectContaining({ comment: 'comment 1', package: 'foo' }),
expect.objectContaining({ comment: 'comment 2', package: 'foo' }),
expect.objectContaining({ comment: 'Bump bar to v1.4.0', package: 'foo' }),
],
});
const barJson = readChangelogJson(repo.pathTo('packages/bar'));
expect(barJson).toEqual({ name: 'bar', entries: [expect.anything()] });
expect(barJson!.entries[0].comments).toEqual({
minor: [expect.objectContaining({ comment: 'bar comment', package: 'bar' })],
});
});
it('generates grouped changelog in monorepo', async () => {
repo = sharedMonoRepo;
const { options, packageInfos } = getOptionsAndPackages({
changelog: {
groups: [
{
mainPackageName: 'foo',
changelogPath: '.',
include: ['packages/*'],
},
],
},
});
// foo and baz have changes.
// bar has no direct changes, but it depends on baz.
generateChangeFiles(['foo', 'baz'], options);
generateChangeFiles([getChange('foo', 'foo comment 2')], options);
await writeChangelogWrapper({
options,
packageInfos,
// Per the fixture structure, bar will have a dependent change from baz, which changes foo
dependentChangedBy: { bar: new Set(['baz']), foo: new Set(['bar']) },
});
// Validate package changelogs
const fooText = readChangelogMd(repo.pathTo('packages/foo'));
// includes the dependent change from bar
expect(fooText).toMatch(/- foo comment.*\n- Bump bar to/);
expect(fooText).not.toContain('baz comment');
const barText = readChangelogMd(repo.pathTo('packages/bar'));
// includes the dependent change from baz
expect(barText).toContain('Bump baz to');
expect(barText).not.toMatch(/(foo|baz) comment/);
const bazText = readChangelogMd(repo.pathTo('packages/baz'));
expect(bazText).toContain('baz comment');
expect(bazText).not.toMatch(/Bump|foo comment/);
// Verify that dependent entries are in foo CHANGELOG.json
const fooJson = readChangelogJson(repo.pathTo('packages/foo'));
expect(fooJson).toEqual({ name: 'foo', entries: [expect.anything()] });
expect(fooJson!.entries[0].comments.minor).toContainEqual(
expect.objectContaining({ comment: 'Bump bar to v1.3.5' })
);
// Validate grouped changelog: it shouldn't have dependent entries
const groupedText = readChangelogMd(repo.rootPath);
expect(groupedText).not.toContain('Bump');
expect(groupedText).toMatch(/- `foo`.*\n - foo comment 2.*\n - foo comment/);
expect(groupedText).toMatch(/- `baz`.*\n - baz comment/);
expect(groupedText).toMatchSnapshot('grouped CHANGELOG.md');
// Validate grouped CHANGELOG.json
const groupedJson = readChangelogJson(repo.rootPath);
expect(groupedJson).toEqual({ name: 'foo', entries: [expect.anything()] });
expect(groupedJson!.entries[0]).toEqual({
comments: {
minor: [
{ comment: 'foo comment 2', package: 'foo', author, commit },
{ comment: 'foo comment', package: 'foo', author, commit },
{ comment: 'baz comment', package: 'baz', author, commit },
],
},
date: '(date)',
tag: 'foo_v1.1.0',
version: '1.1.0',
});
});
it('generates grouped changelog when path overlaps with regular changelog', async () => {
repo = sharedMonoRepo;
const { options, packageInfos } = getOptionsAndPackages({
changelog: {
groups: [
{
mainPackageName: 'foo',
changelogPath: 'packages/foo',
include: ['packages/foo', 'packages/bar'],
},
],
},
});
generateChangeFiles(['foo', 'bar'], options);
await writeChangelogWrapper({ options, packageInfos, dependentChangedBy: { foo: new Set(['bar']) } });
// packages/foo changelog should be grouped, not regular.
// We can verify this by just looking for the bar entry.
const groupedChangelogMd = readChangelogMd(repo.pathTo('packages/foo'));
expect(groupedChangelogMd).toContain('- `bar`\n - bar comment');
const groupedJson = readChangelogJson(repo.pathTo('packages/foo'));
expect(groupedJson).toEqual({ name: 'foo', entries: [expect.anything()] });
expect(groupedJson!.entries[0].comments.minor).toContainEqual(expect.objectContaining({ comment: 'bar comment' }));
});
it('does not write grouped changelog if group would only have dependent bumps', async () => {
repo = sharedMonoRepo;
const { options, packageInfos } = getOptionsAndPackages({
changelog: {
groups: [{ mainPackageName: 'foo', changelogPath: '.', include: ['packages/foo', 'packages/baz'] }],
},
});
// bar is not in the group, but it causes a dependent change for foo
generateChangeFiles(['bar'], options);
await writeChangelogWrapper({ options, packageInfos, dependentChangedBy: { foo: new Set(['bar']) } });
// grouped changelog was not written
expect(readChangelogMd(repo.rootPath)).toBeNull();
expect(readChangelogJson(repo.rootPath)).toBeNull();
// foo changelog was written with the dependent bump
expect(readChangelogMd(repo.pathTo('packages/foo'))).toBeTruthy();
});
it('does not write grouped changelog overlapping regular changelog if it would contain only dependent bumps', async () => {
repo = sharedMonoRepo;
const { options, packageInfos } = getOptionsAndPackages({
changelog: {
groups: [
// The grouped changelog overlaps with the changelog for packages/foo.
{ mainPackageName: 'foo', changelogPath: 'packages/foo', include: ['packages/foo', 'packages/baz'] },
],
},
});
// bar is not in the group
generateChangeFiles(['bar'], options);
// but it causes a dependent change for foo (so normally foo's non-grouped changelog would be written)
await writeChangelogWrapper({ options, packageInfos, dependentChangedBy: { foo: new Set(['bar']) } });
// Nothing was written (not the grouped changelog, and not a normal changelog for foo)
expect(readChangelogMd(repo.pathTo('packages/foo'))).toBeNull();
expect(readChangelogJson(repo.pathTo('packages/foo'))).toBeNull();
});
it('includes pre* changes', async () => {
repo = sharedSingleRepo;
const { options, packageInfos } = getOptionsAndPackages();
generateChangeFiles(
[
{ packageName: 'foo', comment: 'comment 1', type: 'premajor' },
{ packageName: 'foo', comment: 'comment 2', type: 'preminor' },
{ packageName: 'foo', comment: 'comment 3', type: 'prepatch' },
{ packageName: 'foo', comment: 'comment 4', type: 'prerelease' },
],
options
);
await writeChangelogWrapper({ options, packageInfos });
const changelogMd = readChangelogMd(repo.rootPath);
expect(changelogMd).toContain('### Major changes (pre-release)\n\n- comment 1');
expect(changelogMd).toContain('### Minor changes (pre-release)\n\n- comment 2');
expect(changelogMd).toContain('### Patches (pre-release)\n\n- comment 3');
expect(changelogMd).toContain('### Changes\n\n- comment 4');
});
it('includes pre* changes', async () => {
repo = repositoryFactory.cloneRepository();
const { options, packageInfos } = getOptionsAndPackages();
generateChangeFiles(
[
getChange('foo', 'comment 1', 'premajor'),
getChange('foo', 'comment 2', 'preminor'),
getChange('foo', 'comment 3', 'prepatch'),
],
options
);
await writeChangelogWrapper({ options, packageInfos });
const changelogMd = readChangelogMd(repo.rootPath);
expect(changelogMd).toContain('### Major changes (pre-release)\n\n- comment 1');
expect(changelogMd).toContain('### Minor changes (pre-release)\n\n- comment 2');
expect(changelogMd).toContain('### Patches (pre-release)\n\n- comment 3');
});
it('writes only CHANGELOG.md if generateChangelog is "md"', async () => {
repo = sharedSingleRepo;
const { options, packageInfos } = getOptionsAndPackages({ generateChangelog: 'md' });
generateChangeFiles(['foo'], options);
await writeChangelogWrapper({ options, packageInfos });
// CHANGELOG.md is written
expect(readChangelogMd(repo.rootPath)).toContain('## 1.1.0');
// CHANGELOG.json is not written
expect(readChangelogJson(repo.rootPath)).toBeNull();
});
it('writes only CHANGELOG.json if generateChangelog is "json"', async () => {
repo = sharedSingleRepo;
const { options, packageInfos } = getOptionsAndPackages({ generateChangelog: 'json' });
generateChangeFiles(['foo'], options);
await writeChangelogWrapper({ options, packageInfos });
// CHANGELOG.md is not written
expect(readChangelogMd(repo.rootPath)).toBeNull();
// CHANGELOG.json is written
const changelogJson = readChangelogJson(repo.rootPath);
expect(changelogJson).not.toBeNull();
expect(changelogJson!.entries[0].comments.minor).toEqual([expect.objectContaining({ comment: 'foo comment' })]);
});
it('appends to existing changelog', async () => {
// Most of the previous content tests are handled by renderChangelog, but writeChangelog is
// responsible for reading that content and passing it in.
repo = sharedSingleRepo;
const { options, packageInfos } = getOptionsAndPackages();
// Write some changes and generate changelogs
generateChangeFiles(['foo'], options);
await writeChangelogWrapper({ options, packageInfos });
// Read and save the initial changelogs
const firstChangelogMd = readChangelogMd(repo.rootPath);
expect(firstChangelogMd).toContain('foo comment');
const firstChangelogJson = readChangelogJson(repo.rootPath);
expect(firstChangelogJson).toEqual({ name: 'foo', entries: [expect.anything()] });
// Delete the change files, generate new ones, and re-generate changelogs
fs.rmSync(getChangePath(options), { recursive: true, force: true });
generateChangeFiles([getChange('foo', 'extra change')], options);
await writeChangelogWrapper({ options, packageInfos });
// Read the changelogs again and verify that the previous content is still there
const secondChangelogMd = readChangelogMd(repo.rootPath);
expect(secondChangelogMd).toContain('extra change');
expect(secondChangelogMd).toContain(trimChangelogMd(firstChangelogMd!));
const secondChangelogJson = readChangelogJson(repo.rootPath);
expect(secondChangelogJson).toEqual({
name: 'foo',
entries: [expect.anything(), firstChangelogJson!.entries[0]],
});
});
it('appends to existing changelog when migrating from uniqueFilenames=false to true', async () => {
repo = sharedSingleRepo;
const { options, packageInfos } = getOptionsAndPackages();
// Write some changes and generate changelogs
generateChangeFiles(['foo'], options);
await writeChangelogWrapper({ options, packageInfos });
// Read and save the initial changelogs
const firstChangelogMd = readChangelogMd(repo.rootPath);
expect(firstChangelogMd).toContain('foo comment');
const firstChangelogJson = readChangelogJson(repo.rootPath);
expect(firstChangelogJson).toEqual({ name: 'foo', entries: [expect.anything()] });
// Delete the initial change files
fs.rmSync(getChangePath(options), { recursive: true, force: true });
// Change the options to used suffixed filenames, generate new change files, and re-generate changelogs
options.changelog = { uniqueFilenames: true };
generateChangeFiles([getChange('foo', 'extra change')], options);
await writeChangelogWrapper({ options, packageInfos });
// Verify the old changelog is moved
expect(readChangelogMd(repo.rootPath)).toBeNull();
// Read the changelogs again and verify that the previous content is still there
// ("acbd18db" is the start of the md5 hash digest of "foo")
const secondChangelogMd = readChangelogMd(repo.rootPath, 'CHANGELOG-acbd18db.md');
expect(secondChangelogMd).toContain('extra change');
expect(secondChangelogMd).toContain(trimChangelogMd(firstChangelogMd!));
const secondChangelogJson = readChangelogJson(repo.rootPath, 'CHANGELOG-acbd18db.json');
expect(secondChangelogJson).toEqual({
name: 'foo',
entries: [expect.anything(), firstChangelogJson!.entries[0]],
});
});
it('trims previous changelog entries over maxVersions', async () => {
repo = sharedSingleRepo;
const { options, packageInfos } = getOptionsAndPackages({ changelog: { maxVersions: 2 } });
// Bump and write three times
for (let i = 1; i <= 3; i++) {
fs.rmSync(getChangePath(options), { recursive: true, force: true });
generateChangeFiles([{ packageName: 'foo', comment: `foo comment ${i}` }], options);
await writeChangelogWrapper({ options, packageInfos });
}
// Read the changelog md and verify that it only has the last two versions
const changelogMd = readChangelogMd(repo.rootPath);
expect(changelogMd).toContain('## 1.3.0');
expect(changelogMd).toContain('## 1.2.0');
expect(changelogMd).not.toContain('## 1.1.0');
expect(changelogMd).toContain(trimmedVersionsNote);
// Do a snapshot to make sure there's no funny formatting
expect(changelogMd).toMatchSnapshot('CHANGELOG.md');
// Same with changelog json
const changelogJson = readChangelogJson(repo.rootPath);
expect(changelogJson!.entries).toHaveLength(2);
});
});