Skip to content

Commit 21f24f5

Browse files
committed
feat(breakingchange): ✨ add breaking change section
1. add `detectBreakingChange` option. 2. add `promptBreakingChange` option. 3. add two `breakingChangeFormat`.
1 parent 769d890 commit 21f24f5

8 files changed

Lines changed: 222 additions & 31 deletions

File tree

package.json

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,30 @@
130130
"type": "boolean",
131131
"default": false,
132132
"markdownDescription": "%extension.configuration.editor.keepAfterSave.markdownDescription%"
133+
},
134+
"conventionalCommits.detectBreakingChange": {
135+
"type": "boolean",
136+
"default": false,
137+
"markdownDescription": "%extension.configuration.detectBreakingChange.markdownDescription%"
138+
},
139+
"conventionalCommits.promptBreakingChange": {
140+
"type": "boolean",
141+
"default": false,
142+
"markdownDescription": "%extension.configuration.promptBreakingChange.markdownDescription%"
143+
},
144+
"conventionalCommits.breakingChangeFormat": {
145+
"type": "string",
146+
"default": "both",
147+
"enum": [
148+
"space",
149+
"hyphen",
150+
"both"
151+
],
152+
"markdownEnumDescriptions": [
153+
"%extension.configuration.breakingChangeFormat.markdownEnumDescriptions.space%",
154+
"%extension.configuration.breakingChangeFormat.markdownEnumDescriptions.hyphen%",
155+
"%extension.configuration.breakingChangeFormat.markdownEnumDescriptions.both%"
156+
]
133157
}
134158
}
135159
}

package.nls.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@
1515
"extension.configuration.showEditor.markdownDescription": "Control whether the extension should show the commit message as a text document in a separate tab.",
1616
"extension.configuration.showNewVersionNotes.markdownDescription": "Control whether the extension should show the new version notes.",
1717
"extension.configuration.editor.keepAfterSave.markdownDescription": "Control whether the extension should allow keeping edit status after saving the commit message.",
18+
"extension.configuration.detectBreakingChange.markdownDescription": "Control whether the extension should add optional `!` into commit message when have `BREAKING CHANGE: ` or `BREAKING-CHANGE: ` in `footer`.",
19+
"extension.configuration.promptBreakingChange.markdownDescription": "Controls whether the extension should prompt for the `breaking change` section.",
20+
"extension.configuration.breakingChangeFormat.markdownEnumDescriptions.space": "Display one prompt selection as `BREAKING CHANGE: `",
21+
"extension.configuration.breakingChangeFormat.markdownEnumDescriptions.hyphen": "Display one prompt selection as `BREAKING-CHANGE: `",
22+
"extension.configuration.breakingChangeFormat.markdownEnumDescriptions.both": "Display two prompts selection as `BREAKING CHANGE: ` and `BREAKING-CHANGE: `",
1823
"extension.sources.repositoryNotFoundInPath": "Repository not found in path: ",
1924
"extension.sources.repositoriesEmpty": "Please open a repository.",
2025
"extension.sources.promptRepositoryPlaceholder": "Choose a repository.",

package.nls.zh-cn.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@
1515
"extension.configuration.showEditor.markdownDescription": "是否需要在新标签页用文本编辑器展示提交信息",
1616
"extension.configuration.showNewVersionNotes.markdownDescription": "是否需要显示新版本说明。",
1717
"extension.configuration.editor.keepAfterSave.markdownDescription": "是否需要在保存提交消息后保持编辑状态。",
18+
"extension.configuration.detectBreakingChange.markdownDescription": "当检测到 `footer` 中有 `BREAKING-CHANGE: ` 或者 `BREAKING CHANGE: ` 时,是否需要在提交信息中添加可选项 `!`。",
19+
"extension.configuration.promptBreakingChange.markdownDescription": "是否需要提示填写 `Breaking change`",
20+
"extension.configuration.breakingChangeFormat.markdownEnumDescriptions.space": "显示提示选项 `BREAKING CHANGE: `",
21+
"extension.configuration.breakingChangeFormat.markdownEnumDescriptions.hyphen": "显示提示选项 `BREAKING-CHANGE: `",
22+
"extension.configuration.breakingChangeFormat.markdownEnumDescriptions.both": "同时显示两种提示选项 `BREAKING CHANGE: ` 和 `BREAKING-CHANGE: `",
1823
"extension.sources.repositoryNotFoundInPath": "以下路径中未找到仓库:",
1924
"extension.sources.repositoriesEmpty": "请打开一个仓库。",
2025
"extension.sources.promptRepositoryPlaceholder": "请选择一个仓库。",

src/lib/commit-message.ts

Lines changed: 47 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
export class CommitMessage {
66
private _type: string = '';
77
private _scope: string = '';
8+
private _breakingChange: string = '';
89
private _gitmoji: string = '';
910
private _subject: string = '';
1011
private _body: string = '';
@@ -26,6 +27,14 @@ export class CommitMessage {
2627
this._scope = input.trim();
2728
}
2829

30+
get breakingChange() {
31+
return this._breakingChange;
32+
}
33+
34+
set breakingChange(input: string) {
35+
this._breakingChange = input.trim();
36+
}
37+
2938
get gitmoji() {
3039
return this._gitmoji;
3140
}
@@ -49,7 +58,6 @@ export class CommitMessage {
4958
set body(input: string) {
5059
this._body = input.trim();
5160
}
52-
5361
get footer() {
5462
return this._footer;
5563
}
@@ -77,34 +85,51 @@ export function serializeSubject(partialCommitMessage: {
7785
return result;
7886
}
7987

80-
export function serializeHeader(partialCommitMessage: {
81-
type: string;
82-
scope: string;
83-
gitmoji: string;
84-
subject: string;
88+
export function serializeHeader({
89+
partialCommitMessage,
90+
detectBreakingChange,
91+
}: {
92+
partialCommitMessage: {
93+
type: string;
94+
scope: string;
95+
breakingChange: string;
96+
gitmoji: string;
97+
subject: string;
98+
};
99+
detectBreakingChange: boolean;
85100
}) {
86-
let result = '';
87-
result += partialCommitMessage.type;
88-
const { scope } = partialCommitMessage;
89-
if (scope) {
90-
result += `(${scope})`;
91-
}
92-
result += ': ';
101+
let result = '' + partialCommitMessage.type;
102+
103+
const { scope, breakingChange } = partialCommitMessage;
104+
if (scope) result += `(${scope})`;
105+
106+
if (breakingChange && (breakingChange === '!' || detectBreakingChange)) {
107+
result += `!: `;
108+
} else result += ': ';
109+
93110
const subject = serializeSubject(partialCommitMessage);
94-
if (subject) {
95-
result += subject;
96-
}
111+
if (subject) result += subject;
112+
97113
return result;
98114
}
99115

100-
export function serialize(commitMessage: CommitMessage) {
101-
let message = serializeHeader(commitMessage);
102-
const { body, footer } = commitMessage;
103-
if (body) {
104-
message += `\n\n${body}`;
116+
export function serialize(
117+
commitMessage: CommitMessage,
118+
detectBreakingChange: boolean,
119+
) {
120+
let message = serializeHeader({
121+
partialCommitMessage: commitMessage,
122+
detectBreakingChange,
123+
});
124+
const { breakingChange, body, footer } = commitMessage;
125+
if (body) message += `\n\n${body}`;
126+
127+
if (breakingChange && breakingChange != '!') {
128+
message += `\n\n${breakingChange}`;
105129
}
106130
if (footer) {
107-
message += `\n\n${footer}`;
131+
message += breakingChange && breakingChange != '!' ? '\n' : '\n\n';
132+
message += footer;
108133
}
109134
return message;
110135
}

src/lib/configuration.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@ export enum EMOJI_FORMAT {
1010
emoji = 'emoji',
1111
}
1212

13+
export enum BREAKING_CHANGE_FORMAT {
14+
hyphen = 'hyphen',
15+
space = 'space',
16+
both = 'both',
17+
}
18+
1319
export type Configuration = {
1420
autoCommit: boolean;
1521
gitmoji: boolean;
@@ -22,6 +28,9 @@ export type Configuration = {
2228
promptFooter: boolean;
2329
showNewVersionNotes: boolean;
2430
'editor.keepAfterSave': boolean;
31+
detectBreakingChange: boolean;
32+
promptBreakingChange: boolean;
33+
breakingChangeFormat: BREAKING_CHANGE_FORMAT;
2534
};
2635

2736
export function getConfiguration() {

src/lib/conventional-commits.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,9 @@ export default function createConventionalCommits() {
141141
);
142142

143143
// 5. get message
144+
const detectBreakingChange = configuration.get<boolean>(
145+
'detectBreakingChange',
146+
);
144147
const commitMessage = await prompts({
145148
gitmoji: configuration.get<boolean>('gitmoji'),
146149
showEditor: configuration.get<boolean>('showEditor'),
@@ -151,10 +154,17 @@ export default function createConventionalCommits() {
151154
promptScopes: configuration.get<boolean>('promptScopes'),
152155
promptBody: configuration.get<boolean>('promptBody'),
153156
promptFooter: configuration.get<boolean>('promptFooter'),
157+
promptBreakingChange: configuration.get<boolean>(
158+
'promptBreakingChange',
159+
),
160+
detectBreakingChange: detectBreakingChange,
161+
breakingChangeFormat: configuration.get<boolean>(
162+
'breakingChangeFormat',
163+
),
154164
});
155-
output.info(`messageJSON:\n${JSON.stringify(commitMessage, null, 2)}`);
156-
const message = serialize(commitMessage);
157-
output.info(`message:\n${message}`);
165+
output.info(`commitMessage: ${JSON.stringify(commitMessage, null, 2)}`);
166+
let message = serialize(commitMessage, detectBreakingChange);
167+
output.info(`message: ${message}`);
158168

159169
// 6. switch to scm and put message into message box
160170
// or show the entire commit message in a separate tab

src/lib/prompts.ts

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ export default async function prompts({
3232
promptScopes,
3333
promptBody,
3434
promptFooter,
35+
promptBreakingChange,
36+
detectBreakingChange,
37+
breakingChangeFormat,
3538
}: {
3639
gitmoji: boolean;
3740
showEditor: boolean;
@@ -40,6 +43,9 @@ export default async function prompts({
4043
promptScopes: boolean;
4144
promptBody: boolean;
4245
promptFooter: boolean;
46+
promptBreakingChange: boolean;
47+
detectBreakingChange: boolean;
48+
breakingChangeFormat: boolean;
4349
}): Promise<CommitMessage> {
4450
const commitMessage = new CommitMessage();
4551
const conventionalCommitsTypes = getTypesByLocale(locale).types;
@@ -114,14 +120,14 @@ export default async function prompts({
114120
name,
115121
placeholder,
116122
configurationKey: keys.SCOPES as keyof configuration.Configuration,
123+
noneItem,
117124
newItem: {
118125
label: getPromptLocalize('scope.newItem.label'),
119126
description: '',
120127
detail: getPromptLocalize('scope.newItem.detail'),
121128
alwaysShow: true,
122129
placeholder: getPromptLocalize('scope.newItem.placeholder'),
123130
},
124-
noneItem,
125131
newItemWithoutSetting: {
126132
label: getPromptLocalize('scope.newItemWithoutSetting.label'),
127133
description: '',
@@ -146,6 +152,39 @@ export default async function prompts({
146152
},
147153
},
148154
getScopePrompt(),
155+
{
156+
type: PROMPT_TYPES.BREAKING_CHANGE_QUICK_PICK,
157+
name: 'breakingChange',
158+
placeholder: getPromptLocalize('breakingChange.placeholder'),
159+
noneItem: {
160+
label: getPromptLocalize('breakingChange.noneItem.label'),
161+
description: '',
162+
detail: getPromptLocalize('breakingChange.noneItem.detail'),
163+
alwaysShow: true,
164+
},
165+
pointItem: {
166+
label: getPromptLocalize('breakingChange.pointItem.label'),
167+
description: '',
168+
detail: getPromptLocalize('breakingChange.pointItem.detail'),
169+
alwaysShow: true,
170+
},
171+
spaceItem: {
172+
label: getPromptLocalize('breakingChange.spaceItem.label'),
173+
description: '',
174+
detail: getPromptLocalize('breakingChange.spaceItem.detail'),
175+
alwaysShow: true,
176+
placeholder: getPromptLocalize('breakingChange.message.placeholder'),
177+
},
178+
hyphenItem: {
179+
label: getPromptLocalize('breakingChange.hyphenItem.label'),
180+
description: '',
181+
detail: getPromptLocalize('breakingChange.hyphenItem.detail'),
182+
alwaysShow: true,
183+
placeholder: getPromptLocalize('breakingChange.message.placeholder'),
184+
},
185+
breakingChangeFormat: breakingChangeFormat,
186+
format: lineBreakFormatter,
187+
},
149188
{
150189
type: PROMPT_TYPES.QUICK_PICK,
151190
name: 'gitmoji',
@@ -169,7 +208,7 @@ export default async function prompts({
169208
name: 'subject',
170209
placeholder: getPromptLocalize('subject.placeholder'),
171210
validate(input: string) {
172-
const { type, scope, gitmoji } = commitMessage;
211+
const { type, scope, breakingChange, gitmoji } = commitMessage;
173212
const serializedSubject = serializeSubject({
174213
gitmoji,
175214
subject: input,
@@ -188,10 +227,14 @@ export default async function prompts({
188227

189228
let headerError = commitlint.lintHeader(
190229
serializeHeader({
191-
type,
192-
scope,
193-
gitmoji,
194-
subject: input,
230+
partialCommitMessage: {
231+
type,
232+
scope,
233+
breakingChange,
234+
gitmoji,
235+
subject: input,
236+
},
237+
detectBreakingChange: detectBreakingChange,
195238
}),
196239
);
197240
if (headerError) {
@@ -241,6 +284,10 @@ export default async function prompts({
241284

242285
if (question.name === 'gitmoji' && !gitmoji) return false;
243286

287+
if (question.name === 'breakingChange') {
288+
if (!promptBreakingChange) return false;
289+
}
290+
244291
if (question.name === 'body') {
245292
if (showEditor || !promptBody) return false;
246293
}

0 commit comments

Comments
 (0)