| name | release |
| description | Amply's release process — versioning via version.properties/bump.sh, signing material, the release-prepare/release-tag workflows, store-listing metadata, Play Store screenshot generation, and the Google Play publication gate. Use when cutting a release, bumping a version, regenerating store screenshots, or touching signing/release CI. |
Release
Current state (honest)
Amply is pre-launch (0.1.0-beta1). It uses CAPod's versioning system: a version.properties source of truth,
a VERSION mirror, a tools/release/bump.sh bump/validate tool, and release-prepare / release-tag workflows. The
tooling exists but no release has been cut. Fastlane provides store-listing metadata + screenshots
(fastlane/metadata/android/en-US/) plus manual supply lanes in fastlane/Fastfile. Those lanes are not wired
into CI and are gated (see below), so release-tag.yml still publishes a FOSS GitHub release only (see CI below).
Store listing & screenshots
-
Metadata: fastlane/metadata/android/en-US/{title,short_description,full_description}.txt + changelogs/default.txt,
validated in CI by check_metadata_length.sh (title 30 / short 80 / full 3800 / changelog 500 chars).
-
Screenshots: generated from @Preview composables on the JVM (no device) via the Compose Preview Screenshot
Testing plugin (com.android.compose.screenshot, enabled by android.experimental.enableScreenshotTest=true in
gradle.properties). The store composables live in app/src/debug/.../screenshots/ScreenshotContent.kt; the
capture entry points (@PreviewTest) and locale annotations live in app/src/screenshotTest/.../screenshots/.
./fastlane/generate_screenshots.sh
./fastlane/copy_screenshots.sh
Committed output lands in fastlane/metadata/android/en-US/images/phoneScreenshots/ as 1_dashboard_light.png … 6_reconnect_gesture.png (names come from copy_screenshots.sh's screen_file map). Both scripts fail loudly on
any count/dimension/format mismatch and copy_screenshots.sh requires ImageMagick. Needs the JDK 21 build
toolchain like everything else. CI compiles these sources (compileGplayDebugScreenshotTestKotlin) but does
not render — layoutlib output differs across machines — so regenerating screenshots is a manual pre-release
step.
-
supply lanes (beta / production / listing_only / screenshots_only): every lane that mutates Play state
refuses to run unless AMPLY_PLAY_PUBLISH_APPROVED=1, keeping publication behind the specialUse gate below.
Prerequisites (all manual, none automated): an existing Play app for eu.darken.amply, a service-account JSON at the
Appfile path (or AMPLY_SUPPLY_JSON_KEY), gplay signing material, and the specialUse review passed.
Versioning
- Single source:
version.properties at the repo root, parsed at configuration time by the buildSrc
ProjectConfigPlugin (CAPod's scheme): versionName = "major.minor.patch-type{build}",
versionCode = major*10000000 + minor*100000 + patch*1000 + build*10. type must be rc or beta (bump.sh
rejects anything else). A root VERSION file (<name> <code>) mirrors it as a drift check.
- Constraints (enforced by both
ProjectConfig's requires and bump.sh): minor, patch, build are 0..99 —
overflow collides with the next-higher field (e.g. patch=0,build=100 equals patch=1,build=0). Changing only
type does not change the versionCode, so a store update needs another field bumped. versionCode stays
monotonic (bump.sh refuses a non-increasing code).
- Bumping: don't hand-edit — run
./tools/release/bump.sh --mode=plan --bump-kind=<build|patch|minor|major>
to preview, --mode=write to apply (rewrites both files and re-verifies). --mode=check validates consistency
(also run in CI). Prefer the release-prepare workflow, which wraps bump.sh with tag-collision guards.
- No build-type or flavor suffixes: every variant installs as
eu.darken.amply with the same versionName. Because
signing certificates differ (debug key vs foss key vs gplay upload key), installed variants are mutually exclusive
on a device — switching requires an uninstall.
Signing
Release/beta signing loads per flavor (releaseFoss, releaseGplay) from either:
- Environment variables:
STORE_PATH, STORE_PASSWORD, KEY_ALIAS, KEY_PASSWORD (checked first), or
- Properties files under
~/.config/projects/eu.darken.amply/:
signing-foss.properties and signing-gplay-upload.properties, using keys release.storePath,
release.storePassword, release.keyAlias, release.keyPassword.
If signing material is absent, the flavor simply builds unsigned — the config degrades gracefully rather than failing.
Never commit signing material or point these at repo paths.
CI
.github/workflows/code-checks.yml runs on push to main and on PRs as matrix jobs (CAPod parity): wrapper
validation (in the shared common-setup action), lintVital{Foss,Gplay}{Beta,Release}, assemble{Foss,Gplay}Debug,
test{Foss,Gplay}DebugUnitTest, a fastlane metadata length check, and a release-tooling check (shellcheck +
bats on bump.sh, plus bump.sh --mode=check). It skips version-bump-only pushes (paths-ignore: VERSION, version.properties). CI does not run R8/minified packaging (lintVital only compiles the beta/release sources) —
run ./gradlew assembleFossRelease assembleGplayRelease locally before tagging a release.
Release workflows
release-prepare.yml (workflow_dispatch): computes the next version with bump.sh, guards tag collisions,
and — when dry_run=false — commits version.properties+VERSION, tags v<name>, and pushes. The push job needs
the RELEASE_APP_CLIENT_ID / RELEASE_APP_PRIVATE_KEY GitHub App secrets; the dry-run plan needs no secrets.
A manual workflow_dispatch (dry-run/build-only) must be launched from a v* tag ref, not a branch — the
tag-validation job intentionally fails on a branch ref so the publish job can never run against a non-tag.
release-tag.yml (on a v* tag): validates the tag against version.properties, builds assembleFossBeta
(for -beta tags) or assembleFossRelease, and attaches the versioned APK to a GitHub (pre-)release. Signed only
when SIGNING_KEYSTORE_BASE64 + STORE_PASSWORD/KEY_ALIAS/KEY_PASSWORD secrets are present; otherwise the APK
is unsigned (its filename carries an -UNSIGNED marker).
- Deliberately omitted vs. CAPod: no Google Play upload job (the manual
supply lanes exist but are gated on
AMPLY_PLAY_PUBLISH_APPROVED and never wired into CI, and Play
publication must stay gated — see below) and no Pages deploy (the project website is deferred).
Google Play gate
Google Play publication must remain gated on approval of the declared specialUse foreground-service use case (see
privileged-access.md). Do not treat a green CI build as clearance to publish. release-tag.yml intentionally does
not upload to Play — that step is added only after the use-case approval lands.