diff --git a/.gitea/workflows/ios-release.yaml b/.gitea/workflows/ios-release.yaml index 6865ebe..21b338f 100644 --- a/.gitea/workflows/ios-release.yaml +++ b/.gitea/workflows/ios-release.yaml @@ -28,11 +28,12 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Install just - run: command -v just || brew install just - - - name: Set build number from run number - run: just ios-set-build-number ${{ gitea.run_number }} + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: '3.2' + bundler-cache: true + working-directory: ios/LibNovel - name: Import signing certificate env: @@ -45,20 +46,12 @@ jobs: security set-keychain-settings -lut 21600 $KEYCHAIN_PATH security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH echo "$CERTIFICATE_BASE64" | base64 --decode > $RUNNER_TEMP/cert.p12 - echo "DEBUG: p12 file size: $(wc -c < $RUNNER_TEMP/cert.p12) bytes" - echo "DEBUG: p12 first bytes (hex): $(xxd $RUNNER_TEMP/cert.p12 | head -2)" - echo "DEBUG: import result:" security import $RUNNER_TEMP/cert.p12 \ -P "$CERTIFICATE_PASSWORD" \ -A -t cert -f pkcs12 \ - -k $KEYCHAIN_PATH && echo "import OK" || echo "import FAILED exit $?" + -k $KEYCHAIN_PATH security list-keychain -d user -s $KEYCHAIN_PATH $(security list-keychains -d user | tr -d '"' | xargs) - echo "DEBUG: keychain list:" - security list-keychains -d user - echo "DEBUG: all certs in keychain (not just codesigning):" - security find-certificate -a $KEYCHAIN_PATH 2>&1 | grep "labl\|subj" || echo "none" - echo "DEBUG: signing identities found:" - security find-identity -v -p codesigning + security set-key-partition-list -S apple-tool:,apple: -s -k "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH - name: Import provisioning profile env: @@ -70,57 +63,15 @@ jobs: mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles cp $PP_PATH ~/Library/MobileDevice/Provisioning\ Profiles/$UUID.mobileprovision - - name: Write App Store Connect API key + - name: Build and upload to TestFlight env: - ASC_PRIVATE_KEY: ${{ secrets.ASC_PRIVATE_KEY }} - ASC_KEY_ID: ${{ secrets.ASC_KEY_ID }} - run: | - mkdir -p ~/private_keys - echo "$ASC_PRIVATE_KEY" > ~/private_keys/AuthKey_$ASC_KEY_ID.p8 - - - name: Inject team ID into ExportOptions.plist - env: - APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} - run: | - /usr/libexec/PlistBuddy -c \ - "Set :teamID $APPLE_TEAM_ID" \ - ios/LibNovel/ExportOptions.plist - - - name: Archive - env: - USER: runner - APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} - run: | - PROFILE_UUID=$(security cms -D -i $RUNNER_TEMP/profile.mobileprovision | plutil -extract UUID raw -) - PROFILE_NAME=$(security cms -D -i $RUNNER_TEMP/profile.mobileprovision | plutil -extract Name raw -) - PROFILE_BUNDLE=$(security cms -D -i $RUNNER_TEMP/profile.mobileprovision | plutil -extract Entitlements.application-identifier raw - 2>/dev/null || echo "n/a") - PROFILE_TEAM=$(security cms -D -i $RUNNER_TEMP/profile.mobileprovision | plutil -extract TeamIdentifier.0 raw -) - PROFILE_EXPIRY=$(security cms -D -i $RUNNER_TEMP/profile.mobileprovision | plutil -extract ExpirationDate raw -) - echo "DEBUG: PROFILE_UUID=$PROFILE_UUID" - echo "DEBUG: PROFILE_NAME=$PROFILE_NAME" - echo "DEBUG: PROFILE_BUNDLE=$PROFILE_BUNDLE" - echo "DEBUG: PROFILE_TEAM=$PROFILE_TEAM" - echo "DEBUG: PROFILE_EXPIRY=$PROFILE_EXPIRY" - echo "DEBUG: APPLE_TEAM_ID=$APPLE_TEAM_ID" - echo "DEBUG: profiles dir listing:" - ls ~/Library/MobileDevice/Provisioning\ Profiles/ - just ios-archive "$APPLE_TEAM_ID" "$PROFILE_UUID" - - - name: Export IPA - run: just ios-export - - - name: Upload to TestFlight - env: - ASC_KEY_ID: ${{ secrets.ASC_KEY_ID }} - ASC_ISSUER_ID: ${{ secrets.ASC_ISSUER_ID }} - run: just ios-upload - - - name: Upload IPA artifact - uses: actions/upload-artifact@v4 - with: - name: LibNovel-${{ gitea.ref_name }}.ipa - path: ${{ env.RUNNER_TEMP }}/ipa/LibNovel.ipa - retention-days: 30 + APPLE_KEY_ID: ${{ secrets.ASC_KEY_ID }} + APPLE_ISSUER_ID: ${{ secrets.ASC_ISSUER_ID }} + APPLE_KEY_CONTENT: ${{ secrets.ASC_PRIVATE_KEY }} + BUILD_NUMBER: ${{ gitea.run_number }} + PROVISIONING_PROFILE_NAME: LibNovel Distribution + working-directory: ios/LibNovel + run: bundle exec fastlane beta - name: Cleanup keychain if: always() diff --git a/ios/LibNovel/.gitignore b/ios/LibNovel/.gitignore new file mode 100644 index 0000000..930f1d0 --- /dev/null +++ b/ios/LibNovel/.gitignore @@ -0,0 +1,10 @@ +# Fastlane +fastlane/report.xml +fastlane/Preview.html +fastlane/screenshots/**/*.png +fastlane/test_output +fastlane/README.md + +# Bundler +.bundle +vendor/bundle diff --git a/ios/LibNovel/Gemfile b/ios/LibNovel/Gemfile new file mode 100644 index 0000000..7a118b4 --- /dev/null +++ b/ios/LibNovel/Gemfile @@ -0,0 +1,3 @@ +source "https://rubygems.org" + +gem "fastlane" diff --git a/ios/LibNovel/fastlane/Fastfile b/ios/LibNovel/fastlane/Fastfile new file mode 100644 index 0000000..a7b74b4 --- /dev/null +++ b/ios/LibNovel/fastlane/Fastfile @@ -0,0 +1,32 @@ +default_platform(:ios) + +platform :ios do + desc "Build and upload to TestFlight" + lane :beta do + # Generate Xcode project from project.yml + sh("xcodegen generate --spec project.yml --project .") + + # Set build number from CI run number (passed as env var) + increment_build_number( + build_number: ENV["BUILD_NUMBER"] || "1", + xcodeproj: "LibNovel.xcodeproj" + ) + + # Build the app + build_app( + scheme: "LibNovel", + export_method: "app-store", + clean: true, + export_options: { + provisioningProfiles: { + "com.kalekber.LibNovel" => ENV["PROVISIONING_PROFILE_NAME"] || "LibNovel Distribution" + } + } + ) + + # Upload to TestFlight + upload_to_testflight( + skip_waiting_for_build_processing: true + ) + end +end