Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

feat(cz-commitlint): support customizable commit prompt with emojis #4540

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
parloti wants to merge 2 commits into conventional-changelog:master
base: master
Choose a base branch
Loading
from parloti:master
Open
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
272 changes: 271 additions & 1 deletion @commitlint/cz-commitlint/src/services/getRuleQuestionConfig.test.ts
View file Open in desktop
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { describe, test, expect } from "vitest";
import { RuleConfigSeverity } from "@commitlint/types";
import { describe, expect, test } from "vitest";

import { setPromptConfig } from "../store/prompts.js";
import { setRules } from "../store/rules.js";
Expand Down Expand Up @@ -253,6 +253,276 @@ describe("enum list", () => {
expect(enumList?.[1]).toBe("lint");
expect(enumList?.[2]).toBe("cli");
});

test("should format enum items with emojis and descriptions, ensuring consistent spacing", () => {
const ENUM_RULE_LIST = ["feat", "fix", "chore"];
setRules({
"type-enum": [RuleConfigSeverity.Error, "always", ENUM_RULE_LIST],
} as any);

setPromptConfig({
questions: {
type: {
enum: {
feat: {
description: "Features",
emoji: "✨",
},
fix: {
description: "Bug fixes",
emoji: "🐛",
},
chore: {
description: "Chore",
emoji: "♻️",
},
},
},
},
});

const enumList = getRuleQuestionConfig("type")?.enumList;
expect(enumList).toEqual([
{
name: "✨ feat: Features",
value: "feat",
short: "feat",
},
{
name: "🐛 fix: Bug fixes",
value: "fix",
short: "fix",
},
{
name: "♻️ chore: Chore",
value: "chore",
short: "chore",
},
]);
});

test("should handle custom alignment for emoji and description with extra space", () => {
const ENUM_RULE_LIST = ["feat", "fix", "chore"];
setRules({
"type-enum": [RuleConfigSeverity.Error, "always", ENUM_RULE_LIST],
} as any);

setPromptConfig({
questions: {
type: {
enum: {
feat: {
description: "Features",
emoji: "✨ ",
},
fix: {
description: "Bug fixes",
emoji: "🐛 ",
},
chore: {
description: "Chore",
emoji: "♻️ ",
},
},
},
},
});

const enumList = getRuleQuestionConfig("type")?.enumList;
expect(enumList).toEqual([
{
name: "✨ feat: Features",
value: "feat",
short: "feat",
},
{
name: "🐛 fix: Bug fixes",
value: "fix",
short: "fix",
},
{
name: "♻️ chore: Chore",
value: "chore",
short: "chore",
},
]);
});

test("should handle inconsistent emoji usage by using 4 blank spaces as a prefix", () => {
const ENUM_RULE_LIST = ["feat", "fix", "chore"];
setRules({
"type-enum": [RuleConfigSeverity.Error, "always", ENUM_RULE_LIST],
} as any);

setPromptConfig({
questions: {
type: {
enum: {
feat: {
description: "Features",
emoji: "✨",
},
fix: {
description: "Bug fixes",
},
chore: {
description: "Chore",
},
},
},
},
});

const enumList = getRuleQuestionConfig("type")?.enumList;
expect(enumList).toEqual([
{
name: "✨ feat: Features",
value: "feat",
short: "feat",
},
{
name: " fix: Bug fixes",
value: "fix",
short: "fix",
},
{
name: " chore: Chore",
value: "chore",
short: "chore",
},
]);
});

test("should handle no enums having emojis correctly", () => {
const ENUM_RULE_LIST = ["feat", "fix", "chore"];
setRules({
"type-enum": [RuleConfigSeverity.Error, "always", ENUM_RULE_LIST],
} as any);

setPromptConfig({
questions: {
type: {
enum: {
feat: {
description: "Features",
},
fix: {
description: "Bug fixes",
},
chore: {
description: "Chore",
},
},
},
},
});

const enumList = getRuleQuestionConfig("type")?.enumList;
expect(enumList).toEqual([
{
name: "feat: Features",
value: "feat",
short: "feat",
},
{
name: "fix: Bug fixes",
value: "fix",
short: "fix",
},
{
name: "chore: Chore",
value: "chore",
short: "chore",
},
]);
});

test("should include the emoji in the value when `emojiInHeader` is true", () => {
const ENUM_RULE_LIST = ["feat", "fix"];
setRules({
"type-enum": [RuleConfigSeverity.Error, "always", ENUM_RULE_LIST],
} as any);

setPromptConfig({
questions: {
type: {
emojiInHeader: true,
enum: {
feat: {
description: "Features",
emoji: "✨",
},
fix: {
description: "Bug fixes",
emoji: "🐛",
},
},
},
},
});

const enumList = getRuleQuestionConfig("type")?.enumList;
expect(enumList).toEqual([
{
name: "✨ feat: Features",
value: "✨ feat",
short: "feat",
},
{
name: "🐛 fix: Bug fixes",
value: "🐛 fix",
short: "fix",
},
]);
});

test("should trim empty spaces from emoji in the answer", () => {
const ENUM_RULE_LIST = ["feat", "fix", "chore"];
setRules({
"type-enum": [RuleConfigSeverity.Error, "always", ENUM_RULE_LIST],
} as any);

setPromptConfig({
questions: {
type: {
emojiInHeader: true,
enum: {
feat: {
description: "Features",
emoji: "✨ ",
},
fix: {
description: "Bug fixes",
emoji: "🐛 ",
},
chore: {
description: "Chore",
emoji: "♻️ ",
},
},
},
},
});

const enumList = getRuleQuestionConfig("type")?.enumList;
expect(enumList).toEqual([
{
name: "✨ feat: Features",
value: "✨ feat",
short: "feat",
},
{
name: "🐛 fix: Bug fixes",
value: "🐛 fix",
short: "fix",
},
{
name: "♻️ chore: Chore",
value: "♻️ chore",
short: "chore",
},
]);
});
});

test("should return correct question config", () => {
Expand Down
30 changes: 24 additions & 6 deletions @commitlint/cz-commitlint/src/services/getRuleQuestionConfig.ts
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -35,23 +35,41 @@ export default function (rulePrefix: RuleField): QuestionConfig | null {

if (enumRuleList) {
const enumDescriptions = questionSettings?.["enum"];
const emojiInHeader = questionSettings?.emojiInHeader;

if (enumDescriptions) {
const enumNames = Object.keys(enumDescriptions);
const longest = Math.max(
...enumRuleList.map((enumName) => enumName.length),
);
// TODO emoji + title
const firstHasEmoji =
(enumDescriptions[enumNames[0]]?.emoji?.length ?? 0) > 0;
const hasConsistentEmojiUsage = !enumRuleList.some(
(enumName) =>
(enumDescriptions[enumName]?.emoji?.length ?? 0) > 0 !==
firstHasEmoji,
);
enumList = enumRuleList
.sort((a, b) => enumNames.indexOf(a) - enumNames.indexOf(b))
.map((enumName) => {
const enumDescription = enumDescriptions[enumName]?.description;
if (enumDescription) {
return {
name: `${enumName}:`.padEnd(longest + 4) + enumDescription,
value: enumName,
short: enumName,
};
const emoji = enumDescriptions[enumName]?.emoji;

const emojiPrefix = emoji
? `${emoji} `
: hasConsistentEmojiUsage
? ""
: " ";

const paddedName = `${enumName}:`.padEnd(longest + 4);

const name = `${emojiPrefix}${paddedName}${enumDescription}`;

const value =
emojiInHeader && emoji ? `${emoji.trim()} ${enumName}` : enumName;

return { name, value, short: enumName };
} else {
return enumName;
}
Expand Down
1 change: 1 addition & 0 deletions @commitlint/types/src/prompt.ts
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export type PromptConfig = {
emoji?: string;
};
};
emojiInHeader?: boolean;
}
>
>;
Expand Down
Binary file modified docs/public/assets/cz-commitlint.png
View file Open in desktop
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
[フレーム]
Binary file added docs/public/assets/vs-code-commit-msg.png
View file Open in desktop
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
[フレーム]
Binary file added docs/public/assets/vs-code-emoji.png
View file Open in desktop
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
[フレーム]
Loading

AltStyle によって変換されたページ (->オリジナル) /