ci: decouple CocoaPods publish from core release pipeline (#738) #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: Release β Publish | |
| # Release the core SDK and all kits. Triggered automatically when the release PR | |
| # merges to main (VERSION file change), or manually via workflow_dispatch. | |
| on: | |
| push: | |
| branches: | |
| - main | |
| paths: | |
| - VERSION | |
| workflow_dispatch: | |
| inputs: | |
| dry_run: | |
| description: "Dry run β skip creating real releases/tags" | |
| type: boolean | |
| default: true | |
| permissions: | |
| contents: write | |
| env: | |
| DRY_RUN: ${{ github.event.inputs.dry_run || 'false' }} | |
| jobs: | |
| # ββββββββββββββββββββββββββββββββββββββββββββββ | |
| # Core SDK: build artifacts, tag, GitHub release | |
| # ββββββββββββββββββββββββββββββββββββββββββββββ | |
| release-core-sdk: | |
| name: Build & Release Core SDK | |
| runs-on: macOS-latest | |
| env: | |
| XCODE_VERSION: "26.2" | |
| outputs: | |
| version: ${{ steps.version.outputs.version }} | |
| tag: ${{ steps.version.outputs.tag }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Select Xcode | |
| run: sudo xcode-select -s /Applications/Xcode_${{ env.XCODE_VERSION }}.app | |
| - name: Get ecosystem version | |
| id: version | |
| run: | | |
| VERSION=$(head -n 1 VERSION | tr -d '\r\n ') | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| echo "tag=v$VERSION" >> $GITHUB_OUTPUT | |
| echo "π Core SDK version: $VERSION" | |
| - name: Install the signing certificate | |
| env: | |
| BUILD_CERTIFICATE_BASE64: ${{ secrets.MP_IOS_SIGNING_CERTIFICATE_P12 }} | |
| P12_PASSWORD: ${{ secrets.MP_IOS_SIGNING_CERTIFICATE_PASS }} | |
| KEYCHAIN_PASSWORD: ${{ secrets.MP_IOS_SIGNING_CERTIFICATE_PASS }} | |
| run: | | |
| CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12 | |
| KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db | |
| echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode -o $CERTIFICATE_PATH | |
| security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH | |
| security set-keychain-settings -lut 21600 $KEYCHAIN_PATH | |
| security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH | |
| security import $CERTIFICATE_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH | |
| security list-keychain -d user -s $KEYCHAIN_PATH | |
| - name: Build framework artifacts | |
| run: ./Scripts/make_artifacts.sh | |
| - name: Extract release notes | |
| id: release-notes | |
| uses: ffurrer2/extract-release-notes@202313ec7461b6b9e401996714484690ab1ae105 # v3.0.0 | |
| with: | |
| changelog_file: CHANGELOG.md | |
| prerelease: true | |
| - name: Create GitHub release | |
| if: env.DRY_RUN != 'true' | |
| uses: ncipollo/release-action@b7eabc95ff50cbeeedec83973935c8f306dfcd0b # v1.20.0 | |
| with: | |
| tag: ${{ steps.version.outputs.tag }} | |
| commit: ${{ github.sha }} | |
| name: ${{ steps.version.outputs.tag }} | |
| artifacts: "mParticle_Apple_SDK.xcframework.zip" | |
| body: | | |
| ${{ steps.release-notes.outputs.release_notes }} | |
| - name: Summary | |
| run: | | |
| ARTIFACTS=$(ls *.zip 2>/dev/null | tr '\n' ', ' | sed 's/,$//') | |
| cat >> $GITHUB_STEP_SUMMARY <<EOF | |
| ## Core SDK Release | |
| | Property | Value | | |
| |----------|-------| | |
| | **Version** | \`${{ steps.version.outputs.version }}\` | | |
| | **Tag** | \`${{ steps.version.outputs.tag }}\` | | |
| | **Dry Run** | \`${{ env.DRY_RUN }}\` | | |
| | **Artifacts** | \`${ARTIFACTS}\` | | |
| EOF | |
| # ββββββββββββββββββββββββββββββββββββββββββββββ | |
| # Kits: build, mirror, and release | |
| # ββββββββββββββββββββββββββββββββββββββββββββββ | |
| load-matrix: | |
| name: Load kit matrix | |
| runs-on: ubuntu-latest | |
| outputs: | |
| matrix: ${{ steps.set.outputs.matrix }} | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| sparse-checkout: Kits/matrix.json | |
| sparse-checkout-cone-mode: false | |
| - id: set | |
| run: echo "matrix=$(jq -c . Kits/matrix.json)" >> "$GITHUB_OUTPUT" | |
| build-kits: | |
| name: Build ${{ matrix.kit.name }} | |
| needs: load-matrix | |
| runs-on: macOS-latest | |
| timeout-minutes: 30 | |
| env: | |
| XCODE_VERSION: "26.2" | |
| # Build xcframeworks against mParticle-Apple-SDK from this checkout (same commit as VERSION). | |
| USE_LOCAL_VERSION: "1" | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| kit: ${{ fromJson(needs.load-matrix.outputs.matrix) }} | |
| steps: | |
| - name: Checkout monorepo | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Select Xcode | |
| run: sudo xcode-select -s /Applications/Xcode_${{ env.XCODE_VERSION }}.app | |
| - name: Build kit xcframeworks | |
| shell: bash | |
| run: | | |
| SCHEMES_JSON='${{ toJson(matrix.kit.schemes) }}' | |
| LOCAL_PATH="${{ matrix.kit.local_path }}" | |
| BUILD_SETTINGS="CODE_SIGN_IDENTITY= CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO SKIP_INSTALL=NO BUILD_LIBRARY_FOR_DISTRIBUTION=YES" | |
| mkdir -p archives xcframeworks | |
| MODULES=$(echo "$SCHEMES_JSON" | jq -r '.[].module' | sort -u) | |
| for MODULE in $MODULES; do | |
| XCFRAMEWORK_ARGS="" | |
| while IFS= read -r ENTRY; do | |
| SCHEME=$(echo "$ENTRY" | jq -r '.scheme') | |
| DEST=$(echo "$ENTRY" | jq -r '.destination') | |
| if [ -d "$LOCAL_PATH/$SCHEME.xcodeproj" ]; then | |
| PROJECT="$LOCAL_PATH/$SCHEME.xcodeproj" | |
| else | |
| PROJECT="$(ls -d "$LOCAL_PATH"/*.xcodeproj | head -1)" | |
| fi | |
| ARCHIVE_DEVICE="archives/${MODULE}-${DEST}" | |
| ARCHIVE_SIM="archives/${MODULE}-${DEST}_Simulator" | |
| case "$DEST" in | |
| iOS) | |
| PLATFORM_DEVICE="generic/platform=iOS" | |
| PLATFORM_SIM="generic/platform=iOS Simulator" | |
| ;; | |
| tvOS) | |
| PLATFORM_DEVICE="generic/platform=tvOS" | |
| PLATFORM_SIM="generic/platform=tvOS Simulator" | |
| ;; | |
| *) | |
| echo "::error::Unknown destination: $DEST" | |
| exit 1 | |
| ;; | |
| esac | |
| xcodebuild archive -project "$PROJECT" -scheme "$SCHEME" \ | |
| -destination "$PLATFORM_DEVICE" -archivePath "$ARCHIVE_DEVICE" $BUILD_SETTINGS | |
| xcodebuild archive -project "$PROJECT" -scheme "$SCHEME" \ | |
| -destination "$PLATFORM_SIM" -archivePath "$ARCHIVE_SIM" $BUILD_SETTINGS | |
| XCFRAMEWORK_ARGS+=" -archive ${ARCHIVE_DEVICE}.xcarchive -framework ${MODULE}.framework" | |
| XCFRAMEWORK_ARGS+=" -archive ${ARCHIVE_SIM}.xcarchive -framework ${MODULE}.framework" | |
| done < <(echo "$SCHEMES_JSON" | jq -c ".[] | select(.module == \"$MODULE\")") | |
| xcodebuild -create-xcframework $XCFRAMEWORK_ARGS -output "xcframeworks/${MODULE}.xcframework" | |
| (cd xcframeworks && zip -r "${MODULE}.xcframework.zip" "${MODULE}.xcframework" && rm -rf "${MODULE}.xcframework") | |
| done | |
| rm -rf archives | |
| - name: Upload xcframework artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: xcframework-${{ matrix.kit.name }} | |
| path: xcframeworks/*.xcframework.zip | |
| mirror-and-release-kits: | |
| name: Mirror & Release ${{ matrix.kit.name }} | |
| runs-on: macOS-latest | |
| needs: [load-matrix, build-kits, release-core-sdk] | |
| env: | |
| DEST_ORG: mparticle-integrations | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| kit: ${{ fromJson(needs.load-matrix.outputs.matrix) }} | |
| steps: | |
| - name: Checkout monorepo | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| persist-credentials: false | |
| - name: Download xcframework artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: xcframework-${{ matrix.kit.name }} | |
| - name: Get ecosystem version | |
| id: version | |
| run: | | |
| VERSION=$(head -n 1 VERSION | tr -d '\r\n ') | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| echo "tag=v$VERSION" >> $GITHUB_OUTPUT | |
| echo "π Ecosystem version: $VERSION" | |
| - name: Generate GitHub App Token | |
| id: generate-token | |
| uses: actions/create-github-app-token@v1 | |
| with: | |
| app-id: ${{ secrets.SDK_RELEASE_GITHUB_APP_ID }} | |
| private-key: ${{ secrets.SDK_RELEASE_GITHUB_APP_PRIVATE_KEY }} | |
| owner: ${{ env.DEST_ORG }} | |
| repositories: ${{ matrix.kit.dest_repo }} | |
| permission-contents: write | |
| - name: Extract release notes from root CHANGELOG | |
| id: release-notes | |
| uses: ffurrer2/extract-release-notes@202313ec7461b6b9e401996714484690ab1ae105 # v3.0.0 | |
| with: | |
| changelog_file: CHANGELOG.md | |
| prerelease: true | |
| - name: Split kit and push to mirror | |
| id: mirror | |
| run: | | |
| SPLIT_BRANCH="split/${{ matrix.kit.name }}" | |
| git subtree split --prefix ${{ matrix.kit.local_path }} -b "${SPLIT_BRANCH}" | |
| - name: Push split to destination | |
| if: env.DRY_RUN != 'true' | |
| id: push | |
| run: | | |
| DEST_URL="https://x-access-token:${{ steps.generate-token.outputs.token }}@github.com/${{ env.DEST_ORG }}/${{ matrix.kit.dest_repo }}.git" | |
| git push "$DEST_URL" "split/${{ matrix.kit.name }}:main" --force | |
| echo "sha=$(git rev-parse split/${{ matrix.kit.name }})" >> $GITHUB_OUTPUT | |
| - name: Create GitHub release on mirror | |
| if: env.DRY_RUN != 'true' | |
| uses: ncipollo/release-action@b7eabc95ff50cbeeedec83973935c8f306dfcd0b # v1.20.0 | |
| with: | |
| tag: ${{ steps.version.outputs.tag }} | |
| commit: ${{ steps.push.outputs.sha }} | |
| owner: ${{ env.DEST_ORG }} | |
| repo: ${{ matrix.kit.dest_repo }} | |
| token: ${{ steps.generate-token.outputs.token }} | |
| artifacts: "*.xcframework.zip" | |
| body: | | |
| ${{ steps.release-notes.outputs.release_notes }} | |
| - name: Summary | |
| shell: bash | |
| run: | | |
| COMMITS=$(git log "split/${{ matrix.kit.name }}" --oneline -5) | |
| ARTIFACTS=$(ls *.xcframework.zip 2>/dev/null | tr '\n' ', ' | sed 's/,$//') | |
| cat >> $GITHUB_STEP_SUMMARY <<EOF | |
| ## Kit Mirror: ${{ matrix.kit.name }} | |
| | Property | Value | | |
| |----------|-------| | |
| | **Kit** | \`${{ matrix.kit.name }}\` | | |
| | **Source** | \`${{ matrix.kit.local_path }}\` | | |
| | **Destination** | \`${{ env.DEST_ORG }}/${{ matrix.kit.dest_repo }}\` | | |
| | **Tag** | \`${{ steps.version.outputs.tag }}\` | | |
| | **Dry Run** | \`${{ env.DRY_RUN }}\` | | |
| | **Artifacts** | \`${ARTIFACTS}\` | | |
| ### Split branch commits | |
| \`\`\` | |
| ${COMMITS} | |
| \`\`\` | |
| ### Release notes | |
| ${{ steps.release-notes.outputs.release_notes }} | |
| EOF | |
| # ββββββββββββββββββββββββββββββββββββββββββββββ | |
| # CocoaPods: publish core SDK + kits to trunk | |
| # ββββββββββββββββββββββββββββββββββββββββββββββ | |
| publish-core-cocoapods: | |
| name: Publish Core SDK to CocoaPods | |
| needs: [mirror-and-release-kits] | |
| runs-on: macos-15 | |
| if: github.event.inputs.dry_run != 'true' | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - name: Publish core podspecs | |
| env: | |
| COCOAPODS_TRUNK_TOKEN: ${{ secrets.COCOAPODS_TRUNK_TOKEN }} | |
| run: | | |
| set -euo pipefail | |
| PUSH_FLAGS=(--allow-warnings --synchronous) | |
| # Order matters: Swift pod β ObjC core (depends on Swift) β umbrella (depends on ObjC). | |
| pod trunk push mParticle-Apple-SDK-Swift.podspec "${PUSH_FLAGS[@]}" | |
| pod trunk push mParticle-Apple-SDK-ObjC.podspec "${PUSH_FLAGS[@]}" | |
| pod trunk push mParticle-Apple-SDK.podspec "${PUSH_FLAGS[@]}" | |
| publish-kit-cocoapods: | |
| name: Publish ${{ matrix.kit.name }} to CocoaPods | |
| needs: [load-matrix, publish-core-cocoapods] | |
| runs-on: macos-15 | |
| if: github.event.inputs.dry_run != 'true' | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| kit: ${{ fromJson(needs.load-matrix.outputs.matrix) }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - name: Publish to CocoaPods | |
| if: matrix.kit.podspec != '' | |
| env: | |
| COCOAPODS_TRUNK_TOKEN: ${{ secrets.COCOAPODS_TRUNK_TOKEN }} | |
| run: pod trunk push ${{ matrix.kit.podspec }} --allow-warnings --synchronous |