diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml index f233725..b449820 100644 --- a/.gitea/workflows/release.yml +++ b/.gitea/workflows/release.yml @@ -36,51 +36,31 @@ jobs: -archivePath "$RUNNER_TEMP/KisaniCal.xcarchive" \ -allowProvisioningUpdates - - name: Export IPA + # Write the App Store Connect API key to disk. xcodebuild's auto-discovery + # looks for exactly this filename pattern under ~/private_keys. + - name: Write App Store Connect API key + run: | + mkdir -p ~/private_keys + echo "${{ secrets.APP_STORE_CONNECT_API_KEY_P8 }}" > ~/private_keys/AuthKey_${{ secrets.APP_STORE_CONNECT_API_KEY_ID }}.p8 + + # Export AND upload in one step: passing the API key credentials to + # -exportArchive makes xcodebuild upload directly to App Store Connect + # (method "app-store" in ExportOptions.plist) — no separate altool/ + # Transporter step needed. (altool's own upload path was retired by + # Apple in 2023; this is the current supported mechanism.) + - name: Export IPA and upload to TestFlight run: | set -o pipefail xcodebuild -exportArchive \ -archivePath "$RUNNER_TEMP/KisaniCal.xcarchive" \ -exportOptionsPlist ExportOptions.plist \ -exportPath "$RUNNER_TEMP/export" \ - -allowProvisioningUpdates + -allowProvisioningUpdates \ + -authenticationKeyPath ~/private_keys/AuthKey_${{ secrets.APP_STORE_CONNECT_API_KEY_ID }}.p8 \ + -authenticationKeyID ${{ secrets.APP_STORE_CONNECT_API_KEY_ID }} \ + -authenticationKeyIssuerID ${{ secrets.APP_STORE_CONNECT_ISSUER_ID }} ls -la "$RUNNER_TEMP/export" - # ------------------------------------------------------------------ - # PLACEHOLDER: Upload to TestFlight / App Store Connect. - # - # Add these as Gitea repo secrets: Settings → Actions → Secrets - # APP_STORE_CONNECT_API_KEY_ID (the "Key ID" from App Store Connect) - # APP_STORE_CONNECT_ISSUER_ID (the "Issuer ID") - # APP_STORE_CONNECT_API_KEY_P8 (contents of the AuthKey_XXXX.p8 file) - # - # Then uncomment ONE of the approaches below. - # ------------------------------------------------------------------ - - # --- Option A: modern notarytool / App Store Connect API key (recommended) --- - # - name: Write API key to file - # run: | - # mkdir -p ~/private_keys - # echo "${{ secrets.APP_STORE_CONNECT_API_KEY_P8 }}" > ~/private_keys/AuthKey_${{ secrets.APP_STORE_CONNECT_API_KEY_ID }}.p8 - # - # - name: Upload to TestFlight (altool with API key) - # run: | - # xcrun altool --upload-app \ - # --type ios \ - # --file "$RUNNER_TEMP/export/KisaniCal.ipa" \ - # --apiKey "${{ secrets.APP_STORE_CONNECT_API_KEY_ID }}" \ - # --apiIssuer "${{ secrets.APP_STORE_CONNECT_ISSUER_ID }}" - - # --- Option B: notarytool (for notarizing a macOS build, not iOS TestFlight) --- - # - name: Notarize - # run: | - # xcrun notarytool submit "$RUNNER_TEMP/export/KisaniCal.ipa" \ - # --key ~/private_keys/AuthKey_${{ secrets.APP_STORE_CONNECT_API_KEY_ID }}.p8 \ - # --key-id "${{ secrets.APP_STORE_CONNECT_API_KEY_ID }}" \ - # --issuer "${{ secrets.APP_STORE_CONNECT_ISSUER_ID }}" \ - # --wait - - - name: Notice - run: | - echo "IPA exported. TestFlight upload step is a commented-out placeholder." - echo "Add App Store Connect API-key secrets and uncomment Option A in release.yml." + - name: Clean up API key + if: always() + run: rm -rf ~/private_keys diff --git a/KisaniCal/ISSUES.md b/KisaniCal/ISSUES.md index 8033d02..0a2db03 100644 --- a/KisaniCal/ISSUES.md +++ b/KisaniCal/ISSUES.md @@ -2586,3 +2586,60 @@ against the real logic (not copies, not just read): The SwiftUI layer itself (the Stepper row, bindings, sheet wiring) is self-reviewed only — balanced braces/parens confirmed per-file, one pre-existing stray `(` in `TaskItem.swift` predates this (see KC-62). + +## KC-71 — Finish release.yml's TestFlight upload (Xcode Cloud ruled out for this repo) + +Status: Implemented — `release.yml` updated; live end-to-end run still +pending the user adding the App Store Connect API key as Gitea secrets +Reported by: User — wanted automated TestFlight delivery on merge to main +Area: CI/CD (`.gitea/workflows/release.yml`) + +### Description +Spent a long session trying to connect Apple's Xcode Cloud directly to this +repo's self-hosted Gitea instance. Concluded it's not achievable: +- Gitea was only reachable on the LAN (`10.10.1.21:3002`, plain HTTP) — + fixed by standing up Tailscale Funnel on the host (`titantwo`), giving + real public HTTPS at `https://titantwo.tail05af18.ts.net`. Also switched + the local `origin` remote to this URL (user's explicit call — the old + LAN address is no longer used anywhere). +- Xcode Cloud's "GitHub Enterprise" provider option 404s against Gitea — + GitHub Enterprise's API lives at a fixed `/api/v3/` path, Gitea's is + `/api/v1/`. +- Its "GitLab Self-Managed" option rejects Gitea's OAuth2 Client IDs — App + Store Connect strictly requires a 64-character hex string (real GitLab's + ID format); Gitea's OAuth2 provider generates 36-character UUIDs. Not + fixable from the Gitea side — confirmed by actually creating a real + Gitea OAuth2 application and having App Store Connect reject its ID. +- Bitbucket Server wasn't tried — the same class of hard-coded-provider- + format problem was already proven twice, not worth a third confirmation. + +Conclusion: Apple only supports Gitea if it happens to be API/URL- +compatible with GitHub/GitLab/Bitbucket's *specific* hosted or enterprise +products, and it isn't. Pivoted to finishing the automation this repo +already had a placeholder for instead. + +### Change +`release.yml`'s TestFlight upload step was a commented-out placeholder +(altool-based) since it was originally set up. Replaced it with the +currently-supported mechanism — `xcrun altool`'s own upload path was +retired by Apple in 2023, so the placeholder would not have worked even if +uncommented as-is. Now: write the App Store Connect API key (from a new +Gitea secret) to `~/private_keys/AuthKey_.p8`, then pass +`-authenticationKeyPath`/`-authenticationKeyID`/`-authenticationKeyIssuerID` +directly to the existing `xcodebuild -exportArchive` call — this exports +AND uploads to TestFlight in one step, no separate upload tool needed. +Key file is deleted in an `if: always()` cleanup step regardless of +success/failure. + +Needs 3 new Gitea secrets (Settings → Actions → Secrets), from an App +Store Connect API key with App Manager role: +`APP_STORE_CONNECT_API_KEY_ID`, `APP_STORE_CONNECT_ISSUER_ID`, +`APP_STORE_CONNECT_API_KEY_P8`. + +Files: `.gitea/workflows/release.yml`. + +### Note +Not run end-to-end yet — needs the user to generate the App Store Connect +API key and add the 3 secrets before the next merge to `main` actually +exercises this path. `ExportOptions.plist` needed no changes (already +`method: app-store` with the correct team ID).