ci: fail the build when a changelog will not fit F-Droid
`sync_changelog_to_fastlane.sh` has been printing "note: >500 chars — F-Droid may truncate this changelog in-client" for three releases, and every release since 0.2.0 has sailed past it: 1824, 696, 916 characters. A note nobody acts on is not a check. F-Droid truncates the in-client "What's New" box, so everything past the limit is written for nobody — the reader gets a sentence cut mid-word and no way to expand it. The limit is now a hard failure: the script exits non-zero, with a message naming the section to shorten, and `MAX_CHARS` is a variable so the bound lives in one place rather than being copied into the workflows. Enforced in two places, for two different failures: - `.forgejo/workflows/ci.yaml` runs it as an always-on guard beside the reproducible-release invariant, then checks `git status --porcelain` over the changelogs directory. That second half catches a CHANGELOG.md edit whose generated fastlane file was never committed — which until now degraded silently into the official F-Droid listing showing the *previous* version's notes, exactly as RELEASING.md step 3 warns. Porcelain rather than `git diff --exit-code`, so a brand-new file for a bumped versionCode counts as dirty instead of being missed as untracked. - `.gitea/workflows/release.yaml` gets the same call in the cheap `detect` gate. The release job already regenerated the file, but only at step 15 of 24 — after the build, the signing and the keystore setup. Failing in `detect` costs one bash invocation and publishes nothing.
This commit is contained in:
@@ -37,6 +37,26 @@ jobs:
|
||||
- name: Reproducible-release invariant
|
||||
run: bash scripts/check_reproducible_release.sh
|
||||
|
||||
# Also cheap, also always-on. Two failures in one: the script exits
|
||||
# non-zero if this version's changelog is over the character limit
|
||||
# F-Droid truncates at, and the porcelain check below catches a
|
||||
# CHANGELOG.md edit whose generated fastlane file was never committed —
|
||||
# which used to degrade silently into "the official listing shows the
|
||||
# previous version's notes".
|
||||
- name: Changelog fits F-Droid, and is committed
|
||||
run: |
|
||||
set -e
|
||||
bash scripts/sync_changelog_to_fastlane.sh
|
||||
DIRTY=$(git status --porcelain fastlane/metadata/android/en-US/changelogs)
|
||||
if [ -n "$DIRTY" ]; then
|
||||
echo "$DIRTY"
|
||||
echo "ERROR: the generated fastlane changelog is not what is committed." >&2
|
||||
echo "Run scripts/sync_changelog_to_fastlane.sh and commit the result, so" >&2
|
||||
echo "the official F-Droid listing shows this version's notes rather than" >&2
|
||||
echo "the previous one's." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Decide whether anything that affects the app build changed. Docs, store
|
||||
# metadata, licence texts and forge housekeeping don't, so those PRs skip
|
||||
# the SDK + Gradle work below but still report a green `ci`.
|
||||
|
||||
@@ -110,6 +110,16 @@ jobs:
|
||||
;;
|
||||
esac
|
||||
|
||||
# Before a single Gradle task runs: F-Droid truncates the in-client
|
||||
# changelog, so an over-long one would reach users cut off mid-sentence.
|
||||
# The script exits non-zero past the limit. Cheap enough to sit in the
|
||||
# gate job, where failing costs nothing and publishes nothing — the step
|
||||
# further down that regenerates the file for the repo would otherwise be
|
||||
# the first thing to notice, after the build and the signing.
|
||||
- name: Changelog fits F-Droid
|
||||
if: steps.v.outputs.is_release == 'true'
|
||||
run: bash scripts/sync_changelog_to_fastlane.sh
|
||||
|
||||
# Releases: build + sign + publish, then mint the tag and Gitea release.
|
||||
# Also runs on manual dispatch, where it skips the build and just re-signs and
|
||||
# re-uploads the existing index (recovery path).
|
||||
|
||||
@@ -20,6 +20,10 @@ MAJOR=${VERSION%%.*}; rest=${VERSION#*.}; MINOR=${rest%%.*}; PATCH=${rest##*.}
|
||||
MAJOR=${MAJOR:-0}; MINOR=${MINOR:-0}; PATCH=${PATCH:-0}
|
||||
VERSION_CODE=$(( MAJOR * 10000 + MINOR * 100 + PATCH ))
|
||||
|
||||
# F-Droid's in-client changelog box truncates past roughly this length; CI reads
|
||||
# this value rather than hardcoding its own copy.
|
||||
MAX_CHARS=${MAX_CHARS:-500}
|
||||
|
||||
CL_DIR="fastlane/metadata/android/en-US/changelogs"
|
||||
mkdir -p "$CL_DIR"
|
||||
OUT="$CL_DIR/${VERSION_CODE}.txt"
|
||||
@@ -36,6 +40,21 @@ fi
|
||||
|
||||
CHARS=$(wc -m < "$OUT" | tr -d ' ')
|
||||
echo "Wrote $OUT (version $VERSION, code $VERSION_CODE, ${CHARS} chars)"
|
||||
if [ "$CHARS" -gt 500 ]; then
|
||||
echo " note: >500 chars — F-Droid may truncate this changelog in-client." >&2
|
||||
|
||||
# Hard limit, not a note. F-Droid truncates the "What's New" box in-client, so
|
||||
# anything past this is written for nobody: the reader sees a sentence cut
|
||||
# mid-word and no way to expand it. Keep the section in CHANGELOG.md short
|
||||
# enough to survive that, and put the detail in the commit messages and docs,
|
||||
# where there is room for it.
|
||||
#
|
||||
# CI enforces the same bound (.forgejo/workflows/ci.yaml) so a release cannot
|
||||
# reach main with a changelog its users cannot read.
|
||||
if [ "$CHARS" -gt "$MAX_CHARS" ]; then
|
||||
cat >&2 <<MSG
|
||||
ERROR: $OUT is $CHARS characters, over the $MAX_CHARS-character limit.
|
||||
|
||||
F-Droid truncates the in-client changelog, so this one would be cut off
|
||||
mid-sentence. Shorten the "## [$VERSION]" section in CHANGELOG.md and re-run.
|
||||
MSG
|
||||
exit 1
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user