Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
1ea9be5
phase 1: add Gemfile pinned to github-pages for reproducible local bu…
claude May 10, 2026
b956cd5
phase 1: add pre-commit config with image compression hooks
claude May 10, 2026
4c0ebf3
phase 1: add CI workflow as pre-commit safety net
claude May 10, 2026
fc67af4
phase 1: lock github-pages dependencies
claude May 10, 2026
f78219c
phase 1: document pre-commit setup and local preview in README
claude May 10, 2026
782280e
phase 2: add image size-cap script
claude May 10, 2026
8ff67fb
phase 2: wire size-cap into pre-commit; add empty overrides allow-list
claude May 10, 2026
78623c4
phase 2: document image size policy in README
claude May 10, 2026
a12c450
phase 4: add code-quality hooks (baseline + yamllint + markdownlint)
claude May 10, 2026
c1942e9
phase 4: loosen yamllint to allow non-extra-indented sequences
claude May 10, 2026
857104e
chore: normalize whitespace and line endings (pre-commit baseline)
claude May 10, 2026
9ffab2e
phase 4: document code-quality hooks in README
claude May 10, 2026
a5e43cc
phase 6: add lychee and html5validator configs
claude May 10, 2026
e7d293d
phase 6: add site-health CI workflow (lychee + html5validator)
claude May 10, 2026
9c088f2
phase 6: document site-health CI in README
claude May 10, 2026
eb5cf77
phase 7: enable jekyll-sitemap and jekyll-seo-tag plugins
claude May 10, 2026
5904ae7
phase 7: wire {% seo %} into head and set default OG image
claude May 10, 2026
14e6baf
phase 7: document per-page SEO overrides in README
claude May 10, 2026
676096c
phase 6: pin html5validator-action to v7.2.0
claude May 10, 2026
60374d4
phase 1: scope pre-commit CI to changed files only
claude May 10, 2026
f5d0868
fix CI: bundler 2.5 lockfile + full git history for pre-commit diff
claude May 10, 2026
b80b89f
phase 6: fix lychee config to resolve relative links and skip noise
claude May 10, 2026
984f6a5
ignore lychee's local cache file
claude May 10, 2026
5b33378
phase 6: harden lychee config against academic-publisher false positives
claude May 10, 2026
81b3cb2
phase 6: exclude academic publishers from lychee link checking
claude May 10, 2026
8793cd3
phase 6: revert academic-publisher excludes; surface lychee report
claude May 10, 2026
59c3abb
phase 6: fix real link rot found by lychee; defer legacy blog cleanup
claude May 10, 2026
e1437f0
phase 6: fix lychee --exclude-path syntax (takes regex, not literal p…
claude May 10, 2026
d2709d6
phase 6: unwrap 4 more dead LinkedIn anchors on people.html
claude May 10, 2026
1d33aec
phase 6: exclude linkedin.com from lychee (bot-detection too noisy)
claude May 10, 2026
79ed796
phase 6: soft-fail html5validator (defer HTML cleanup to its own phase)
claude May 10, 2026
76a6efa
phase 6: drop dead --exclude-path arg
claude May 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions .github/workflows/pre-commit.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: pre-commit

on:
pull_request:
push:
branches: [master]

jobs:
pre-commit:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
# Need full history so the diff range below can resolve the
# base/before SHA against actual commits, not just HEAD.
fetch-depth: 0

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'

- name: Install pre-commit
run: pip install pre-commit

- name: Install image tooling (jpegoptim, oxipng, svgo)
run: |
sudo apt-get update
sudo apt-get install -y jpegoptim
cargo install oxipng --locked
npm install -g svgo

- name: Run pre-commit on the PR's changed files
if: github.event_name == 'pull_request'
run: |
pre-commit run --show-diff-on-failure \
--from-ref ${{ github.event.pull_request.base.sha }} \
--to-ref ${{ github.event.pull_request.head.sha }}

- name: Run pre-commit on the push's changed files
if: github.event_name == 'push'
run: |
pre-commit run --show-diff-on-failure \
--from-ref ${{ github.event.before }} \
--to-ref ${{ github.sha }}
76 changes: 76 additions & 0 deletions .github/workflows/site-health.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
name: site-health

on:
pull_request:
paths:
- '*.html'
- '*.md'
- '_layouts/**'
- '_includes/**'
- '_config.yml'
- '_data/**'
- '_posts/**'
- 'images/**'
- 'css/**'
- 'js/**'
- 'Gemfile'
- 'Gemfile.lock'
- 'lychee.toml'
- '.html5validator.yaml'
schedule:
# Weekly Monday 9am UTC, matching update-publications cadence.
- cron: '0 9 * * 1'
workflow_dispatch:

jobs:
site-health:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: '3.3'
bundler-cache: true

- name: Build site
run: bundle exec jekyll build

- name: Check links with lychee
id: lychee
uses: lycheeverse/lychee-action@v2
with:
# --exclude-path takes a regex matched against file paths.
# Skip legacy blog posts (deferred to a content-cleanup phase).
args: >-
--config ./lychee.toml
--no-progress
--root-dir ${{ github.workspace }}/_site
--exclude-path _site/blog
_site
output: lychee-report.md
fail: true

# On failure, post the lychee report as a sticky PR comment so
# the specific failing URLs are easy to see without digging
# through job logs. Sticky = updates in place rather than piling up.
- name: Comment lychee report on PR
if: failure() && github.event_name == 'pull_request'
uses: marocchino/sticky-pull-request-comment@v2
with:
header: lychee
path: lychee-report.md

- name: Validate HTML
id: html5validator
# Soft-fail for now: surface errors via the workflow log but
# don't gate the PR on them. The Jekyll site has Bootstrap-3-era
# HTML that needs a separate cleanup pass to be HTML5-spec clean.
continue-on-error: true
uses: Cyb3r-Jak3/html5validator-action@v7.2.0
with:
root: _site/
config: .html5validator.yaml
14 changes: 7 additions & 7 deletions .github/workflows/update-publications.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,37 +9,37 @@ on:
jobs:
update-publications:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install scholarly pyyaml "httpx==0.27.2"

- name: Run publication updater
run: |
python scholar_scraper.py

- name: Check for changes
id: git-check
run: |
git diff --exit-code _data/publications.yaml || echo "changed=true" >> $GITHUB_OUTPUT

- name: Commit and push if changed
if: steps.git-check.outputs.changed == 'true'
run: |
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
git add _data/publications.yaml
git commit -m "Auto-update publications from Google Scholar [skip ci]"
git push
git push
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
_site/
.sass-cache/
Gemfile
Gemfile.lock
.lycheecache
**/.DS_Store
10 changes: 10 additions & 0 deletions .html5validator.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# html5validator config. See https://github.com/svenkreiss/html5validator.
# Used by .github/workflows/site-health.yml.

root: _site
match: '*.html'

# Patterns to ignore. Add Bootstrap-3-era / Jekyll-specific noise here
# as it surfaces; keep the list short so real errors aren't masked.
ignore_re:
[]
6 changes: 6 additions & 0 deletions .image-size-overrides
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Allow-list for images that legitimately exceed the 1 MB size cap.
# One repo-relative path per line. Lines starting with # are comments.
# Example:
# images/research/big-zebrafish-figure.png
#
# Files listed here will not block commits but will still print a warning.
12 changes: 12 additions & 0 deletions .markdownlint.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"default": true,
"MD001": false,
"MD013": false,
"MD025": false,
"MD033": false,
"MD034": false,
"MD036": false,
"MD041": false,
"MD045": false,
"MD059": false
}
58 changes: 58 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Pre-commit hook configuration. See https://pre-commit.com/ for docs.
# Contributor setup: README.md > Contributing.

repos:
- repo: local
hooks:
- id: jpegoptim
name: jpegoptim (compress JPEGs to q=85, strip metadata)
entry: jpegoptim --max=85 --strip-all --preserve --all-progressive
language: system
types: [jpeg]

- id: oxipng
name: oxipng (lossless PNG optimization)
entry: oxipng --opt 4 --strip safe
language: system
types: [png]

- id: svgo
name: svgo (SVG minification)
entry: svgo --multipass
language: system
types: [svg]

# Runs after the compression hooks so it sees post-compression sizes.
- id: image-size-cap
name: image-size-cap (warn >500 KB, block >1 MB)
entry: python3 scripts/check_image_size.py
language: system
types_or: [image, svg]

- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.0
hooks:
- id: trailing-whitespace
exclude: '\.svg$'
- id: end-of-file-fixer
# svgo strips the trailing newline; let it win on .svg files.
exclude: '\.svg$'
- id: check-yaml
- id: check-json
- id: check-merge-conflict
- id: mixed-line-ending
args: [--fix=lf]
- id: check-added-large-files
args: [--maxkb=1000]
- id: detect-private-key

- repo: https://github.com/adrienverge/yamllint
rev: v1.38.0
hooks:
- id: yamllint

- repo: https://github.com/igorshubovych/markdownlint-cli
rev: v0.48.0
hooks:
- id: markdownlint
args: [--fix]
15 changes: 15 additions & 0 deletions .yamllint
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# yamllint configuration. See https://yamllint.readthedocs.io/.
# Start from the bundled "relaxed" profile and loosen further for data
# files (where long lines are normal and indent style varies).

extends: relaxed

rules:
document-start: disable
line-length: disable
indentation:
spaces: 2
indent-sequences: whatever
check-multi-line-strings: false
truthy:
check-keys: false
5 changes: 5 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
source "https://rubygems.org"

# GitHub Pages pins all gem versions used by the live build, so installing
# this locally gives a reproducible preview that matches production.
gem "github-pages", group: :jekyll_plugins
Loading
Loading