iOS CI #11
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: iOS CI | |
| on: | |
| push: | |
| tags: [ 'v*' ] | |
| schedule: | |
| # GitHub Actions cron uses UTC: 21:00 UTC is 05:00 in Asia/Shanghai. | |
| - cron: '0 21 * * *' | |
| workflow_dispatch: | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| prepare-version: | |
| name: Prepare version | |
| runs-on: ubuntu-latest | |
| outputs: | |
| version_code: ${{ steps.version.outputs.version_code }} | |
| version_name: ${{ steps.version.outputs.version_name }} | |
| channel: ${{ steps.version.outputs.channel }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v7 | |
| with: | |
| fetch-depth: 0 | |
| - name: Resolve version | |
| id: version | |
| run: | | |
| COMMIT_TIMESTAMP="$(git show -s --format=%ct HEAD)" | |
| VERSION_CODE="$(TZ=Asia/Shanghai date -d "@${COMMIT_TIMESTAMP}" +%Y%m%d%H)" | |
| if [[ "$GITHUB_REF_TYPE" == "tag" ]]; then | |
| VERSION_NAME="${GITHUB_REF_NAME#v}" | |
| CHANNEL="release" | |
| else | |
| VERSION_NAME="$(awk -F= '/^appVersionName=/{print $2; exit}' gradle.properties)" | |
| CHANNEL="pre-release" | |
| fi | |
| echo "version_code=${VERSION_CODE}" >> "$GITHUB_OUTPUT" | |
| echo "version_name=${VERSION_NAME}" >> "$GITHUB_OUTPUT" | |
| echo "channel=${CHANNEL}" >> "$GITHUB_OUTPUT" | |
| build-ios: | |
| name: Build iOS IPA | |
| needs: prepare-version | |
| runs-on: macos-15-intel | |
| timeout-minutes: 60 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v7 | |
| - name: Setup JDK | |
| uses: actions/setup-java@v5 | |
| with: | |
| distribution: 'temurin' | |
| java-version: '21' | |
| - name: Setup Gradle cache | |
| uses: gradle/actions/setup-gradle@v5 | |
| - name: Generate Kotlin framework for CocoaPods | |
| run: ./gradlew :shared:core-native:generateDummyFramework | |
| - name: Install CocoaPods dependencies | |
| run: pod install --project-directory=iosApp | |
| - name: Build unsigned IPA | |
| env: | |
| VERSION_CODE: ${{ needs.prepare-version.outputs.version_code }} | |
| VERSION_NAME: ${{ needs.prepare-version.outputs.version_name }} | |
| run: | | |
| ARCHIVE_PATH="$PWD/build/ios/iosApp.xcarchive" | |
| LOG_PATH="$PWD/build/ios/xcodebuild.log" | |
| mkdir -p "$(dirname "${LOG_PATH}")" | |
| xcodebuild \ | |
| -workspace iosApp/iosApp.xcworkspace \ | |
| -scheme iosApp \ | |
| -configuration Release \ | |
| -sdk iphoneos \ | |
| -jobs 1 \ | |
| -archivePath "${ARCHIVE_PATH}" \ | |
| -derivedDataPath "$PWD/build/ios/DerivedData" \ | |
| archive \ | |
| CODE_SIGNING_ALLOWED=NO \ | |
| CODE_SIGNING_REQUIRED=NO \ | |
| CODE_SIGN_IDENTITY="" \ | |
| DEVELOPMENT_TEAM="" \ | |
| APP_VERSION_CODE="${VERSION_CODE}" \ | |
| APP_VERSION_NAME="${VERSION_NAME}" > "${LOG_PATH}" 2>&1 & | |
| XCODEBUILD_PID=$! | |
| while kill -0 "${XCODEBUILD_PID}" 2>/dev/null; do | |
| sleep 60 | |
| echo "::notice::xcodebuild is still running; recent log output follows." | |
| ps -o pid,etime,%mem,command -p "${XCODEBUILD_PID}" || true | |
| pgrep -alf 'GradleDaemon|konanc|xcodebuild' || true | |
| tail -n 60 "${LOG_PATH}" || true | |
| done | |
| if ! wait "${XCODEBUILD_PID}"; then | |
| echo "::error::xcodebuild failed; final log output follows." | |
| tail -n 200 "${LOG_PATH}" || true | |
| exit 1 | |
| fi | |
| tail -n 60 "${LOG_PATH}" | |
| APP_PATH="$(find "${ARCHIVE_PATH}/Products/Applications" -maxdepth 1 -type d -name '*.app' -print -quit)" | |
| test -n "${APP_PATH}" | |
| mkdir -p build/ios/ipa/Payload | |
| cp -R "${APP_PATH}" build/ios/ipa/Payload/ | |
| ditto -c -k --sequesterRsrc --keepParent build/ios/ipa/Payload build/ios/bangumi-ios.ipa | |
| - name: Upload unsigned IPA | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: ios-ipa | |
| path: build/ios/bangumi-ios.ipa | |
| if-no-files-found: error | |
| publish-ios: | |
| name: Publish iOS IPA | |
| needs: [ prepare-version, build-ios ] | |
| if: (github.event_name == 'schedule' || github.event_name == 'push' || github.event_name == 'workflow_dispatch') && success() | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v7 | |
| with: | |
| fetch-depth: 0 | |
| - name: Download IPA | |
| uses: actions/download-artifact@v7 | |
| with: | |
| name: ios-ipa | |
| path: ios-release | |
| - name: Upload IPA to rolling pre-release | |
| if: needs.prepare-version.outputs.channel == 'pre-release' | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| GH_REPO: ${{ github.repository }} | |
| VERSION_CODE: ${{ needs.prepare-version.outputs.version_code }} | |
| VERSION_NAME: ${{ needs.prepare-version.outputs.version_name }} | |
| run: | | |
| RELEASE_TAG="pre-release" | |
| RELEASE_NAME="Pre-release" | |
| RELEASE_BODY="$(bash .github/scripts/release-notes.sh pre-release "${RELEASE_TAG}")" | |
| if gh release view "${RELEASE_TAG}" >/dev/null 2>&1; then | |
| gh release edit "${RELEASE_TAG}" --title "${RELEASE_NAME}" --prerelease --latest=false --target "${GITHUB_SHA}" --notes "${RELEASE_BODY}" | |
| else | |
| gh release create "${RELEASE_TAG}" --title "${RELEASE_NAME}" --prerelease --latest=false --target "${GITHUB_SHA}" --notes "${RELEASE_BODY}" | |
| fi | |
| gh release upload "${RELEASE_TAG}" ios-release/*.ipa --clobber | |
| - name: Upload IPA to release | |
| if: needs.prepare-version.outputs.channel == 'release' | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| GH_REPO: ${{ github.repository }} | |
| VERSION_CODE: ${{ needs.prepare-version.outputs.version_code }} | |
| VERSION_NAME: ${{ needs.prepare-version.outputs.version_name }} | |
| run: | | |
| RELEASE_TAG="${GITHUB_REF_NAME}" | |
| RELEASE_NAME="Release ${VERSION_NAME}" | |
| RELEASE_BODY="$(bash .github/scripts/release-notes.sh release "${RELEASE_TAG}")" | |
| if gh release view "${RELEASE_TAG}" >/dev/null 2>&1; then | |
| gh release edit "${RELEASE_TAG}" --title "${RELEASE_NAME}" --latest --notes "${RELEASE_BODY}" | |
| else | |
| gh release create "${RELEASE_TAG}" --title "${RELEASE_NAME}" --latest --target "${GITHUB_SHA}" --notes "${RELEASE_BODY}" | |
| fi | |
| gh release upload "${RELEASE_TAG}" ios-release/*.ipa --clobber |