feat: separate store delivery from releases
This commit is contained in:
1 parent
313c3dab64
commit
c941dcf032
14 files changed
+876
-70
No files matched your search
@@ -4,8 +4,8 @@ on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
release_tag:
|
||||
description: "Upload the signed arm64 APK to this existing GitHub Release (optional)"
|
||||
required: false
|
||||
description: "Upload the signed arm64 APK to this existing Draft GitHub Release"
|
||||
required: true
|
||||
type: string
|
||||
release:
|
||||
types: [published]
|
||||
@@ -33,7 +33,7 @@ jobs:
|
||||
github.repository == 'tianma-if/edgeever' &&
|
||||
(
|
||||
github.event_name == 'release' ||
|
||||
(github.event_name == 'workflow_dispatch' && inputs.release_tag != '')
|
||||
github.event_name == 'workflow_dispatch'
|
||||
)
|
||||
}}
|
||||
name: Plan Android release asset
|
||||
@@ -49,7 +49,7 @@ jobs:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Validate Draft Release target
|
||||
if: github.event_name == 'workflow_dispatch' && inputs.release_tag != ''
|
||||
if: github.event_name == 'workflow_dispatch'
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
RELEASE_TAG: ${{ inputs.release_tag }}
|
||||
@@ -123,7 +123,6 @@ jobs:
|
||||
${{
|
||||
github.repository == 'tianma-if/edgeever' &&
|
||||
github.event_name == 'workflow_dispatch' &&
|
||||
inputs.release_tag != '' &&
|
||||
needs.release-plan.result == 'success' &&
|
||||
needs.release-plan.outputs.asset_ready == 'false' &&
|
||||
needs.release-plan.outputs.rebuild == 'false'
|
||||
@@ -155,10 +154,8 @@ jobs:
|
||||
github.repository == 'tianma-if/edgeever' &&
|
||||
(
|
||||
(github.event_name == 'push' && github.ref == 'refs/heads/main') ||
|
||||
(github.event_name == 'workflow_dispatch' && inputs.release_tag == '') ||
|
||||
(
|
||||
github.event_name == 'workflow_dispatch' &&
|
||||
inputs.release_tag != '' &&
|
||||
needs.release-plan.result == 'success' &&
|
||||
needs.release-plan.outputs.asset_ready == 'false' &&
|
||||
needs.release-plan.outputs.rebuild == 'true'
|
||||
@@ -206,17 +203,8 @@ jobs:
|
||||
printf '%s' "$ANDROID_KEYSTORE_BASE64" | openssl base64 -d -A > "$RUNNER_TEMP/edgeever-upload.p12"
|
||||
chmod 600 "$RUNNER_TEMP/edgeever-upload.p12"
|
||||
|
||||
- name: Build signed release AAB
|
||||
if: github.event_name == 'workflow_dispatch' && inputs.release_tag == ''
|
||||
env:
|
||||
ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
|
||||
ANDROID_KEYSTORE_FILE: ${{ runner.temp }}/edgeever-upload.p12
|
||||
ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }}
|
||||
ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }}
|
||||
run: bun run build:android:play
|
||||
|
||||
- name: Build signed release APK for GitHub Release
|
||||
if: github.event_name == 'workflow_dispatch' && inputs.release_tag != ''
|
||||
if: github.event_name == 'workflow_dispatch'
|
||||
env:
|
||||
ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
|
||||
ANDROID_KEYSTORE_FILE: ${{ runner.temp }}/edgeever-upload.p12
|
||||
@@ -225,23 +213,12 @@ jobs:
|
||||
EDGE_EVER_ANDROID_APK_ARCHS: arm64-v8a
|
||||
run: bun run build:android:apk
|
||||
|
||||
- name: Verify release AAB signature
|
||||
if: github.event_name == 'workflow_dispatch' && inputs.release_tag == ''
|
||||
run: |
|
||||
"$JAVA_HOME/bin/jarsigner" -verify app/build/outputs/bundle/release/*.aab
|
||||
working-directory: apps/mobile/android
|
||||
|
||||
- name: Verify release APK signature
|
||||
if: github.event_name == 'workflow_dispatch' && inputs.release_tag != ''
|
||||
if: github.event_name == 'workflow_dispatch'
|
||||
run: |
|
||||
"$ANDROID_SDK_ROOT/build-tools/36.0.0/apksigner" verify --verbose app/build/outputs/apk/release/app-release.apk
|
||||
working-directory: apps/mobile/android
|
||||
|
||||
- name: Verify R8 deobfuscation mapping
|
||||
if: github.event_name == 'workflow_dispatch' && inputs.release_tag == ''
|
||||
run: test -s app/build/outputs/mapping/release/mapping.txt
|
||||
working-directory: apps/mobile/android
|
||||
|
||||
- name: Upload APK
|
||||
if: github.event_name == 'push'
|
||||
uses: actions/upload-artifact@v7
|
||||
@@ -251,17 +228,8 @@ jobs:
|
||||
if-no-files-found: error
|
||||
compression-level: 0
|
||||
|
||||
- name: Upload release AAB
|
||||
if: github.event_name == 'workflow_dispatch' && inputs.release_tag == ''
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: edgeever-android-release-aab
|
||||
path: apps/mobile/android/app/build/outputs/bundle/release/*.aab
|
||||
if-no-files-found: error
|
||||
compression-level: 0
|
||||
|
||||
- name: Upload release APK to GitHub Release
|
||||
if: github.event_name == 'workflow_dispatch' && inputs.release_tag != ''
|
||||
if: github.event_name == 'workflow_dispatch'
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
RELEASE_TAG: ${{ inputs.release_tag }}
|
||||
@@ -270,14 +238,6 @@ jobs:
|
||||
cp apps/mobile/android/app/build/outputs/apk/release/app-release.apk "$release_asset"
|
||||
gh release upload "$RELEASE_TAG" "$release_asset" --repo "$GITHUB_REPOSITORY" --clobber
|
||||
|
||||
- name: Upload R8 deobfuscation mapping
|
||||
if: github.event_name == 'workflow_dispatch' && inputs.release_tag == ''
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: edgeever-android-release-mapping
|
||||
path: apps/mobile/android/app/build/outputs/mapping/release/mapping.txt
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Remove temporary upload keystore
|
||||
if: always() && github.event_name == 'workflow_dispatch'
|
||||
run: rm -f "$RUNNER_TEMP/edgeever-upload.p12"
|
||||
@@ -0,0 +1,231 @@
|
||||
name: Deliver Mobile Stores
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
release_tag:
|
||||
description: "Formal GitHub Release tag to deliver (vX.Y.Z)"
|
||||
required: true
|
||||
type: string
|
||||
platform:
|
||||
description: "Store platform"
|
||||
required: true
|
||||
default: both
|
||||
type: choice
|
||||
options:
|
||||
- both
|
||||
- android
|
||||
- ios
|
||||
android_track:
|
||||
description: "Google Play track (production is uploaded as a Draft)"
|
||||
required: true
|
||||
default: internal
|
||||
type: choice
|
||||
options:
|
||||
- internal
|
||||
- alpha
|
||||
- beta
|
||||
- production
|
||||
production_confirmation:
|
||||
description: "For Google Play production, type the exact release tag"
|
||||
required: false
|
||||
default: ""
|
||||
type: string
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: edgeever-store-delivery-${{ inputs.release_tag }}
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
plan:
|
||||
if: github.repository == 'tianma-if/edgeever'
|
||||
name: Validate store delivery source
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
version: ${{ steps.validate.outputs.version }}
|
||||
version_code: ${{ steps.validate.outputs.version_code }}
|
||||
steps:
|
||||
- name: Check out the immutable Release tag
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
ref: ${{ inputs.release_tag }}
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Validate formal Release and resolve its predecessor
|
||||
id: release
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
RELEASE_TAG: ${{ inputs.release_tag }}
|
||||
run: |
|
||||
release="$(
|
||||
gh api "repos/${GITHUB_REPOSITORY}/releases/tags/${RELEASE_TAG}"
|
||||
)"
|
||||
test "$(jq -r '.draft' <<<"$release")" = "false"
|
||||
test "$(jq -r '.prerelease' <<<"$release")" = "false"
|
||||
test "$(jq -r '.tag_name' <<<"$release")" = "$RELEASE_TAG"
|
||||
|
||||
release_target="$(jq -r '.target_commitish' <<<"$release")"
|
||||
test "$(git rev-parse "${RELEASE_TAG}^{commit}")" = "$(git rev-parse "${release_target}^{commit}")"
|
||||
|
||||
mapfile -t release_tags < <(
|
||||
gh api "repos/${GITHUB_REPOSITORY}/releases?per_page=100" \
|
||||
--jq '.[] | select(.draft == false and .prerelease == false) | .tag_name'
|
||||
)
|
||||
previous_tag=""
|
||||
current_found="false"
|
||||
for candidate in "${release_tags[@]}"; do
|
||||
if [[ "$current_found" = "true" ]]; then
|
||||
previous_tag="$candidate"
|
||||
break
|
||||
fi
|
||||
if [[ "$candidate" = "$RELEASE_TAG" ]]; then
|
||||
current_found="true"
|
||||
fi
|
||||
done
|
||||
test "$current_found" = "true"
|
||||
test -n "$previous_tag"
|
||||
git fetch origin "refs/tags/${previous_tag}:refs/tags/${previous_tag}"
|
||||
echo "previous_tag=$previous_tag" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Validate mobile version and audited change range
|
||||
id: validate
|
||||
env:
|
||||
ANDROID_TRACK: ${{ inputs.android_track }}
|
||||
PLATFORM: ${{ inputs.platform }}
|
||||
PREVIOUS_TAG: ${{ steps.release.outputs.previous_tag }}
|
||||
PRODUCTION_CONFIRMATION: ${{ inputs.production_confirmation }}
|
||||
RELEASE_TAG: ${{ inputs.release_tag }}
|
||||
run: |
|
||||
node scripts/validate-store-delivery.mjs \
|
||||
"$RELEASE_TAG" \
|
||||
"$PREVIOUS_TAG" \
|
||||
"$PLATFORM" \
|
||||
"$ANDROID_TRACK" \
|
||||
"$PRODUCTION_CONFIRMATION" |
|
||||
tee -a "$GITHUB_OUTPUT"
|
||||
|
||||
android:
|
||||
needs: plan
|
||||
if: inputs.platform == 'android' || inputs.platform == 'both'
|
||||
name: Deliver Google Play
|
||||
runs-on: [self-hosted, macOS, ARM64, edgeever-mobile]
|
||||
timeout-minutes: 60
|
||||
environment: ${{ inputs.android_track == 'production' && 'store-production' || 'store-delivery' }}
|
||||
env:
|
||||
ANDROID_HOME: /opt/homebrew/share/android-commandlinetools
|
||||
ANDROID_SDK_ROOT: /opt/homebrew/share/android-commandlinetools
|
||||
JAVA_HOME: /opt/homebrew/opt/openjdk@17/libexec/openjdk.jdk/Contents/Home
|
||||
steps:
|
||||
- name: Check out the immutable Release tag
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
ref: ${{ inputs.release_tag }}
|
||||
clean: true
|
||||
|
||||
- name: Set up Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: 1.3.14
|
||||
|
||||
- name: Restore Android upload keystore
|
||||
env:
|
||||
ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }}
|
||||
run: |
|
||||
test -n "$ANDROID_KEYSTORE_BASE64"
|
||||
printf '%s' "$ANDROID_KEYSTORE_BASE64" | openssl base64 -d -A > "$RUNNER_TEMP/edgeever-upload.p12"
|
||||
chmod 600 "$RUNNER_TEMP/edgeever-upload.p12"
|
||||
|
||||
- name: Build and verify signed Play bundle
|
||||
env:
|
||||
ANDROID_KEYSTORE_FILE: ${{ runner.temp }}/edgeever-upload.p12
|
||||
ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
|
||||
ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }}
|
||||
ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }}
|
||||
run: bun run build:android:play
|
||||
|
||||
- name: Preserve Play bundle and deobfuscation mapping
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: edgeever-${{ inputs.release_tag }}-google-play
|
||||
path: |
|
||||
apps/mobile/android/app/build/outputs/bundle/release/app-release.aab
|
||||
apps/mobile/android/app/build/outputs/mapping/release/mapping.txt
|
||||
if-no-files-found: error
|
||||
compression-level: 0
|
||||
|
||||
- name: Upload bundle to Google Play
|
||||
env:
|
||||
ANDROID_TRACK: ${{ inputs.android_track }}
|
||||
EXPO_TOKEN: ${{ secrets.EXPO_TOKEN }}
|
||||
run: |
|
||||
test -n "$EXPO_TOKEN"
|
||||
bunx eas-cli submit \
|
||||
--platform android \
|
||||
--profile "store-${ANDROID_TRACK}" \
|
||||
--path android/app/build/outputs/bundle/release/app-release.aab \
|
||||
--non-interactive \
|
||||
--wait
|
||||
working-directory: apps/mobile
|
||||
|
||||
- name: Remove temporary upload keystore
|
||||
if: always()
|
||||
run: rm -f "$RUNNER_TEMP/edgeever-upload.p12"
|
||||
|
||||
ios:
|
||||
needs: plan
|
||||
if: inputs.platform == 'ios' || inputs.platform == 'both'
|
||||
name: Deliver App Store Connect
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 90
|
||||
environment: store-delivery
|
||||
steps:
|
||||
- name: Check out the immutable Release tag
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
ref: ${{ inputs.release_tag }}
|
||||
|
||||
- name: Set up Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: 1.3.14
|
||||
|
||||
- name: Install dependencies
|
||||
run: bun install --frozen-lockfile
|
||||
|
||||
- name: Build the iOS archive on EAS
|
||||
id: build
|
||||
env:
|
||||
EXPO_TOKEN: ${{ secrets.EXPO_TOKEN }}
|
||||
RELEASE_TAG: ${{ inputs.release_tag }}
|
||||
run: |
|
||||
test -n "$EXPO_TOKEN"
|
||||
build_json="$(
|
||||
bunx eas-cli build \
|
||||
--platform ios \
|
||||
--profile production \
|
||||
--message "Store delivery ${RELEASE_TAG}" \
|
||||
--freeze-credentials \
|
||||
--non-interactive \
|
||||
--wait \
|
||||
--json
|
||||
)"
|
||||
build_id="$(jq -r 'if type == "array" then .[0].id else .id end' <<<"$build_json")"
|
||||
test -n "$build_id"
|
||||
test "$build_id" != "null"
|
||||
echo "build_id=$build_id" >> "$GITHUB_OUTPUT"
|
||||
working-directory: apps/mobile
|
||||
|
||||
- name: Upload archive to App Store Connect and TestFlight
|
||||
env:
|
||||
EXPO_TOKEN: ${{ secrets.EXPO_TOKEN }}
|
||||
run: |
|
||||
bunx eas-cli submit \
|
||||
--platform ios \
|
||||
--profile store-ios \
|
||||
--id "${{ steps.build.outputs.build_id }}" \
|
||||
--non-interactive \
|
||||
--wait
|
||||
working-directory: apps/mobile
|
||||
Reference in new issue
Block a user