
✨ feat: avoid commiting files with "TODO" ♻️ refactor: loop over all files, not just markdown and png. Useful to catch TODOs in Tera templates, for example.
174 lines
7.1 KiB
Bash
Executable File
174 lines
7.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
###################################################################################
|
|
# This script is run by git before a commit is made. #
|
|
# To use it, copy it to .git/hooks/pre-commit and make it executable. #
|
|
# Alternatively, run the following command from the root of the repo: #
|
|
# git config core.hooksPath .githooks #
|
|
# #
|
|
# FEATURES #
|
|
# Updates the "updated" field in the front matter of .md files. #
|
|
# Compresses PNG files with either oxipng or optipng if available. #
|
|
# Runs subset_font if config.toml has been modified. #
|
|
# Aborts the commit if a draft .md file or a file with "TODO" is being committed. #
|
|
# Updates the README if the line numbers for the language section have changed. #
|
|
###################################################################################
|
|
|
|
# Function to exit the script with an error message.
|
|
function error_exit() {
|
|
echo "ERROR: $1" >&2
|
|
exit "${2:-1}"
|
|
}
|
|
|
|
# Function to extract the date from the front matter.
|
|
function extract_date() {
|
|
local file="$1"
|
|
local field="$2"
|
|
grep -m 1 "^$field =" "$file" | sed -e "s/$field = //" -e 's/ *$//'
|
|
}
|
|
|
|
# Function to check if the .md file is a draft.
|
|
function is_draft() {
|
|
local file="$1"
|
|
awk '/^\+\+\+$/,/^\+\+\+$/ { if(/draft = true/) exit 0 } END { exit 1 }' "$file"
|
|
}
|
|
|
|
# Check if the file contains "TODO".
|
|
function contains_todo() {
|
|
local file="$1"
|
|
grep -q "TODO" "$file"
|
|
}
|
|
|
|
# Check if the script is being run from the root of the repo.
|
|
if [[ ! $(git rev-parse --show-toplevel) == $(pwd) ]]; then
|
|
error_exit "This script must be run from the root of the repo."
|
|
fi
|
|
|
|
# Check if oxipng is installed.
|
|
png_compressor=""
|
|
if command -v oxipng &> /dev/null; then
|
|
png_compressor="oxipng -o max"
|
|
elif command -v optipng &> /dev/null; then
|
|
png_compressor="optipng -o 7"
|
|
fi
|
|
|
|
##################################################################
|
|
# Compress PNG files with either oxipng or optipng if available. #
|
|
# Update the "updated" field in the front matter of .md files. #
|
|
# https://osc.garden/blog/zola-date-git-hook/ #
|
|
# Interrupt the commit if a draft .md file is being committed. #
|
|
##################################################################
|
|
|
|
# Get the newly added and modified files.
|
|
all_changed_files=$(git diff --cached --name-only --diff-filter=AM)
|
|
|
|
# Loop through each newly added or modified .md or .png file for PNG optimization and draft checking.
|
|
for file in $all_changed_files; do
|
|
# If the file is a PNG and png_compressor is set, compress it and add it to the commit.
|
|
if [[ "$file" == *.png ]] && [[ -n "$png_compressor" ]]; then
|
|
$png_compressor "$file" || error_exit "Failed to compress PNG file $file"
|
|
git add --force "$file" || error_exit "Failed to add compressed PNG file $file"
|
|
continue
|
|
fi
|
|
|
|
# If the file is an .md file and it's a draft, abort the commit.
|
|
if [[ "$file" == *.md ]]; then
|
|
if is_draft "$file"; then
|
|
error_exit "Draft file $file is being committed!"
|
|
fi
|
|
fi
|
|
|
|
# If the file contains "TODO", abort the commit.
|
|
if contains_todo "$file"; then
|
|
error_exit "File $file contains TODO! Remove or complete the TODO before committing."
|
|
fi
|
|
done
|
|
|
|
# Get the modified .md to update the "updated" field in the front matter.
|
|
modified_files=$(git diff --cached --name-only --diff-filter=M | grep -E '\.md$' | grep -v '_index.md$')
|
|
|
|
# Loop through each modified .md file.
|
|
for file in $modified_files; do
|
|
# Get the last modified date from the filesystem.
|
|
last_modified_date=$(date -r "$file" +'%Y-%m-%d')
|
|
|
|
# Extract the "date" field from the front matter.
|
|
date_value=$(extract_date "$file" "date")
|
|
|
|
# Skip the file if the last modified date is the same as the "date" field.
|
|
if [[ "$last_modified_date" == "$date_value" ]]; then
|
|
continue
|
|
fi
|
|
|
|
# Update the "updated" field with the last modified date.
|
|
# If the "updated" field doesn't exist, create it below the "date" field.
|
|
if ! awk -v date_line="$last_modified_date" 'BEGIN{FS=OFS=" = "; first = 1} {
|
|
if (/^date =/ && first) {
|
|
print; getline;
|
|
if (!/^updated =/) print "updated" OFS date_line;
|
|
first=0;
|
|
}
|
|
if (/^updated =/ && !first) gsub(/[^ ]*$/, date_line, $2);
|
|
print;
|
|
}' "$file" > "${file}.tmp"
|
|
then
|
|
error_exit "Failed to process $file with AWK"
|
|
fi
|
|
|
|
mv "${file}.tmp" "$file" || error_exit "Failed to overwrite $file with updated content"
|
|
|
|
# Stage the changes.
|
|
git add "$file"
|
|
done
|
|
|
|
#########################################################
|
|
# Run subset_font if config.toml has been modified. #
|
|
# https://welpo.github.io/tabi/blog/custom-font-subset/ #
|
|
#########################################################
|
|
if git diff --cached --name-only | grep -q "config.toml"; then
|
|
echo "config.toml modified. Running subset_font…"
|
|
|
|
# Call the subset_font script.
|
|
~/bin/subset_font -c config.toml -f static/fonts/Inter4.woff2 -o static/
|
|
|
|
# Add the generated subset.css file to the commit.
|
|
git add static/custom_subset.css
|
|
fi
|
|
|
|
################################################################################
|
|
# Update the README if the line numbers for the language section have changed. #
|
|
################################################################################
|
|
|
|
# File paths and names.
|
|
config_file="config.toml"
|
|
config_readme="README.md"
|
|
|
|
# Ensure the required files are present.
|
|
[ ! -f "$config_file" ] && error_exit "$config_file not found!"
|
|
[ ! -f "$config_readme" ] && error_exit "$config_readme not found!"
|
|
|
|
# Determine the line numbers for relevant sections in config.toml.
|
|
lang_start_line=$(grep -n "^\[languages.es\]$" "$config_file" | cut -d: -f1)
|
|
extra_start_line=$(grep -n "^\[extra\]$" "$config_file" | cut -d: -f1)
|
|
lang_end_line=$((extra_start_line - 2))
|
|
|
|
# Extract currently documented line numbers from README.
|
|
documented_lines=$(grep -o 'https://github.com/welpo/tabi/blob/main/config.toml#L[0-9]*-L[0-9]*' "$config_readme" | grep -o 'L[0-9]*-L[0-9]*')
|
|
doc_start_line=$(echo "$documented_lines" | cut -d'-' -f1 | tr -d 'L')
|
|
doc_end_line=$(echo "$documented_lines" | cut -d'-' -f2 | tr -d 'L')
|
|
|
|
# Ensure that the variables are set and are numbers.
|
|
if [[ ! $lang_start_line =~ ^[0-9]+$ ]] || [[ ! $doc_start_line =~ ^[0-9]+$ ]] || [[ ! $lang_end_line =~ ^[0-9]+$ ]] || [[ ! $doc_end_line =~ ^[0-9]+$ ]]; then
|
|
error_exit "Line number variables are not set correctly."
|
|
fi
|
|
|
|
# Update the README if there's a discrepancy in the line numbers.
|
|
if [ "$lang_start_line" -ne "$doc_start_line" ] || [ "$lang_end_line" -ne "$doc_end_line" ]; then
|
|
if ! perl -pi -e "s|https://github.com/welpo/tabi/blob/main/config.toml#L[0-9]*-L[0-9]*|https://github.com/welpo/tabi/blob/main/config.toml#L$lang_start_line-L$lang_end_line|g" "$config_readme"; then
|
|
error_exit "Perl processing failed for $config_readme"
|
|
fi
|
|
|
|
# Add updated README to commit.
|
|
git add "$config_readme"
|
|
fi
|