Skip to content

Commit 5930a02

Browse files
JSAbrahamsJoel Abrahams
andauthored
Feat: githooks, nix dev env and nu shell (#472)
* feat: add githooks to the project * doc: update CONTRIBUTING * chore: spellcheck hook checks for jargon list * fix: ensure githooks actually run * chore: add nix develop environment * chore: skip checks if not relevant * fix: rust version on CI * doc: add nix installation instructions --------- Co-authored-by: Joel Abrahams <joel@q-bird.nl>
1 parent e1b4f94 commit 5930a02

29 files changed

Lines changed: 795 additions & 177 deletions

.config/nushell/config.nu

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
$env.config.show_banner = false
2+
3+
# Aliases
4+
5+
alias gc = git commit
6+
alias gst = git status
7+
alias gp = git push
8+
alias ga = git add
9+
alias gl = git log --oneline
10+
11+
# Startship prompt
12+
13+
# Tell Starship which shell to target
14+
$env.STARSHIP_SHELL = "nu"
15+
16+
# Create a left-side prompt via Starship
17+
def create_left_prompt [] {
18+
starship prompt --cmd-duration $env.CMD_DURATION_MS --status=$env.LAST_EXIT_CODE
19+
}
20+
21+
# Hook it into Nushell’s prompt
22+
$env.PROMPT_COMMAND = { || create_left_prompt }
23+
$env.PROMPT_COMMAND_RIGHT = ""
24+
25+
# Tweak the indicators (optional)
26+
$env.PROMPT_INDICATOR = ""
27+
$env.PROMPT_INDICATOR_VI_INSERT = ": "
28+
$env.PROMPT_INDICATOR_VI_NORMAL = ""
29+
$env.PROMPT_MULTILINE_INDICATOR = "::: "

.config/nushell/env.nu

Whitespace-only changes.

.gitattributes

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Git will always convert line endings to LF on checkout.
2+
text eol=lf

.githooks/commit-msg

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#!/usr/bin/env bash
2+
3+
. ./scripts/log.sh
4+
export LOG_LEVEL=4 # debug
5+
. ./.githooks/util
6+
7+
log_info "Running commit-msg checks"
8+
9+
msgfile="$1"
10+
11+
export SUBJECT_LINE=$(head -n1 "$msgfile")
12+
13+
export SECOND_LINE=$(cat $msgfile | sed -n '2p')
14+
# This reads the file and cuts at the first 'diff --git' (and any later lines).
15+
# use tail to skip first 2 lines, and drop comment lines
16+
export BODY=$(sed '/^diff --git/,$d' "$msgfile" | tail -n +2 | sed '/^#/d')
17+
18+
export WORD_COUNT=$(echo "$SUBJECT_LINE" | wc -w)
19+
export LINE_COUNT=$(cat $msgfile | wc -l)
20+
21+
export VALID_TYPES="doc test feat fix style refactor revert git chore perf build ci cd deploy security"
22+
23+
print_help_msg() {
24+
log_error "Please fix commit message and then commit again"
25+
log_error "Valid commit message has a first line of the form '<type>: <short summary>', where"
26+
log_error "- <type> is one of: ${VALID_TYPES// /, }"
27+
log_error "- The entire first line of the commit message is less than 50 characters"
28+
log_error "- The subject line does *not* end with a period"
29+
log_error "Additionally, if there is a body"
30+
log_error "- There must be a newline between the subject line (first line) and body"
31+
log_error "- Each body line may be no more than 72 characters"
32+
}
33+
export -f print_help_msg
34+
35+
set -euo pipefail
36+
37+
if [[ "$SUBJECT_LINE" == "dropme"* || "$SUBJECT_LINE" == "fixup" || "$SUBJECT_LINE" == "[skip]"* ]]; then
38+
log_warn "Commit message '$SUBJECT_LINE' is allowed but should be removed before merging with base branch."
39+
else
40+
# do proper checks
41+
for script in "$(dirname "$0")/commit-msg"*; do
42+
if [ "$script" = "$0" ]; then
43+
continue # dont run self
44+
fi
45+
46+
"$script" $@
47+
done
48+
fi
49+
50+
log_info "Commit message check passed"

.githooks/commit-msg_0_warnings

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
2+
. ./scripts/log.sh
3+
export LOG_LEVEL=4 # debug
4+
. ./.githooks/util
5+
6+
log_trace "Running $0"
7+
8+
if ! min_bash_version 4; then
9+
log_warn "Cannot perform spellcheck"
10+
fi
11+
12+
# require bash version 4 for 'mapfile'
13+
if which_bin aspell; then
14+
jargon_list=jargon.txt
15+
log_debug "Performing spellcheck, using custom whitelist '$jargon_list'"
16+
# aspell also has a --personal option to add a custom whitelist, but then the file must have metadata at the top which is ugly
17+
# instead, we just manually remove entries manually which are in this whitelist
18+
misspelled=$(printf "%s\n" "$SUBJECT_LINE" | aspell --personal="$jargon_list" --lang=en_US list)
19+
20+
mapfile -t uniq_misspelled < <(echo "$misspelled" | sort -u)
21+
22+
# filter out words which are whitelisted
23+
mapfile -t whitelist < "$jargon_list"
24+
filtered_misspelled=()
25+
for w in "${uniq_misspelled[@]}"; do
26+
# If $w is NOT exactly in the whitelist, keep it
27+
if ! contains_element "$w" "${whitelist[@]}"; then
28+
filtered_misspelled+=("$w")
29+
fi
30+
done
31+
32+
if [[ -n "$filtered_misspelled" ]]; then
33+
log_warn -n "Subject line contains ${#filtered_misspelled[@]} unknown "
34+
if [ "${#filtered_misspelled[@]}" -eq 1 ]; then
35+
echo "word:"
36+
else
37+
echo "words:"
38+
fi
39+
40+
for w in "${filtered_misspelled[@]}"; do
41+
log_warn "- '$w'"
42+
done
43+
log_warn "hint: if you think this word is correctly spelled, consider adding it to '$jargon_list'"
44+
fi
45+
fi
46+
47+
min_words=5
48+
if (( WORD_COUNT < min_words )); then
49+
log_warn "Subject line is less than $min_words words (was $WORD_COUNT), consider being more descriptive: '$SUBJECT_LINE'"
50+
fi

.githooks/commit-msg_1_errors

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
#!/usr/bin/env bash
2+
3+
. ./scripts/log.sh
4+
export LOG_LEVEL=4 # debug
5+
. ./.githooks/util
6+
7+
log_trace "Running $0"
8+
9+
if [ -z "$SUBJECT_LINE" ]; then
10+
log_error "Commit message cannot be empty"
11+
print_help_msg
12+
exit 1
13+
fi
14+
15+
if [[ "$SUBJECT_LINE" != *": "* ]]; then
16+
log_error "Commit message has invalid format: '$SUBJECT_LINE'"
17+
print_help_msg
18+
exit 1
19+
fi
20+
21+
type="${SUBJECT_LINE%%:*}"
22+
if ! grep -qx "$type" <(printf "%s\n" $VALID_TYPES); then
23+
log_error "Commit message has invalid type: '$type'"
24+
log_error "Allowed types are: $VALID_TYPES"
25+
print_help_msg
26+
exit 1
27+
fi
28+
29+
summary="${SUBJECT_LINE#*: }"
30+
if [[ -z "$summary" ]]; then
31+
log_error "Commit message missing summary"
32+
log_error "The part after ":" must describe your change."
33+
print_help_msg
34+
exit 1
35+
fi
36+
37+
len_SUBJECT_LINE=${#SUBJECT_LINE}
38+
if (( len_SUBJECT_LINE > 50 )); then
39+
log_error "First line of commit message is too long: $len_SUBJECT_LINE characters (max 50)."
40+
41+
# print the part which is too long in red
42+
prefix="${SUBJECT_LINE:0:50}" # everything before 50th place
43+
suffix="${SUBJECT_LINE:50}" # everything after 50th place
44+
log_error "Message subject line, with excessive characters shown in red: "
45+
log_error
46+
log_error -n && printf "%s%b\n" "$prefix" "${ANSI_RED}${suffix}${ANSI_NC}"
47+
log_error
48+
49+
print_help_msg
50+
exit 1
51+
fi
52+
53+
if [[ "$SUBJECT_LINE" == *."" ]]; then
54+
log_error "Subject line should not end with a period: '$SUBJECT_LINE'"
55+
print_help_msg
56+
exit 1
57+
fi
58+
59+
if (( LINE_COUNT > 1 )); then
60+
# If there's a body, ensure blank line separator
61+
if [ -n "$SECOND_LINE" ]; then
62+
log_error "Missing blank line between subject and body: '$SECOND_LINE'"
63+
print_help_msg
64+
exit 1
65+
fi
66+
fi
67+
68+
line_no=0
69+
found_too_long_body_line=false
70+
while IFS= read -r line; do
71+
# skip blank lines
72+
[[ -z "$line" ]] && { (( line_no++ )); continue; }
73+
74+
len=${#line}
75+
if (( len > 72 )); then
76+
prefix="${line:0:72}" # everything before 72nd place
77+
suffix="${line:72}" # everything after 72nd place
78+
79+
log_error "Body line $line_no is too long: $len characters (max 72):"
80+
log_error
81+
log_error -n && printf "%s%b\n" "$prefix" "${ANSI_RED}${suffix}${ANSI_NC}"
82+
log_error
83+
84+
found_too_long_body_line=true
85+
fi
86+
(( line_no++ ))
87+
done <<< "$BODY"
88+
89+
if [ "$found_too_long_body_line" = "true" ]; then
90+
exit 1
91+
fi

.githooks/pre-commit

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#!/usr/bin/env bash
2+
3+
. ./scripts/log.sh
4+
export LOG_LEVEL=4 # debug
5+
. ./.githooks/util
6+
7+
log_info "Running pre-commit checks"
8+
9+
set -euo pipefail
10+
11+
for script in "$(dirname "$0")/pre-commit"*; do
12+
if [ "$script" = "$0" ]; then
13+
continue # dont run self
14+
fi
15+
16+
"$script" $@
17+
done
18+
19+
log_info "Pre-commit checks passed"

.githooks/pre-commit_0_toml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#!/usr/bin/env bash
2+
3+
. ./scripts/log.sh
4+
export LOG_LEVEL=4 # debug
5+
. ./.githooks/util
6+
7+
if ! git diff --cached --name-only --diff-filter=ACM | grep -q '^Cargo\.toml$'; then
8+
log_trace "No changes in Cargo.toml."
9+
exit 0
10+
fi
11+
12+
cargo sort
13+
if [ $? -ne 0 ]; then
14+
log_error "Dependencies in $project_dir/Cargo.toml not in alphabetical order, please run \"cargo sort\" in $project_dir"
15+
exit 1
16+
fi

.githooks/pre-commit_1_cargo

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#!/usr/bin/env bash
2+
3+
. ./scripts/log.sh
4+
export LOG_LEVEL=4 # debug
5+
. ./.githooks/util
6+
7+
# only run if Cargo.toml or any *.rs file is in the staged diff
8+
if ! git diff --cached --name-only --diff-filter=ACM \
9+
| grep -Eq '\.(rs|toml)$'; then
10+
log_trace "No Rust source or Cargo.toml changes detected, skipping cargo checks."
11+
exit 0
12+
fi
13+
14+
log_info "Running cargo fmt"
15+
cargo fmt --all -- --check
16+
if [ $? -ne 0 ]; then
17+
log_error "cargo fmt failed. Please format your code before committing."
18+
exit 1
19+
fi
20+
21+
log_info "${INFO} Running cargo check tests"
22+
cargo check --tests --all
23+
if [ $? -ne 0 ]; then
24+
log_error "cargo check --tests failed. Please fix your test compilation errors before committing."
25+
exit 1
26+
fi
27+
cargo check --tests --all --release
28+
if [ $? -ne 0 ]; then
29+
log_error "cargo check --tests failed. Please fix your test compilation errors before committing."
30+
exit 1
31+
fi
32+
33+
cargo sort
34+
if [ $? -ne 0 ]; then
35+
log_error "Dependencies in $project_dir/Cargo.toml not in alphabetical order, please run \"cargo sort\" in $project_dir"
36+
exit 1
37+
fi
38+
39+
log_info "Running cargo clippy"
40+
cargo clippy -- -D warnings
41+
if [ $? -ne 0 ]; then
42+
log_error "cargo clippy found issues. Please fix them before committing."
43+
exit 1
44+
fi
45+
cargo clippy --all-features --release -- -D warnings
46+
if [ $? -ne 0 ]; then
47+
log_error "cargo clippy found issues. Please fix them before committing."
48+
exit 1
49+
fi
50+
51+
log_info "Running cargo check benches"
52+
cargo check --benches --release
53+
if [ $? -ne 0 ]; then
54+
log_error "cargo check --benches failed. Please fix your benchmarks before committing."
55+
exit 1
56+
fi
57+
58+
log_info "Running cargo check --benches --all-features"
59+
cargo check --benches --release --all-features
60+
if [ $? -ne 0 ]; then
61+
log_error "cargo check --benches failed. Please fix your benchmarks before committing."
62+
exit 1
63+
fi

.githooks/pre-push

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#!/usr/bin/env bash
2+
3+
. ./scripts/log.sh
4+
export LOG_LEVEL=4 # debug
5+
6+
set -euo pipefail
7+
8+
log_info "Running pre-push checks"
9+
10+
for script in "$(dirname "$0")/pre-push"*; do
11+
if [ "$script" = "$0" ]; then
12+
continue # dont run self
13+
fi
14+
15+
"$script" $@
16+
done
17+
18+
log_info "Pre-push checks passed"

0 commit comments

Comments
 (0)