This document describes the automated build and release process for Futon.
The project uses GitHub Actions for continuous integration and automated releases:
Automatically builds and publishes signed release APKs to GitHub Releases.
Trigger: Push a git tag with format v* (e.g., v9.4.2)
git tag v9.4.2
git push origin v9.4.2Output: Signed release APK published to GitHub Releases
Builds and publishes nightly APKs on a weekly schedule.
Trigger: Every Sunday at 2:00 UTC (or manual trigger via workflow_dispatch)
Smart Skip: Automatically skips the build if there are no new commits since the last nightly release
Output: Pre-release APK tagged as N{YYYYMMDD} (e.g., N20251208)
Builds debug APK on pull requests for validation.
Trigger: On every pull request to main or devel branches
Output: Debug APK available as workflow artifact (7-day retention)
To enable automated signing, configure the following secrets in your GitHub repository settings:
-
Get the Keystore File (base64-encoded)
- If you have an existing keystore:
base64 -w 0 your-keystore.jks
- Copy the output
- If you have an existing keystore:
-
Create GitHub Secrets Navigate to: Settings → Secrets and variables → Actions → New repository secret
Create these secrets:
- KEYSTORE_FILE: Base64-encoded keystore file (entire output from step 1)
- KEYSTORE_PASSWORD: Password for the keystore
- KEY_ALIAS: Alias of the signing key (default:
futon-key) - KEY_PASSWORD: Password for the signing key
A new keystore was generated with:
Key Alias: futon-key
Keystore Password: [from setup]
Key Password: [from setup]
SHA-256 Fingerprint: EF:48:B2:2E:F2:C5:40:45:53:1F:6E:76:00:C2:7E:C3:D0:3B:71:22:1E:0B:05:FF:B6:8E:33:57:CF:8E:4D:40
The build.gradle is configured to support both local development and CI environments:
Environment variables are read automatically:
KEYSTORE_FILE: Path to keystore (or set via secrets)KEYSTORE_PASSWORDKEY_ALIASKEY_PASSWORD
If environment variables are not set, the build system will prompt for credentials interactively.
To set up locally with a keystore:
export KEYSTORE_FILE=/path/to/keystore.jks
export KEYSTORE_PASSWORD=your-password
export KEY_ALIAS=futon-key
export KEY_PASSWORD=key-password
./gradlew assembleRelease./gradlew assembleDebug
# Output: app/build/outputs/apk/debug/app-debug.apk./gradlew assembleRelease
# Output: app/build/outputs/apk/release/app-release.apk./gradlew assembleNightly
# Output: app/build/outputs/apk/nightly/app-nightly.apk
# Version: N{YYYYMMDD} (auto-generated from current date)- Release builds: Check GitHub Releases
- Nightly builds: Check GitHub Releases (marked as pre-release)
- PR builds: Check "Actions" tab → "Debug Build" → Artifacts section
Ensure Android SDK is properly set up. The workflows use android-actions/setup-android@v3 which handles this automatically.
- Verify the base64 encoding of the keystore is correct
- Ensure all password secrets are set correctly
- Test locally:
keytool -list -v -keystore keystore.jks -storepass <password>
The workflow checks for commits since the last nightly release. If no commits exist, the build is skipped. Force a build with the "workflow_dispatch" trigger.
Current release keystore SHA-256 fingerprint:
EF:48:B2:2E:F2:C5:40:45:53:1F:6E:76:00:C2:7E:C3:D0:3B:71:22:1E:0B:05:FF:B6:8E:33:57:CF:8E:4D:40
This matches the built-in app validator check in AppValidator.kt. All release builds must use a keystore with this fingerprint for proper app signature validation.