iftypeset/scripts/checkpoint.sh
codex e92f1c3b93
Some checks are pending
ci / ci (push) Waiting to run
iftypeset: document CI pipeline + Playwright + font contract
2026-01-08 18:10:41 +00:00

114 lines
3.2 KiB
Bash
Executable file

#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$ROOT"
ts="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
safe_ts="$(date -u +"%Y-%m-%dT%H-%M-%SZ")"
note="${1:-}"
mkdir -p out/checkpoints
echo "== running ci ==" >&2
ci_json="$(./scripts/ci.sh)"
echo "$ci_json" > "out/checkpoints/ci_${safe_ts}.json"
echo "== writing session state ==" >&2
./scripts/state.sh >/dev/null
git_branch="(unknown)"
git_head_short=""
dirty_count="0"
modified_count="0"
untracked_count="0"
diffstat=""
diffstat_lines="0"
diffstat_note=""
if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
git_branch="$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "(unknown)")"
git_head_short="$(git rev-parse --short HEAD 2>/dev/null || echo "")"
porcelain="$(git status --porcelain=v1 2>/dev/null || true)"
if [ -n "${porcelain}" ]; then
dirty_count="$(printf "%s\n" "${porcelain}" | wc -l | awk '{print $1}')"
untracked_count="$(printf "%s\n" "${porcelain}" | grep -c '^??' || true)"
modified_count="$(printf "%s\n" "${porcelain}" | grep -vc '^??' || true)"
fi
diffstat="$(git diff --stat 2>/dev/null || true)"
if [ -n "${diffstat}" ]; then
diffstat_lines="$(printf "%s\n" "${diffstat}" | wc -l | awk '{print $1}')"
if [ "${diffstat_lines}" -gt 200 ]; then
diffstat="$(printf "%s\n" "${diffstat}" | head -n 200)"
diffstat_note="(diffstat truncated to first 200 lines)"
fi
fi
fi
tar_path="out/checkpoints/iftypeset_checkpoint_${safe_ts}.tar.gz"
details_path="out/checkpoints/checkpoint_${safe_ts}.md"
echo "== creating snapshot ${tar_path} ==" >&2
snapshot_paths=(.forgejo .gitignore README.md STATUS.md app docs fixtures forgejo pyproject.toml requirements.txt scripts spec src tests tools)
if [ -f AGENTS.md ]; then
snapshot_paths+=(AGENTS.md)
fi
tar \
--exclude=".git" \
--exclude=".venv" \
--exclude="out" \
-czf "$tar_path" \
"${snapshot_paths[@]}"
sha="$(sha256sum "$tar_path" | awk '{print $1}')"
cat > "${details_path}" <<EOF
# iftypeset checkpoint
- timestamp_utc: ${ts}
- snapshot: ${tar_path}
- snapshot_sha256: ${sha}
- ci: \`out/checkpoints/ci_${safe_ts}.json\`
- git: ${git_branch} ${git_head_short}
- working_tree: dirty_paths=${dirty_count} (modified=${modified_count}, untracked=${untracked_count})
$( [ -n "${note}" ] && printf -- "- note: %s\n" "${note}" )
## Diffstat (uncommitted changes)
${diffstat_note}
\`\`\`text
${diffstat}
\`\`\`
EOF
if [ ! -s docs/CHECKPOINTS.md ]; then
cat > docs/CHECKPOINTS.md <<'EOF'
# Checkpoints
Durable restore points for this repo (useful when chat context resets).
How to create a checkpoint:
- `./scripts/checkpoint.sh "short note about what changed"`
Each entry records the snapshot tarball path + sha256 and the CI JSON for that moment.
EOF
fi
cat >> docs/CHECKPOINTS.md <<EOF
## ${ts}
- snapshot: \`${tar_path}\`
- snapshot_sha256: \`${sha}\`
- ci_json: \`out/checkpoints/ci_${safe_ts}.json\`
- details: \`${details_path}\`
- git: \`${git_branch}\` \`${git_head_short}\`
- working_tree: dirty_paths=${dirty_count} (modified=${modified_count}, untracked=${untracked_count})
$( [ -n "${note}" ] && printf -- "- note: %s\n" "${note}" )
EOF
echo "checkpoint complete: ${tar_path} (sha256=${sha})" >&2