From e78d79cdfb67fbe1906f1114c74c1ab05cde9e7b Mon Sep 17 00:00:00 2001 From: Elizabeth Craig Date: Fri, 6 Sep 2024 11:11:30 -0700 Subject: [PATCH] Use generateChangelog instead --- ...-526ee2eb-1931-449a-b24e-cc00cf631525.json | 2 +- src/__fixtures__/changelog.ts | 22 ++++--- .../changefile/readChangeFiles.test.ts | 48 ++++++++++++++ .../changelog/writeChangelog.test.ts | 65 ++++++------------- src/changelog/writeChangelog.ts | 12 ++-- src/options/getDefaultOptions.ts | 1 - src/types/BeachballOptions.ts | 14 ++-- 7 files changed, 93 insertions(+), 71 deletions(-) diff --git a/change/beachball-526ee2eb-1931-449a-b24e-cc00cf631525.json b/change/beachball-526ee2eb-1931-449a-b24e-cc00cf631525.json index 6a16ac0d7..7f0a0f76e 100644 --- a/change/beachball-526ee2eb-1931-449a-b24e-cc00cf631525.json +++ b/change/beachball-526ee2eb-1931-449a-b24e-cc00cf631525.json @@ -1,5 +1,5 @@ { - "comment": "Add writeChangelogJson option", + "comment": "Add `'md'` and `'json'` options for `generateChangelog`", "type": "minor", "packageName": "beachball", "email": "elcraig@microsoft.com", diff --git a/src/__fixtures__/changelog.ts b/src/__fixtures__/changelog.ts index 34b5511a5..42c11b35d 100644 --- a/src/__fixtures__/changelog.ts +++ b/src/__fixtures__/changelog.ts @@ -4,21 +4,27 @@ import _ from 'lodash'; import { SortedChangeTypes } from '../changefile/changeTypes'; import { ChangelogJson } from '../types/ChangeLog'; -/** Read the CHANGELOG.md under the given package path, sanitizing any dates for snapshots */ -export function readChangelogMd(packagePath: string): string | undefined { +/** + * Read the CHANGELOG.md under the given package path, sanitizing any dates for snapshots. + * Returns null if it doesn't exist. + */ +export function readChangelogMd(packagePath: string): string | null { const changelogFile = path.join(packagePath, 'CHANGELOG.md'); if (!fs.existsSync(changelogFile)) { - return undefined; + return null; } const text = fs.readFileSync(changelogFile, { encoding: 'utf-8' }); return text.replace(/\w\w\w, \d\d \w\w\w [\d :]+?GMT/gm, '(date)'); } -/** Read the CHANGELOG.json under the given package path */ -export function readChangelogJson(packagePath: string, cleanForSnapshot: boolean = false): ChangelogJson | undefined { +/** + * Read the CHANGELOG.json under the given package path. + * Returns null if it doesn't exist. + */ +export function readChangelogJson(packagePath: string, cleanForSnapshot: boolean = false): ChangelogJson | null { const changelogJsonFile = path.join(packagePath, 'CHANGELOG.json'); if (!fs.existsSync(changelogJsonFile)) { - return undefined; + return null; } const json = fs.readJSONSync(changelogJsonFile, { encoding: 'utf-8' }); return cleanForSnapshot ? cleanChangelogJson(json) : json; @@ -28,9 +34,9 @@ export function readChangelogJson(packagePath: string, cleanForSnapshot: boolean * Clean changelog json for a snapshot: replace dates and SHAs with placeholders. * Note: this clones the changelog object rather than modifying the original. */ -export function cleanChangelogJson(changelog: ChangelogJson | undefined): ChangelogJson | undefined { +export function cleanChangelogJson(changelog: ChangelogJson | null): ChangelogJson | null { if (!changelog) { - return undefined; + return null; } changelog = _.cloneDeep(changelog); // for a better snapshot, make the fake commit match if the real commit did diff --git a/src/__functional__/changefile/readChangeFiles.test.ts b/src/__functional__/changefile/readChangeFiles.test.ts index 7b26027e3..de582c340 100644 --- a/src/__functional__/changefile/readChangeFiles.test.ts +++ b/src/__functional__/changefile/readChangeFiles.test.ts @@ -9,6 +9,7 @@ import { readChangeFiles } from '../../changefile/readChangeFiles'; import { BeachballOptions } from '../../types/BeachballOptions'; import type { Repository } from '../../__fixtures__/repository'; import { getDefaultOptions } from '../../options/getDefaultOptions'; +import { ChangeInfo } from '../../types/ChangeInfo'; describe('readChangeFiles', () => { let repositoryFactory: RepositoryFactory; @@ -129,4 +130,51 @@ describe('readChangeFiles', () => { expect(changeSet).toHaveLength(1); expect(logs.mocks.warn).not.toHaveBeenCalled(); }); + + it('runs transform.changeFiles functions if provided', async () => { + const editedComment: string = 'Edited comment for testing'; + repo = monoRepoFactory.cloneRepository(); + + const options = getOptions({ + command: 'change', + transform: { + changeFiles: (changeFile, changeFilePath, { command }) => { + // For test, we will be changing the comment based on the package name + if ((changeFile as ChangeInfo).packageName === 'foo') { + (changeFile as ChangeInfo).comment = editedComment; + (changeFile as ChangeInfo).command = command; + } + return changeFile as ChangeInfo; + }, + }, + changelog: { + groups: [ + { + masterPackageName: 'foo', + changelogPath: repo.pathTo('packages/foo'), + include: ['packages/foo', 'packages/bar'], + }, + ], + }, + }); + + repo.commitChange('foo'); + generateChangeFiles([{ packageName: 'foo', comment: 'comment 1' }], options); + + repo.commitChange('bar'); + generateChangeFiles([{ packageName: 'bar', comment: 'comment 2' }], options); + + const packageInfos = getPackageInfos(repo.rootPath); + const changes = readChangeFiles(options, packageInfos); + + // Verify that the comment of only the intended change file is changed + for (const { change, changeFile } of changes) { + if (changeFile.startsWith('foo')) { + expect(change.comment).toBe(editedComment); + expect(change.command).toEqual('change'); + } else { + expect(change.comment).toBe('comment 2'); + } + } + }); }); diff --git a/src/__functional__/changelog/writeChangelog.test.ts b/src/__functional__/changelog/writeChangelog.test.ts index d93c02341..45fa80217 100644 --- a/src/__functional__/changelog/writeChangelog.test.ts +++ b/src/__functional__/changelog/writeChangelog.test.ts @@ -1,5 +1,4 @@ import { describe, expect, it, beforeAll, afterAll, afterEach } from '@jest/globals'; -import fs from 'fs'; import { generateChangeFiles } from '../../__fixtures__/changeFiles'; import { cleanChangelogJson, readChangelogJson, readChangelogMd } from '../../__fixtures__/changelog'; import { initMockLogs } from '../../__fixtures__/mockLogs'; @@ -9,7 +8,7 @@ import { writeChangelog } from '../../changelog/writeChangelog'; import { getPackageInfos } from '../../monorepo/getPackageInfos'; import { readChangeFiles } from '../../changefile/readChangeFiles'; import { BeachballOptions } from '../../types/BeachballOptions'; -import { ChangeFileInfo, ChangeInfo, ChangeType } from '../../types/ChangeInfo'; +import { ChangeFileInfo, ChangeType } from '../../types/ChangeInfo'; import type { Repository } from '../../__fixtures__/repository'; import { getDefaultOptions } from '../../options/getDefaultOptions'; @@ -298,56 +297,28 @@ describe('writeChangelog', () => { expect(readChangelogMd(repo.pathTo('packages/foo'))).toMatchSnapshot(); }); - it('runs transform.changeFiles functions if provided', async () => { - const editedComment: string = 'Edited comment for testing'; - repo = monoRepoFactory.cloneRepository(); - - const options = getOptions({ - command: 'change', - transform: { - changeFiles: (changeFile, changeFilePath, { command }) => { - // For test, we will be changing the comment based on the package name - if ((changeFile as ChangeInfo).packageName === 'foo') { - (changeFile as ChangeInfo).comment = editedComment; - (changeFile as ChangeInfo).command = command; - } - return changeFile as ChangeInfo; - }, - }, - changelog: { - groups: [ - { - masterPackageName: 'foo', - changelogPath: repo.pathTo('packages/foo'), - include: ['packages/foo', 'packages/bar'], - }, - ], - }, - }); + it('writes only CHANGELOG.md if generateChangelog is "md"', async () => { + repo = repositoryFactory.cloneRepository(); + const options = getOptions({ generateChangelog: 'md' }); repo.commitChange('foo'); generateChangeFiles([getChange('foo', 'comment 1')], options); - repo.commitChange('bar'); - generateChangeFiles([getChange('bar', 'comment 2')], options); - const packageInfos = getPackageInfos(repo.rootPath); const changes = readChangeFiles(options, packageInfos); - // Verify that the comment of only the intended change file is changed - for (const { change, changeFile } of changes) { - if (changeFile.startsWith('foo')) { - expect(change.comment).toBe(editedComment); - expect(change.command).toEqual('change'); - } else { - expect(change.comment).toBe('comment 2'); - } - } + await writeChangelog(options, changes, { foo: 'patch' }, { foo: new Set(['foo']) }, packageInfos); + + // CHANGELOG.md is written + expect(readChangelogMd(repo.rootPath)).toContain('## 1.0.0'); + + // CHANGELOG.json is not written + expect(readChangelogJson(repo.rootPath)).toBeNull(); }); - it('does not write CHANGELOG.json if writeChangelogJson is false', async () => { + it('writes only CHANGELOG.json if generateChangelog is "json"', async () => { repo = repositoryFactory.cloneRepository(); - const options = getOptions({ writeChangelogJson: false }); + const options = getOptions({ generateChangelog: 'json' }); repo.commitChange('foo'); generateChangeFiles([getChange('foo', 'comment 1')], options); @@ -357,10 +328,12 @@ describe('writeChangelog', () => { await writeChangelog(options, changes, { foo: 'patch' }, { foo: new Set(['foo']) }, packageInfos); - // CHANGELOG.md is written - expect(readChangelogMd(repo.rootPath)).toContain('## 1.0.0'); + // CHANGELOG.md is not written + expect(readChangelogMd(repo.rootPath)).toBeNull(); - // CHANGELOG.json is not written - expect(fs.existsSync(repo.pathTo('CHANGELOG.json'))).toBe(false); + // CHANGELOG.json is written + const changelogJson = readChangelogJson(repo.rootPath); + expect(changelogJson).not.toBeNull(); + expect(changelogJson!.entries[0].comments.patch).toEqual([expect.objectContaining({ comment: 'comment 1' })]); }); }); diff --git a/src/changelog/writeChangelog.ts b/src/changelog/writeChangelog.ts index 0b599625b..26ea6ec84 100644 --- a/src/changelog/writeChangelog.ts +++ b/src/changelog/writeChangelog.ts @@ -122,8 +122,8 @@ async function writeChangelogFiles( ): Promise { let previousJson: ChangelogJson | undefined; - if (options.writeChangelogJson) { - // Update CHANGELOG.json + // Update CHANGELOG.json + if (options.generateChangelog === true || options.generateChangelog === 'json') { const changelogJsonFile = path.join(changelogPath, 'CHANGELOG.json'); try { previousJson = fs.existsSync(changelogJsonFile) ? fs.readJSONSync(changelogJsonFile) : undefined; @@ -138,12 +138,10 @@ async function writeChangelogFiles( } } - // Update CHANGELOG.md + // Update CHANGELOG.md if there are changes of types besides "none" if ( - newVersionChangelog.comments.major || - newVersionChangelog.comments.minor || - newVersionChangelog.comments.patch || - newVersionChangelog.comments.prerelease + (options.generateChangelog === true || options.generateChangelog === 'md') && + Object.entries(newVersionChangelog.comments).some(([type, comments]) => type !== 'none' && comments?.length) ) { const changelogFile = path.join(changelogPath, 'CHANGELOG.md'); const previousContent = fs.existsSync(changelogFile) ? fs.readFileSync(changelogFile).toString() : ''; diff --git a/src/options/getDefaultOptions.ts b/src/options/getDefaultOptions.ts index 014b2ce92..b3d87dd72 100644 --- a/src/options/getDefaultOptions.ts +++ b/src/options/getDefaultOptions.ts @@ -36,7 +36,6 @@ export function getDefaultOptions(): BeachballOptions { timeout: undefined, type: null, version: false, - writeChangelogJson: true, yes: env.isCI, }; } diff --git a/src/types/BeachballOptions.ts b/src/types/BeachballOptions.ts index c45830ee4..8dec4fba0 100644 --- a/src/types/BeachballOptions.ts +++ b/src/types/BeachballOptions.ts @@ -109,10 +109,13 @@ export interface RepoOptions { */ fetch: boolean; /** - * Whether to generate changelog files - * @default true + * Whether to generate changelog files. + * - `true` (default) to generate both CHANGELOG.md and CHANGELOG.json + * - `false` to skip changelog generation + * - `'md'` to generate only CHANGELOG.md + * - `'json'` to generate only CHANGELOG.json */ - generateChangelog: boolean; + generateChangelog: boolean | 'md' | 'json'; /** Options for bumping package versions together */ groups?: VersionGroupOptions[]; /** @@ -171,11 +174,6 @@ export interface RepoOptions { groupChanges?: boolean; /** For shallow clones only: Depth of git history to consider when doing fetch */ depth?: number; - /** - * Whether to write CHANGELOG.json files. - * @default true - */ - writeChangelogJson?: boolean; } export interface PackageOptions {