From 6f45e5552e6eb43868a71c8c296117b45c7773b9 Mon Sep 17 00:00:00 2001 From: Kerber0x Date: Thu, 1 Feb 2024 14:36:14 +0000 Subject: [PATCH] ci: improve pre-commit hook --- justfile | 3 ++ scripts/hooks/commit-msg.sh | 54 ++++++++++++++++++++++ scripts/hooks/pre-commit.sh | 90 +++++++++++++++++++++++-------------- 3 files changed, 114 insertions(+), 33 deletions(-) create mode 100755 scripts/hooks/commit-msg.sh diff --git a/justfile b/justfile index 30014e5e..8f01569f 100644 --- a/justfile +++ b/justfile @@ -18,6 +18,9 @@ test FEATURE='': cargo test --features {{FEATURE}} fi +fmt: + @just format + format: cargo fmt --all find . -type f -iname "*.toml" -print0 | xargs -0 taplo format diff --git a/scripts/hooks/commit-msg.sh b/scripts/hooks/commit-msg.sh new file mode 100755 index 00000000..d8bb464e --- /dev/null +++ b/scripts/hooks/commit-msg.sh @@ -0,0 +1,54 @@ +#!/bin/bash +export PATH=$PATH:/usr/local/bin + +# +# White Whale contracts commit hook, used to make sure commits follow the conventional commits format. +# See more at https://www.conventionalcommits.org/ +# +# Install the hook with the --install option. +# + +project_toplevel=$(git rev-parse --show-toplevel) +git_directory=$(git rev-parse --git-dir) + +install_hook() { + mkdir -p "$git_directory/hooks" + ln -sfv "$project_toplevel/scripts/hooks/commit-msg.sh" "$git_directory/hooks/commit-msg" +} + +if [ "$1" = "--install" ]; then + if [ -f "$git_directory/hooks/commit-msg" ]; then + read -r -p "There's an existing commit-msg hook. Do you want to overwrite it? [y/N] " response + case "$response" in + [yY][eE][sS] | [yY]) + install_hook + ;; + *) + printf "Skipping hook installation :(" + exit $? + ;; + esac + else + install_hook + fi + exit $? +fi + +printf "Checking commit message format...\n" + +COMMIT_MSG_FILE="$1" + +if [ ! -f "$COMMIT_MSG_FILE" ]; then + echo "Error: Commit message file not found." + exit 1 +fi + +COMMIT_MSG=$(cat "$COMMIT_MSG_FILE") + +# Regular expression to match Conventional Commits format +CONVENTIONAL_COMMIT_REGEX="^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\(\S+\))?: .+$" + +if ! echo "$COMMIT_MSG" | grep -qE "$CONVENTIONAL_COMMIT_REGEX"; then + echo "Commit message does not follow Conventional Commits format." + exit 1 +fi diff --git a/scripts/hooks/pre-commit.sh b/scripts/hooks/pre-commit.sh index b8cbe255..27af8d7b 100755 --- a/scripts/hooks/pre-commit.sh +++ b/scripts/hooks/pre-commit.sh @@ -13,6 +13,7 @@ git_directory=$(git rev-parse --git-dir) install_hook() { mkdir -p "$git_directory/hooks" ln -sfv "$project_toplevel/scripts/hooks/pre-commit.sh" "$git_directory/hooks/pre-commit" + cargo install taplo-cli --locked } if [ "$1" = "--install" ]; then @@ -39,46 +40,69 @@ format_check() { has_formatting_issues=0 first_file=1 + + # Check and format Rust files rust_staged_files=$(git diff --name-only --staged -- '*.rs') + format_files "$rust_staged_files" - # check for issues - for file in $rust_staged_files; do - format_check_result=$(rustfmt --check $file) - if [ "$format_check_result" != "" ]; then - if [ $first_file -eq 0 ]; then - printf "\n" - fi - printf "$file" - has_formatting_issues=1 - first_file=0 - fi + # Check and format TOML files + toml_staged_files=$(git diff --name-only --staged -- '*.toml') + format_files "$toml_staged_files" + + # Check and format Shell script files + sh_staged_files=$(git diff --name-only --staged -- '*.sh') + format_files "$sh_staged_files" + + if [ $has_formatting_issues -ne 0 ]; then + printf "\nSome files were formatted and added to the commit.\n" + fi +} + +format_files() { + local staged_files=$1 + + for file in $staged_files; do + case "$file" in + *.rs) + format_check_result=$(rustfmt --check $file 2>&1) + ;; + *.toml) + taplo fmt $file >/dev/null 2>&1 + git add $file + printf "$file\n" + ;; + *.sh) + format_check_result=$(shfmt -d $file 2>&1) + ;; + esac + + format_file done +} - if [ $has_formatting_issues -ne 0 ]; then # there are formatting issues - printf "\nFormatting issues were found in files listed above. Trying to format them for you...\n" - exit_code=0 +format_file() { + if [ "$format_check_result" != "" ]; then + if [ $first_file -eq 0 ]; then + printf "\n" + fi + printf "$file" + has_formatting_issues=1 + first_file=0 - for file in $rust_staged_files; do + case "$file" in + *.rs) rustfmt $file - format_exit_code=$? - - if [ $format_exit_code -ne 0 ]; then - # rustfmt couldn't format the current file - exit_code=1 - else - not_staged_file=$(git diff --name-only -- $file) - - if [ "$not_staged_file" != "" ]; then # it means the file changed and it's not staged, i.e. rustfmt did the job. - git add $not_staged_file - fi - fi - done - - if [ $exit_code -ne 0 ]; then - printf "rustfmt failed to format some files. Please review, fix them and stage them manually." - exit 1 - fi + ;; + *.sh) + shfmt -w $file + ;; + esac + # Add formatted file to commit if changes were made + not_staged_file=$(git diff --name-only -- $file) + if [ "$not_staged_file" != "" ]; then + git add $not_staged_file + fi fi }