mirror of
https://github.com/Jellify-Music/App.git
synced 2026-01-06 11:00:09 -06:00
340 lines
12 KiB
YAML
340 lines
12 KiB
YAML
name: Publish Android APK and TestFlight Betas
|
||
on:
|
||
workflow_dispatch:
|
||
inputs:
|
||
build-platform:
|
||
description: 'Select the platform to build'
|
||
required: true
|
||
default: 'Both'
|
||
type: choice
|
||
options:
|
||
- Android
|
||
- iOS
|
||
- Both
|
||
|
||
version-bump:
|
||
description: 'Version bump type'
|
||
required: true
|
||
default: 'No Bump'
|
||
type: choice
|
||
options:
|
||
- No Bump
|
||
- minor
|
||
- patch
|
||
- major
|
||
|
||
jobs:
|
||
generate-release-notes:
|
||
runs-on: ubuntu-latest
|
||
outputs:
|
||
release_notes: ${{ steps.set-output.outputs.release_notes }}
|
||
steps:
|
||
- name: 📦 Checkout
|
||
uses: actions/checkout@v4
|
||
with:
|
||
fetch-depth: 0
|
||
token: ${{ secrets.SIGNING_REPO_PAT }}
|
||
|
||
- name: 🧠 Collect commit messages
|
||
id: commits
|
||
run: |
|
||
git fetch --tags --quiet
|
||
|
||
# Find the latest tag reachable from current HEAD
|
||
LAST_TAG=$(git describe --tags --abbrev=0)
|
||
|
||
# Get all non-merge commit messages since that tag
|
||
COMMIT_MESSAGES=$(git log --no-merges --pretty=format:"- %s" "${LAST_TAG}..HEAD")
|
||
|
||
# Output for GitHub Actions
|
||
{
|
||
echo "messages<<EOF"
|
||
echo "$COMMIT_MESSAGES"
|
||
echo "EOF"
|
||
} >> "$GITHUB_OUTPUT"
|
||
|
||
|
||
- name: 📜 Generate release notes using Node.js
|
||
run: |
|
||
yarn install --network-concurrency 1
|
||
node scripts/generate-release-notes.js "${{ steps.commits.outputs.messages }}"
|
||
env:
|
||
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
||
|
||
- name: 🧾 Read release notes from file and export
|
||
id: set-output
|
||
run: |
|
||
NOTES=$(cat release_notes.txt)
|
||
echo "release_notes<<EOF" >> $GITHUB_OUTPUT
|
||
echo "$NOTES" >> $GITHUB_OUTPUT
|
||
echo "EOF" >> $GITHUB_OUTPUT
|
||
|
||
publish-android:
|
||
if: ${{ github.event.inputs['build-platform'] == 'Android' || github.event.inputs['build-platform'] == 'Both' }}
|
||
runs-on: macos-15
|
||
outputs:
|
||
version: ${{ steps.setver.outputs.version }}
|
||
steps:
|
||
- name: 🛒 Checkout
|
||
uses: actions/checkout@v4
|
||
with:
|
||
token: ${{ secrets.SIGNING_REPO_PAT }}
|
||
|
||
- name: 🖥 Setup Node 20
|
||
uses: actions/setup-node@v4
|
||
with:
|
||
node-version: 20
|
||
|
||
- name: 💎 Set up Ruby
|
||
uses: ruby/setup-ruby@v1
|
||
with:
|
||
ruby-version: '3.0'
|
||
bundler-cache: true
|
||
|
||
- name: 🍎 Run yarn init-android
|
||
run: yarn install --network-concurrency 1
|
||
|
||
- name: ➕ Version Up
|
||
if: ${{ github.event.inputs['version-bump'] != 'No Bump' }}
|
||
run: yarn react-native bump-version --type ${{ github.event.inputs['version-bump'] }}
|
||
|
||
- id: setver
|
||
run: echo "version=$(node -p -e "require('./package.json').version")" >> $GITHUB_OUTPUT
|
||
|
||
|
||
- name: 💬 Echo package.json version to Github ENV
|
||
run: echo VERSION_NUMBER=$(node -p -e "require('./package.json').version") >> $GITHUB_ENV
|
||
|
||
- name: 🔑 Setup release keystore
|
||
run: |
|
||
if [ -n "${{ secrets.ANDROID_SIGNING_BASE64 }}" ]; then
|
||
echo "${{ secrets.ANDROID_SIGNING_BASE64 }}" | base64 --decode > android/app/jellify.keystore
|
||
echo "Release keystore created"
|
||
else
|
||
echo "ERROR: No keystore secret found!"
|
||
exit 1
|
||
fi
|
||
|
||
- name: 🔑 Setup Play Store credentials
|
||
run: |
|
||
if [ -n "$PLAY_STORE_CREDENTIALS" ]; then
|
||
echo "$PLAY_STORE_CREDENTIALS" > android/play-store-credentials.json
|
||
echo "Play Store credentials created"
|
||
else
|
||
echo "ERROR: No Play Store credentials secret found!"
|
||
exit 1
|
||
fi
|
||
env:
|
||
PLAY_STORE_CREDENTIALS: ${{ secrets.PLAY_STORE_SERVICE_ACCOUNT }}
|
||
|
||
- name: 🤫 Output TelemetryDeck Secrets to TelemetryDeck.json
|
||
run: |
|
||
echo "{" > telemetrydeck.json
|
||
echo "\"appID\": \"${{ secrets.TELEMETRYDECK_APPID }}\"," >> telemetrydeck.json
|
||
echo "\"clientUser\": \"anonymous\"," >> telemetrydeck.json
|
||
echo "\"app\": \"Jellify\"" >> telemetrydeck.json
|
||
echo "}" >> telemetrydeck.json
|
||
|
||
|
||
- name: 🤫 Output Glitchtip Secrets to Glitchtip.json
|
||
run: |
|
||
echo "{" > glitchtip.json
|
||
echo "\"dsn\": \"${{ secrets.GLITCHTIP_DSN }}\"" >> glitchtip.json
|
||
echo "}" >> glitchtip.json
|
||
|
||
- name: ✅ Validate Config Files
|
||
run: |
|
||
node -e "JSON.parse(require('fs').readFileSync('telemetrydeck.json'))"
|
||
node -e "JSON.parse(require('fs').readFileSync('glitchtip.json'))"
|
||
|
||
- name: 🚀 Run Android fastlane deploy
|
||
run: yarn fastlane:android:deploy
|
||
env:
|
||
KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
|
||
KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }}
|
||
KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }}
|
||
|
||
- name: 📤 Upload Android Artifacts
|
||
uses: actions/upload-artifact@v4
|
||
with:
|
||
name: android-artifacts
|
||
path: ./android/app/build/outputs/apk/release/*.apk
|
||
|
||
|
||
publish-iOS:
|
||
if: ${{ github.event.inputs['build-platform'] == 'iOS' || github.event.inputs['build-platform'] == 'Both' }}
|
||
runs-on: macos-15
|
||
outputs:
|
||
version: ${{ steps.setver.outputs.version }}
|
||
needs: [generate-release-notes]
|
||
steps:
|
||
|
||
- name: 🛒 Checkout
|
||
uses: actions/checkout@v4
|
||
with:
|
||
token: ${{ secrets.SIGNING_REPO_PAT }}
|
||
|
||
- name: 🖥 Setup Node 20
|
||
uses: actions/setup-node@v4
|
||
with:
|
||
node-version: 20
|
||
|
||
- name: 🍎 Setup Xcode
|
||
uses: ./.github/actions/setup-xcode
|
||
|
||
- name: 🍎 Run yarn init-ios:new-arch
|
||
run: yarn init-ios:new-arch
|
||
|
||
- name: ➕ Version Up
|
||
if: ${{ github.event.inputs['version-bump'] != 'No Bump' }}
|
||
run: yarn react-native bump-version --type ${{ github.event.inputs['version-bump'] }}
|
||
|
||
- id: setver
|
||
run: echo "version=$(node -p -e "require('./package.json').version")" >> $GITHUB_OUTPUT
|
||
|
||
- name: 💬 Echo package.json version to Github ENV
|
||
run: echo VERSION_NUMBER=$(node -p -e "require('./package.json').version") >> $GITHUB_ENV
|
||
|
||
- name: 🤫 Output App Store Connect API Key JSON to Fastlane
|
||
run: echo -e '${{ secrets.APPSTORE_CONNECT_API_KEY_JSON }}' > appstore_connect_api_key.json
|
||
working-directory: ./ios/fastlane
|
||
|
||
- name: 🤫 Output TelemetryDeck Secrets to TelemetryDeck.json
|
||
run: |
|
||
echo "{" > telemetrydeck.json
|
||
echo "\"appID\": \"${{ secrets.TELEMETRYDECK_APPID }}\"," >> telemetrydeck.json
|
||
echo "\"clientUser\": \"anonymous\"," >> telemetrydeck.json
|
||
echo "\"app\": \"Jellify\"" >> telemetrydeck.json
|
||
echo "}" >> telemetrydeck.json
|
||
|
||
|
||
- name: 🤫 Output Glitchtip Secrets to Glitchtip.json
|
||
run: |
|
||
echo "{" > glitchtip.json
|
||
echo "\"dsn\": \"${{ secrets.GLITCHTIP_DSN }}\"" >> glitchtip.json
|
||
echo "}" >> glitchtip.json
|
||
|
||
- name: ✅ Validate Config Files
|
||
run: |
|
||
node -e "JSON.parse(require('fs').readFileSync('telemetrydeck.json'))"
|
||
node -e "JSON.parse(require('fs').readFileSync('glitchtip.json'))"
|
||
|
||
- name: 🚀 Run iOS fastlane build and publish to TestFlight
|
||
run: yarn fastlane:ios:beta
|
||
env:
|
||
APPSTORE_CONNECT_API_KEY_JSON: ${{ secrets.APPSTORE_CONNECT_API_KEY_JSON }}
|
||
FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD: ${{ secrets.FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD }}
|
||
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
|
||
MATCH_REPO_PAT: "anultravioletaurora:${{ secrets.SIGNING_REPO_PAT }}"
|
||
|
||
- name: 📤 Upload iOS Artifact
|
||
uses: actions/upload-artifact@v4
|
||
with:
|
||
name: ios-artifacts
|
||
path: ./ios/Jellify.ipa
|
||
|
||
finalize-release:
|
||
needs: [publish-android, publish-iOS, generate-release-notes]
|
||
if: always()
|
||
runs-on: macos-15
|
||
steps:
|
||
- name: 🛒 Checkout Repo
|
||
uses: actions/checkout@v4
|
||
with:
|
||
token: ${{ secrets.SIGNING_REPO_PAT }}
|
||
|
||
- name: ❌ Fail if selected job failed
|
||
run: |
|
||
SELECTED="${{ github.event.inputs['build-platform'] }}"
|
||
IOS_RESULT="${{ needs.publish-ios.result }}"
|
||
ANDROID_RESULT="${{ needs.publish-android.result }}"
|
||
|
||
echo "Selected: $SELECTED"
|
||
echo "iOS Result: $IOS_RESULT"
|
||
echo "Android Result: $ANDROID_RESULT"
|
||
|
||
if [[ "$SELECTED" == "iOS" && "$IOS_RESULT" != "success" ]]; then
|
||
echo "❌ iOS build failed!"
|
||
exit 1
|
||
fi
|
||
|
||
if [[ "$SELECTED" == "Android" && "$ANDROID_RESULT" != "success" ]]; then
|
||
echo "❌ Android build failed!"
|
||
exit 1
|
||
fi
|
||
|
||
if [[ "$SELECTED" == "Both" && ( "$IOS_RESULT" != "success" || "$ANDROID_RESULT" != "success" ) ]]; then
|
||
echo "❌ One or more platform builds failed!"
|
||
exit 1
|
||
fi
|
||
|
||
- name: 📦 Install dependencies
|
||
run: yarn install --network-concurrency 1
|
||
|
||
- name: ⬇️ Download Android Artifacts
|
||
if: ${{ github.event.inputs['build-platform'] == 'Android' || github.event.inputs['build-platform'] == 'Both' }}
|
||
uses: actions/download-artifact@v4
|
||
with:
|
||
name: android-artifacts
|
||
path: artifacts/
|
||
|
||
- name: ⬇️ Download iOS Artifacts
|
||
if: ${{ github.event.inputs['build-platform'] == 'iOS' || github.event.inputs['build-platform'] == 'Both' }}
|
||
uses: actions/download-artifact@v4
|
||
with:
|
||
name: ios-artifacts
|
||
path: artifacts/
|
||
|
||
- name: ➕ Version Up
|
||
if: ${{ github.event.inputs['version-bump'] != 'No Bump' }}
|
||
run: yarn react-native bump-version --type ${{ github.event.inputs['version-bump'] }}
|
||
|
||
- name: 🔢 Set artifact version numbers
|
||
run: |
|
||
VERSION=${{ needs.publish-ios.outputs.version || needs.publish-android.outputs.version }}
|
||
mkdir final-artifacts
|
||
|
||
# Rename IPA
|
||
if [ -f artifacts/Jellify.ipa ]; then
|
||
cp artifacts/Jellify.ipa "final-artifacts/Jellify-${VERSION}.ipa"
|
||
fi
|
||
|
||
# Rename APKs
|
||
if [ -d artifacts/ ]; then
|
||
for apk in artifacts/*.apk; do
|
||
filename=$(basename "$apk")
|
||
cp "$apk" "final-artifacts/Jellify-${VERSION}-${filename}"
|
||
done
|
||
fi
|
||
|
||
- name: 🔢 Commit version bump if any
|
||
if: ${{ github.event.inputs['version-bump'] != 'No Bump' }}
|
||
run: |
|
||
git config --global user.name "anultravioletaurora"
|
||
git config --global user.email "violet@jellify.app"
|
||
git add package.json ios/Jellify.xcodeproj/project.pbxproj android/app/build.gradle || true
|
||
git commit -m "[skip actions] version bump" || echo "No changes to commit"
|
||
git pull origin main
|
||
git push origin main
|
||
|
||
- name: 🎉 Create Unified GitHub Release
|
||
uses: ncipollo/release-action@v1
|
||
id: githubRelease
|
||
with:
|
||
artifacts: ./final-artifacts/*
|
||
name: ${{ needs.publish-ios.outputs.version || needs.publish-android.outputs.version }}
|
||
tag: ${{ needs.publish-ios.outputs.version || needs.publish-android.outputs.version }}
|
||
body: ${{ needs.generate-release-notes.outputs.release_notes }}
|
||
prerelease: true
|
||
token: ${{ secrets.SIGNING_REPO_PAT }}
|
||
|
||
- name: 🗣️ Notify on Discord
|
||
run: |
|
||
cd ios
|
||
bundle install && bundle exec fastlane notifyOnDiscordForRelease
|
||
cd ..
|
||
env:
|
||
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
||
APP_VERSION: ${{ needs.publish-ios.outputs.version || needs.publish-android.outputs.version }}
|
||
release_url: ${{ steps.githubRelease.outputs.html_url }}
|
||
RELEASE_NOTES: ${{ needs.generate-release-notes.outputs.release_notes }} |