diff --git a/src/check_formalities.sh b/src/check_formalities.sh index 4b2878a..e4c1442 100755 --- a/src/check_formalities.sh +++ b/src/check_formalities.sh @@ -61,6 +61,7 @@ SKIP_REASONS=() # Use these global vars to improve header creation readability COMMIT="" HEADER_SET=0 +IS_FIXUP=0 REPO_PATH=${1:+-C "$1"} # shellcheck disable=SC2206 @@ -230,6 +231,8 @@ is_not_alias() { [[ ! "$1" =~ [^[:space:]] ]]; } # shellcheck disable=SC2329 is_not_name() { [[ ! "$1" =~ [^[:space:]]+[[:space:]][^[:space:]]+ ]]; } is_revert() { [[ "$1" == "Revert "* ]]; } +is_fixup_or_squash() { [[ "$1" =~ ^(fixup|squash)! ]]; } +is_in_fixup_mode() { [ "$IS_FIXUP" = 1 ]; } is_warn() { [ "$1" = "$RES_WARN" ]; } # shellcheck disable=SC2329 omits() { [[ "$1" != *"$2"* ]]; } @@ -299,6 +302,10 @@ reset_skip_reasons() { if [ $? = 0 ]; then push_skip_reason "authored by $exception" fi + + if is_in_fixup_mode; then + push_skip_reason 'fixup or squash commit' + fi } get_arity() { @@ -515,6 +522,8 @@ check_body() { check \ -rule 'Commit message must exist' \ -always \ + -skip-if is_in_fixup_mode \ + -skip-reason 'fixup or squash commit' \ -fail-if is_body_empty "$body" \ -fail-set-skip 'missing commit message' @@ -592,6 +601,7 @@ main() { do HEADER_SET=0 COMMIT="$commit" + IS_FIXUP=0 echo "$commit_header" @@ -606,6 +616,16 @@ main() { continue fi + check \ + -rule 'Fixup commit has been detected' \ + -warn-if is_fixup_or_squash "$subject" + + if is_warn $?; then + output_raw "Fixup commit has been detected, skipping formality checks for now. This allows easier review of individual changes. Please squash these commits before merging, after which formality checks will be enforced." + echo + IS_FIXUP=1 + fi + reset_skip_reasons "$author_email" check_name 'Author' "$author_name" check_email 'Author' "$author_email" diff --git a/src/test.sh b/src/test.sh index e97ac5b..254c1f5 100755 --- a/src/test.sh +++ b/src/test.sh @@ -90,7 +90,7 @@ define() { define \ -test 'Good commit' \ - -expected '0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3' \ + -expected '0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3' \ -author 'Good Author' \ -email 'good.author@example.com' \ -subject 'package: add new feature' \ @@ -102,7 +102,7 @@ define \ define \ -test 'Subject: double prefix' \ - -expected '0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3' \ + -expected '0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3' \ -author 'Good Author' \ -email 'good.author@example.com' \ -subject 'kernel: 6.18: add new feature' \ @@ -114,7 +114,7 @@ define \ define \ -test 'Subject: double prefix and capitalized first word' \ - -expected '0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 3' \ + -expected '0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 3' \ -author 'Good Author' \ -email 'good.author@example.com' \ -subject 'kernel: 6.18: Add new feature' \ @@ -126,7 +126,7 @@ define \ define \ -test 'Bad check parsing test' \ - -expected '0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3' \ + -expected '0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3' \ -author 'Good Author' \ -email 'good.author@example.com' \ -subject 'package: add new feature' \ @@ -142,7 +142,7 @@ define \ define \ -test 'Revert commit' \ - -expected '0 0 0 0 0 0 3 3 3 3 3 0 0 0 0 3' \ + -expected '0 0 0 0 0 0 0 3 3 3 3 3 0 0 0 0 3' \ -author 'Revert Author' \ -email 'revert.author@example.com' \ -subject "Revert 'package: add new feature'" \ @@ -152,10 +152,36 @@ define \ Signed-off-by: Revert Author EOF +# shellcheck disable=SC2016 +define \ + -test 'Fixup commit' \ + -expected '0 0 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3' \ + -author 'Good Author' \ + -email 'good.author@example.com' \ + -subject 'fixup! package: subject' \ + -body <<-'EOF' + This is a fixup commit. + + Signed-off-by: Good Author + EOF + +# shellcheck disable=SC2016 +define \ + -test 'Squash commit' \ + -expected '0 0 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3' \ + -author 'Good Author' \ + -email 'good.author@example.com' \ + -subject 'squash! package: subject' \ + -body <<-'EOF' + This is a squash commit. + + Signed-off-by: Good Author + EOF + # shellcheck disable=SC2016 define \ -test 'Body: malicious body shell injection' \ - -expected '0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3' \ + -expected '0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3' \ -author 'Good Author' \ -email 'good.author@example.com' \ -subject 'test: malicious body shell injection' \ @@ -167,7 +193,7 @@ define \ define \ -test 'Body: malicious body check injection' \ - -expected '0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3' \ + -expected '0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3' \ -author 'Good Author' \ -email 'good.author@example.com' \ -subject 'test: malicious body check injection' \ @@ -179,7 +205,7 @@ define \ define \ -test 'Body: missing Signed-off-by but check disabled' \ - -expected '0 0 0 0 0 0 0 0 0 0 0 3 3 0 0 3' \ + -expected '0 0 0 0 0 0 0 0 0 0 0 0 3 3 0 0 3' \ -author 'Good Author' \ -email 'good.author@example.com' \ -subject 'test: fail on missing signed-off-by' \ @@ -188,7 +214,7 @@ define \ define \ -test 'Body: mismatched Signed-off-by but check disabled' \ - -expected '0 0 0 0 0 0 0 0 0 0 0 3 3 0 0 3' \ + -expected '0 0 0 0 0 0 0 0 0 0 0 0 3 3 0 0 3' \ -author 'Good Author' \ -email 'good.author@example.com' \ -subject 'test: fail on mismatched signed-off-by' \ @@ -201,7 +227,7 @@ define \ define \ -test 'Bad author email (GitHub noreply)' \ - -expected '0 0 0 1 0 1 0 0 0 0 0 0 1 0 0 3' \ + -expected '0 0 0 0 1 0 1 0 0 0 0 0 0 1 0 0 3' \ -author 'Bad Email' \ -email 'bad.email@users.noreply.github.com' \ -subject 'test: fail on bad author email' \ @@ -213,7 +239,7 @@ define \ define \ -test 'Subject: starts with whitespace' \ - -expected '0 0 0 0 0 0 1 1 3 0 0 0 0 0 0 3' \ + -expected '0 0 0 0 0 0 0 1 1 3 0 0 0 0 0 0 3' \ -author 'Good Author' \ -email 'good.author@example.com' \ -subject ' package: subject starts with whitespace' \ @@ -225,7 +251,7 @@ define \ define \ -test 'Subject: no prefix' \ - -expected '0 0 0 0 0 0 0 1 3 0 0 0 0 0 0 3' \ + -expected '0 0 0 0 0 0 0 0 1 3 0 0 0 0 0 0 3' \ -author 'Good Author' \ -email 'good.author@example.com' \ -subject 'This subject has no prefix' \ @@ -237,7 +263,7 @@ define \ define \ -test 'Subject: capitalized first word' \ - -expected '0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 3' \ + -expected '0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 3' \ -author 'Good Author' \ -email 'good.author@example.com' \ -subject 'package: Capitalized first word' \ @@ -249,7 +275,7 @@ define \ define \ -test 'Subject: ends with a period' \ - -expected '0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 3' \ + -expected '0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 3' \ -author 'Good Author' \ -email 'good.author@example.com' \ -subject 'package: subject ends with a period.' \ @@ -261,7 +287,7 @@ define \ define \ -test 'Subject: too long (hard limit)' \ - -expected '0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 3' \ + -expected '0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 3' \ -author 'Good Author' \ -email 'good.author@example.com' \ -subject 'package: this subject is way too long and should fail the hard limit check of 60 chars' \ @@ -273,7 +299,7 @@ define \ define \ -test 'Body: missing Signed-off-by' \ - -expected '0 0 0 0 0 0 0 0 0 0 0 1 3 0 0 3' \ + -expected '0 0 0 0 0 0 0 0 0 0 0 0 1 3 0 0 3' \ -author 'Good Author' \ -email 'good.author@example.com' \ -subject 'test: fail on missing signed-off-by' \ @@ -281,7 +307,7 @@ define \ define \ -test 'Body: mismatched Signed-off-by' \ - -expected '0 0 0 0 0 0 0 0 0 0 0 1 3 0 0 3' \ + -expected '0 0 0 0 0 0 0 0 0 0 0 0 1 3 0 0 3' \ -author 'Good Author' \ -email 'good.author@example.com' \ -subject 'test: fail on mismatched signed-off-by' \ @@ -293,7 +319,7 @@ define \ define \ -test 'Body: empty' \ - -expected '0 0 0 0 0 0 0 0 0 0 0 0 0 1 3 3' \ + -expected '0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 3 3' \ -author 'Good Author' \ -email 'good.author@example.com' \ -subject 'test: fail on empty body' \ @@ -301,7 +327,7 @@ define \ define \ -test 'Author name is a single word' \ - -expected '0 0 2 0 2 0 0 0 0 0 0 0 0 0 0 3' \ + -expected '0 0 0 2 0 2 0 0 0 0 0 0 0 0 0 0 3' \ -author 'Nickname' \ -email 'nickname@example.com' \ -subject 'test: warn on single-word author name' \ @@ -313,7 +339,7 @@ define \ define \ -test 'Subject: too long (soft limit)' \ - -expected '0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 3' \ + -expected '0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 3' \ -author 'Good Author' \ -email 'good.author@example.com' \ -subject 'package: this subject is long and should trigger a warning' \ @@ -325,7 +351,7 @@ define \ define \ -test 'Body: line too long' \ - -expected '0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3' \ + -expected '0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3' \ -author 'Good Author' \ -email 'good.author@example.com' \ -subject 'test: warn on long body line' \ @@ -337,7 +363,7 @@ define \ define \ -test 'Body: line almost too long' \ - -expected '0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3' \ + -expected '0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3' \ -author 'Good Author' \ -email 'good.author@example.com' \ -subject 'test: pass on not too long body line' \ @@ -349,7 +375,7 @@ define \ define \ -test 'Exception: dependabot' \ - -expected '0 0 3 3 3 3 3 3 3 3 3 3 3 0 3 3' \ + -expected '0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 3 3' \ -author 'dependabot[bot]' \ -email 'dependabot[bot]@users.noreply.github.com' \ -subject 'CI: bump something from 1 to 2' \ @@ -360,7 +386,7 @@ define \ define \ -test 'No exception: dependabot' \ - -expected '0 0 2 1 2 1 0 0 0 0 0 1 3 0 0 3' \ + -expected '0 0 0 2 1 2 1 0 0 0 0 0 1 3 0 0 3' \ -author 'dependabot[bot]' \ -email 'dependabot[bot]@users.noreply.github.com' \ -subject 'CI: bump something from 1 to 2' \ @@ -370,7 +396,7 @@ define \ define \ -test 'Exception: weblate' \ - -expected '0 0 3 3 3 3 3 3 3 3 3 3 3 0 3 3' \ + -expected '0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 3 3' \ -author 'Hosted Weblate' \ -email 'hosted@weblate.org' \ -subject 'Translated using Weblate (English)' \ @@ -381,7 +407,7 @@ define \ define \ -test 'No exception: weblate' \ - -expected '0 0 0 0 0 0 0 1 3 0 0 1 3 0 0 3' \ + -expected '0 0 0 0 0 0 0 0 1 3 0 0 1 3 0 0 3' \ -author 'Hosted Weblate' \ -email 'hosted@weblate.org' \ -subject 'Translated using Weblate (English)' \ @@ -400,7 +426,7 @@ define \ define \ -test 'PR from master' \ - -expected '1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3' \ + -expected '1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3' \ -author 'Good Author' \ -email 'good.author@example.com' \ -subject 'package: add new feature' \ @@ -415,7 +441,7 @@ define \ define \ -test 'Feature branch check disabled' \ - -expected '3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3' \ + -expected '3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3' \ -author 'Good Author' \ -email 'good.author@example.com' \ -subject 'package: add new feature' \ @@ -428,7 +454,7 @@ define \ define \ -test 'Feature branch check enabled, PR from main fails' \ - -expected '1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3' \ + -expected '1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3' \ -author 'Good Author' \ -email 'good.author@example.com' \ -subject 'package: add new feature' \ @@ -442,7 +468,7 @@ define \ define \ -test 'Feature branch check enabled, PR from feature branch passes' \ - -expected '0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3' \ + -expected '0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3' \ -author 'Good Author' \ -email 'good.author@example.com' \ -subject 'package: add new feature' \