Reworks the pipeline so a change is built once and a release is driven by the
merge, not a manual tag push.
- ci.yaml now runs on pull_request (one gate per PR) instead of every branch
push, so there's no CI-on-push + CI-on-merge double run. A single `ci` job
with a docs-only fast-path keeps the required "CI" check always reporting
(docs/metadata-only PRs skip the Android build but still go green).
- release.yaml triggers on push to main. A cheap `detect` job reads versionName
from build.gradle; only when no tag for it exists does the `release` job run:
tests on the merged commit, build + sign, publish to F-Droid, then create the
vX.Y.Z tag + Gitea release via the API (target_commitish = the merged sha).
The tag is now an OUTPUT of a successful release, not its trigger — a failure
before publish leaves no tag, so re-running safely retries. No more separate
tag-triggered run or duplicate ci job.
- The committed versionName/versionCode are now the source of truth (pipeline
pins versionCode from versionName); updated the build.gradle comment.
- translations.yaml switched to pull_request (same path filter).
- docs/RELEASING.md: release-by-merge flow, no manual git tag.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds a mandatory pre-tag step to the release process: build the R8-shrunk
release candidate and smoke-test it on a real device, including a first-run /
permission-not-granted state. The v2.7.0 launch crash (calendar observer
registered before the permission gate) reached users because it only manifests
in the minified release build on a device without the permission already
granted — the debug build and an already-permissioned phone both hid it.
- New `releaseTest` build type: same R8 shrinking + obfuscation as `release`,
but debug-signed with a `.releasetest` applicationId suffix so it installs
alongside the production and debug apps. Never published; CI only ever builds
the real `release` variant from the tag.
- scripts/verify-release.sh: builds + installs `releaseTest` and resets it to a
first-run state, with an on-device checklist.
- docs/RELEASING.md: formalize the release/vX.Y.Z branch flow and the on-device
verification gate before tagging.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add scripts/check_translations.py and a lightweight Translations workflow
that runs it (no Android SDK needed) so Weblate PRs get fast feedback. The
script fails on stale keys (present in a translation but not the base) and on
translating translatable="false" entries; missing keys are reported as
coverage only.
Downgrade lint's MissingTranslation to informational: partial community
translations are expected and fall back to the English base at runtime.
Stale/extra keys (ExtraTranslation) remain fatal in lintDebug.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>