Release Engineering Skill
This skill provides a comprehensive guide for managing the release lifecycle of the Upnext Android application. It encapsulates logic for GitHub Actions, Fastlane, Semantic Versioning, and troubleshooting.
🚀 Triggering a Release
The release pipeline is fully automated via GitHub Actions, prioritizing stability and reducing noise.
1. Nightly Scheduled Builds (CD)
Automated deployments run daily at 2:00 AM UTC via .github/workflows/deploy.yml. This batches all dependency updates and merges from the day into a single release.
Triggers:
- Schedule:
cron: '0 2 * * *' - Manual:
workflow_dispatch(Run via GitHub Actions UI)
Process:
- Versioning: Bumps
VERSION_CODEandVERSION_NAMEinversion.properties. - Build: Generates signed Release Bundle (
.aab). - Distribution: Fastlane uploads to Google Play Internal Track.
- Tagging: Pushes a git tag (e.g.,
v2025.1.4-215).
Critical Implementation Detail (GitHub Releases): For scheduled builds, the workflow runs on the
mainbranch ref (refs/heads/main), not the tag ref. To ensure a GitHub Release is attached to the newly created tag:
- Fastlane updates
version.properties.- The workflow explicitly reads
VERSION_NAMEandVERSION_CODEfrom the updated file.- It constructs the tag name (
v{NAME}-{CODE}) and passes it to thesoftprops/action-gh-releaseaction. Do not rely ongithub.reffor scheduled release tagging.
2. Pull Request Verification (CI)
Every Pull Request to main undergoes strict quality checks via .github/workflows/pull_request.yml.
Unified verify Job:
To radically optimize GitHub Actions minutes consumption, all verification tasks are executed within a single runner matrix step using Gradle's internal dependency graph to share Daemon state and avoid redundant :app:compileDebugKotlin invocations:
ktlintCheck(Code Style)detekt(Static Analysis)lintDebug(Android best practices, permissions, security)testDebugUnitTest(Unit Tests)assembleDebug(Compilation validation)assembleRelease(Verifies R8/ProGuard shrinking without crashing)
Note on Signing in Pull Requests: PR builds do not have access to production signing keys.
app/build.gradleis configured to fallback to debug signing automatically when the release keystore is missing. This allowsassembleReleaseto verify compilation and shrinking logic in CI without needing secrets.
⏱️ CI/CD Minute Optimization
To prevent excessive consumption of GitHub Actions minutes, especially from automated dependency bots like Renovate, the following strategies are implemented:
1. Conditional Deployment (deploy.yml)
The nightly scheduled build incorporates a check_changes pre-job.
- It evaluates the commit history over the last 24 hours.
- If no new commits were merged into
main, it skips the expensivedeployjob entirely. - Manual triggers (
workflow_dispatch) bypass this check and force a deployment.
2. Renovate & PR Auto-Cancellation (renovate.json & pull_request.yml)
Dependency updates can cause massive CI fan-out. To mitigate this:
rebaseWhen: conflicted: Renovate is configured to only rebase PRs if there is a git conflict, preventing it from auto-rebasing 10+ PRs whenever a single PR is merged intomain.- Update Grouping: Minor and patch dependency updates are grouped into a single PR (
all-minor-patch), reducing PR volume. prConcurrentLimit: 3: Restricts the maximum number of simultaneous Renovate PRs.- Concurrency Cancellation:
pull_request.ymlincludes aconcurrencyblock (cancel-in-progress: true). If a PR receives new commits (e.g. during a manual rebase), GitHub instantly cancels the running tests for the old commit, saving minutes.
🛠 Manual Release & Debugging
You can run the release logic locally using Fastlane to verify builds before pushing.
Prerequisites
fastlaneinstalled.key.propertiespresent (or environment variables set).service-account.jsonfor Google Play API access.
Commands
Run Internal Track Deployment locally:
fastlane deploy_internal
Note: This will perform the build, signing, and upload to Google Play, and will commit/tag version bumps.
Run Specific CI Checks Locally:
# Verify Code Style
./gradlew ktlintCheck
# Verify Static Analysis
./gradlew detekt
# Verify Android Lint
./gradlew lintDebug
# Verify Release Build (Compilation + R8)
./gradlew assembleRelease
📦 Versioning Strategy
Upnext uses Calendar Versioning (CalVer): YYYY.M.Patch
- Major: Year (e.g., 2025)
- Minor: Month (e.g., 1 for January)
- Patch: Incremental number for releases within that month.
File: version.properties
VERSION_CODE=214
VERSION_NAME=2025.1.4
Automated Bumping:
The Fastfile (deploy_internal lane) automatically:
- Increments
VERSION_CODEfor every build. - Sets
VERSION_NAMEtoYYYY.M.1(if new month) orYYYY.M.Patch+1(if same month).
🔧 Troubleshooting Guide
1. HTTP 403 / "Title Unknown" (Trakt API)
- Symptom: App runs, but data fails to load or showing titles are missing.
- Cause: Missing Trakt API Client ID/Secret in
local.propertiesor Secrets. - Fix: Ensure
TRAKT_CLIENT_IDandTRAKT_CLIENT_SECRETare set in GitHub Actions Secrets.
2. Release Build "Missing Keystore"
- Symptom:
assembleReleasefails withSigningConfig "release" is missing required property "storeFile". - Context: This should NOT happen in CI anymore due to our fallback logic.
- Fix: Check
app/build.gradle. Ensure thebuildTypes.releaseblock contains the fallback logic:if (signingConfigs.release.storeFile != null) { ... } else { signingConfig signingConfigs.debug }
3. Missing Resources / Permissions (Lint Failures)
- Symptom:
lintDebugfails with "Missing permission" (e.g.,WAKE_LOCK) or "Resource not found". - Cause: Multi-module projects (
core:common,core:data) often need their ownAndroidManifest.xmland resource definitions to satisfy lint, even if the app module provides them. - Fix: Add
AndroidManifest.xmlwith<uses-permission>to the specific module (e.g.,core/common/src/main/AndroidManifest.xml) or define the missing resource in that module.
4. Git Identity Issues
- Symptom: "Please tell me who you are" during CI/CD.
- Fix: The
deploy.ymlconfigures git user/email before tagging usinggithub-actions[bot].
📂 Key Files
.github/workflows/deploy.yml: Nightly CD workflow..github/workflows/pull_request.yml: PR CI workflow.fastlane/Fastfile: Build automation script.version.properties: App version definition.app/build.gradle: Build & signing configuration.
Converted and distributed by TomeVault — claim your Tome and manage your conversions.