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
|
@ -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
|
||||
|
|
|
@ -32,3 +32,5 @@ keystore.properties
|
|||
|
||||
# Secrets
|
||||
/secrets.properties
|
||||
/fastlane/play-store-credentials.json
|
||||
/fastlane/report.xml
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
3.2
|
|
@ -0,0 +1,3 @@
|
|||
source "https://rubygems.org"
|
||||
|
||||
gem "fastlane"
|
|
@ -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
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
Przed Szerokość: | Wysokość: | Rozmiar: 16 KiB |
|
@ -1 +0,0 @@
|
|||
An inexpensive open-source GPS mesh radio for hiking, skiing, flying, marching.
|
|
@ -1 +0,0 @@
|
|||
Meshtastic
|
|
@ -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.
|
|
@ -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.
|
|
@ -1 +0,0 @@
|
|||
An internal build
|
|
@ -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.
|
|
@ -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
|
|
@ -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
|
|
@ -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).
|
|
@ -0,0 +1 @@
|
|||
For detailed release notes, please visit: https://github.com/meshtastic/Meshtastic-Android/releases/
|
|
@ -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)
|
Przed Szerokość: | Wysokość: | Rozmiar: 67 KiB Po Szerokość: | Wysokość: | Rozmiar: 67 KiB |
Po Szerokość: | Wysokość: | Rozmiar: 13 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 91 KiB Po Szerokość: | Wysokość: | Rozmiar: 91 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 108 KiB Po Szerokość: | Wysokość: | Rozmiar: 108 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 125 KiB Po Szerokość: | Wysokość: | Rozmiar: 125 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 2.0 MiB Po Szerokość: | Wysokość: | Rozmiar: 2.0 MiB |
Przed Szerokość: | Wysokość: | Rozmiar: 72 KiB Po Szerokość: | Wysokość: | Rozmiar: 72 KiB |
|
@ -0,0 +1 @@
|
|||
The official app for Meshtastic, an open-source, off-grid, mesh GPS radio.
|
|
@ -0,0 +1 @@
|
|||
Meshtastic
|