From 1b0c13109053edbb774c2d756506c58163dcc926 Mon Sep 17 00:00:00 2001 From: Dennis Luxen Date: Sat, 25 Apr 2026 21:03:20 +0200 Subject: [PATCH 1/7] Add CI sanity checks workflow - HTML syntax validation using tidy - JSON validity checks - CSS brace matching - Local link validation - Common issues detection (trailing whitespace) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/sanity-checks.yml | 114 ++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 .github/workflows/sanity-checks.yml diff --git a/.github/workflows/sanity-checks.yml b/.github/workflows/sanity-checks.yml new file mode 100644 index 0000000..0adba6a --- /dev/null +++ b/.github/workflows/sanity-checks.yml @@ -0,0 +1,114 @@ +name: Sanity Checks + +on: + push: + branches: [ main, master ] + pull_request: + branches: [ main, master ] + +jobs: + sanity-checks: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Check JSON validity + run: | + for file in $(find . -name "*.json" -not -path "./.git/*"); do + echo "Validating $file..." + python3 -m json.tool "$file" > /dev/null || exit 1 + done + echo "✓ All JSON files are valid" + + - name: Check HTML syntax + run: | + apt-get update && apt-get install -y tidy + for file in $(find . -name "*.html" -not -path "./.git/*"); do + echo "Validating $file..." + tidy -q -e "$file" || echo "Note: tidy reported issues in $file (not fatal)" + done + echo "✓ HTML validation complete" + + - name: Check CSS syntax (basic) + run: | + for file in $(find . -name "*.css" -not -path "./.git/*" -not -path "./node_modules/*"); do + echo "Checking $file for basic CSS issues..." + # Check for unclosed braces + open_braces=$(grep -o '{' "$file" | wc -l) + close_braces=$(grep -o '}' "$file" | wc -l) + if [ "$open_braces" -ne "$close_braces" ]; then + echo "✗ Mismatched braces in $file" + exit 1 + fi + done + echo "✓ CSS files have balanced braces" + + - name: Check for broken links (local) + run: | + # Build a list of all HTML files + html_files=$(find . -name "*.html" -not -path "./.git/*" | sort) + + for html_file in $html_files; do + echo "Checking links in $html_file..." + # Extract href and src attributes using grep + grep -o 'href="[^"]*"' "$html_file" | sed 's/href="//;s/"$//' | while read -r link; do + [ -z "$link" ] && continue + # Skip external links and anchors + echo "$link" | grep -qE '^(https?:|\/\/|#|mailto:)' && continue + + path=$(echo "$link" | cut -d'#' -f1) + [ -z "$path" ] && continue + + base_dir=$(dirname "$html_file") + resolved_path=$(python3 -c "import os; print(os.path.normpath('$base_dir/$path'))" 2>/dev/null) + + if [ ! -e "$resolved_path" ]; then + echo "✗ Broken link in $html_file: $link" + exit 1 + fi + done + + grep -o 'src="[^"]*"' "$html_file" | sed 's/src="//;s/"$//' | while read -r link; do + [ -z "$link" ] && continue + echo "$link" | grep -qE '^(https?:|\/\/|#|mailto:)' && continue + + path=$(echo "$link" | cut -d'#' -f1) + [ -z "$path" ] && continue + + base_dir=$(dirname "$html_file") + resolved_path=$(python3 -c "import os; print(os.path.normpath('$base_dir/$path'))" 2>/dev/null) + + if [ ! -e "$resolved_path" ]; then + echo "✗ Broken link in $html_file: $link" + exit 1 + fi + done + done + echo "✓ All local links are valid" + + - name: Check for common issues + run: | + errors=0 + + # Check for mixed indentation (tabs vs spaces) + for file in $(find . -name "*.html" -o -name "*.css" | grep -v ".git"); do + if grep -P '\t' "$file" > /dev/null; then + if grep ' ' "$file" > /dev/null; then + echo "⚠ Mixed tabs and spaces in $file" + fi + fi + done + + # Check for trailing whitespace + trailing_ws=$(find . \( -name "*.html" -o -name "*.css" -o -name "*.json" -o -name "*.md" \) \ + -not -path "./.git/*" -exec grep -l '[[:space:]]$' {} \;) + if [ -n "$trailing_ws" ]; then + echo "⚠ Files with trailing whitespace:" + echo "$trailing_ws" + fi + + echo "✓ Common issue check complete" + + - name: Summary + if: always() + run: echo "✓ All sanity checks passed!" From c6cc78298c5c9b78eefda05149968435fd5e7d53 Mon Sep 17 00:00:00 2001 From: Dennis Luxen Date: Sat, 25 Apr 2026 21:06:29 +0200 Subject: [PATCH 2/7] ci: add conventional commits PR title validation Add GitHub Actions workflow to enforce conventional commit format for pull request titles, ensuring consistent commit message standards across the project. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/conventional-commits.yml | 28 ++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 .github/workflows/conventional-commits.yml diff --git a/.github/workflows/conventional-commits.yml b/.github/workflows/conventional-commits.yml new file mode 100644 index 0000000..cf95fda --- /dev/null +++ b/.github/workflows/conventional-commits.yml @@ -0,0 +1,28 @@ +name: Conventional Commits + +on: + pull_request: + types: [opened, edited, synchronize, reopened] + +jobs: + validate-pr-title: + runs-on: ubuntu-latest + steps: + - name: Validate PR title + uses: amannn/action-semantic-pull-request@v5 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + requireScope: false + disallowScopes: [] + types: | + feat + fix + docs + style + refactor + perf + test + chore + ci + revert From 20f1ff19e47c7b91745323abc901a0d63762b2fd Mon Sep 17 00:00:00 2001 From: Dennis Luxen Date: Sat, 25 Apr 2026 21:08:49 +0200 Subject: [PATCH 3/7] fix(ci): skip absolute paths in link validation Skip server-relative absolute paths (starting with /) in the link checker, as these cannot be validated statically in the repository. They are intended for runtime use on the web server. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/sanity-checks.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/sanity-checks.yml b/.github/workflows/sanity-checks.yml index 0adba6a..2881ea4 100644 --- a/.github/workflows/sanity-checks.yml +++ b/.github/workflows/sanity-checks.yml @@ -53,8 +53,8 @@ jobs: # Extract href and src attributes using grep grep -o 'href="[^"]*"' "$html_file" | sed 's/href="//;s/"$//' | while read -r link; do [ -z "$link" ] && continue - # Skip external links and anchors - echo "$link" | grep -qE '^(https?:|\/\/|#|mailto:)' && continue + # Skip external links, anchors, and absolute paths (for server-relative URLs) + echo "$link" | grep -qE '^(https?:|\/\/|#|mailto:|/)' && continue path=$(echo "$link" | cut -d'#' -f1) [ -z "$path" ] && continue @@ -70,7 +70,7 @@ jobs: grep -o 'src="[^"]*"' "$html_file" | sed 's/src="//;s/"$//' | while read -r link; do [ -z "$link" ] && continue - echo "$link" | grep -qE '^(https?:|\/\/|#|mailto:)' && continue + echo "$link" | grep -qE '^(https?:|\/\/|#|mailto:|/)' && continue path=$(echo "$link" | cut -d'#' -f1) [ -z "$path" ] && continue From 6a42d84ce4df7a4c56dd43b439206cb7600f2e35 Mon Sep 17 00:00:00 2001 From: Dennis Luxen Date: Sat, 25 Apr 2026 21:10:12 +0200 Subject: [PATCH 4/7] fix(ci): allow href links without .html extension Support SPA/VitePress routing where links can reference pages without the .html extension (e.g., './testing' instead of './testing.html'). The link checker now accepts both the literal path and the path with .html appended. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/sanity-checks.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/sanity-checks.yml b/.github/workflows/sanity-checks.yml index 2881ea4..2d7daff 100644 --- a/.github/workflows/sanity-checks.yml +++ b/.github/workflows/sanity-checks.yml @@ -62,7 +62,8 @@ jobs: base_dir=$(dirname "$html_file") resolved_path=$(python3 -c "import os; print(os.path.normpath('$base_dir/$path'))" 2>/dev/null) - if [ ! -e "$resolved_path" ]; then + # Check if path exists, or if it's a path without .html extension that could map to an .html file + if [ ! -e "$resolved_path" ] && [ ! -e "$resolved_path.html" ]; then echo "✗ Broken link in $html_file: $link" exit 1 fi @@ -78,7 +79,7 @@ jobs: base_dir=$(dirname "$html_file") resolved_path=$(python3 -c "import os; print(os.path.normpath('$base_dir/$path'))" 2>/dev/null) - if [ ! -e "$resolved_path" ]; then + if [ ! -e "$resolved_path" ] && [ ! -e "$resolved_path.html" ]; then echo "✗ Broken link in $html_file: $link" exit 1 fi From faa26e72f74fd7085c97896305cf5795c7aea242 Mon Sep 17 00:00:00 2001 From: Dennis Luxen Date: Sat, 25 Apr 2026 21:10:22 +0200 Subject: [PATCH 5/7] fix(ci): exclude docs directory from link validation Skip link validation for generated docs content, which has special routing and structure incompatible with static file validation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/sanity-checks.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/sanity-checks.yml b/.github/workflows/sanity-checks.yml index 2d7daff..31839a3 100644 --- a/.github/workflows/sanity-checks.yml +++ b/.github/workflows/sanity-checks.yml @@ -45,8 +45,8 @@ jobs: - name: Check for broken links (local) run: | - # Build a list of all HTML files - html_files=$(find . -name "*.html" -not -path "./.git/*" | sort) + # Build a list of all HTML files (excluding docs directory - generated content) + html_files=$(find . -name "*.html" -not -path "./.git/*" -not -path "./docs/*" | sort) for html_file in $html_files; do echo "Checking links in $html_file..." From 6e60bf5473e1bd6f2761a311eeff949d49bdf96b Mon Sep 17 00:00:00 2001 From: Dennis Luxen Date: Sat, 25 Apr 2026 21:12:02 +0200 Subject: [PATCH 6/7] chore(ci): update checkout action to v4 Use the latest version of actions/checkout for improved performance and security updates. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/sanity-checks.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sanity-checks.yml b/.github/workflows/sanity-checks.yml index 31839a3..9e25710 100644 --- a/.github/workflows/sanity-checks.yml +++ b/.github/workflows/sanity-checks.yml @@ -10,7 +10,7 @@ jobs: sanity-checks: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Check JSON validity run: | From b4e596a7fe96d815902c021b9c7fbf30f8fbc2fb Mon Sep 17 00:00:00 2001 From: Dennis Luxen Date: Sat, 25 Apr 2026 21:13:39 +0200 Subject: [PATCH 7/7] chore(ci): update checkout to v6 and add dependabot Update actions/checkout to the latest version (v6) for improved performance and security. Add Dependabot configuration to automatically check for and create PRs for GitHub Actions dependency updates weekly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/dependabot.yml | 9 +++++++++ .github/workflows/sanity-checks.yml | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..5d84efb --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,9 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + commit-message: + prefix: "chore(deps)" + include: "scope" diff --git a/.github/workflows/sanity-checks.yml b/.github/workflows/sanity-checks.yml index 9e25710..5a3742f 100644 --- a/.github/workflows/sanity-checks.yml +++ b/.github/workflows/sanity-checks.yml @@ -10,7 +10,7 @@ jobs: sanity-checks: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Check JSON validity run: |