Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
131 changes: 130 additions & 1 deletion @commitlint/cz-commitlint/src/SectionHeader.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,13 @@ import { setRules } from "./store/rules.js";

beforeEach(() => {
setRules({});
setPromptConfig({});
setPromptConfig({
settings: {
scopeEnumSeparator: ",",
enableMultipleScopes: false,
useExclamationMark: false,
},
});
});
describe("getQuestions", () => {
test("should contain 'type','scope','subject'", () => {
Expand Down Expand Up @@ -120,6 +126,88 @@ describe("combineCommitMessage", () => {
});
expect(commitMessage).toBe("build(typescript)");
});
test("should add ! after type when isBreaking and useExclamationMark is enabled", () => {
setPromptConfig({
settings: {
useExclamationMark: true,
},
});
const commitMessage = combineCommitMessage({
type: "feat",
subject: "add new api",
isBreaking: true,
});
expect(commitMessage).toBe("feat!: add new api");
});

test("should add ! after scope when isBreaking and useExclamationMark is enabled", () => {
setPromptConfig({
settings: {
useExclamationMark: true,
},
});
const commitMessage = combineCommitMessage({
type: "feat",
scope: "api",
subject: "add new endpoint",
isBreaking: true,
});
expect(commitMessage).toBe("feat(api)!: add new endpoint");
});

test("should not add ! when isBreaking but useExclamationMark is disabled (default)", () => {
setPromptConfig({
settings: {
useExclamationMark: false,
},
});
const commitMessage = combineCommitMessage({
type: "feat",
subject: "add new api",
isBreaking: true,
});
expect(commitMessage).toBe("feat: add new api");
});

test("should not add ! when useExclamationMark is enabled but not breaking", () => {
setPromptConfig({
settings: {
useExclamationMark: true,
},
});
const commitMessage = combineCommitMessage({
type: "feat",
subject: "add new api",
});
expect(commitMessage).toBe("feat: add new api");
});

test("should add ! without subject when isBreaking and useExclamationMark is enabled", () => {
setPromptConfig({
settings: {
useExclamationMark: true,
},
});
const commitMessage = combineCommitMessage({
type: "feat",
scope: "api",
isBreaking: true,
});
expect(commitMessage).toBe("feat(api)!");
});

test("should not add ! when type and scope are both empty", () => {
setPromptConfig({
settings: {
useExclamationMark: true,
},
});
const commitMessage = combineCommitMessage({
isBreaking: true,
subject: "drop support",
});
expect(commitMessage).toBe("drop support");
});
});

describe("HeaderQuestion", () => {
Expand Down Expand Up @@ -153,4 +241,45 @@ describe("HeaderQuestion", () => {
"subject: subject over limit 6",
);
});

test("should reserve 1 char for '!' when useExclamationMark is enabled", () => {
const headerMaxLength = 20;
const type = "refactor";
const scope = "config";
// "refactor(config)" = 16 chars
const charsUsed = `${type}(${scope})`.length; // 16
const charsAvailable = headerMaxLength - charsUsed - 1; // -1 for '!'
setRules({
"header-max-length": [
RuleConfigSeverity.Error,
"always",
headerMaxLength,
],
"subject-max-length": [RuleConfigSeverity.Error, "always", 10],
});
setPromptConfig({
settings: {
useExclamationMark: true,
},
messages: {
skip: "(press enter to skip)",
max: "upper %d chars",
min: "%d chars at least",
emptyWarning: "%s can not be empty",
upperLimitWarning: "%s: %s over limit %d",
lowerLimitWarning: "%s: %s below limit %d",
},
});
const questions = getQuestions();
const answers = { type, scope };
const subject = questions[2];
(subject.message as any)(answers);

expect("fix".length).toBeLessThanOrEqual(charsAvailable);
expect(subject?.validate?.("fix", answers)).toBe(true);
expect("test".length).toBeGreaterThan(charsAvailable);
expect(subject?.validate?.("test", answers)).toBe(
"subject: subject over limit 1",
);
});
});
14 changes: 11 additions & 3 deletions @commitlint/cz-commitlint/src/SectionHeader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,22 @@ export class HeaderQuestion extends Question {
beforeQuestionStart(answers: Answers): void {
const headerRemainLength =
this.headerMaxLength - combineCommitMessage(answers).length;
this.maxLength = Math.min(this.maxLength, headerRemainLength);
// Reserve 1 char for '!' when useExclamationMark is enabled.
const reservedLength = getPromptSettings()["useExclamationMark"] ? 1 : 0;
const remainingLength = Math.max(0, headerRemainLength - reservedLength);
this.maxLength = Math.min(this.maxLength, remainingLength);
this.minLength = Math.min(this.minLength, this.headerMinLength);
}
}

export function combineCommitMessage(answers: Answers): string {
const { type = "", scope = "", subject = "" } = answers;
const prefix = `${type}${scope ? `(${scope})` : ""}`;
const { type = "", scope = "", subject = "", isBreaking } = answers;
const hasPrefix = Boolean(type || scope);
const breakingMark =
hasPrefix && isBreaking && getPromptSettings()["useExclamationMark"]
? "!"
: "";
const prefix = `${type}${scope ? `(${scope})` : ""}${breakingMark}`;
Comment thread
mrt181 marked this conversation as resolved.

if (subject) {
return ((prefix ? prefix + ": " : "") + subject).trim();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export default {
settings: {
scopeEnumSeparator: ",",
enableMultipleScopes: false,
useExclamationMark: false,
},
messages: {
skip: "(press enter to skip)",
Expand Down
1 change: 1 addition & 0 deletions @commitlint/types/src/prompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export type PromptConfig = {
settings: {
scopeEnumSeparator: string;
enableMultipleScopes: boolean;
useExclamationMark: boolean;
Comment thread
mrt181 marked this conversation as resolved.
};
messages: PromptMessages;
questions: Partial<
Expand Down
1 change: 1 addition & 0 deletions docs/reference/prompt.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Set optional options.

- `enableMultipleScopes`: `(boolean)` Enable multiple scopes, select scope with a radio list, disabled by default.
- `scopeEnumSeparator`: `(string)` Commitlint supports [multiple scopes](/concepts/commit-conventions#multiple-scopes), you can specify the delimiter. It is applied when `enableMultipleScopes` set true.
- `useExclamationMark`: `(boolean)` Append `!` after the type/scope in the commit header when a breaking change is indicated, disabled by default.

## `messages`

Expand Down