[mobile] Adjust release workflow to include apk app #54
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 / desktop publish | |
| # Triggered when a desktop release-prepare PR is merged. The merge commit's | |
| # message begins with "release(desktop): vX.Y.Z" — that's how we filter. | |
| # | |
| # Order: assert secrets → import signing identity → install JS deps + Pods → | |
| # stamp CFBundleVersion → xcodebuild archive + export → notarize + staple → | |
| # create-dmg → move tag onto merge commit → create GitHub Release with .dmg. | |
| on: | |
| push: | |
| branches: | |
| - main | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: 'Version to publish (e.g. 0.0.1). Must already be committed in Info.plist / package.json on the chosen ref.' | |
| required: true | |
| type: string | |
| permissions: | |
| contents: write | |
| jobs: | |
| publish: | |
| # On push: `contains` (not `startsWith`) so this fires regardless of merge | |
| # strategy — default merge commits put the PR title in the body, while | |
| # squash/rebase put it on the first line. | |
| # On workflow_dispatch: always run (version comes from the input). | |
| if: "${{ github.event_name == 'workflow_dispatch' || contains(github.event.head_commit.message, 'release(desktop): v') }}" | |
| runs-on: macos-15 | |
| timeout-minutes: 60 | |
| env: | |
| APP_NAME: entangle | |
| SCHEME: entangle-macOS | |
| WORKSPACE: apps/desktop/macos/entangle.xcworkspace | |
| ARCHIVE_PATH: build/entangle.xcarchive | |
| EXPORT_PATH: build/export | |
| EXPORT_OPTIONS: apps/desktop/macos/ExportOptions.plist | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Switch to Xcode 26.2 | |
| run: sudo xcode-select --switch /Applications/Xcode_26.2.app | |
| - name: Resolve version | |
| id: parse | |
| env: | |
| COMMIT_MSG: ${{ github.event.head_commit.message }} | |
| INPUT_VERSION: ${{ inputs.version }} | |
| # workflow_dispatch → use the input; push → scan the merge commit | |
| # message (PR title may be on any line, depending on merge strategy). | |
| run: | | |
| if [ -n "$INPUT_VERSION" ]; then | |
| VERSION="$INPUT_VERSION" | |
| else | |
| VERSION=$(printf '%s' "$COMMIT_MSG" | sed -nE 's/.*release\(desktop\): v([0-9]+\.[0-9]+\.[0-9]+).*/\1/p' | head -n1) | |
| fi | |
| if [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then | |
| echo "Could not determine a valid x.y.z version" >&2 | |
| echo " input: $INPUT_VERSION" >&2 | |
| echo " commit: $COMMIT_MSG" >&2 | |
| exit 1 | |
| fi | |
| echo "version=$VERSION" >> "$GITHUB_OUTPUT" | |
| - name: Assert required secrets | |
| env: | |
| MACOS_CERT_P12_BASE64: ${{ secrets.MACOS_CERT_P12_BASE64 }} | |
| MACOS_CERT_PASSWORD: ${{ secrets.MACOS_CERT_PASSWORD }} | |
| APPLE_ID: ${{ secrets.APPLE_ID }} | |
| APPLE_APP_PASSWORD: ${{ secrets.APPLE_APP_PASSWORD }} | |
| APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} | |
| run: | | |
| missing=() | |
| for s in MACOS_CERT_P12_BASE64 MACOS_CERT_PASSWORD APPLE_ID APPLE_APP_PASSWORD APPLE_TEAM_ID; do | |
| if [ -z "${!s}" ]; then missing+=("$s"); fi | |
| done | |
| if [ ${#missing[@]} -gt 0 ]; then | |
| echo "Missing required repo secrets: ${missing[*]}" >&2 | |
| echo "See RELEASING.md for how to set them up." >&2 | |
| exit 1 | |
| fi | |
| - name: Setup Node + pnpm | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: "20" | |
| - run: corepack enable && corepack prepare pnpm@10.33.0 --activate | |
| - name: Install monorepo deps | |
| run: pnpm install --frozen-lockfile | |
| - name: Install JS deps | |
| working-directory: apps/desktop | |
| run: pnpm install --ignore-workspace --frozen-lockfile | |
| - name: Setup Ruby + Bundler | |
| uses: ruby/setup-ruby@v1 | |
| with: | |
| ruby-version: "3.2" | |
| bundler-cache: true | |
| working-directory: apps/desktop | |
| - name: Install Pods | |
| working-directory: apps/desktop/macos | |
| run: bundle exec pod install --verbose | |
| - name: Import signing certificate | |
| env: | |
| MACOS_CERT_P12_BASE64: ${{ secrets.MACOS_CERT_P12_BASE64 }} | |
| MACOS_CERT_PASSWORD: ${{ secrets.MACOS_CERT_PASSWORD }} | |
| run: | | |
| KEYCHAIN=build.keychain | |
| KEYCHAIN_PWD=$(uuidgen) | |
| echo "$MACOS_CERT_P12_BASE64" | base64 --decode > /tmp/cert.p12 | |
| security create-keychain -p "$KEYCHAIN_PWD" "$KEYCHAIN" | |
| security set-keychain-settings -lut 21600 "$KEYCHAIN" | |
| security unlock-keychain -p "$KEYCHAIN_PWD" "$KEYCHAIN" | |
| security import /tmp/cert.p12 -k "$KEYCHAIN" -P "$MACOS_CERT_PASSWORD" \ | |
| -T /usr/bin/codesign -T /usr/bin/productbuild -T /usr/bin/security | |
| security set-key-partition-list -S apple-tool:,apple:,codesign: \ | |
| -s -k "$KEYCHAIN_PWD" "$KEYCHAIN" >/dev/null | |
| security list-keychains -d user -s "$KEYCHAIN" $(security list-keychains -d user | tr -d '"') | |
| rm /tmp/cert.p12 | |
| - name: xcodebuild archive | |
| # Signing config (Developer ID identity, hardened runtime, timestamp, | |
| # team) lives in entangle.xcodeproj/project.pbxproj Release config so | |
| # local archives match CI. Nothing to override here. | |
| run: | | |
| xcodebuild \ | |
| -workspace "$WORKSPACE" \ | |
| -scheme "$SCHEME" \ | |
| -configuration Release \ | |
| -archivePath "$ARCHIVE_PATH" \ | |
| -destination 'generic/platform=macOS' \ | |
| archive | |
| - name: xcodebuild exportArchive | |
| run: | | |
| xcodebuild \ | |
| -exportArchive \ | |
| -archivePath "$ARCHIVE_PATH" \ | |
| -exportPath "$EXPORT_PATH" \ | |
| -exportOptionsPlist "$EXPORT_OPTIONS" | |
| - name: Notarize | |
| env: | |
| APPLE_ID: ${{ secrets.APPLE_ID }} | |
| APPLE_APP_PASSWORD: ${{ secrets.APPLE_APP_PASSWORD }} | |
| APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} | |
| run: | | |
| APP_PATH="$EXPORT_PATH/$APP_NAME.app" | |
| ZIP_PATH="$EXPORT_PATH/$APP_NAME.zip" | |
| ditto -c -k --keepParent "$APP_PATH" "$ZIP_PATH" | |
| JSON=$(xcrun notarytool submit "$ZIP_PATH" \ | |
| --apple-id "$APPLE_ID" \ | |
| --password "$APPLE_APP_PASSWORD" \ | |
| --team-id "$APPLE_TEAM_ID" \ | |
| --output-format json \ | |
| --wait) | |
| echo "$JSON" | |
| ID=$(echo "$JSON" | jq -r .id) | |
| STATUS=$(echo "$JSON" | jq -r .status) | |
| # Always fetch the log — even Accepted submissions can have warnings | |
| # worth seeing, and on Invalid the log is the only useful signal. | |
| echo "::group::notarytool log ($ID)" | |
| xcrun notarytool log "$ID" \ | |
| --apple-id "$APPLE_ID" \ | |
| --password "$APPLE_APP_PASSWORD" \ | |
| --team-id "$APPLE_TEAM_ID" || true | |
| echo "::endgroup::" | |
| if [ "$STATUS" != "Accepted" ]; then | |
| echo "Notarization status: $STATUS — see the log group above for details." >&2 | |
| exit 1 | |
| fi | |
| xcrun stapler staple "$APP_PATH" | |
| - name: Build DMG | |
| env: | |
| VERSION: ${{ steps.parse.outputs.version }} | |
| run: | | |
| brew install create-dmg | |
| DMG_PATH="$EXPORT_PATH/${APP_NAME}-${VERSION}.dmg" | |
| create-dmg \ | |
| --volname "${APP_NAME} ${VERSION}" \ | |
| --window-size 600 400 \ | |
| --icon-size 100 \ | |
| --app-drop-link 450 200 \ | |
| "$DMG_PATH" \ | |
| "$EXPORT_PATH/${APP_NAME}.app" | |
| # Re-staple the DMG itself for offline Gatekeeper checks. | |
| xcrun stapler staple "$DMG_PATH" || true | |
| echo "DMG=$DMG_PATH" >> "$GITHUB_ENV" | |
| - name: Move tag onto merge commit | |
| env: | |
| VERSION: ${{ steps.parse.outputs.version }} | |
| # The original tag pointed at the developer's pre-bump commit; we move | |
| # it so the GitHub Release reflects the actually-released tree. | |
| run: | | |
| git config user.name "entangle-release-bot" | |
| git config user.email "release-bot@users.noreply.github.com" | |
| git tag -f "v${VERSION}-desktop" | |
| git push -f origin "v${VERSION}-desktop" | |
| - name: Create GitHub Release | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| VERSION: ${{ steps.parse.outputs.version }} | |
| run: | | |
| gh release create "v${VERSION}-desktop" "$DMG" \ | |
| --title "Desktop v${VERSION}" \ | |
| --generate-notes \ | |
| --verify-tag |