chore: bump version to 1.0.41 #48
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: Build iOS IPA (Sideload - AltStore/Sideloadly) | |
| on: | |
| push: | |
| branches: [main] | |
| paths: | |
| - "src/**" | |
| - "ios/**" | |
| - "app.json" | |
| - "package.json" | |
| - ".github/workflows/build-ios.yml" | |
| pull_request: | |
| branches: [main] | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: "Version to use (e.g. 1.2.3). Leave empty to use app.json version." | |
| required: false | |
| default: "" | |
| create_release: | |
| description: "Create a GitHub Release with the IPA" | |
| required: false | |
| type: boolean | |
| default: false | |
| release_notes: | |
| description: "Release notes for GitHub Release" | |
| required: false | |
| default: "" | |
| permissions: | |
| contents: write | |
| jobs: | |
| build: | |
| runs-on: macos-15 | |
| outputs: | |
| version: ${{ steps.version.outputs.version }} | |
| ipa_name: ${{ steps.rename.outputs.ipa_name }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Generate Release Notes from Commit History | |
| id: release_notes | |
| run: | | |
| echo "Recent tags:" | |
| git tag --sort=-v:refname | head -n 5 | |
| if [[ "${{ github.ref }}" == "refs/tags/"* ]]; then | |
| CURRENT_REF="${{ github.ref_name }}" | |
| PREVIOUS_TAG=$(git describe --tags --abbrev=0 "${CURRENT_REF}^" 2>/dev/null || echo "") | |
| else | |
| CURRENT_REF="HEAD" | |
| PREVIOUS_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "") | |
| fi | |
| echo "Generating notes from '$PREVIOUS_TAG' to '$CURRENT_REF'" | |
| if [[ -z "$PREVIOUS_TAG" ]]; then | |
| echo "No previous tag found. Getting last 20 commits." | |
| COMMITS=$(git log -n 20 --pretty=format:"- %s (%h)" "$CURRENT_REF") | |
| else | |
| COMMITS=$(git log "$PREVIOUS_TAG..$CURRENT_REF" --pretty=format:"- %s (%h)") | |
| fi | |
| EOF=$(dd if=/dev/urandom bs=15 count=1 status=none | base64) | |
| echo "LOG<<$EOF" >> $GITHUB_OUTPUT | |
| echo "$COMMITS" >> $GITHUB_OUTPUT | |
| echo "$EOF" >> $GITHUB_OUTPUT | |
| - name: Determine version | |
| id: version | |
| run: | | |
| if [[ -n "${{ github.event.inputs.version || '' }}" ]]; then | |
| VERSION="${{ github.event.inputs.version }}" | |
| echo "Using manual input version: $VERSION" | |
| elif [[ "${{ github.ref }}" == refs/tags/* ]]; then | |
| VERSION=${GITHUB_REF#refs/tags/v} | |
| echo "Using tag-based version: $VERSION" | |
| else | |
| # Read version from app.json | |
| VERSION=$(node -p "require('./app.json').expo.version") | |
| echo "Using app.json version: $VERSION" | |
| fi | |
| VERSION=${VERSION#v} | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: 18 | |
| cache: "npm" | |
| - name: Install dependencies | |
| run: | | |
| npm install | |
| # Install expo-cli globally to ensure prebuild works | |
| npm install -g expo-cli @expo/cli | |
| - name: Update app.json version | |
| run: | | |
| node -e " | |
| const fs = require('fs'); | |
| const appJson = JSON.parse(fs.readFileSync('app.json', 'utf8')); | |
| appJson.expo.version = '${{ steps.version.outputs.version }}'; | |
| appJson.expo.ios.buildNumber = '${{ github.run_number }}'; | |
| fs.writeFileSync('app.json', JSON.stringify(appJson, null, 2)); | |
| " | |
| - name: Setup Ruby | |
| uses: ruby/setup-ruby@v1 | |
| with: | |
| ruby-version: "3.2" | |
| bundler-cache: false | |
| - name: Install CocoaPods | |
| run: | | |
| gem install cocoapods -v '~> 1.16' | |
| - name: Setup Go | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version: "1.22.x" | |
| - name: Verify iOS directory | |
| run: | | |
| echo "Checking iOS directory structure..." | |
| ls -la ios/ | |
| echo "Checking for xcodeproj..." | |
| ls -la ios/*.xcodeproj/ || echo "No xcodeproj found" | |
| echo "Checking for xcworkspace..." | |
| ls -la ios/*.xcworkspace/ || echo "No xcworkspace found" | |
| - name: Install iOS dependencies | |
| run: | | |
| cd ios | |
| pod install --repo-update | |
| - name: Update iOS Info.plist versions | |
| run: | | |
| /usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString ${{ steps.version.outputs.version }}" ios/CBVVPN/Info.plist | |
| /usr/libexec/PlistBuddy -c "Set :CFBundleVersion ${{ github.run_number }}" ios/CBVVPN/Info.plist | |
| /usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString ${{ steps.version.outputs.version }}" ios/CBVVPNProxyExtension/Info.plist | |
| /usr/libexec/PlistBuddy -c "Set :CFBundleVersion ${{ github.run_number }}" ios/CBVVPNProxyExtension/Info.plist | |
| - name: Verify workspace creation | |
| run: | | |
| cd ios | |
| if [ ! -d "CBVVPN.xcworkspace" ]; then | |
| echo "Error: CBVVPN.xcworkspace not found!" | |
| echo "Contents of ios directory:" | |
| ls -la | |
| exit 1 | |
| fi | |
| echo "Workspace found successfully" | |
| ls -la CBVVPN.xcworkspace/ | |
| - name: Build iOS Archive (Unsigned for Sideloading) | |
| run: | | |
| cd ios | |
| set -o pipefail | |
| set +e | |
| xcodebuild \ | |
| -workspace CBVVPN.xcworkspace \ | |
| -scheme CBVVPN \ | |
| -configuration Release \ | |
| -archivePath "$PWD/build/CBProProxy.xcarchive" \ | |
| -sdk iphoneos \ | |
| -destination 'generic/platform=iOS' \ | |
| CODE_SIGN_IDENTITY="" \ | |
| CODE_SIGNING_REQUIRED=NO \ | |
| CODE_SIGNING_ALLOWED=NO \ | |
| DEVELOPMENT_TEAM="" \ | |
| PROVISIONING_PROFILE_SPECIFIER="" \ | |
| clean archive 2>&1 | tee "$PWD/build/xcodebuild.log" | |
| build_status=${PIPESTATUS[0]} | |
| set -e | |
| echo "---- Xcode build errors (if any) ----" | |
| rg -n "error:|fatal error:|clang: error:" "$PWD/build/xcodebuild.log" || true | |
| echo "---- Xcode build tail (last 200 lines) ----" | |
| tail -n 200 "$PWD/build/xcodebuild.log" || true | |
| exit $build_status | |
| - name: Install ldid for TrollStore signing | |
| run: | | |
| if ! command -v ldid &> /dev/null; then | |
| echo "Installing ldid..." | |
| brew install ldid | |
| fi | |
| ldid --version || echo "ldid installed" | |
| - name: Create IPA with ldid signing for TrollStore | |
| run: | | |
| cd ios | |
| echo "Creating IPA with ldid signing for TrollStore..." | |
| mkdir -p "$PWD/build/output/Payload" | |
| # Investigate archive structure | |
| echo "Examining archive structure..." | |
| ls -la "$PWD/build/CBProProxy.xcarchive/Products/Applications/" || true | |
| # Find .app bundle (app name may vary based on archive name) | |
| APP_PATH=$(find "$PWD/build/CBProProxy.xcarchive/Products/Applications" -name "*.app" -type d -maxdepth 1 | head -n 1) | |
| if [ -z "$APP_PATH" ]; then | |
| # Fallback: try Products/ directly | |
| APP_PATH=$(find "$PWD/build/CBProProxy.xcarchive/Products" -name "*.app" -type d -maxdepth 1 | head -n 1) | |
| fi | |
| if [ -z "$APP_PATH" ]; then | |
| # Last resort: search entire archive | |
| APP_PATH=$(find "$PWD/build/CBProProxy.xcarchive" -name "*.app" -type d | grep -v "Plugins" | head -n 1) | |
| fi | |
| if [ -n "$APP_PATH" ]; then | |
| echo "✅ Found app at: $APP_PATH" | |
| else | |
| echo "❌ Error: No .app bundle found in archive" | |
| echo "Archive structure:" | |
| find "$PWD/build/CBProProxy.xcarchive" -type d -maxdepth 3 | |
| exit 1 | |
| fi | |
| # Copy the .app to Payload | |
| cp -r "$APP_PATH" "$PWD/build/output/Payload/" | |
| # Get app name from path | |
| APP_NAME=$(basename "$APP_PATH") | |
| BINARY_NAME="${APP_NAME%.app}" | |
| echo "📱 App bundle: $APP_NAME" | |
| echo "📱 Binary name: $BINARY_NAME" | |
| # Sign with ldid for TrollStore VPN support | |
| echo "🔐 Signing with ldid for TrollStore..." | |
| MAIN_ENTITLEMENTS="$GITHUB_WORKSPACE/ios/CBVVPN/CBVVPN.entitlements" | |
| EXT_ENTITLEMENTS="$GITHUB_WORKSPACE/ios/CBVVPNProxyExtension/CBVVPNProxyExtension.entitlements" | |
| # Sign main app | |
| MAIN_BINARY="$PWD/build/output/Payload/$APP_NAME/$BINARY_NAME" | |
| if [ -f "$MAIN_BINARY" ] && [ -f "$MAIN_ENTITLEMENTS" ]; then | |
| echo "Signing main app: $MAIN_BINARY" | |
| ldid "-S$MAIN_ENTITLEMENTS" "$MAIN_BINARY" | |
| echo "✅ Main app signed with entitlements" | |
| # Verify | |
| ldid -e "$MAIN_BINARY" > /tmp/main-ent-check.xml | |
| if [ -s /tmp/main-ent-check.xml ]; then | |
| echo "✅ Main app entitlements verified:" | |
| head -15 /tmp/main-ent-check.xml | |
| fi | |
| else | |
| echo "⚠️ Main binary or entitlements not found" | |
| fi | |
| # Sign extensions | |
| if [ -d "$PWD/build/output/Payload/$APP_NAME/PlugIns" ]; then | |
| for EXTENSION in "$PWD/build/output/Payload/$APP_NAME/PlugIns"/*.appex; do | |
| if [ -d "$EXTENSION" ]; then | |
| EXT_NAME=$(basename "$EXTENSION" .appex) | |
| EXT_BINARY="$EXTENSION/$EXT_NAME" | |
| if [ -f "$EXT_BINARY" ] && [ -f "$EXT_ENTITLEMENTS" ]; then | |
| echo "Signing extension: $EXT_NAME" | |
| ldid "-S$EXT_ENTITLEMENTS" "$EXT_BINARY" | |
| echo "✅ Extension signed: $EXT_NAME" | |
| fi | |
| fi | |
| done | |
| fi | |
| # Remove Apple code signatures (keep ldid signatures) | |
| echo "Removing Apple code signatures..." | |
| find "$PWD/build/output/Payload/$APP_NAME" -name "_CodeSignature" -type d -prune -exec rm -rf {} + 2>/dev/null || true | |
| find "$PWD/build/output/Payload/$APP_NAME" -name "embedded.mobileprovision" -type f -exec rm -f {} + 2>/dev/null || true | |
| find "$PWD/build/output/Payload/$APP_NAME" -name "embedded.entitlements" -type f -exec rm -f {} + 2>/dev/null || true | |
| echo "✅ Apple signatures removed (ldid signatures preserved)" | |
| # Create IPA with proper structure | |
| cd "$PWD/build/output" | |
| zip -qr CBProProxy.ipa Payload | |
| rm -rf Payload | |
| echo "✅ IPA created with ldid signing for TrollStore VPN support" | |
| echo "📱 Compatible with: TrollStore (VPN works!), AltStore, Sideloadly" | |
| ls -lh CBProProxy.ipa | |
| - name: Rename IPA with version | |
| id: rename | |
| run: | | |
| cd ios/build/output | |
| IPA_NAME="CBProProxy-${{ steps.version.outputs.version }}-b${{ github.run_number }}-unsigned.ipa" | |
| mv CBProProxy.ipa "$IPA_NAME" | |
| echo "ipa_name=$IPA_NAME" >> $GITHUB_OUTPUT | |
| echo "📦 IPA: $IPA_NAME" | |
| - name: Upload IPA artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ios-unsigned-ipa | |
| path: ios/build/output/*.ipa | |
| retention-days: 30 | |
| # Optional: Create GitHub Release | |
| release: | |
| needs: build | |
| runs-on: ubuntu-latest | |
| if: github.event.inputs.create_release == 'true' || startsWith(github.ref, 'refs/tags/') | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Download IPA artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: ios-unsigned-ipa | |
| path: ./release | |
| - name: Generate Release Notes | |
| id: notes | |
| run: | | |
| if [[ -n "${{ github.event.inputs.release_notes }}" ]]; then | |
| NOTES="${{ github.event.inputs.release_notes }}" | |
| else | |
| # Get commits since last tag | |
| PREVIOUS_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "") | |
| if [[ -n "$PREVIOUS_TAG" ]]; then | |
| COMMITS=$(git log "$PREVIOUS_TAG..HEAD" --pretty=format:"- %s" | head -20) | |
| else | |
| COMMITS=$(git log -n 10 --pretty=format:"- %s") | |
| fi | |
| NOTES="$COMMITS" | |
| fi | |
| EOF=$(dd if=/dev/urandom bs=15 count=1 status=none | base64) | |
| echo "notes<<$EOF" >> $GITHUB_OUTPUT | |
| echo "$NOTES" >> $GITHUB_OUTPUT | |
| echo "$EOF" >> $GITHUB_OUTPUT | |
| - name: Create GitHub Release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: v${{ needs.build.outputs.version }} | |
| name: CB Pro Proxy v${{ needs.build.outputs.version }} (iOS) | |
| body: | | |
| ## 📱 CB Pro Proxy v${{ needs.build.outputs.version }} | |
| ### Installation Guide | |
| **Using AltStore:** | |
| 1. Download the IPA file below | |
| 2. Open AltStore on your device | |
| 3. Go to "My Apps" tab → tap "+" button | |
| 4. Select the downloaded IPA file | |
| 5. Wait for installation to complete | |
| **Using Sideloadly:** | |
| 1. Download the IPA file below | |
| 2. Connect your iPhone to computer | |
| 3. Open Sideloadly and drag the IPA into it | |
| 4. Enter your Apple ID and install | |
| **Using TrollStore:** | |
| 1. Download the IPA file below | |
| 2. Open in TrollStore and tap "Install" | |
| --- | |
| ### Changes | |
| ${{ steps.notes.outputs.notes }} | |
| --- | |
| Build: #${{ github.run_number }} | |
| files: ./release/*.ipa | |
| draft: false | |
| prerelease: false | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |