From 212b129c3108a81503294bfb7c50f09777eed642 Mon Sep 17 00:00:00 2001 From: Conrad Kramer Date: Sun, 7 Jun 2026 07:52:30 -0700 Subject: [PATCH] Add focused Apple tester distribution workflow --- .../workflows/apple-distribute-testers.yml | 544 ++++++++++++++++++ 1 file changed, 544 insertions(+) create mode 100644 .forgejo/workflows/apple-distribute-testers.yml diff --git a/.forgejo/workflows/apple-distribute-testers.yml b/.forgejo/workflows/apple-distribute-testers.yml new file mode 100644 index 0000000..d3ca415 --- /dev/null +++ b/.forgejo/workflows/apple-distribute-testers.yml @@ -0,0 +1,544 @@ +name: "Apple: Distribute Testers" +run-name: "Apple: Distribute Testers (${{ github.ref_name }})" + +on: + workflow_dispatch: + inputs: + build_number_override: + description: Optional explicit build number + required: false + default: "" + upload_app_store: + description: Upload iOS artifact to App Store Connect and TestFlight + required: false + default: "true" + upload_sparkle: + description: Publish Sparkle appcast and macOS artifact + required: false + default: "true" + sparkle_channel: + description: Sparkle channel, defaults to build- + required: false + default: "" + sparkle_point_main: + description: Update Sparkle main channel pointers + required: false + default: "true" + testflight_distribute_external: + description: Distribute to external TestFlight groups + required: false + default: "false" + testflight_groups: + description: Optional comma-separated TestFlight groups + required: false + default: "" + ios_uses_non_exempt_encryption: + description: Set true only when the iOS build uses non-exempt encryption + required: false + default: "false" + +permissions: + actions: write + contents: read + +concurrency: + group: burrow-apple-distribute-testers-${{ github.ref }} + cancel-in-progress: true + +env: + BURROW_RELEASE_GCS_BUCKET: ${{ vars.BURROW_RELEASE_GCS_BUCKET || 'burrow-net-releases' }} + BURROW_RELEASE_GCS_BACKUP: ${{ vars.BURROW_RELEASE_GCS_BACKUP || 'true' }} + BURROW_RELEASE_GARAGE_BUCKET: ${{ vars.BURROW_RELEASE_GARAGE_BUCKET || 'burrow-releases' }} + BURROW_RELEASE_REQUIRE_GARAGE: ${{ vars.BURROW_RELEASE_REQUIRE_GARAGE || 'true' }} + BURROW_GARAGE_ENDPOINT: ${{ vars.BURROW_GARAGE_ENDPOINT || 'https://objects.burrow.net' }} + BURROW_GARAGE_REGION: ${{ vars.BURROW_GARAGE_REGION || 'garage' }} + AWS_ACCESS_KEY_ID: ${{ secrets.BURROW_GARAGE_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.BURROW_GARAGE_SECRET_ACCESS_KEY }} + BURROW_GOOGLE_PROJECT_ID: ${{ vars.GOOGLE_PROJECT_ID || 'project-88c23ce9-918a-470a-b33' }} + GOOGLE_CLOUD_PROJECT: ${{ vars.GOOGLE_PROJECT_ID || 'project-88c23ce9-918a-470a-b33' }} + BURROW_GOOGLE_PROJECT_NUMBER: ${{ vars.GOOGLE_PROJECT_NUMBER || '416198671487' }} + BURROW_GOOGLE_WIF_POOL_ID: ${{ vars.BURROW_GOOGLE_WIF_POOL_ID || 'burrow-authentik' }} + BURROW_GOOGLE_WIF_PROVIDER_ID: ${{ vars.BURROW_GOOGLE_WIF_PROVIDER_ID || 'forgejo-runners' }} + BURROW_GOOGLE_WIF_SERVICE_ACCOUNT: ${{ vars.BURROW_GOOGLE_WIF_SERVICE_ACCOUNT || 'burrow-forgejo-runner@project-88c23ce9-918a-470a-b33.iam.gserviceaccount.com' }} + BURROW_AUTHENTIK_WIF_ISSUER: ${{ vars.BURROW_AUTHENTIK_WIF_ISSUER || 'https://auth.burrow.net/application/o/google-cloud/' }} + BURROW_AUTHENTIK_WIF_AUDIENCE: ${{ vars.BURROW_AUTHENTIK_WIF_AUDIENCE || 'google-wif.burrow.net' }} + BURROW_AUTHENTIK_WIF_CLIENT_ID: ${{ vars.BURROW_AUTHENTIK_WIF_CLIENT_ID || 'google-wif.burrow.net' }} + BURROW_AUTHENTIK_WIF_CLIENT_SECRET: ${{ secrets.BURROW_AUTHENTIK_WIF_CLIENT_SECRET }} + BURROW_NIX_CACHE_URL: ${{ vars.BURROW_NIX_CACHE_URL || 'https://nix.burrow.net/burrow' }} + BURROW_NIX_CACHE_PUBLIC_KEY: ${{ vars.BURROW_NIX_CACHE_PUBLIC_KEY }} + BURROW_APPLE_BUNDLE_ID: ${{ vars.BURROW_APPLE_BUNDLE_ID || 'net.burrow.app' }} + BURROW_APPLE_NETWORK_EXTENSION_BUNDLE_ID: ${{ vars.BURROW_APPLE_NETWORK_EXTENSION_BUNDLE_ID || 'net.burrow.app.network' }} + BURROW_IOS_DISTRIBUTION_CERTIFICATE_ID: ${{ vars.BURROW_IOS_DISTRIBUTION_CERTIFICATE_ID || '3G42677598' }} + BURROW_DEVELOPER_ID_CERTIFICATE_ID: ${{ vars.BURROW_DEVELOPER_ID_CERTIFICATE_ID || '9JKN6HXBHC' }} + BURROW_APPLE_SIGNING_MODE: google-kms-staged + BURROW_NOTARIZE_MACOS: ${{ vars.BURROW_NOTARIZE_MACOS || 'true' }} + BURROW_SPARKLE_SIGN_WITH_KMS: ${{ vars.BURROW_SPARKLE_SIGN_WITH_KMS || 'true' }} + BURROW_SPARKLE_KMS_KEY: ${{ vars.BURROW_SPARKLE_KMS_KEY || 'sparkle-ed25519' }} + BURROW_SPARKLE_KMS_VERSION: ${{ vars.BURROW_SPARKLE_KMS_VERSION || '1' }} + BURROW_SPARKLE_FEED_URL: ${{ vars.BURROW_SPARKLE_FEED_URL || 'https://releases.burrow.net/sparkle/appcast.xml' }} + BURROW_SPARKLE_PUBLIC_ED_KEY: ${{ vars.BURROW_SPARKLE_PUBLIC_ED_KEY || 'Myv9ZNZT6YGKMtMezh52ra4WqaeEKc4VlvVU0evhJeI=' }} + BURROW_KMS_LOCATION: ${{ vars.BURROW_KMS_LOCATION || 'global' }} + BURROW_KMS_KEYRING: ${{ vars.BURROW_KMS_KEYRING || 'burrow-identity' }} + BURROW_VERSION_REQUIRE_REMOTE: "1" + +jobs: + prepare: + name: Prepare Apple Distribution + runs-on: namespace-profile-linux-medium + outputs: + build_number: ${{ steps.plan.outputs.build_number }} + sparkle_channel: ${{ steps.plan.outputs.sparkle_channel }} + steps: + - name: Checkout + uses: https://code.forgejo.org/actions/checkout@v4 + with: + token: ${{ github.token }} + fetch-depth: 0 + + - name: Fetch Build Tags + shell: bash + run: git fetch --force --prune origin "+refs/tags/builds/*:refs/tags/builds/*" + + - name: Compute Apple Distribution Plan + id: plan + shell: bash + env: + BUILD_NUMBER_OVERRIDE: ${{ github.event.inputs.build_number_override || '' }} + SPARKLE_CHANNEL_INPUT: ${{ github.event.inputs.sparkle_channel || '' }} + run: | + set -euo pipefail + if [[ -n "$BUILD_NUMBER_OVERRIDE" ]]; then + build_number="$BUILD_NUMBER_OVERRIDE" + else + build_number="$(Scripts/version.sh pre-increment)" + fi + channel="$SPARKLE_CHANNEL_INPUT" + if [[ -z "$channel" ]]; then + channel="build-${build_number}" + fi + echo "build_number=${build_number}" >> "$GITHUB_OUTPUT" + echo "sparkle_channel=${channel}" >> "$GITHUB_OUTPUT" + printf 'build_number=%s\nsparkle_channel=%s\n' "$build_number" "$channel" + + build-ios: + name: Build Apple iOS + needs: prepare + runs-on: namespace-profile-macos-large + steps: + - name: Checkout + uses: https://code.forgejo.org/actions/checkout@v4 + with: + token: ${{ github.token }} + fetch-depth: 0 + submodules: recursive + + - name: Select Apple SDK + shell: bash + run: | + set -euo pipefail + xcrun --find swiftc + xcrun --sdk iphoneos --show-sdk-path + xcrun --sdk iphonesimulator --show-sdk-path + + - name: Prepare Rust Apple Targets + shell: bash + run: | + set -euo pipefail + if ! command -v rustup >/dev/null 2>&1; then + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain stable + export PATH="$HOME/.cargo/bin:$PATH" + fi + rustup target add aarch64-apple-ios aarch64-apple-ios-sim x86_64-apple-ios + + - name: Bootstrap Runner Environment + shell: bash + run: | + set -euo pipefail + runner_home="${RUNNER_HOME:-}" + if [[ -z "$runner_home" ]]; then + runner_home="$(python3 -c 'import os,pwd; print(pwd.getpwuid(os.getuid()).pw_dir)' 2>/dev/null || true)" + if [[ -z "$runner_home" ]]; then + runner_home="$PWD/.home" + fi + fi + mkdir -p "$runner_home" "$PWD/.tmp" + { + echo "HOME=$runner_home" + echo "XDG_CACHE_HOME=$runner_home/.cache" + echo "XDG_CONFIG_HOME=$runner_home/.config" + echo "XDG_DATA_HOME=$runner_home/.local/share" + echo "TMPDIR=$PWD/.tmp" + echo "TMP=$PWD/.tmp" + } >> "$GITHUB_ENV" + + - name: Ensure Nix + shell: bash + run: bash Scripts/ci/ensure-nix.sh + + - name: Namespace Cache + shell: bash + run: | + set -euo pipefail + NIX_BIN="$(bash Scripts/ci/resolve-nix-bin.sh)" + "$NIX_BIN" develop .#ci --command bash Scripts/ci/nscloud-cache.sh bazel + + - name: Build Staged iOS Artifact + shell: bash + env: + BUILD_NUMBER: ${{ needs.prepare.outputs.build_number }} + run: | + set -euo pipefail + bazel_args=() + if [[ -n "${BURROW_BAZEL_NSCCACHE_BAZELRC:-}" && -f "${BURROW_BAZEL_NSCCACHE_BAZELRC:-}" ]]; then + bazel_args+=("--bazelrc=${BURROW_BAZEL_NSCCACHE_BAZELRC}") + fi + NIX_BIN="$(bash Scripts/ci/resolve-nix-bin.sh)" + "$NIX_BIN" develop .#ci --command bazel "${bazel_args[@]}" build \ + --verbose_failures \ + --show_timestamps \ + --action_env=BUILD_WORKSPACE_DIRECTORY="$PWD" \ + --action_env=BUILD_NUMBER="$BUILD_NUMBER" \ + --action_env=BURROW_RELEASE_OUT="$PWD/dist/builds/$BUILD_NUMBER" \ + --action_env=BURROW_APPLE_SIGNING_MODE="$BURROW_APPLE_SIGNING_MODE" \ + --action_env=BURROW_APPLE_REQUIRE_SIGNING=true \ + --action_env=BURROW_APPLE_BUNDLE_ID="$BURROW_APPLE_BUNDLE_ID" \ + --action_env=BURROW_APPLE_NETWORK_EXTENSION_BUNDLE_ID="$BURROW_APPLE_NETWORK_EXTENSION_BUNDLE_ID" \ + --action_env=HOME="$HOME" \ + --action_env=XDG_CACHE_HOME="$XDG_CACHE_HOME" \ + //bazel/apple:release_ios_stamp + + - name: Upload Staged iOS Artifact + uses: https://code.forgejo.org/actions/upload-artifact@v4 + with: + name: burrow-apple-ios-${{ needs.prepare.outputs.build_number }} + path: | + dist/builds/${{ needs.prepare.outputs.build_number }}/apple/Burrow-iOS-${{ needs.prepare.outputs.build_number }}.unsigned.ipa + dist/builds/${{ needs.prepare.outputs.build_number }}/apple/Burrow-iOS-${{ needs.prepare.outputs.build_number }}.unsigned.ipa.sha256 + if-no-files-found: error + + build-macos: + name: Build Apple macOS + needs: prepare + runs-on: namespace-profile-macos-large + steps: + - name: Checkout + uses: https://code.forgejo.org/actions/checkout@v4 + with: + token: ${{ github.token }} + fetch-depth: 0 + submodules: recursive + + - name: Select Apple SDK + shell: bash + run: | + set -euo pipefail + xcrun --find swiftc + xcrun --sdk macosx --show-sdk-path + + - name: Prepare Rust Apple Targets + shell: bash + run: | + set -euo pipefail + if ! command -v rustup >/dev/null 2>&1; then + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain stable + export PATH="$HOME/.cargo/bin:$PATH" + fi + rustup target add aarch64-apple-darwin x86_64-apple-darwin + + - name: Bootstrap Runner Environment + shell: bash + run: | + set -euo pipefail + runner_home="${RUNNER_HOME:-}" + if [[ -z "$runner_home" ]]; then + runner_home="$(python3 -c 'import os,pwd; print(pwd.getpwuid(os.getuid()).pw_dir)' 2>/dev/null || true)" + if [[ -z "$runner_home" ]]; then + runner_home="$PWD/.home" + fi + fi + mkdir -p "$runner_home" "$PWD/.tmp" + { + echo "HOME=$runner_home" + echo "XDG_CACHE_HOME=$runner_home/.cache" + echo "XDG_CONFIG_HOME=$runner_home/.config" + echo "XDG_DATA_HOME=$runner_home/.local/share" + echo "TMPDIR=$PWD/.tmp" + echo "TMP=$PWD/.tmp" + } >> "$GITHUB_ENV" + + - name: Ensure Nix + shell: bash + run: bash Scripts/ci/ensure-nix.sh + + - name: Namespace Cache + shell: bash + run: | + set -euo pipefail + NIX_BIN="$(bash Scripts/ci/resolve-nix-bin.sh)" + "$NIX_BIN" develop .#ci --command bash Scripts/ci/nscloud-cache.sh bazel + + - name: Build Staged macOS Artifact + shell: bash + env: + BUILD_NUMBER: ${{ needs.prepare.outputs.build_number }} + run: | + set -euo pipefail + bazel_args=() + if [[ -n "${BURROW_BAZEL_NSCCACHE_BAZELRC:-}" && -f "${BURROW_BAZEL_NSCCACHE_BAZELRC:-}" ]]; then + bazel_args+=("--bazelrc=${BURROW_BAZEL_NSCCACHE_BAZELRC}") + fi + NIX_BIN="$(bash Scripts/ci/resolve-nix-bin.sh)" + "$NIX_BIN" develop .#ci --command bazel "${bazel_args[@]}" build \ + --verbose_failures \ + --show_timestamps \ + --action_env=BUILD_WORKSPACE_DIRECTORY="$PWD" \ + --action_env=BUILD_NUMBER="$BUILD_NUMBER" \ + --action_env=BURROW_RELEASE_OUT="$PWD/dist/builds/$BUILD_NUMBER" \ + --action_env=BURROW_APPLE_SIGNING_MODE="$BURROW_APPLE_SIGNING_MODE" \ + --action_env=BURROW_APPLE_REQUIRE_SIGNING=true \ + --action_env=BURROW_APPLE_BUNDLE_ID="$BURROW_APPLE_BUNDLE_ID" \ + --action_env=BURROW_APPLE_NETWORK_EXTENSION_BUNDLE_ID="$BURROW_APPLE_NETWORK_EXTENSION_BUNDLE_ID" \ + --action_env=BURROW_SPARKLE_FEED_URL="$BURROW_SPARKLE_FEED_URL" \ + --action_env=BURROW_SPARKLE_PUBLIC_ED_KEY="$BURROW_SPARKLE_PUBLIC_ED_KEY" \ + --action_env=HOME="$HOME" \ + --action_env=XDG_CACHE_HOME="$XDG_CACHE_HOME" \ + //bazel/apple:release_macos_stamp + + - name: Upload Staged macOS Artifact + uses: https://code.forgejo.org/actions/upload-artifact@v4 + with: + name: burrow-apple-macos-${{ needs.prepare.outputs.build_number }} + path: | + dist/builds/${{ needs.prepare.outputs.build_number }}/apple/Burrow-macOS-${{ needs.prepare.outputs.build_number }}.unsigned.zip + dist/builds/${{ needs.prepare.outputs.build_number }}/apple/Burrow-macOS-${{ needs.prepare.outputs.build_number }}.unsigned.zip.sha256 + if-no-files-found: error + + sign-apple: + name: Sign Apple Artifacts + needs: + - prepare + - build-ios + - build-macos + runs-on: namespace-profile-linux-medium + steps: + - name: Checkout + uses: https://code.forgejo.org/actions/checkout@v4 + with: + token: ${{ github.token }} + fetch-depth: 0 + + - name: Ensure Nix + shell: bash + run: bash Scripts/ci/ensure-nix.sh + + - name: Configure Age + shell: bash + env: + AGE_FORGE_SSH_KEY: ${{ secrets.AGE_FORGE_SSH_KEY }} + run: Scripts/resolve-age-identity.sh >> "$GITHUB_ENV" + + - name: Decrypt Release Secrets + uses: ./.forgejo/actions/decrypt-release-secrets + + - name: Validate App Store Credentials + shell: bash + run: Scripts/ci/check-release-config.sh app-store + + - name: Authenticate Google WIF + shell: bash + run: nix develop .#ci -c Scripts/ci/google-wif-auth.sh + + - name: Download Staged Apple Artifacts + uses: https://code.forgejo.org/actions/download-artifact@v4 + with: + path: dist/downloaded + + - name: Prepare Staged Apple Directory + shell: bash + env: + BUILD_NUMBER: ${{ needs.prepare.outputs.build_number }} + run: | + set -euo pipefail + mkdir -p "dist/builds/${BUILD_NUMBER}/apple" + find dist/downloaded -type f -name 'Burrow-*.unsigned.*' -exec cp -v {} "dist/builds/${BUILD_NUMBER}/apple/" \; + find "dist/builds/${BUILD_NUMBER}/apple" -type f -print | sort + + - name: Sync Apple Provisioning Profiles + shell: bash + run: nix develop .#ci -c Scripts/ci/sync-apple-provisioning-profiles.sh all + + - name: Sign Apple Artifacts With KMS + shell: bash + env: + BUILD_NUMBER: ${{ needs.prepare.outputs.build_number }} + SPARKLE_CHANNEL: ${{ needs.prepare.outputs.sparkle_channel }} + run: nix develop .#ci -c Scripts/apple/sign-release-artifacts-kms.sh all + + - name: Upload Signed Apple Artifacts To Release Storage + shell: bash + env: + BUILD_NUMBER: ${{ needs.prepare.outputs.build_number }} + run: nix develop .#ci -c Scripts/ci/upload-release-storage.sh + + - name: Upload Signed Apple Artifacts + uses: https://code.forgejo.org/actions/upload-artifact@v4 + with: + name: burrow-apple-signed-${{ needs.prepare.outputs.build_number }} + path: | + dist/builds/${{ needs.prepare.outputs.build_number }}/apple/Burrow-iOS-${{ needs.prepare.outputs.build_number }}.ipa + dist/builds/${{ needs.prepare.outputs.build_number }}/apple/Burrow-iOS-${{ needs.prepare.outputs.build_number }}.ipa.sha256 + dist/builds/${{ needs.prepare.outputs.build_number }}/apple/Burrow-macOS-${{ needs.prepare.outputs.build_number }}.zip + dist/builds/${{ needs.prepare.outputs.build_number }}/apple/Burrow-macOS-${{ needs.prepare.outputs.build_number }}.zip.sha256 + dist/builds/${{ needs.prepare.outputs.build_number }}/sparkle/** + if-no-files-found: error + + upload-testflight: + name: Upload TestFlight + needs: + - prepare + - sign-apple + if: ${{ github.event.inputs.upload_app_store == 'true' }} + runs-on: namespace-profile-macos-large + steps: + - name: Checkout + uses: https://code.forgejo.org/actions/checkout@v4 + with: + token: ${{ github.token }} + fetch-depth: 0 + + - name: Ensure Nix + shell: bash + run: bash Scripts/ci/ensure-nix.sh + + - name: Configure Age + shell: bash + env: + AGE_FORGE_SSH_KEY: ${{ secrets.AGE_FORGE_SSH_KEY }} + run: Scripts/resolve-age-identity.sh >> "$GITHUB_ENV" + + - name: Decrypt Release Secrets + uses: ./.forgejo/actions/decrypt-release-secrets + + - name: Download Signed Apple Artifacts + uses: https://code.forgejo.org/actions/download-artifact@v4 + with: + name: burrow-apple-signed-${{ needs.prepare.outputs.build_number }} + path: publish + + - name: Upload iOS IPA To App Store Connect + shell: bash + env: + BUILD_NUMBER: ${{ needs.prepare.outputs.build_number }} + run: | + set -euo pipefail + Scripts/ci/check-release-config.sh app-store + key_dir="${RUNNER_TEMP:-/tmp}/burrow-asc" + altool_key_dir="${HOME}/.appstoreconnect/private_keys" + mkdir -p "$key_dir" "$altool_key_dir" + key_path="$key_dir/AuthKey_${ASC_API_KEY_ID}.p8" + if [[ -n "${ASC_API_KEY_PATH:-}" && -f "${ASC_API_KEY_PATH:-}" ]]; then + cp "$ASC_API_KEY_PATH" "$key_path" + else + printf '%s' "$ASC_API_KEY_BASE64" | base64 --decode > "$key_path" + fi + cp "$key_path" "$altool_key_dir/AuthKey_${ASC_API_KEY_ID}.p8" + chmod 600 "$key_path" "$altool_key_dir/AuthKey_${ASC_API_KEY_ID}.p8" + ipa="publish/apple/Burrow-iOS-${BUILD_NUMBER}.ipa" + if [[ ! -s "$ipa" ]]; then + echo "::error ::No signed iOS IPA found at $ipa" >&2 + find publish -type f -print | sort + exit 1 + fi + xcrun altool --upload-app \ + --type ios \ + --file "$ipa" \ + --apiKey "$ASC_API_KEY_ID" \ + --apiIssuer "$ASC_API_ISSUER_ID" + + - name: Distribute iOS Build To TestFlight + shell: bash + env: + BUILD_NUMBER: ${{ needs.prepare.outputs.build_number }} + TESTFLIGHT_DISTRIBUTE_EXTERNAL: ${{ github.event.inputs.testflight_distribute_external || 'false' }} + TESTFLIGHT_GROUPS: ${{ github.event.inputs.testflight_groups || '' }} + TESTFLIGHT_INTERNAL_GROUP: Internal + IOS_USES_NON_EXEMPT_ENCRYPTION: ${{ github.event.inputs.ios_uses_non_exempt_encryption || 'false' }} + run: | + set -euo pipefail + Scripts/ci/check-release-config.sh app-store + api_key_json="$(mktemp "${RUNNER_TEMP:-/tmp}/burrow-appstore-api-key.XXXXXX.json")" + key_file="$(mktemp "${RUNNER_TEMP:-/tmp}/burrow-appstore-key.XXXXXX.p8")" + if [[ -n "${ASC_API_KEY_PATH:-}" && -f "${ASC_API_KEY_PATH:-}" ]]; then + cp "$ASC_API_KEY_PATH" "$key_file" + else + printf '%s' "$ASC_API_KEY_BASE64" | base64 --decode > "$key_file" + fi + KEY_FILE="$key_file" python3 -c 'import json, os, pathlib; print(json.dumps({"key_id": os.environ["ASC_API_KEY_ID"], "issuer_id": os.environ["ASC_API_ISSUER_ID"], "key": pathlib.Path(os.environ["KEY_FILE"]).read_text(), "duration": 1200, "in_house": False}))' > "$api_key_json" + + args=( + run pilot + "api_key_path:${api_key_json}" + "app_identifier:${BURROW_APPLE_BUNDLE_ID:-net.burrow.app}" + "app_platform:ios" + "distribute_only:true" + "build_number:${BUILD_NUMBER}" + "wait_processing_interval:30" + "wait_processing_timeout_duration:1800" + "distribute_external:${TESTFLIGHT_DISTRIBUTE_EXTERNAL:-false}" + "uses_non_exempt_encryption:${IOS_USES_NON_EXEMPT_ENCRYPTION:-false}" + ) + if [[ -n "${TESTFLIGHT_GROUPS:-}" ]]; then + args+=("groups:${TESTFLIGHT_GROUPS}") + elif [[ "${TESTFLIGHT_DISTRIBUTE_EXTERNAL:-false}" != "true" && -n "${TESTFLIGHT_INTERNAL_GROUP:-}" ]]; then + args+=("groups:${TESTFLIGHT_INTERNAL_GROUP}") + fi + nix run nixpkgs#fastlane -- "${args[@]}" + rm -f "$api_key_json" "$key_file" + + publish-sparkle: + name: Publish Sparkle + needs: + - prepare + - sign-apple + if: ${{ github.event.inputs.upload_sparkle == 'true' }} + runs-on: namespace-profile-linux-medium + steps: + - name: Checkout + uses: https://code.forgejo.org/actions/checkout@v4 + with: + token: ${{ github.token }} + fetch-depth: 0 + + - name: Ensure Nix + shell: bash + run: bash Scripts/ci/ensure-nix.sh + + - name: Authenticate Google WIF + shell: bash + run: nix develop .#ci -c Scripts/ci/google-wif-auth.sh + + - name: Download Signed Apple Artifacts + uses: https://code.forgejo.org/actions/download-artifact@v4 + with: + name: burrow-apple-signed-${{ needs.prepare.outputs.build_number }} + path: publish + + - name: Publish Sparkle Channel + shell: bash + env: + CHANNEL: ${{ needs.prepare.outputs.sparkle_channel }} + SPARKLE_POINT_MAIN: ${{ github.event.inputs.sparkle_point_main || 'true' }} + run: | + set -euo pipefail + if [[ ! -f "publish/sparkle/${CHANNEL}/appcast.xml" ]]; then + echo "::error ::No Sparkle appcast staged for channel ${CHANNEL}" >&2 + find publish -type f -print | sort + exit 1 + fi + nix develop .#ci -c gcloud storage rsync --recursive "publish/sparkle/${CHANNEL}" "gs://${BURROW_RELEASE_GCS_BUCKET}/sparkle/${CHANNEL}" + if [[ "$SPARKLE_POINT_MAIN" == "true" ]]; then + printf '%s\n' "$CHANNEL" > main-channel.txt + nix develop .#ci -c gcloud storage cp main-channel.txt "gs://${BURROW_RELEASE_GCS_BUCKET}/sparkle/main-channel.txt" + nix develop .#ci -c gcloud storage cp "publish/sparkle/${CHANNEL}/appcast.xml" "gs://${BURROW_RELEASE_GCS_BUCKET}/sparkle/appcast.xml" + nix develop .#ci -c gcloud storage rsync --recursive "publish/sparkle/${CHANNEL}" "gs://${BURROW_RELEASE_GCS_BUCKET}/sparkle/default" + fi