feat(ci): migrate to fastlane for release management (#3038)

Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
(cherry picked from commit 5cfa44cb64)
pull/3042/head
James Rich 2025-09-09 16:08:11 -05:00
rodzic bf11b7b342
commit d2d5487d92
32 zmienionych plików z 588 dodań i 212 usunięć

Wyświetl plik

@ -55,7 +55,7 @@ jobs:
# This will overflow Integer.MAX_VALUE in the year 6052, hopefully we'll have moved on by then.
run: echo "versionCode=$(( $(date +%s) / 60 ))" >> $GITHUB_OUTPUT
build-fdroid:
release-google:
runs-on: ubuntu-latest
needs: prepare-build-info
steps:
@ -79,54 +79,7 @@ jobs:
build-scan-terms-of-use-url: 'https://gradle.com/terms-of-service'
build-scan-terms-of-use-agree: 'yes'
- name: Load Fdroid secrets
run: |
echo $KEYSTORE | base64 -di > ./app/$KEYSTORE_FILENAME
echo "$KEYSTORE_PROPERTIES" > ./keystore.properties
env:
KEYSTORE: ${{ secrets.KEYSTORE }}
KEYSTORE_FILENAME: ${{ secrets.KEYSTORE_FILENAME }}
KEYSTORE_PROPERTIES: ${{ secrets.KEYSTORE_PROPERTIES }}
- name: Build F-Droid Release APK
run: |
./gradlew :app:assembleFdroidRelease --parallel --continue --scan
env:
VERSION_NAME: ${{ needs.prepare-build-info.outputs.APP_VERSION_NAME }}
VERSION_CODE: ${{ needs.prepare-build-info.outputs.APP_VERSION_CODE }}
- name: Upload F-Droid APK artifact
uses: actions/upload-artifact@v4
with:
name: fdroid-apk
path: app/build/outputs/apk/fdroid/release/app-fdroid-release.apk
retention-days: 1
build-google:
runs-on: ubuntu-latest
needs: prepare-build-info
steps:
- name: Checkout code
uses: actions/checkout@v5
with:
fetch-depth: 0
submodules: 'recursive'
- name: Set up JDK 21
uses: actions/setup-java@v5
with:
java-version: '21'
distribution: 'jetbrains'
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
with:
cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }}
build-scan-publish: true
build-scan-terms-of-use-url: 'https://gradle.com/terms-of-service'
build-scan-terms-of-use-agree: 'yes'
- name: Load Google secrets
- name: Load secrets
env:
GSERVICES: ${{ secrets.GSERVICES }}
KEYSTORE: ${{ secrets.KEYSTORE }}
@ -135,6 +88,7 @@ jobs:
DATADOG_APPLICATION_ID: ${{ secrets.DATADOG_APPLICATION_ID }}
DATADOG_CLIENT_TOKEN: ${{ secrets.DATADOG_CLIENT_TOKEN }}
GOOGLE_MAPS_API_KEY: ${{ secrets.GOOGLE_MAPS_API_KEY }}
GOOGLE_PLAY_JSON_KEY: ${{ secrets.GOOGLE_PLAY_JSON_KEY }}
run: |
rm -f ./app/google-services.json # Ensure clean state
echo $GSERVICES > ./app/google-services.json
@ -143,13 +97,33 @@ jobs:
echo "datadogApplicationId=$DATADOG_APPLICATION_ID" >> ./secrets.properties
echo "datadogClientToken=$DATADOG_CLIENT_TOKEN" >> ./secrets.properties
echo "MAPS_API_KEY=$GOOGLE_MAPS_API_KEY" >> ./secrets.properties
echo "$GOOGLE_PLAY_JSON_KEY" > ./fastlane/play-store-credentials.json
- name: Build Google Release Artifacts (AAB and APK)
- name: Setup Fastlane
uses: ruby/setup-ruby@v1
with:
ruby-version: '3.2'
bundler-cache: true
- name: Determine Fastlane Lane
id: fastlane_lane
run: |
./gradlew :app:bundleGoogleRelease :app:assembleGoogleRelease --parallel --continue --scan
TAG_NAME="${{ github.ref_name }}"
if [[ "$TAG_NAME" == *"-internal"* ]]; then
echo "lane=internal" >> $GITHUB_OUTPUT
elif [[ "$TAG_NAME" == *"-closed"* ]]; then
echo "lane=closed" >> $GITHUB_OUTPUT
elif [[ "$TAG_NAME" == *"-open"* ]]; then
echo "lane=open" >> $GITHUB_OUTPUT
else
echo "lane=production" >> $GITHUB_OUTPUT
fi
- name: Build and Deploy Google Play Tracks with Fastlane
env:
VERSION_NAME: ${{ needs.prepare-build-info.outputs.APP_VERSION_NAME }}
VERSION_CODE: ${{ needs.prepare-build-info.outputs.APP_VERSION_CODE }}
run: bundle exec fastlane ${{ steps.fastlane_lane.outputs.lane }}
- name: Upload Google AAB artifact
uses: actions/upload-artifact@v4
@ -165,21 +139,9 @@ jobs:
path: app/build/outputs/apk/google/release/app-google-release.apk
retention-days: 1
- name: Upload Mapping File
uses: actions/upload-artifact@v4
with:
name: mapping
path: app/build/outputs/mapping/googleRelease/mapping.txt
retention-days: 1
publish-release:
release-fdroid:
runs-on: ubuntu-latest
needs: [prepare-build-info, build-fdroid, build-google]
outputs:
RELEASE_UPLOAD_URL: ${{ steps.create_gh_release.outputs.upload_url }}
CHANGELOG: ${{ steps.generate_changelog.outputs.changelog }}
APP_VERSION_NAME: ${{ needs.prepare-build-info.outputs.APP_VERSION_NAME }}
APP_VERSION_CODE: ${{ needs.prepare-build-info.outputs.APP_VERSION_CODE }}
needs: prepare-build-info
steps:
- name: Checkout code
uses: actions/checkout@v5
@ -187,34 +149,69 @@ jobs:
fetch-depth: 0
submodules: 'recursive'
- name: Download F-Droid APK
uses: actions/download-artifact@v5
- name: Set up JDK 21
uses: actions/setup-java@v5
with:
java-version: '21'
distribution: 'jetbrains'
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
with:
cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }}
build-scan-publish: true
build-scan-terms-of-use-url: 'https://gradle.com/terms-of-service'
build-scan-terms-of-use-agree: 'yes'
- name: Load secrets
env:
KEYSTORE: ${{ secrets.KEYSTORE }}
KEYSTORE_FILENAME: ${{ secrets.KEYSTORE_FILENAME }}
KEYSTORE_PROPERTIES: ${{ secrets.KEYSTORE_PROPERTIES }}
run: |
echo $KEYSTORE | base64 -di > ./app/$KEYSTORE_FILENAME
echo "$KEYSTORE_PROPERTIES" > ./keystore.properties
- name: Setup Fastlane
uses: ruby/setup-ruby@v1
with:
ruby-version: '3.2'
bundler-cache: true
- name: Build F-Droid with Fastlane
env:
VERSION_NAME: ${{ needs.prepare-build-info.outputs.APP_VERSION_NAME }}
VERSION_CODE: ${{ needs.prepare-build-info.outputs.APP_VERSION_CODE }}
run: bundle exec fastlane fdroid_build
- name: Upload F-Droid APK artifact
uses: actions/upload-artifact@v4
with:
name: fdroid-apk
path: ./build-artifacts/fdroid
path: app/build/outputs/apk/fdroid/release/app-fdroid-release.apk
retention-days: 1
finalize-release:
runs-on: ubuntu-latest
needs: [release-google, release-fdroid]
steps:
- name: Download Google AAB
uses: actions/download-artifact@v5
uses: actions/download-artifact@v4
with:
name: google-aab
path: ./build-artifacts/google/bundle
path: ./google/bundle
- name: Download Google APK
uses: actions/download-artifact@v5
uses: actions/download-artifact@v4
with:
name: google-apk
path: ./build-artifacts/google/apk
path: ./google/apk
- name: Download Mapping File
uses: actions/download-artifact@v5
- name: Download F-Droid APK
uses: actions/download-artifact@v4
with:
name: mapping
path: ./build-artifacts/google/mapping
- name: Create version_info.txt
run: |
echo "versionNameBase=${{ needs.prepare-build-info.outputs.APP_VERSION_NAME }}" > ./version_info.txt
echo "versionCode=${{ needs.prepare-build-info.outputs.APP_VERSION_CODE }}" >> ./version_info.txt
name: fdroid-apk
path: ./fdroid
- name: Create GitHub Release
id: create_gh_release
@ -224,56 +221,10 @@ jobs:
name: Release ${{ github.ref_name }}
generate_release_notes: true
files: |
./build-artifacts/google/bundle/app-google-release.aab
./build-artifacts/google/apk/app-google-release.apk
./build-artifacts/fdroid/app-fdroid-release.apk
./version_info.txt
./google/bundle/app-google-release.aab
./google/apk/app-google-release.apk
./fdroid/app-fdroid-release.apk
draft: true
prerelease: ${{ contains(github.ref_name, '-internal') || contains(github.ref_name, '-closed') || contains(github.ref_name, '-open') }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Create Play Store whatsnew File
run: |
mkdir -p whatsnew
echo "For detailed release notes, please visit: ${{ steps.create_gh_release.outputs.url }}" > whatsnew/whatsnew-en-US
shell: bash
# Attest the build artifacts for supply chain security.
# See: https://github.com/meshtastic/Meshtastic-Android/attestations
- name: Attest Build Provenance
uses: actions/attest-build-provenance@v3
with:
subject-path: |
./build-artifacts/google/bundle/app-google-release.aab
./build-artifacts/google/apk/app-google-release.apk
./build-artifacts/fdroid/app-fdroid-release.apk
- name: Determine Play Store Track
id: play_track
run: |
TAG_NAME="${{ github.ref_name }}"
if [[ "$TAG_NAME" == *"-internal"* ]]; then
echo "track=internal" >> $GITHUB_OUTPUT
elif [[ "$TAG_NAME" == *"-closed"* ]]; then
echo "track=NewAlpha" >> $GITHUB_OUTPUT
elif [[ "$TAG_NAME" == *"-open"* ]]; then
echo "track=beta" >> $GITHUB_OUTPUT
else
echo "track=production" >> $GITHUB_OUTPUT
echo "user_fraction=0.1" >> $GITHUB_OUTPUT
echo "status=inProgress" >> $GITHUB_OUTPUT
fi
- name: Upload to Google Play
if: success() && github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
uses: r0adkll/upload-google-play@v1.1.3
with:
serviceAccountJsonPlainText: ${{ secrets.GOOGLE_PLAY_JSON_KEY }}
packageName: com.geeksville.mesh
releaseFiles: ./build-artifacts/google/bundle/app-google-release.aab
track: ${{ steps.play_track.outputs.track }}
status: ${{ steps.play_track.outputs.status || (steps.play_track.outputs.track == 'internal' && 'completed' || 'draft') }}
userFraction: ${{ steps.play_track.outputs.userFraction }}
whatsNewDirectory: ./whatsnew/
mappingFile: ./build-artifacts/google/mapping/mapping.txt

2
.gitignore vendored
Wyświetl plik

@ -32,3 +32,5 @@ keystore.properties
# Secrets
/secrets.properties
/fastlane/play-store-credentials.json
/fastlane/report.xml

1
.ruby-version 100644
Wyświetl plik

@ -0,0 +1 @@
3.2

3
Gemfile 100644
Wyświetl plik

@ -0,0 +1,3 @@
source "https://rubygems.org"
gem "fastlane"

229
Gemfile.lock 100644
Wyświetl plik

@ -0,0 +1,229 @@
GEM
remote: https://rubygems.org/
specs:
CFPropertyList (3.0.7)
base64
nkf
rexml
addressable (2.8.7)
public_suffix (>= 2.0.2, < 7.0)
artifactory (3.0.17)
atomos (0.1.3)
aws-eventstream (1.4.0)
aws-partitions (1.1157.0)
aws-sdk-core (3.232.0)
aws-eventstream (~> 1, >= 1.3.0)
aws-partitions (~> 1, >= 1.992.0)
aws-sigv4 (~> 1.9)
base64
bigdecimal
jmespath (~> 1, >= 1.6.1)
logger
aws-sdk-kms (1.112.0)
aws-sdk-core (~> 3, >= 3.231.0)
aws-sigv4 (~> 1.5)
aws-sdk-s3 (1.199.0)
aws-sdk-core (~> 3, >= 3.231.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.5)
aws-sigv4 (1.12.1)
aws-eventstream (~> 1, >= 1.0.2)
babosa (1.0.4)
base64 (0.3.0)
bigdecimal (3.2.3)
claide (1.1.0)
colored (1.2)
colored2 (3.1.2)
commander (4.6.0)
highline (~> 2.0.0)
declarative (0.0.20)
digest-crc (0.7.0)
rake (>= 12.0.0, < 14.0.0)
domain_name (0.6.20240107)
dotenv (2.8.1)
emoji_regex (3.2.3)
excon (0.112.0)
faraday (1.10.4)
faraday-em_http (~> 1.0)
faraday-em_synchrony (~> 1.0)
faraday-excon (~> 1.1)
faraday-httpclient (~> 1.0)
faraday-multipart (~> 1.0)
faraday-net_http (~> 1.0)
faraday-net_http_persistent (~> 1.0)
faraday-patron (~> 1.0)
faraday-rack (~> 1.0)
faraday-retry (~> 1.0)
ruby2_keywords (>= 0.0.4)
faraday-cookie_jar (0.0.7)
faraday (>= 0.8.0)
http-cookie (~> 1.0.0)
faraday-em_http (1.0.0)
faraday-em_synchrony (1.0.1)
faraday-excon (1.1.0)
faraday-httpclient (1.0.1)
faraday-multipart (1.1.1)
multipart-post (~> 2.0)
faraday-net_http (1.0.2)
faraday-net_http_persistent (1.2.0)
faraday-patron (1.0.0)
faraday-rack (1.0.0)
faraday-retry (1.0.3)
faraday_middleware (1.2.1)
faraday (~> 1.0)
fastimage (2.4.0)
fastlane (2.228.0)
CFPropertyList (>= 2.3, < 4.0.0)
addressable (>= 2.8, < 3.0.0)
artifactory (~> 3.0)
aws-sdk-s3 (~> 1.0)
babosa (>= 1.0.3, < 2.0.0)
bundler (>= 1.12.0, < 3.0.0)
colored (~> 1.2)
commander (~> 4.6)
dotenv (>= 2.1.1, < 3.0.0)
emoji_regex (>= 0.1, < 4.0)
excon (>= 0.71.0, < 1.0.0)
faraday (~> 1.0)
faraday-cookie_jar (~> 0.0.6)
faraday_middleware (~> 1.0)
fastimage (>= 2.1.0, < 3.0.0)
fastlane-sirp (>= 1.0.0)
gh_inspector (>= 1.1.2, < 2.0.0)
google-apis-androidpublisher_v3 (~> 0.3)
google-apis-playcustomapp_v1 (~> 0.1)
google-cloud-env (>= 1.6.0, < 2.0.0)
google-cloud-storage (~> 1.31)
highline (~> 2.0)
http-cookie (~> 1.0.5)
json (< 3.0.0)
jwt (>= 2.1.0, < 3)
mini_magick (>= 4.9.4, < 5.0.0)
multipart-post (>= 2.0.0, < 3.0.0)
naturally (~> 2.2)
optparse (>= 0.1.1, < 1.0.0)
plist (>= 3.1.0, < 4.0.0)
rubyzip (>= 2.0.0, < 3.0.0)
security (= 0.1.5)
simctl (~> 1.6.3)
terminal-notifier (>= 2.0.0, < 3.0.0)
terminal-table (~> 3)
tty-screen (>= 0.6.3, < 1.0.0)
tty-spinner (>= 0.8.0, < 1.0.0)
word_wrap (~> 1.0.0)
xcodeproj (>= 1.13.0, < 2.0.0)
xcpretty (~> 0.4.1)
xcpretty-travis-formatter (>= 0.0.3, < 2.0.0)
fastlane-sirp (1.0.0)
sysrandom (~> 1.0)
gh_inspector (1.1.3)
google-apis-androidpublisher_v3 (0.54.0)
google-apis-core (>= 0.11.0, < 2.a)
google-apis-core (0.11.3)
addressable (~> 2.5, >= 2.5.1)
googleauth (>= 0.16.2, < 2.a)
httpclient (>= 2.8.1, < 3.a)
mini_mime (~> 1.0)
representable (~> 3.0)
retriable (>= 2.0, < 4.a)
rexml
google-apis-iamcredentials_v1 (0.17.0)
google-apis-core (>= 0.11.0, < 2.a)
google-apis-playcustomapp_v1 (0.13.0)
google-apis-core (>= 0.11.0, < 2.a)
google-apis-storage_v1 (0.31.0)
google-apis-core (>= 0.11.0, < 2.a)
google-cloud-core (1.8.0)
google-cloud-env (>= 1.0, < 3.a)
google-cloud-errors (~> 1.0)
google-cloud-env (1.6.0)
faraday (>= 0.17.3, < 3.0)
google-cloud-errors (1.5.0)
google-cloud-storage (1.47.0)
addressable (~> 2.8)
digest-crc (~> 0.4)
google-apis-iamcredentials_v1 (~> 0.1)
google-apis-storage_v1 (~> 0.31.0)
google-cloud-core (~> 1.6)
googleauth (>= 0.16.2, < 2.a)
mini_mime (~> 1.0)
googleauth (1.8.1)
faraday (>= 0.17.3, < 3.a)
jwt (>= 1.4, < 3.0)
multi_json (~> 1.11)
os (>= 0.9, < 2.0)
signet (>= 0.16, < 2.a)
highline (2.0.3)
http-cookie (1.0.8)
domain_name (~> 0.5)
httpclient (2.9.0)
mutex_m
jmespath (1.6.2)
json (2.13.2)
jwt (2.10.2)
base64
logger (1.7.0)
mini_magick (4.13.2)
mini_mime (1.1.5)
multi_json (1.17.0)
multipart-post (2.4.1)
mutex_m (0.3.0)
nanaimo (0.4.0)
naturally (2.3.0)
nkf (0.2.0)
optparse (0.6.0)
os (1.1.4)
plist (3.7.2)
public_suffix (6.0.2)
rake (13.3.0)
representable (3.2.0)
declarative (< 0.1.0)
trailblazer-option (>= 0.1.1, < 0.2.0)
uber (< 0.2.0)
retriable (3.1.2)
rexml (3.4.3)
rouge (3.28.0)
ruby2_keywords (0.0.5)
rubyzip (2.4.1)
security (0.1.5)
signet (0.21.0)
addressable (~> 2.8)
faraday (>= 0.17.5, < 3.a)
jwt (>= 1.5, < 4.0)
multi_json (~> 1.10)
simctl (1.6.10)
CFPropertyList
naturally
sysrandom (1.0.5)
terminal-notifier (2.0.0)
terminal-table (3.0.2)
unicode-display_width (>= 1.1.1, < 3)
trailblazer-option (0.1.2)
tty-cursor (0.7.1)
tty-screen (0.8.2)
tty-spinner (0.9.3)
tty-cursor (~> 0.7)
uber (0.1.0)
unicode-display_width (2.6.0)
word_wrap (1.0.0)
xcodeproj (1.27.0)
CFPropertyList (>= 2.3.3, < 4.0)
atomos (~> 0.1.3)
claide (>= 1.0.2, < 2.0)
colored2 (~> 3.1)
nanaimo (~> 0.4.0)
rexml (>= 3.3.6, < 4.0)
xcpretty (0.4.1)
rouge (~> 3.28.0)
xcpretty-travis-formatter (1.0.1)
xcpretty (~> 0.2, >= 0.0.7)
PLATFORMS
arm64-darwin-24
ruby
DEPENDENCIES
fastlane
BUNDLED WITH
2.6.9

Wyświetl plik

@ -1,92 +1,131 @@
# Meshtastic-Android Release Process
This document outlines the steps for releasing a new version of the Meshtastic-Android application. Adhering to this process ensures consistency and helps manage the release lifecycle, leveraging automation via the `release.yml` GitHub Action.
This document outlines the steps for releasing a new version of the Meshtastic-Android application. The process is heavily automated using GitHub Actions and Fastlane, triggered by pushing a Git tag from a `release/*` branch.
**Note on Automation:** The `release.yml` GitHub Action is primarily triggered by **pushing a Git tag** matching the pattern `v*` (e.g., `v1.2.3`, `v1.2.3-open.1`). It can also be manually triggered via `workflow_dispatch` from the GitHub Actions UI.
## High-Level Overview
The workflow uses a simple and robust **"upload-only"** model. It automatically:
* Determines a `versionName` from the Git tag.
* Generates a unique, always-increasing `versionCode` based on the number of minutes since the Unix epoch. This prevents `versionCode` conflicts and will not overflow until the year 6052.
* Builds fresh F-Droid (APK) and Google (AAB, APK) artifacts for every run.
* Creates a **draft GitHub Release** and attaches the artifacts.
* Attests build provenance for the artifacts.
* **Uploads** the newly built AAB directly to the appropriate track in the Google Play Console based on the tag.
The automation is designed to be safe, repeatable, and efficient. When a new tag matching the `v*` pattern is pushed from a release branch, the `release.yml` GitHub Action workflow will:
There is no promotion of builds between tracks; every release is a new, independent upload. Finalizing and publishing the GitHub Release and the Google Play Store submission remain **manual steps**.
1. **Determine Versioning:** A `versionName` is derived from the Git tag, and a unique, always-increasing `versionCode` is generated from the current timestamp.
2. **Build in Parallel:** Two jobs run simultaneously to build the `google` and `fdroid` flavors of the app.
3. **Deploy to Google Play:** The `google` build job uses Fastlane to automatically upload the Android App Bundle (AAB) to the correct track on the Google Play Console, based on the tag name.
4. **Create a Draft GitHub Release:** After both builds are complete, a final job gathers the artifacts (AAB, Google APK, and F-Droid APK) and creates a single, consolidated **draft** release on GitHub.
## Prerequisites
Finalizing and publishing the release on both GitHub and the Google Play Console are the only **manual steps**.
Before initiating the release process, ensure the following are completed:
## Versioning and Tagging Strategy
1. **Main Branch Stability:** The `main` branch (or your chosen release branch) must be stable, with all features and bug fixes intended for the release merged and thoroughly tested.
2. **Automated Testing:** All automated tests must be passing.
3. **Versioning and Tagging Strategy:**
* Tags **must** start with `v` and follow Semantic Versioning (e.g., `vX.X.X`).
* Use the correct suffixes for the desired release track:
* **Internal/QA:** `vX.X.X-internal.Y`
* **Closed Alpha:** `vX.X.X-closed.Y`
* **Open Alpha/Beta:** `vX.X.X-open.Y`
* **Production:** `vX.X.X` (no suffix)
* **Recommendation:** Before tagging, update `VERSION_NAME_BASE` in `buildSrc/src/main/kotlin/Configs.kt` to match the `X.X.X` part of your tag. This ensures consistency for local development builds.
The entire process is driven by your Git tagging strategy. Tags **must** start with `v` and should follow Semantic Versioning. Use the correct suffix for the desired release track:
## Core Release Workflow: Triggering via Tag Push
* **Internal Track:** `vX.X.X-internal.Y` (e.g., `v2.3.5-internal.1`)
* **Closed Track:** `vX.X.X-closed.Y` (e.g., `v2.3.5-closed.1`)
* **Open Track:** `vX.X.X-open.Y` (e.g., `v2.3.5-open.1`)
* **Production Track:** `vX.X.X` (e.g., `v2.3.5`)
1. **Create and push a tag for the desired release track.**
```bash
# This build will be uploaded and rolled out on the 'internal' track
git tag v1.2.3-internal.1
git push origin v1.2.3-internal.1
```
2. **Wait for the workflow to complete.**
3. **Verify the build** in the Google Play Console and with testers.
4. When ready to advance to the next track, create and push a new tag.
```bash
# This will create and upload a NEW build to the 'NewAlpha' (closed alpha) track
git tag v1.2.3-closed.1
git push origin v1.2.3-closed.1
```
The `.Y` suffix is for iterations. If you find a bug in `v2.3.5-closed.1`, you would fix it on the release branch and tag the new commit as `v2.3.5-closed.2`.
## Iterating on a Bad Build
## Core Release Workflow
If you discover a critical bug in a build, the process is simple:
The entire release process happens on a dedicated release branch, allowing `main` to remain open for new feature development.
1. **Fix the Code:** Merge the necessary bug fixes into your main branch.
2. **Create a New Iteration Tag:** Create a new tag for the same release phase, simply incrementing the final number.
```bash
# If v1.2.3-internal.1 was bad, the new build is v1.2.3-internal.2
git tag v1.2.3-internal.2
git push origin v1.2.3-internal.2
```
3. **A New Build is Uploaded:** The workflow will run, generate a new epoch-minute-based `versionCode`, and upload a fresh build to the `internal` track. There is no risk of a `versionCode` collision.
### 1. Creating the Release Branch
First, create a `release/X.X.X` branch from a stable `main`. This branch is now "feature frozen." Only critical bug fixes should be added.
## Managing Different Release Phases (Manual Steps Post-Workflow)
As a housekeeping step, it's recommended to update the `VERSION_NAME_BASE` in `buildSrc/src/main/kotlin/Configs.kt` on this new branch. While the final release version is set by the Git tag in CI, this ensures local development builds have a sensible version name.
After the `release.yml` workflow completes, manual actions are needed on GitHub and in the Google Play Console.
```bash
git checkout main
git pull origin main
git checkout -b release/2.3.5
# (Now, update the version in buildSrc, commit the change, and then push)
git push origin release/2.3.5
```
### Phase 1: Internal / QA Release
* **Tag format:** `vX.X.X-internal.Y`
* **Automated Action:** The AAB is **uploaded** to the `internal` track and rolled out automatically.
* **Manual Steps:**
1. **GitHub:** Find the **draft release**, verify artifacts, and publish it if desired.
2. **Google Play Console:** Verify the release has been successfully rolled out to internal testers.
### 2. Testing and Iterating on a Track
Start by deploying to the `internal` track to begin testing.
### Phase 2: Closed Alpha Release
* **Tag format:** `vX.X.X-closed.Y`
* **Automated Action:** A new AAB is built and **uploaded** as a **draft** to the `NewAlpha` track.
* **Manual Steps:**
1. **GitHub:** Find and publish the **draft release**.
2. **Google Play Console:** Manually review the draft release and submit it for your closed alpha testers.
**A. Create and Push a Tag:**
Tag a commit on the release branch to trigger the automation.
```bash
# Ensure you are on the release branch
git checkout release/2.3.5
### Phase 3: Open Alpha / Beta Release
* **Tag format:** `vX.X.X-open.Y`
* **Automated Action:** A new AAB is built and **uploaded** as a **draft** to the `beta` track.
* **Manual Steps:**
1. **GitHub:** Find and publish the **draft pre-release**.
2. **Google Play Console:** Manually review the draft, add release notes, and submit it.
# Tag for the "Internal" track
git tag v2.3.5-internal.1
git push origin v2.3.5-internal.1
```
### Phase 4: Production Release
* **Tag format:** `vX.X.X`
* **Automated Action:** A new AAB is built and **uploaded** to the `production` track. By default, it is configured for a 10% staged rollout.
* **Manual Steps:**
1. **GitHub:** Find the **draft release**. **Crucially, uncheck "This is a pre-release"** before publishing.
2. **Google Play Console:** Manually review the release, add release notes, and **start the staged rollout**.
**B. Monitor and Verify:**
Monitor the workflow in GitHub Actions. Once complete, verify the build in the Google Play Console and with your internal testers.
**C. Apply Fixes (If Necessary):**
If a bug is found, commit the fix to the release branch. Remember to also cherry-pick or merge this fix back to `main`. Then, create an iterated tag.
```bash
# Assuming you've committed a fix
git tag v2.3.5-internal.2
git push origin v2.3.5-internal.2
```
This will upload a new, fixed build to the same `internal` track. Repeat this process until the build is stable.
### 3. Promoting to the Next Track
Once you are confident that a build is stable, you can "promote" it to a wider audience by tagging the **exact same commit** for the next track.
```bash
# The commit tagged as v2.3.5-internal.2 is stable and ready for the "Closed" track
git tag v2.3.5-closed.1
git push origin v2.3.5-closed.1
```
This triggers the workflow again, but this time it will send the build to the `NewAlpha` track for your closed testers. You can then continue the cycle of testing, fixing, and promoting all the way to production.
### 4. Merging Back to `main`
After the final production release is complete and verified, merge the release branch back into `main` to ensure any hotfixes are included. Then, delete the release branch.
```bash
git checkout main
git pull origin main
git merge release/2.3.5
git push origin main
git branch -d release/2.3.5
git push origin --delete release/2.3.5
```
## Manual Finalization Steps
### For Internal Releases
* **Automated Action:** The AAB is uploaded to the `internal` track and is **rolled out to 100% of testers automatically**.
* **Your Manual Step:**
1. **Verify the build** in the Google Play Console and with your internal testers.
### For Closed Releases
* **Automated Action:** The AAB is uploaded to the `NewAlpha` track and is **rolled out to 100% of testers automatically**.
* **Your Manual Step:**
1. **Verify the build** in the Google Play Console and with your closed track testers.
### For Open Releases
* **Automated Action:** The AAB is uploaded to the `beta` track and begins a **staged rollout to 25% of your open track testers automatically**.
* **Your Manual Steps:**
1. **Verify the build** in the Google Play Console.
2. **(Optional)** Go to the GitHub "Releases" page, find the **draft release**, and publish it so your open track testers can see the official release notes.
### For Production Releases
* **Automated Action:**
* The AAB is uploaded to the `production` track in a **draft** state. It is **not** rolled out to any users.
* A corresponding **draft** release is created on GitHub with all build artifacts.
* **Your Manual Steps:**
1. **Publish on GitHub First:** Go to the GitHub "Releases" page and find the draft. Review the release notes and artifacts, then **Publish release**. This makes the release notes publicly visible.
2. **Promote on Google Play Second:** *After* publishing on GitHub, go to your Google Play Console. Find the draft release, review it, and then proceed to **start the rollout to production**.
## Monitoring the Release
After a release has been rolled out to users (especially for Open and Production), it is crucial to monitor its performance.
* **Google Play Console:** Keep a close eye on the **Vitals** section for your app. Pay special attention to the crash rate and ANR (Application Not Responding) rate. A sudden spike in these numbers is a strong indicator of a problem.
* **Datadog:** Check your Datadog dashboards for any unusual trends or new errors that may have been introduced with the release.
* **Crashlytics:** Review crash reports in Firebase Crashlytics to identify any new issues that users may be experiencing.
* **User Reviews:** Monitor user reviews on the Google Play Store for any negative feedback or reports of bugs.
* **Community Feedback:** Monitor Discord, GitHub Issues, and community forums for feedback from users who have received the update.
If you identify a critical issue, be prepared to halt the rollout in the Google Play Console and tag a new, fixed version.

Wyświetl plik

@ -1,3 +0,0 @@
This is a beta release of the meshtastic.org project. We'd love you to try it and tell us what you think. You'll need to buy an inexpensive ($30ish) radio from a variety of vendors to use this application, see our website for details. We don't make these devices.
***Please*** if you encounter problems or have questions: post on our forum at https://github.com/orgs/meshtastic/discussions and we'll work together to fix them (we are volunteer hobbyists). We would really appreciate good Google reviews if you think this is a good project.

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 16 KiB

Wyświetl plik

@ -1 +0,0 @@
An inexpensive open-source GPS mesh radio for hiking, skiing, flying, marching.

Wyświetl plik

@ -1 +0,0 @@
Meshtastic

Wyświetl plik

@ -1 +0,0 @@
For more information visit <a href="https://meshtastic.org">meshtastic.org</a>. This application is made by volunteers. We are friendly and actively respond to forum posts with any questions you have. Post at <a href="https://github.com/orgs/meshtastic/discussions">https://github.com/orgs/meshtastic/discussions</a> and we'll help.

Wyświetl plik

@ -1 +0,0 @@
For more information visit <a href="https://meshtastic.org">meshtastic.org</a>. This application is made by volunteers. We are friendly and actively respond to forum posts with any questions you have. Post at <a href="https://github.com/orgs/meshtastic/discussions">https://github.com/orgs/meshtastic/discussions</a> and we'll help.

Wyświetl plik

@ -1 +0,0 @@
An internal build

Wyświetl plik

@ -1 +0,0 @@
For more information visit <a href="https://meshtastic.org">meshtastic.org</a>. This application is made by volunteers. We are friendly and actively respond to forum posts with any questions you have. Post at <a href="https://github.com/orgs/meshtastic/discussions">https://github.com/orgs/meshtastic/discussions</a> and we'll help.

2
fastlane/Appfile 100644
Wyświetl plik

@ -0,0 +1,2 @@
json_key_file("./fastlane/play-store-credentials.json") # Path to the json secret file - Follow https://docs.fastlane.tools/actions/supply/#setup to get one
package_name("com.geeksville.mesh") # e.g. com.krausefx.app

86
fastlane/Fastfile 100644
Wyświetl plik

@ -0,0 +1,86 @@
# This file contains the fastlane.tools configuration
# You can find the documentation at https://docs.fastlane.tools
#
# For a list of all available actions, check out
#
# https://docs.fastlane.tools/actions
#
# For a list of all available plugins, check out
#
# https://docs.fastlane.tools/plugins/available-plugins
#
# Uncomment the line if you want fastlane to automatically update itself
# update_fastlane
default_platform(:android)
platform :android do
desc "Runs all the tests"
lane :test do
gradle(task: "test")
end
desc "Deploy a new version to the internal track on Google Play"
lane :internal do
aab_path = build_google_release
upload_to_play_store(
track: 'internal',
aab: aab_path,
release_status: 'completed'
)
end
desc "Deploy a new version to the closed track on Google Play"
lane :closed do
aab_path = build_google_release
upload_to_play_store(
track: 'NewAlpha',
aab: aab_path,
release_status: 'completed'
)
end
desc "Deploy a new version to the open track on Google Play"
lane :open do
aab_path = build_google_release
upload_to_play_store(
track: 'beta',
aab: aab_path,
release_status: 'inProgress',
rollout: '0.25'
)
end
desc "Deploy a new version to the production track on Google Play"
lane :production do
aab_path = build_google_release
upload_to_play_store(
track: 'production',
aab: aab_path,
release_status: 'draft'
)
end
desc "Build the F-Droid release"
lane :fdroid_build do
gradle(
task: "clean assembleFdroidRelease",
properties: {
"android.injected.version.name" => ENV['VERSION_NAME'],
"android.injected.version.code" => ENV['VERSION_CODE']
}
)
end
private_lane :build_google_release do
gradle(
task: "clean bundleGoogleRelease assembleGoogleRelease",
print_command: false,
properties: {
"android.injected.version.name" => ENV['VERSION_NAME'],
"android.injected.version.code" => ENV['VERSION_CODE']
}
)
end
end

48
fastlane/README.md 100644
Wyświetl plik

@ -0,0 +1,48 @@
fastlane documentation
----
# Installation
Make sure you have the latest version of the Xcode command line tools installed:
```sh
xcode-select --install
```
For _fastlane_ installation instructions, see [Installing _fastlane_](https://docs.fastlane.tools/#installing-fastlane)
# Available Actions
## Android
### android test
```sh
[bundle exec] fastlane android test
```
Runs all the tests
### android beta
```sh
[bundle exec] fastlane android beta
```
Submit a new Beta Build to Crashlytics Beta
### android deploy
```sh
[bundle exec] fastlane android deploy
```
Deploy a new version to the Google Play
----
This README.md is auto-generated and will be re-generated every time [_fastlane_](https://fastlane.tools) is run.
More information about _fastlane_ can be found on [fastlane.tools](https://fastlane.tools).
The documentation of _fastlane_ can be found on [docs.fastlane.tools](https://docs.fastlane.tools).

Wyświetl plik

@ -0,0 +1 @@
For detailed release notes, please visit: https://github.com/meshtastic/Meshtastic-Android/releases/

Wyświetl plik

@ -0,0 +1,21 @@
Meshtastic is a tool for using Android devices with open-source, off-grid mesh radios. This app is the main client for the Meshtastic project, allowing you to manage your mesh devices and communicate with other users.
For more information about the Meshtastic project, please visit our website: [meshtastic.org](https://www.meshtastic.org). The firmware that runs on the radio devices is a separate open-source project, which you can find here: [https://github.com/meshtastic/Meshtastic-device](https://github.com/meshtastic/Meshtastic-device).
**Community and Support**
This project is currently in beta. We would love to hear from you! If you have questions, feedback, or encounter any problems, please join our friendly and active community:
* **Discussion Forum:** [https://github.com/orgs/meshtastic/discussions](https://github.com/orgs/meshtastic/discussions)
* **Discord:** [https://discord.gg/meshtastic](https://discord.gg/meshtastic)
* **Report an Issue:** [https://github.com/meshtastic/Meshtastic-Android/issues](https://github.com/meshtastic/Meshtastic-Android/issues)
**Documentation**
To learn more about the features and capabilities of this app and Meshtastic, please view our official documentation:
[**View Documentation**](https://meshtastic.org/docs/)
**Translations**
You can help translate the app into your native language using Crowdin:
[https://crowdin.meshtastic.org/android](https://crowdin.meshtastic.org/android)

Wyświetl plik

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 67 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 67 KiB

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 13 KiB

Wyświetl plik

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 91 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 91 KiB

Wyświetl plik

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 108 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 108 KiB

Wyświetl plik

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 125 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 125 KiB

Wyświetl plik

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 2.0 MiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 2.0 MiB

Wyświetl plik

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 72 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 72 KiB

Wyświetl plik

@ -0,0 +1 @@
The official app for Meshtastic, an open-source, off-grid, mesh GPS radio.

Wyświetl plik

@ -0,0 +1 @@
Meshtastic