fix(ci): let the version check tell a release from a local build

The check demanded csproj, repo.json and every DownloadLink carry the same
version. That is right for a published release and impossible for anything else,
so it went red the moment v1.11.0 closed -- and pre-push blocks on it.

The two states were conflated. repo.json is the distribution manifest, so its
version has to describe what the links actually serve. Claiming 1.11.0 while
every link serves v1.5.6 makes Dalamud offer an update, install the old build,
and offer the same update again on the next launch. Satisfying the old rule
meant building exactly that.

Now: the manifest must always agree with itself and with its links, and the
build must never be older than what is published. --release additionally demands
the three match, which is the mode for cutting a tag and still catches the v1.2.2
burn it was written for.

The link check moved from the csproj version to the manifest version, which is
the pairing that protects users. In the old form a manifest could name a version
none of its links served and pass, as long as the csproj agreed -- the exact
mismatch it now rejects.
This commit is contained in:
2026-08-18 20:28:28 +02:00
parent d0eb2934ed
commit 6a3bbe2357
+46 -12
View File
@@ -1,10 +1,29 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# verify-version-consistency.sh — Block A of preflight. # verify-version-consistency.sh — Block A of preflight.
# csproj <Version> is 3-digit SemVer; repo.json AssemblyVersion is 4-digit (.0 suffix). #
# csproj <Version> is 3-digit SemVer; repo.json AssemblyVersion is 4-digit.
#
# Two states, and conflating them is what made this check unsatisfiable:
#
# Published csproj == repo.json == the tag in every DownloadLink.
# Unreleased csproj is ahead; repo.json and the links stay on whatever is
# actually downloadable.
#
# repo.json is the distribution manifest, so its version has to describe what the
# links serve. A manifest claiming 1.11.0 while every link serves v1.5.6 makes
# Dalamud offer an update, install the old build, and offer the same update on
# the next launch.
#
# Default run allows both states and enforces what holds in each. Pass --release
# to demand the published one; that is the mode for cutting a tag, and it is what
# catches the v1.2.2 burn (csproj bumped, repo.json forgotten).
set -euo pipefail set -euo pipefail
ROOT="$(cd "$(dirname "$0")/.." && pwd)" ROOT="$(cd "$(dirname "$0")/.." && pwd)"
RELEASE_MODE=0
[ "${1:-}" = "--release" ] && RELEASE_MODE=1
CSPROJ="$ROOT/HellionChat/HellionChat.csproj" CSPROJ="$ROOT/HellionChat/HellionChat.csproj"
REPO_JSON="$ROOT/repo.json" REPO_JSON="$ROOT/repo.json"
@@ -14,23 +33,38 @@ ok() { echo "verify-version-consistency: OK — $1"; }
CSPROJ_VER="$(grep -oE '<Version>[^<]+</Version>' "$CSPROJ" | head -1 | sed -E 's/<[^>]+>//g')" CSPROJ_VER="$(grep -oE '<Version>[^<]+</Version>' "$CSPROJ" | head -1 | sed -E 's/<[^>]+>//g')"
[ -n "$CSPROJ_VER" ] || fail "$CSPROJ has no <Version> element" [ -n "$CSPROJ_VER" ] || fail "$CSPROJ has no <Version> element"
EXPECTED_4DIGIT="${CSPROJ_VER}.0"
REPO_VER="$(jq -r '.[0].AssemblyVersion' "$REPO_JSON")" 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="$(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" # Always: the manifest must agree with itself.
[ "$TEST_VER" = "$REPO_VER" ] \
|| fail "TestingAssemblyVersion=$TEST_VER must match AssemblyVersion=$REPO_VER in $REPO_JSON."
# Always: every link must serve exactly the version the manifest claims. This is
# the check that actually protects users -- a mismatch here is an update loop.
REPO_TAG="v${REPO_VER%.*}"
for KEY in DownloadLinkInstall DownloadLinkUpdate DownloadLinkTesting; do for KEY in DownloadLinkInstall DownloadLinkUpdate DownloadLinkTesting; do
URL="$(jq -r ".[0].$KEY" "$REPO_JSON")" URL="$(jq -r ".[0].$KEY" "$REPO_JSON")"
case "$URL" in case "$URL" in
*"/$TAG/"*) ;; *"/$REPO_TAG/"*) ;;
*) fail "$KEY=$URL does not contain tag $TAG. Fix: update $REPO_JSON $KEY to releases/download/$TAG/latest.zip." ;; *) fail "$KEY=$URL does not serve $REPO_TAG, which is what AssemblyVersion=$REPO_VER claims. Either point the link at $REPO_TAG or set AssemblyVersion to the version the link serves." ;;
esac esac
done done
ok "csproj=$CSPROJ_VER, repo.json=$EXPECTED_4DIGIT, tag $TAG present in DownloadLinks" # Always: the build must never be older than what is published.
LOWER="$(printf '%s\n%s\n' "$CSPROJ_VER" "${REPO_VER%.*}" | sort -V | head -1)"
[ "$LOWER" = "${REPO_VER%.*}" ] \
|| fail "csproj=$CSPROJ_VER is older than the published ${REPO_VER%.*}. A build behind the manifest cannot be right."
if [ "$RELEASE_MODE" -eq 1 ]; then
[ "$REPO_VER" = "${CSPROJ_VER}.0" ] \
|| fail "release mode: csproj=$CSPROJ_VER requires repo.json AssemblyVersion=${CSPROJ_VER}.0 but got $REPO_VER. Fix: align $REPO_JSON and point the DownloadLinks at v$CSPROJ_VER."
ok "release: csproj=$CSPROJ_VER, repo.json=$REPO_VER, links serve $REPO_TAG"
exit 0
fi
if [ "$REPO_VER" = "${CSPROJ_VER}.0" ]; then
ok "published: csproj=$CSPROJ_VER, repo.json=$REPO_VER, links serve $REPO_TAG"
else
ok "unreleased: csproj=$CSPROJ_VER ahead of published ${REPO_VER%.*}, links serve $REPO_TAG consistently"
fi