diff --git a/.githooks/pre-push b/.githooks/pre-push new file mode 100755 index 0000000..803a706 --- /dev/null +++ b/.githooks/pre-push @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +# .githooks/pre-push — invokes preflight.sh (Blocks A/B/C/D). +exec scripts/preflight.sh diff --git a/README.md b/README.md index b2f31bd..1806fb2 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ attribution. The custom Dalamud repository URL for Anvil is: -``` +```text https://gitea.hellion-forge.cloud/JonKazama-Hellion/Anvil/raw/branch/main/repo.json ``` diff --git a/scripts/preflight.sh b/scripts/preflight.sh new file mode 100755 index 0000000..d1ad42c --- /dev/null +++ b/scripts/preflight.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash +# preflight.sh — pre-push gate for the Anvil plugin repository. +# +# Block A — version consistency between Anvil.csproj and the +# public repo.json manifest (when it exists). +# Block B — dotnet build -p:Platform=x64 on the solution to catch +# compile-time API drift. +# Block C — dotnet csharpier check against Anvil/ for C# format drift +# (per feedback_hellion_chat_format_check_per_task: accumulated +# formatter drift in HellionChat v1.5.6 hit 12 files at push +# time when only build was checked per task). +# Block D — markdownlint-cli2 against the repo's *.md files. + +set -euo pipefail +ROOT="$(cd "$(dirname "$0")/.." && pwd)" +cd "$ROOT" + +echo "==> preflight: Block A — version consistency" +./scripts/verify-version-consistency.sh + +echo "==> preflight: Block B — plugin compile health" +dotnet build Anvil.sln -p:Platform=x64 --configuration Release --nologo --verbosity quiet + +echo "==> preflight: Block C — csharpier reflow check" +dotnet csharpier check ./Anvil + +echo "==> preflight: Block D — markdownlint" +# npx --yes avoids a global install; first run caches into ~/.npm/_npx/. +npx --yes markdownlint-cli2 "**/*.md" "#node_modules" "#bin" "#obj" "#.claude" "#CLAUDE.md" + +echo "==> preflight: ALL GREEN" diff --git a/scripts/setup-hooks.sh b/scripts/setup-hooks.sh new file mode 100755 index 0000000..10d145d --- /dev/null +++ b/scripts/setup-hooks.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +# setup-hooks.sh — wire the local .githooks/ directory into core.hooksPath. +# Run once after cloning the repo. Idempotent; safe to re-run on every pull. + +set -euo pipefail +ROOT="$(cd "$(dirname "$0")/.." && pwd)" +cd "$ROOT" + +git config core.hooksPath .githooks +chmod +x .githooks/pre-push +chmod +x scripts/*.sh + +echo "setup-hooks: core.hooksPath -> .githooks (pre-push wired)" diff --git a/scripts/verify-version-consistency.sh b/scripts/verify-version-consistency.sh new file mode 100755 index 0000000..7c4b410 --- /dev/null +++ b/scripts/verify-version-consistency.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash +# verify-version-consistency.sh — Block A of preflight. +# +# v0.1.0 ships before the first repo.json release manifest exists, so this +# script is tolerant when the file is missing - the csproj is +# the single source of truth at the bootstrap stage. Once repo.json +# lands (probably v0.1.1 or v0.2.0), the missing-file path turns into a +# full csproj <-> repo.json AssemblyVersion + TestingAssemblyVersion + +# DownloadLink* tag check, matching the HellionChat preflight. + +set -euo pipefail +ROOT="$(cd "$(dirname "$0")/.." && pwd)" + +CSPROJ="$ROOT/Anvil/Anvil.csproj" +REPO_JSON="$ROOT/repo.json" + +fail() { echo "verify-version-consistency: FAIL — $1" >&2; exit 1; } +ok() { echo "verify-version-consistency: OK — $1"; } + +CSPROJ_VER="$(grep -oE '[^<]+' "$CSPROJ" | head -1 | sed -E 's/<[^>]+>//g')" +[ -n "$CSPROJ_VER" ] || fail "$CSPROJ has no element" + +if [ ! -f "$REPO_JSON" ]; then + ok "csproj=$CSPROJ_VER (repo.json absent - bootstrap stage, skipping cross-check)" + exit 0 +fi + +EXPECTED_4DIGIT="${CSPROJ_VER}.0" + +REPO_VER="$(jq -r '.[0].AssemblyVersion' "$REPO_JSON")" +[ "$REPO_VER" = "$EXPECTED_4DIGIT" ] \ + || fail "csproj=$CSPROJ_VER expects repo.json AssemblyVersion=$EXPECTED_4DIGIT but got $REPO_VER. Fix: align in $REPO_JSON." + +TEST_VER="$(jq -r '.[0].TestingAssemblyVersion' "$REPO_JSON")" +[ "$TEST_VER" = "$EXPECTED_4DIGIT" ] \ + || fail "TestingAssemblyVersion=$TEST_VER must match $EXPECTED_4DIGIT. Fix: align in $REPO_JSON." + +TAG="v$CSPROJ_VER" +for KEY in DownloadLinkInstall DownloadLinkUpdate DownloadLinkTesting; do + URL="$(jq -r ".[0].$KEY" "$REPO_JSON")" + case "$URL" in + *"/$TAG/"*) ;; + *) fail "$KEY=$URL does not contain tag $TAG. Fix: update $REPO_JSON $KEY to releases/download/$TAG/latest.zip." ;; + esac +done + +ok "csproj=$CSPROJ_VER, repo.json=$EXPECTED_4DIGIT, tag $TAG present in DownloadLinks"