From ea608267342ec958fe8194d1c9375e4c14310618 Mon Sep 17 00:00:00 2001 From: reynkonig Date: Thu, 18 Jun 2026 17:36:19 +0800 Subject: [PATCH] Support git autosquash `amend!` prefix in commit message task MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `git commit --fixup=amend:` / `--fixup=reword:` produce an `amend! …` subject, the sibling of `fixup!`/`squash!`. These were special-cased in three places but `amend!` was missing from all of them, so amend commits were rejected. Centralize the prefixes into one constant and add `amend`. --- src/Task/Git/CommitMessage.php | 16 +++++-- test/Unit/Task/Git/CommitMessageTest.php | 59 ++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 3 deletions(-) diff --git a/src/Task/Git/CommitMessage.php b/src/Task/Git/CommitMessage.php index e81fe97ff..ad0e09293 100644 --- a/src/Task/Git/CommitMessage.php +++ b/src/Task/Git/CommitMessage.php @@ -23,6 +23,12 @@ class CommitMessage implements TaskInterface public const MERGE_COMMIT_REGEX = '(Merge branch|tag \'.+\'(?:\s.+)?|Merge remote-tracking branch \'.+\'|Merge pull request #\d+\s.+)'; + /** + * Subject prefixes added by git's autosquash helpers + * (`git commit --fixup`, `--squash`, `--fixup=amend:` and `--fixup=reword:`). + */ + private const AUTOSQUASH_PREFIXES = 'fixup|squash|amend'; + /** * @var TaskConfigInterface */ @@ -252,7 +258,7 @@ private function runMatcher(array $config, string $commitMessage, string $rule, private function getSpecialPrefixLength(string $string): int { - if (1 !== preg_match('/^(fixup|squash)! /', $string, $match)) { + if (1 !== preg_match('/^(' . self::AUTOSQUASH_PREFIXES . ')! /', $string, $match)) { return 0; } @@ -312,7 +318,11 @@ private function subjectIsCapitalized(GitCommitMsgContext $context): bool $firstLetter = $match[1] ?? ''; - return !(1 !== preg_match('/^(fixup|squash)!/u', $subject) && 1 !== preg_match('/[[:upper:]]/u', $firstLetter)); + if (1 === preg_match('/^(' . self::AUTOSQUASH_PREFIXES . ')!/u', $subject)) { + return true; + } + + return 1 === preg_match('/[[:upper:]]/u', $firstLetter); } private function subjectIsSingleLined(GitCommitMsgContext $context): bool @@ -375,7 +385,7 @@ private function checkTypeScopeConventions(GitCommitMsgContext $context): void $scopes = $config['type_scope_conventions']['scopes'] ?? []; - $specialPrefix = '(?:(?:fixup|squash)! )?'; + $specialPrefix = '(?:(?:' . self::AUTOSQUASH_PREFIXES . ')! )?'; $typesPattern = '([a-zA-Z0-9]+)'; $scopesPattern = '(:\s|(\(.+\)?:\s))'; diff --git a/test/Unit/Task/Git/CommitMessageTest.php b/test/Unit/Task/Git/CommitMessageTest.php index c5c4b6dbd..ae9952e66 100644 --- a/test/Unit/Task/Git/CommitMessageTest.php +++ b/test/Unit/Task/Git/CommitMessageTest.php @@ -488,6 +488,14 @@ function () { function () { } ]; + yield 'dont-enforce_capitalized_subject_amend' => [ + [ + 'enforce_capitalized_subject' => true, + ], + self::mockCommitMsgContext(self::amend('no capital subject')), + function () { + } + ]; yield 'enforce_capitalized_subject_special_utf8_char' => [ [ 'enforce_capitalized_subject' => true, @@ -560,6 +568,14 @@ function () { function () { } ]; + yield 'enforce_text_with_special_prefix_amend' => [ + [ + 'max_subject_width' => 10, + ], + self::mockCommitMsgContext(self::amend('123456789')), + function () { + } + ]; yield 'enforce_text_with_ignore_below_comment' => [ [ 'enforce_single_lined_subject' => false, @@ -688,6 +704,38 @@ function () { function () { }, ]; + yield 'amend_type_scope_conventions_match_type_without_scope' => [ + [ + 'enforce_capitalized_subject' => false, + 'type_scope_conventions' => [ + 'types' => [ + 'fix' + ], + 'scopes' => [ + 'app' + ] + ], + ], + self::mockCommitMsgContext(self::amend('fix: match type scope convention')), + function () { + }, + ]; + yield 'amend_type_scope_conventions_match_type_with_scope' => [ + [ + 'enforce_capitalized_subject' => false, + 'type_scope_conventions' => [ + 'types' => [ + 'fix' + ], + 'scopes' => [ + 'app' + ] + ], + ], + self::mockCommitMsgContext(self::amend('fix(app): match type scope convention')), + function () { + }, + ]; yield 'skip_type_scope_conventions_on_merge' => [ [ 'enforce_capitalized_subject' => false, @@ -947,4 +995,15 @@ private static function squash(string ... $messages): string ...$messages ); } + + private static function amend(string ... $messages): string + { + $subject = array_shift($messages); + + return self::buildMessage( + 'amend! '.$subject, + '# This was created by running git commit --fixup=amend:...', + ...$messages + ); + } }