Files
App/.github/workflows/publish-beta.yml
2025-11-11 09:28:12 -06:00

340 lines
12 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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 }}