name: Manager Dev Repo # Builds an unsigned dev IPA of FTStore Manager and publishes it together with a # freshly-generated AltStore source (manager-devrepo.json) to a rolling # "manager-dev" prerelease. # https://github.com/FTStuff/FTStore/releases/download/manager-dev/manager-devrepo.json # # Monorepo: the Manager's Xcode project lives in manager/, so the build steps run # there. The tag is `manager-dev`, NOT `dev` — the app's own dev prerelease # (ios-dev-repo.yml) owns that one, and sharing it would make each build # overwrite the other's assets. on: push: branches: [main] paths: - "manager/**" - ".github/workflows/manager-dev-repo.yml" workflow_dispatch: concurrency: group: manager-dev-repo-${{ github.ref }} cancel-in-progress: true permissions: contents: write jobs: build: # macOS label required: the bare `self-hosted` label also matches the org's # Linux runners, which have no xcodebuild and fail the build outright. runs-on: [self-hosted, macOS] env: DEVELOPER_DIR: /Applications/Xcode.app/Contents/Developer # statt sudo xcode-select steps: - name: Checkout uses: actions/checkout@v5 with: submodules: recursive fetch-depth: 1 - name: Cache SwiftPM uses: actions/cache@v5 with: path: ~/Library/Caches/org.swift.swiftpm key: spm-${{ runner.os }}-${{ hashFiles('**/Package.resolved') }} restore-keys: spm-${{ runner.os }}- - name: Compute dev version run: | BASE=$(grep '^FTSTORE_PROJECT_VERSION' manager/FTStore.xcconfig | cut -d= -f2 | tr -d '[:space:]') echo "VERSION=${BASE}-dev.${{ github.run_number }}" >> "$GITHUB_ENV" echo "DATE=$(date -u +%Y-%m-%dT%H:%M:%SZ)" >> "$GITHUB_ENV" - name: Stamp marketing version # NOT agvtool: it writes CFBundleShortVersionString into Info.plist, but # the target sets MARKETING_VERSION = $(FTSTORE_PROJECT_VERSION) and # GENERATE_INFOPLIST_FILE = YES, so Xcode regenerates that key from the # build setting and the edit is thrown away. The IPA then reports the # base version while manager-devrepo.json advertises the dev one, and # every AltStore client sees a permanent "update available". Set the # variable the build actually reads, and fail loudly if it ever stops # matching. run: | sed -i '' "s|^FTSTORE_PROJECT_VERSION=.*|FTSTORE_PROJECT_VERSION=${VERSION}|" manager/FTStore.xcconfig grep -q "^FTSTORE_PROJECT_VERSION=${VERSION}$" manager/FTStore.xcconfig - name: Stamp build number (best effort) # Records the source commit in CFBundleVersion. Best effort because # agvtool trips over GENERATE_INFOPLIST_FILE=YES ("Cannot find …/YES") # while still doing the write. continue-on-error: true working-directory: manager run: agvtool new-version -all "${{ github.sha }}" - name: Build (iphoneos, unsigned) working-directory: manager run: make iphoneos - name: Verify the Live Activity extension shipped and can load # The Dynamic Island lives in an embedded appex, so an IPA that is wrong # about it installs and runs perfectly — the island just never appears, # and nothing in the build says why. The same three silent failures the # app checks for apply here unchanged: the extension missing, its bundle # id not sitting under the host app's, and the wrong extension point. # See ios/scripts/verify-live-activity.sh for what each one costs. # # The missing case is not hypothetical between these two products: they # share a project name, a scheme, a target name and their pbxproj GUIDs, # and now they both have an extension to sweep. run: ios/scripts/verify-live-activity.sh manager/packages/FTStore-Manager.ipa - name: Generate manager-devrepo.json run: | IPA=manager/packages/FTStore-Manager.ipa SIZE=$(stat -f%z "$IPA") URL="https://github.com/${{ github.repository }}/releases/download/manager-dev/FTStore-Manager.ipa" jq \ --arg v "$VERSION" --arg d "$DATE" --argjson s "$SIZE" --arg u "$URL" ' .name = "FTStore Manager (Dev)" | .identifier = "app.ftstore.manager.devrepo" | .apps[0].name = "FTStore Manager (Dev)" | .apps[0].subtitle = "Latest commit build — for testing" | .apps[0].version = $v | .apps[0].versionDate = $d | .apps[0].size = $s | .apps[0].downloadURL = $u | .apps[0].versions = [ { "version": $v, "date": $d, "size": $s, "downloadURL": $u } ] | .news = [] ' manager/app-repo.json > manager-devrepo.json echo "Generated manager-devrepo.json for $VERSION (${SIZE} bytes)" - name: Publish dev prerelease uses: softprops/action-gh-release@v3 with: tag_name: manager-dev name: Manager dev build prerelease: true make_latest: false body: "Rolling development build of FTStore Manager from the latest `main` commit (${{ github.sha }}). FTStore Manager installs and updates FTStore on-device. Unsigned — sign it on-device at install (e.g. with your own certificate)." files: | manager/packages/FTStore-Manager.ipa manager-devrepo.json