kopia lustrzana https://github.com/meshtastic/Meshtastic-Android
339 wiersze
14 KiB
YAML
339 wiersze
14 KiB
YAML
name: Make Release
|
|
|
|
on:
|
|
workflow_dispatch:
|
|
push:
|
|
tags:
|
|
- 'v*'
|
|
|
|
concurrency:
|
|
group: ${{ github.workflow }}-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
permissions:
|
|
contents: write
|
|
pull-requests: read
|
|
id-token: write
|
|
attestations: write
|
|
|
|
jobs:
|
|
prepare-build-info:
|
|
runs-on: ubuntu-latest
|
|
outputs:
|
|
APP_VERSION_NAME: ${{ steps.get_version_name.outputs.APP_VERSION_NAME }}
|
|
APP_VERSION_CODE: ${{ steps.calculate_version_code.outputs.versionCode }}
|
|
BASE_TAG: ${{ steps.get_base_tag.outputs.BASE_TAG }}
|
|
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@v5
|
|
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: Determine Version Name from Tag
|
|
id: get_version_name
|
|
run: echo "APP_VERSION_NAME=$(echo ${GITHUB_REF_NAME#v} | sed 's/-.*//')" >> $GITHUB_OUTPUT
|
|
|
|
- name: Get Base Tag (for release/artifact naming)
|
|
id: get_base_tag
|
|
run: |
|
|
VERSION_NAME=$(echo ${GITHUB_REF_NAME#v} | sed 's/-.*//')
|
|
echo "BASE_TAG=v${VERSION_NAME}" >> $GITHUB_OUTPUT
|
|
|
|
- name: Extract VERSION_CODE_OFFSET from config.properties
|
|
id: get_version_code_offset
|
|
run: |
|
|
OFFSET=$(grep '^VERSION_CODE_OFFSET=' config.properties | cut -d'=' -f2)
|
|
echo "VERSION_CODE_OFFSET=$OFFSET" >> $GITHUB_OUTPUT
|
|
|
|
- name: Calculate Version Code from Git Commit Count
|
|
id: calculate_version_code
|
|
run: |
|
|
COMMIT_COUNT=$(git rev-list --count HEAD)
|
|
OFFSET=${{ steps.get_version_code_offset.outputs.VERSION_CODE_OFFSET }}
|
|
VERSION_CODE=$((COMMIT_COUNT + OFFSET))
|
|
echo "versionCode=$VERSION_CODE" >> $GITHUB_OUTPUT
|
|
shell: bash
|
|
|
|
prepare-release-environment:
|
|
runs-on: ubuntu-latest
|
|
needs: prepare-build-info
|
|
outputs:
|
|
exists: ${{ steps.check_and_clean.outputs.exists }}
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v5
|
|
- name: Check for Existing Release and Clean if Superseded
|
|
id: check_and_clean
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: |
|
|
BASE_TAG=${{ needs.prepare-build-info.outputs.BASE_TAG }}
|
|
COMMIT_SHA=$(git rev-parse HEAD)
|
|
RELEASE_INFO=$(gh release view $BASE_TAG --json targetCommitish -q ".targetCommitish.oid" || echo "")
|
|
if [ -z "$RELEASE_INFO" ]; then
|
|
echo "No existing release for tag '${BASE_TAG}'. Starting fresh."
|
|
echo "exists=false" >> $GITHUB_OUTPUT
|
|
elif [ "$RELEASE_INFO" == "$COMMIT_SHA" ]; then
|
|
echo "Existing release for '${BASE_TAG}' found on the current commit. This is a promotion."
|
|
echo "exists=true" >> $GITHUB_OUTPUT
|
|
else
|
|
echo "Existing release for '${BASE_TAG}' found on a DIFFERENT commit ($RELEASE_INFO)."
|
|
echo "This new tag supersedes the old one. Deleting old release and tag to restart the process."
|
|
gh release delete $BASE_TAG --cleanup-tag --yes || echo "Could not delete release. It might have been deleted already."
|
|
echo "Old release and tag deleted. A new build will be created."
|
|
echo "exists=false" >> $GITHUB_OUTPUT
|
|
fi
|
|
|
|
check-versioncode-google-play:
|
|
runs-on: ubuntu-latest
|
|
needs: prepare-build-info
|
|
outputs:
|
|
exists: ${{ steps.check_versioncode.outputs.exists }}
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v5
|
|
- name: Setup Fastlane
|
|
uses: ruby/setup-ruby@v1
|
|
with:
|
|
ruby-version: '3.2'
|
|
bundler-cache: true
|
|
- name: Check if versionCode exists on Google Play Internal Track
|
|
id: check_versioncode
|
|
env:
|
|
VERSION_CODE: ${{ needs.prepare-build-info.outputs.APP_VERSION_CODE }}
|
|
GOOGLE_PLAY_JSON_KEY: ${{ secrets.GOOGLE_PLAY_JSON_KEY }}
|
|
run: |
|
|
set -euo pipefail
|
|
echo "$GOOGLE_PLAY_JSON_KEY" > /tmp/play-store-credentials.json
|
|
exists=false
|
|
if bundle exec fastlane supply --help | grep -q -- '--json'; then
|
|
JSON=$(bundle exec fastlane supply --json_key /tmp/play-store-credentials.json --package_name com.geeksville.mesh --track internal --json || true)
|
|
if echo "$JSON" | jq -e ".tracks.internal.releases[].versionCodes[] | select(. == ${VERSION_CODE})" >/dev/null 2>&1; then
|
|
exists=true
|
|
fi
|
|
else
|
|
# Fallback: use fastlane action output and parse array from stdout
|
|
OUTFILE=$(mktemp)
|
|
bundle exec fastlane run google_play_track_version_codes json_key:/tmp/play-store-credentials.json package_name:com.geeksville.mesh track:internal --capture_output | tee "$OUTFILE" || true
|
|
ARR=$(grep -oE '\\[[^]]*\\]' "$OUTFILE" | head -n1)
|
|
if echo "$ARR" | tr -d '[] ' | tr ',' '\n' | grep -x "${VERSION_CODE}" >/dev/null 2>&1; then
|
|
exists=true
|
|
fi
|
|
fi
|
|
echo "exists=${exists}" >> $GITHUB_OUTPUT
|
|
|
|
release-google:
|
|
runs-on: ubuntu-latest
|
|
needs: [prepare-build-info, prepare-release-environment, check-versioncode-google-play]
|
|
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@v5
|
|
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:
|
|
GSERVICES: ${{ secrets.GSERVICES }}
|
|
KEYSTORE: ${{ secrets.KEYSTORE }}
|
|
KEYSTORE_FILENAME: ${{ secrets.KEYSTORE_FILENAME }}
|
|
KEYSTORE_PROPERTIES: ${{ secrets.KEYSTORE_PROPERTIES }}
|
|
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
|
|
echo $KEYSTORE | base64 -di > ./app/$KEYSTORE_FILENAME
|
|
echo "$KEYSTORE_PROPERTIES" > ./keystore.properties
|
|
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: Setup Fastlane
|
|
uses: ruby/setup-ruby@v1
|
|
with:
|
|
ruby-version: '3.2'
|
|
bundler-cache: true
|
|
|
|
- name: Build and Deploy to Internal Track
|
|
if: contains(github.ref_name, '-internal') && needs.prepare-release-environment.outputs.exists == 'false' && needs.check-versioncode-google-play.outputs.exists == 'false'
|
|
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 internal
|
|
|
|
- name: Build Google artifacts without upload
|
|
if: contains(github.ref_name, '-internal') && needs.prepare-release-environment.outputs.exists == 'false' && needs.check-versioncode-google-play.outputs.exists == 'true'
|
|
env:
|
|
VERSION_NAME: ${{ needs.prepare-build-info.outputs.APP_VERSION_NAME }}
|
|
VERSION_CODE: ${{ needs.prepare-build-info.outputs.APP_VERSION_CODE }}
|
|
run: ./gradlew clean bundleGoogleRelease assembleGoogleRelease -Pandroid.injected.version.name=${VERSION_NAME} -Pandroid.injected.version.code=${VERSION_CODE}
|
|
|
|
- name: Determine Fastlane Promotion Lane
|
|
id: fastlane_lane
|
|
if: "!contains(github.ref_name, '-internal')"
|
|
run: |
|
|
TAG_NAME="${{ github.ref_name }}"
|
|
if [[ "$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: Ensure internal track has version for promotion
|
|
if: "!contains(github.ref_name, '-internal') && needs.check-versioncode-google-play.outputs.exists != 'true'"
|
|
run: |
|
|
echo "::error::Cannot promote: versionCode ${{ needs.prepare-build-info.outputs.APP_VERSION_CODE }} not found on Google Play internal track. Run internal build first." >&2
|
|
exit 1
|
|
|
|
- name: Promote on Google Play
|
|
if: "steps.fastlane_lane.outputs.lane != '' && needs.check-versioncode-google-play.outputs.exists == 'true'"
|
|
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
|
|
if: needs.prepare-release-environment.outputs.exists == 'false' && contains(github.ref_name, '-internal')
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: google-aab
|
|
path: app/build/outputs/bundle/googleRelease/app-google-release.aab
|
|
retention-days: 1
|
|
|
|
- name: Upload Google APK artifact
|
|
if: needs.prepare-release-environment.outputs.exists == 'false' && contains(github.ref_name, '-internal')
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: google-apk
|
|
path: app/build/outputs/apk/google/release/app-google-release.apk
|
|
retention-days: 1
|
|
|
|
- name: Attest Google artifacts provenance
|
|
if: needs.prepare-release-environment.outputs.exists == 'false' && contains(github.ref_name, '-internal')
|
|
uses: actions/attest-build-provenance@v3
|
|
with:
|
|
subject-path: |
|
|
app/build/outputs/bundle/googleRelease/app-google-release.aab
|
|
app/build/outputs/apk/google/release/app-google-release.apk
|
|
|
|
release-fdroid:
|
|
if: contains(github.ref_name, '-internal') && needs.prepare-release-environment.outputs.exists == 'false' && needs.check-versioncode-google-play.outputs.exists == 'false'
|
|
runs-on: ubuntu-latest
|
|
needs: [prepare-build-info, prepare-release-environment, check-versioncode-google-play]
|
|
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@v5
|
|
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: app/build/outputs/apk/fdroid/release/app-fdroid-release.apk
|
|
retention-days: 1
|
|
|
|
- name: Attest F-Droid APK provenance
|
|
uses: actions/attest-build-provenance@v3
|
|
with:
|
|
subject-path: app/build/outputs/apk/fdroid/release/app-fdroid-release.apk
|
|
|
|
manage-github-release:
|
|
runs-on: ubuntu-latest
|
|
needs: [prepare-build-info, prepare-release-environment, check-versioncode-google-play, release-google, release-fdroid]
|
|
steps:
|
|
- name: Download all artifacts
|
|
if: needs.prepare-release-environment.outputs.exists == 'false'
|
|
uses: actions/download-artifact@v5
|
|
with:
|
|
path: ./artifacts
|
|
|
|
- name: Create GitHub Release
|
|
if: needs.prepare-release-environment.outputs.exists == 'false'
|
|
uses: softprops/action-gh-release@v2
|
|
with:
|
|
tag_name: ${{ needs.prepare-build-info.outputs.BASE_TAG }}
|
|
name: v${{ needs.prepare-build-info.outputs.APP_VERSION_NAME }}-internal
|
|
generate_release_notes: true
|
|
files: ./artifacts/*/*
|
|
draft: true
|
|
prerelease: true
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Promote GitHub Release
|
|
if: "!contains(github.ref_name, '-internal')"
|
|
uses: softprops/action-gh-release@v2
|
|
with:
|
|
tag_name: ${{ needs.prepare-build-info.outputs.BASE_TAG }}
|
|
name: ${{ github.ref_name }}
|
|
draft: false
|
|
prerelease: ${{ contains(github.ref_name, '-closed') || contains(github.ref_name, '-open') }}
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|