Skip to content

Commit ff94bb4

Browse files
authored
Ability to skip changelog creation when there are no changes. (#191)
1 parent 4bcbcc6 commit ff94bb4

File tree

8 files changed

+74
-31
lines changed

8 files changed

+74
-31
lines changed

src/application/Apexdocs.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,6 @@ async function processChangeLog(config: UserDefinedChangelogConfig) {
7676
return pipe(
7777
TE.tryCatch(loadFiles, (e) => new FileReadingError('An error occurred while reading files.', e)),
7878
TE.flatMap(([previous, current]) => changelog(previous, current, config)),
79-
TE.map(() => '✔️ Changelog generated successfully!'),
8079
TE.mapLeft(toErrors),
8180
);
8281
}

src/application/generators/changelog.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,32 @@
11
import { pipe } from 'fp-ts/function';
2-
import { PageData, UnparsedSourceFile, UserDefinedChangelogConfig } from '../../core/shared/types';
2+
import { PageData, Skip, UnparsedSourceFile, UserDefinedChangelogConfig } from '../../core/shared/types';
33
import * as TE from 'fp-ts/TaskEither';
44
import { writeFiles } from '../file-writer';
55
import { ChangeLogPageData, generateChangeLog } from '../../core/changelog/generate-change-log';
66
import { FileWritingError } from '../errors';
7+
import { isSkip } from '../../core/shared/utils';
78

89
export default function generate(
910
oldBundles: UnparsedSourceFile[],
1011
newBundles: UnparsedSourceFile[],
1112
config: UserDefinedChangelogConfig,
1213
) {
13-
return pipe(
14-
generateChangeLog(oldBundles, newBundles, config),
15-
TE.flatMap((files) => writeFilesToSystem(files, config.targetDir)),
16-
);
14+
function handleFile(file: ChangeLogPageData | Skip) {
15+
if (isSkip(file)) {
16+
return TE.right('✔️ Done! Skipped writing files to the system.');
17+
}
18+
19+
return writeFilesToSystem(file, config.targetDir);
20+
}
21+
22+
return pipe(generateChangeLog(oldBundles, newBundles, config), TE.flatMap(handleFile));
1723
}
1824

1925
function writeFilesToSystem(pageData: ChangeLogPageData, outputDir: string) {
2026
return pipe(
2127
[pageData],
2228
(files) => writeFiles(files as PageData[], outputDir),
29+
TE.map(() => '✔️ Changelog generated successfully!'),
2330
TE.mapLeft((error) => {
2431
return new FileWritingError('An error occurred while writing files to the system.', error);
2532
}),

src/cli/commands/changelog.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,9 @@ export const changeLogOptions: { [key: string]: Options } = {
3535
'Values should be separated by a space, e.g --scope global public namespaceaccessible. ' +
3636
'Annotations are supported and should be passed lowercased and without the @ symbol, e.g. namespaceaccessible auraenabled.',
3737
},
38+
skipIfNoChanges: {
39+
type: 'boolean',
40+
default: changeLogDefaults.skipIfNoChanges,
41+
describe: 'Skip the changelog generation if there are no changes between the previous and current version.',
42+
},
3843
};

src/core/changelog/__test__/generating-change-log.spec.ts

Lines changed: 36 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { UnparsedSourceFile } from '../../shared/types';
2-
import { generateChangeLog } from '../generate-change-log';
2+
import { ChangeLogPageData, generateChangeLog } from '../generate-change-log';
33
import { assertEither } from '../../test-helpers/assert-either';
4+
import { isSkip } from '../../shared/utils';
45

56
const config = {
67
fileName: 'changelog',
@@ -9,13 +10,26 @@ const config = {
910
currentVersionDir: '',
1011
previousVersionDir: '',
1112
exclude: [],
13+
skipIfNoChanges: false,
1214
};
1315

1416
describe('when generating a changelog', () => {
17+
it('should not skip when skipIfNoChanges, even if there are no changes', async () => {
18+
const result = await generateChangeLog([], [], { ...config })();
19+
20+
assertEither(result, (data) => expect(isSkip(data)).toBe(false));
21+
});
22+
23+
it('should skip when there are no changes', async () => {
24+
const result = await generateChangeLog([], [], { ...config, skipIfNoChanges: true })();
25+
26+
assertEither(result, (data) => expect(isSkip(data)).toBe(true));
27+
});
28+
1529
it('should return a file path', async () => {
1630
const result = await generateChangeLog([], [], config)();
1731

18-
assertEither(result, (data) => expect(data.outputDocPath).toContain('changelog.md'));
32+
assertEither(result, (data) => expect((data as ChangeLogPageData).outputDocPath).toContain('changelog.md'));
1933
});
2034

2135
describe('that does not include new classes', () => {
@@ -25,7 +39,7 @@ describe('when generating a changelog', () => {
2539

2640
const result = await generateChangeLog(oldBundle, newBundle, config)();
2741

28-
assertEither(result, (data) => expect(data.content).not.toContain('## New Classes'));
42+
assertEither(result, (data) => expect((data as ChangeLogPageData).content).not.toContain('## New Classes'));
2943
});
3044
});
3145

@@ -40,7 +54,7 @@ describe('when generating a changelog', () => {
4054

4155
const result = await generateChangeLog(oldBundle, newBundle, config)();
4256

43-
assertEither(result, (data) => expect(data.content).toContain('## New Classes'));
57+
assertEither(result, (data) => expect((data as ChangeLogPageData).content).toContain('## New Classes'));
4458
});
4559

4660
it('should include the new class name', async () => {
@@ -53,7 +67,7 @@ describe('when generating a changelog', () => {
5367

5468
const result = await generateChangeLog(oldBundle, newBundle, config)();
5569

56-
assertEither(result, (data) => expect(data.content).toContain('### Test'));
70+
assertEither(result, (data) => expect((data as ChangeLogPageData).content).toContain('### Test'));
5771
});
5872

5973
it('should include the new class description', async () => {
@@ -71,7 +85,7 @@ describe('when generating a changelog', () => {
7185

7286
const result = await generateChangeLog(oldBundle, newBundle, config)();
7387

74-
assertEither(result, (data) => expect(data.content).toContain('This is a test class.'));
88+
assertEither(result, (data) => expect((data as ChangeLogPageData).content).toContain('This is a test class.'));
7589
});
7690
});
7791

@@ -86,7 +100,7 @@ describe('when generating a changelog', () => {
86100

87101
const result = await generateChangeLog(oldBundle, newBundle, config)();
88102

89-
assertEither(result, (data) => expect(data.content).toContain('## New Interfaces'));
103+
assertEither(result, (data) => expect((data as ChangeLogPageData).content).toContain('## New Interfaces'));
90104
});
91105

92106
it('should include the new interface name', async () => {
@@ -99,7 +113,7 @@ describe('when generating a changelog', () => {
99113

100114
const result = await generateChangeLog(oldBundle, newBundle, config)();
101115

102-
assertEither(result, (data) => expect(data.content).toContain('### Test'));
116+
assertEither(result, (data) => expect((data as ChangeLogPageData).content).toContain('### Test'));
103117
});
104118

105119
it('should include the new interface description', async () => {
@@ -117,7 +131,9 @@ describe('when generating a changelog', () => {
117131

118132
const result = await generateChangeLog(oldBundle, newBundle, config)();
119133

120-
assertEither(result, (data) => expect(data.content).toContain('This is a test interface.'));
134+
assertEither(result, (data) =>
135+
expect((data as ChangeLogPageData).content).toContain('This is a test interface.'),
136+
);
121137
});
122138
});
123139

@@ -130,7 +146,7 @@ describe('when generating a changelog', () => {
130146

131147
const result = await generateChangeLog(oldBundle, newBundle, config)();
132148

133-
assertEither(result, (data) => expect(data.content).toContain('## New Enums'));
149+
assertEither(result, (data) => expect((data as ChangeLogPageData).content).toContain('## New Enums'));
134150
});
135151

136152
it('should include the new enum name', async () => {
@@ -141,7 +157,7 @@ describe('when generating a changelog', () => {
141157

142158
const result = await generateChangeLog(oldBundle, newBundle, config)();
143159

144-
assertEither(result, (data) => expect(data.content).toContain('### Test'));
160+
assertEither(result, (data) => expect((data as ChangeLogPageData).content).toContain('### Test'));
145161
});
146162

147163
it('should include the new enum description', async () => {
@@ -157,7 +173,7 @@ describe('when generating a changelog', () => {
157173

158174
const result = await generateChangeLog(oldBundle, newBundle, config)();
159175

160-
assertEither(result, (data) => expect(data.content).toContain('This is a test enum.'));
176+
assertEither(result, (data) => expect((data as ChangeLogPageData).content).toContain('This is a test enum.'));
161177
});
162178
});
163179

@@ -172,7 +188,7 @@ describe('when generating a changelog', () => {
172188

173189
const result = await generateChangeLog(oldBundle, newBundle, { ...config, scope: ['global'] })();
174190

175-
assertEither(result, (data) => expect(data.content).not.toContain('## New Classes'));
191+
assertEither(result, (data) => expect((data as ChangeLogPageData).content).not.toContain('## New Classes'));
176192
});
177193
});
178194

@@ -187,7 +203,7 @@ describe('when generating a changelog', () => {
187203

188204
const result = await generateChangeLog(oldBundle, newBundle, config)();
189205

190-
assertEither(result, (data) => expect(data.content).toContain('## Removed Types'));
206+
assertEither(result, (data) => expect((data as ChangeLogPageData).content).toContain('## Removed Types'));
191207
});
192208

193209
it('should include the removed type name', async () => {
@@ -200,7 +216,7 @@ describe('when generating a changelog', () => {
200216

201217
const result = await generateChangeLog(oldBundle, newBundle, config)();
202218

203-
assertEither(result, (data) => expect(data.content).toContain('- Test'));
219+
assertEither(result, (data) => expect((data as ChangeLogPageData).content).toContain('- Test'));
204220
});
205221
});
206222

@@ -219,7 +235,9 @@ describe('when generating a changelog', () => {
219235

220236
const result = await generateChangeLog(oldBundle, newBundle, config)();
221237

222-
assertEither(result, (data) => expect(data.content).toContain('## New or Modified Members in Existing Types'));
238+
assertEither(result, (data) =>
239+
expect((data as ChangeLogPageData).content).toContain('## New or Modified Members in Existing Types'),
240+
);
223241
});
224242

225243
it('should include the new or modified type name', async () => {
@@ -236,7 +254,7 @@ describe('when generating a changelog', () => {
236254

237255
const result = await generateChangeLog(oldBundle, newBundle, config)();
238256

239-
assertEither(result, (data) => expect(data.content).toContain('### Test'));
257+
assertEither(result, (data) => expect((data as ChangeLogPageData).content).toContain('### Test'));
240258
});
241259

242260
it('should include the new or modified member name', async () => {
@@ -253,7 +271,7 @@ describe('when generating a changelog', () => {
253271

254272
const result = await generateChangeLog(oldBundle, newBundle, config)();
255273

256-
assertEither(result, (data) => expect(data.content).toContain('myMethod'));
274+
assertEither(result, (data) => expect((data as ChangeLogPageData).content).toContain('myMethod'));
257275
});
258276
});
259277
});

src/core/changelog/generate-change-log.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
1-
import { ParsedFile, UnparsedSourceFile, UserDefinedChangelogConfig } from '../shared/types';
1+
import { ParsedFile, Skip, UnparsedSourceFile, UserDefinedChangelogConfig } from '../shared/types';
22
import { pipe } from 'fp-ts/function';
33
import * as TE from 'fp-ts/TaskEither';
44
import { reflectBundles } from '../reflection/reflect-source';
5-
import { processChangelog, VersionManifest } from './process-changelog';
5+
import { Changelog, hasChanges, processChangelog, VersionManifest } from './process-changelog';
66
import { convertToRenderableChangelog, RenderableChangelog } from './renderable-changelog';
77
import { CompilationRequest, Template } from '../template';
88
import { changelogTemplate } from './templates/changelog-template';
99
import { ReflectionErrors } from '../errors/errors';
1010
import { apply } from '#utils/fp';
1111
import { filterScope } from '../reflection/filter-scope';
12+
import { skip } from '../../index';
1213

1314
export type ChangeLogPageData = {
1415
content: string;
@@ -19,7 +20,7 @@ export function generateChangeLog(
1920
oldBundles: UnparsedSourceFile[],
2021
newBundles: UnparsedSourceFile[],
2122
config: Omit<UserDefinedChangelogConfig, 'targetGenerator'>,
22-
): TE.TaskEither<ReflectionErrors, ChangeLogPageData> {
23+
): TE.TaskEither<ReflectionErrors, ChangeLogPageData | Skip> {
2324
const filterOutOfScope = apply(filterScope, config.scope);
2425

2526
function reflect(sourceFiles: UnparsedSourceFile[]) {
@@ -28,18 +29,23 @@ export function generateChangeLog(
2829

2930
const convertToPageData = apply(toPageData, config.fileName);
3031

32+
function handleConversion({ changelog, newManifest }: { changelog: Changelog; newManifest: VersionManifest }) {
33+
if (config.skipIfNoChanges && !hasChanges(changelog)) {
34+
return skip();
35+
}
36+
return pipe(convertToRenderableChangelog(changelog, newManifest.types), compile, convertToPageData);
37+
}
38+
3139
return pipe(
3240
reflect(oldBundles),
3341
TE.bindTo('oldVersion'),
3442
TE.bind('newVersion', () => reflect(newBundles)),
3543
TE.map(toManifests),
3644
TE.map(({ oldManifest, newManifest }) => ({
37-
changeLog: processChangelog(oldManifest, newManifest),
45+
changelog: processChangelog(oldManifest, newManifest),
3846
newManifest,
3947
})),
40-
TE.map(({ changeLog, newManifest }) => convertToRenderableChangelog(changeLog, newManifest.types)),
41-
TE.map(compile),
42-
TE.map(convertToPageData),
48+
TE.map(handleConversion),
4349
);
4450
}
4551

src/core/changelog/process-changelog.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@ export type Changelog = {
3434
newOrModifiedMembers: NewOrModifiedMember[];
3535
};
3636

37+
export function hasChanges(changelog: Changelog): boolean {
38+
return (
39+
changelog.newTypes.length > 0 || changelog.removedTypes.length > 0 || changelog.newOrModifiedMembers.length > 0
40+
);
41+
}
42+
3743
export function processChangelog(oldVersion: VersionManifest, newVersion: VersionManifest): Changelog {
3844
return {
3945
newTypes: getNewTypes(oldVersion, newVersion),

src/core/shared/types.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ export type UserDefinedChangelogConfig = {
4848
fileName: string;
4949
scope: string[];
5050
exclude: string[];
51+
skipIfNoChanges: boolean;
5152
};
5253

5354
export type UserDefinedConfig = UserDefinedMarkdownConfig | UserDefinedOpenApiConfig | UserDefinedChangelogConfig;

src/defaults.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,5 @@ export const changeLogDefaults = {
2727
fileName: 'changelog',
2828
scope: ['global'],
2929
exclude: [],
30+
skipIfNoChanges: true,
3031
};

0 commit comments

Comments
 (0)