DataConnect v0.7.33 #114
Workflow file for this run
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: Release | |
| on: | |
| release: | |
| types: [created] | |
| permissions: | |
| contents: write | |
| env: | |
| CARGO_TERM_COLOR: always | |
| jobs: | |
| build: | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - platform: macos-latest | |
| target: aarch64-apple-darwin | |
| pkg_target: node22-macos-arm64 | |
| binary_name: playwright-runner | |
| ps_binary_name: personal-server | |
| - platform: macos-latest | |
| target: x86_64-apple-darwin | |
| pkg_target: node22-macos-x64 | |
| binary_name: playwright-runner | |
| ps_binary_name: personal-server | |
| - platform: ubuntu-22.04 | |
| target: x86_64-unknown-linux-gnu | |
| pkg_target: node22-linux-x64 | |
| binary_name: playwright-runner | |
| ps_binary_name: personal-server | |
| - platform: windows-latest | |
| target: x86_64-pc-windows-msvc | |
| pkg_target: node22-win-x64 | |
| binary_name: playwright-runner.exe | |
| ps_binary_name: personal-server.exe | |
| runs-on: ${{ matrix.platform }} | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Verify version matches release tag | |
| shell: bash | |
| run: | | |
| tag="${{ github.ref_name }}" | |
| conf_version=$(grep '"version"' src-tauri/tauri.conf.json | head -1 | sed 's/.*"\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\)".*/\1/') | |
| tag_version="${tag#v}" | |
| if [ "$conf_version" != "$tag_version" ]; then | |
| echo "::error::Version mismatch: tauri.conf.json has '$conf_version' but release tag is '$tag' ($tag_version)." | |
| echo "::error::Run 'npm run release:github -- --version $tag_version' instead of creating a release manually." | |
| exit 1 | |
| fi | |
| echo "Version check passed: $conf_version matches tag $tag" | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| cache: 'npm' | |
| - name: Setup Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: ${{ matrix.target }} | |
| - name: Install dependencies (Ubuntu) | |
| if: matrix.platform == 'ubuntu-22.04' | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf | |
| - name: Install Apple certificate and API key | |
| if: matrix.platform == 'macos-latest' | |
| env: | |
| APPLE_CERTIFICATE: ${{ secrets.APPLE_BUILD_CERTIFICATE_BASE64 }} | |
| APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_BUILD_CERTIFICATE_PASSWORD }} | |
| KEYCHAIN_PASSWORD: ${{ secrets.APPLE_BUILD_CERTIFICATE_PASSWORD }} | |
| APPLE_API_KEY: ${{ secrets.APPLE_ASC_API_KEY_KEY_BASE64 }} | |
| APPLE_API_KEY_ID: ${{ secrets.APPLE_ASC_API_KEY_ID }} | |
| run: | | |
| # Create variables | |
| CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12 | |
| KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db | |
| API_KEY_PATH=$RUNNER_TEMP/AuthKey_${APPLE_API_KEY_ID}.p8 | |
| # Decode certificate | |
| echo -n "$APPLE_CERTIFICATE" | base64 --decode -o $CERTIFICATE_PATH | |
| # Decode API key for notarization | |
| echo -n "$APPLE_API_KEY" | base64 --decode -o $API_KEY_PATH | |
| echo "APPLE_API_KEY_PATH=$API_KEY_PATH" >> $GITHUB_ENV | |
| # Create temporary keychain | |
| security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH | |
| security set-keychain-settings -lut 21600 $KEYCHAIN_PATH | |
| security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH | |
| # Import certificate to keychain | |
| security import $CERTIFICATE_PATH -P "$APPLE_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH | |
| security set-key-partition-list -S apple-tool:,apple: -k "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH | |
| security list-keychain -d user -s $KEYCHAIN_PATH | |
| - name: Install frontend dependencies | |
| run: npm ci | |
| - name: Install playwright-runner dependencies | |
| working-directory: playwright-runner | |
| run: npm ci | |
| - name: Build playwright-runner binary | |
| working-directory: playwright-runner | |
| run: | | |
| npx pkg index.cjs -t ${{ matrix.pkg_target }} -o dist/${{ matrix.binary_name }} --no-bytecode --public-packages '*' --public | |
| - name: Sign playwright-runner binary (macOS) | |
| if: matrix.platform == 'macos-latest' | |
| run: | | |
| codesign --force --options runtime --timestamp \ | |
| --entitlements playwright-runner/entitlements.plist \ | |
| --sign "Developer ID Application: Corsali, Inc (${{ secrets.APPLE_TEAM_ID }})" \ | |
| playwright-runner/dist/${{ matrix.binary_name }} | |
| - name: Install personal-server dependencies | |
| working-directory: personal-server | |
| run: npm ci | |
| - name: Build personal-server binary | |
| working-directory: personal-server | |
| run: npm run build | |
| - name: Sign personal-server binary (macOS) | |
| if: matrix.platform == 'macos-latest' | |
| run: | | |
| codesign --force --options runtime --timestamp \ | |
| --entitlements personal-server/entitlements.plist \ | |
| --sign "Developer ID Application: Corsali, Inc (${{ secrets.APPLE_TEAM_ID }})" \ | |
| personal-server/dist/${{ matrix.ps_binary_name }} | |
| - name: Sign personal-server native modules (macOS) | |
| if: matrix.platform == 'macos-latest' | |
| run: | | |
| echo "=== Signing native .node binaries in personal-server/dist/node_modules ===" | |
| find personal-server/dist/node_modules -name "*.node" -type f | while read node_binary; do | |
| echo "Signing: $node_binary" | |
| codesign --force --options runtime --timestamp \ | |
| --sign "Developer ID Application: Corsali, Inc (${{ secrets.APPLE_TEAM_ID }})" \ | |
| "$node_binary" | |
| done | |
| - name: Build Tauri app | |
| uses: tauri-apps/tauri-action@v0 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| VITE_PRIVY_APP_ID: ${{ secrets.VITE_PRIVY_APP_ID }} | |
| VITE_PRIVY_CLIENT_ID: ${{ secrets.VITE_PRIVY_CLIENT_ID }} | |
| VITE_SESSION_RELAY_URL: ${{ secrets.VITE_SESSION_RELAY_URL }} | |
| VITE_GATEWAY_URL: ${{ secrets.VITE_GATEWAY_URL }} | |
| APPLE_CERTIFICATE: ${{ secrets.APPLE_BUILD_CERTIFICATE_BASE64 }} | |
| APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_BUILD_CERTIFICATE_PASSWORD }} | |
| APPLE_SIGNING_IDENTITY: "Developer ID Application: Corsali, Inc (${{ secrets.APPLE_TEAM_ID }})" | |
| APPLE_API_KEY_PATH: ${{ env.APPLE_API_KEY_PATH }} | |
| APPLE_API_KEY: ${{ secrets.APPLE_ASC_API_KEY_ID }} | |
| APPLE_API_ISSUER: ${{ secrets.APPLE_ASC_API_KEY_ISSUER_UUID }} | |
| with: | |
| tagName: ${{ github.ref_name }} | |
| releaseName: 'DataConnect v__VERSION__' | |
| releaseBody: 'See the assets to download this version and install.' | |
| releaseDraft: false | |
| prerelease: false | |
| args: --target ${{ matrix.target }} | |
| - name: Free disk space before finalization | |
| run: | | |
| echo "=== Disk usage before cleanup ===" | |
| df -h / || true | |
| # Remove Rust build artifacts (no longer needed after Tauri build) | |
| rm -rf src-tauri/target/${{ matrix.target }}/release/deps | |
| rm -rf src-tauri/target/${{ matrix.target }}/release/build | |
| rm -rf src-tauri/target/${{ matrix.target }}/release/.fingerprint | |
| rm -rf src-tauri/target/${{ matrix.target }}/release/incremental | |
| # Remove npm caches no longer needed | |
| rm -rf node_modules | |
| rm -rf playwright-runner/node_modules | |
| rm -rf ~/.cargo/registry/cache | |
| echo "=== Disk usage after cleanup ===" | |
| df -h / || true | |
| shell: bash | |
| - name: Copy native modules and finalize bundles | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| set -x # Enable verbose debugging | |
| # Copy node_modules into macOS .app bundles (preserving directory structure) | |
| if [ "${{ matrix.platform }}" = "macos-latest" ]; then | |
| # Debug: Show what's in personal-server/dist | |
| echo "=== Contents of personal-server/dist ===" | |
| ls -la personal-server/dist/ || echo "dist not found" | |
| echo "=== Contents of personal-server/dist/node_modules ===" | |
| ls -la personal-server/dist/node_modules/ || echo "node_modules not found in dist" | |
| # Sign all native .node binaries BEFORE copying to app bundle | |
| # This is required for Apple notarization to succeed | |
| echo "=== Signing native .node binaries ===" | |
| find personal-server/dist/node_modules -name "*.node" -type f | while read node_binary; do | |
| echo "Signing: $node_binary" | |
| codesign --force --options runtime --timestamp \ | |
| --sign "Developer ID Application: Corsali, Inc (${{ secrets.APPLE_TEAM_ID }})" \ | |
| "$node_binary" | |
| done | |
| for app in src-tauri/target/${{ matrix.target }}/release/bundle/macos/*.app; do | |
| [ -e "$app" ] || { echo "No .app found at $app"; continue; } | |
| echo "=== Processing $app ===" | |
| # Show current state | |
| echo "Before copy - Resources contents:" | |
| ls -la "$app/Contents/Resources/personal-server/dist/" || echo "personal-server/dist not in Resources" | |
| dest="$app/Contents/Resources/personal-server/dist/node_modules" | |
| mkdir -p "$dest" | |
| # Copy with verbose output | |
| if [ -d "personal-server/dist/node_modules" ]; then | |
| cp -Rv personal-server/dist/node_modules/* "$dest/" | |
| echo "=== After copy - node_modules contents ===" | |
| ls -la "$dest/" || echo "copy failed" | |
| else | |
| echo "ERROR: personal-server/dist/node_modules does not exist!" | |
| exit 1 | |
| fi | |
| echo "Copied node_modules to $dest" | |
| done | |
| # Re-sign nested binaries with their entitlements, then re-sign the .app | |
| for app in src-tauri/target/${{ matrix.target }}/release/bundle/macos/*.app; do | |
| [ -e "$app" ] || continue | |
| # Sign personal-server binary with JIT entitlements (--deep would strip them) | |
| ps_bin="$app/Contents/Resources/personal-server/dist/${{ matrix.ps_binary_name }}" | |
| if [ -f "$ps_bin" ]; then | |
| codesign --force --options runtime --timestamp \ | |
| --entitlements personal-server/entitlements.plist \ | |
| --sign "Developer ID Application: Corsali, Inc (${{ secrets.APPLE_TEAM_ID }})" \ | |
| "$ps_bin" | |
| echo "Signed personal-server binary with JIT entitlements" | |
| fi | |
| # Sign native .node addons inside the app bundle | |
| find "$app/Contents/Resources/personal-server/dist/node_modules" -name "*.node" -type f | while read node_binary; do | |
| codesign --force --options runtime --timestamp \ | |
| --sign "Developer ID Application: Corsali, Inc (${{ secrets.APPLE_TEAM_ID }})" \ | |
| "$node_binary" | |
| done | |
| # Sign the outer .app (without --deep to preserve nested entitlements) | |
| codesign --force --options runtime --timestamp \ | |
| --sign "Developer ID Application: Corsali, Inc (${{ secrets.APPLE_TEAM_ID }})" \ | |
| "$app" | |
| echo "Re-signed $app" | |
| done | |
| # Recreate DMG with updated .app (including Applications symlink) | |
| for app in src-tauri/target/${{ matrix.target }}/release/bundle/macos/*.app; do | |
| [ -e "$app" ] || continue | |
| app_name=$(basename "$app" .app) | |
| version=$(grep '"version"' src-tauri/tauri.conf.json | head -1 | sed 's/.*: "\(.*\)".*/\1/') | |
| arch=$(echo "${{ matrix.target }}" | cut -d- -f1) | |
| dmg_name="${app_name}_${version}_${arch}.dmg" | |
| dmg_path="src-tauri/target/${{ matrix.target }}/release/bundle/dmg/${dmg_name}" | |
| # Create temp folder with app and Applications symlink | |
| dmg_temp="dmg_temp_${arch}" | |
| rm -rf "$dmg_temp" | |
| mkdir -p "$dmg_temp" | |
| cp -R "$app" "$dmg_temp/" | |
| ln -s /Applications "$dmg_temp/Applications" | |
| # Verify node_modules is in the temp folder before creating DMG | |
| echo "=== Verifying temp folder contents ===" | |
| ls -la "$dmg_temp/" | |
| ls -la "$dmg_temp/$(basename $app)/Contents/Resources/personal-server/dist/" || echo "WARNING: personal-server dist not found in temp" | |
| ls -la "$dmg_temp/$(basename $app)/Contents/Resources/personal-server/dist/node_modules/" || { echo "ERROR: node_modules NOT in temp folder app!"; exit 1; } | |
| # Create DMG (two-step: writable image with padding, then convert to compressed) | |
| # Single-step -srcfolder -format UDZO can underestimate temp volume size | |
| rm -f "$dmg_path" | |
| folder_size_mb=$(du -sm "$dmg_temp" | cut -f1) | |
| image_size_mb=$(( folder_size_mb + 50 )) | |
| echo "Source folder: ${folder_size_mb}MB, image size: ${image_size_mb}MB" | |
| hdiutil create -volname "$app_name" -srcfolder "$dmg_temp" -ov -format UDRW -size "${image_size_mb}m" "${dmg_path}.rw.dmg" | |
| rm -rf "$dmg_temp" | |
| hdiutil convert "${dmg_path}.rw.dmg" -format UDZO -o "$dmg_path" | |
| rm -f "${dmg_path}.rw.dmg" | |
| echo "Created $dmg_path" | |
| # Verify DMG contents by mounting and checking | |
| echo "=== Verifying DMG contents ===" | |
| mount_point="/tmp/verify_dmg_${arch}" | |
| mkdir -p "$mount_point" | |
| hdiutil attach "$dmg_path" -mountpoint "$mount_point" -nobrowse -quiet | |
| ls -la "$mount_point/" | |
| ls -la "$mount_point/DataConnect.app/Contents/Resources/personal-server/dist/" || echo "WARNING: dist not in mounted DMG" | |
| ls -la "$mount_point/DataConnect.app/Contents/Resources/personal-server/dist/node_modules/" || { hdiutil detach "$mount_point" -quiet; echo "ERROR: node_modules NOT in final DMG!"; exit 1; } | |
| hdiutil detach "$mount_point" -quiet | |
| echo "=== DMG verification passed ===" | |
| # Notarize the DMG using App Store Connect API key | |
| echo "=== Notarizing $dmg_path ===" | |
| if xcrun notarytool submit "$dmg_path" \ | |
| --key "${{ env.APPLE_API_KEY_PATH }}" \ | |
| --key-id "${{ secrets.APPLE_ASC_API_KEY_ID }}" \ | |
| --issuer "${{ secrets.APPLE_ASC_API_KEY_ISSUER_UUID }}" \ | |
| --wait 2>&1 | tee /tmp/notarize_${arch}.log; then | |
| # Staple the notarization ticket | |
| xcrun stapler staple "$dmg_path" && echo "Notarized and stapled $dmg_path" | |
| else | |
| echo "::error::Notarization FAILED for $dmg_path" | |
| cat /tmp/notarize_${arch}.log || true | |
| # Get detailed log from Apple | |
| submission_id=$(grep -oE '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}' /tmp/notarize_${arch}.log | head -1) | |
| if [ -n "$submission_id" ]; then | |
| echo "=== Fetching notarization log for $submission_id ===" | |
| xcrun notarytool log "$submission_id" \ | |
| --key "${{ env.APPLE_API_KEY_PATH }}" \ | |
| --key-id "${{ secrets.APPLE_ASC_API_KEY_ID }}" \ | |
| --issuer "${{ secrets.APPLE_ASC_API_KEY_ISSUER_UUID }}" || true | |
| fi | |
| exit 1 | |
| fi | |
| done | |
| fi | |
| # Copy node_modules for Linux AppImage (extract, modify, repack) | |
| if [ "${{ matrix.platform }}" = "ubuntu-22.04" ]; then | |
| for appimage in src-tauri/target/${{ matrix.target }}/release/bundle/appimage/*.AppImage; do | |
| [ -e "$appimage" ] || continue | |
| # Extract AppImage | |
| chmod +x "$appimage" | |
| "$appimage" --appimage-extract | |
| # Copy node_modules | |
| dest="squashfs-root/usr/lib/personal-server/dist/node_modules" | |
| mkdir -p "$dest" | |
| cp -R personal-server/dist/node_modules/* "$dest/" | |
| # Repack (requires appimagetool) | |
| if command -v appimagetool &> /dev/null; then | |
| rm "$appimage" | |
| ARCH=x86_64 appimagetool squashfs-root "$appimage" | |
| fi | |
| rm -rf squashfs-root | |
| echo "Updated AppImage with node_modules" | |
| done | |
| fi | |
| # Copy node_modules for Windows (into the installation directory structure) | |
| if [ "${{ matrix.platform }}" = "windows-latest" ]; then | |
| # For NSIS, we need to modify the installer or include in resources | |
| # The simpler approach is to ensure node_modules is included in the bundle | |
| echo "Windows: node_modules should be handled by resource bundling" | |
| fi | |
| shell: bash | |
| - name: Upload release artifacts | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| # Upload macOS DMG | |
| if [ "${{ matrix.platform }}" = "macos-latest" ]; then | |
| for f in src-tauri/target/${{ matrix.target }}/release/bundle/dmg/*.dmg; do | |
| if [ -f "$f" ]; then | |
| gh release upload "${{ github.ref_name }}" "$f" --clobber | |
| echo "Uploaded $(basename "$f")" | |
| fi | |
| done | |
| fi | |
| # Upload Linux artifacts | |
| if [ "${{ matrix.platform }}" = "ubuntu-22.04" ]; then | |
| for f in src-tauri/target/${{ matrix.target }}/release/bundle/deb/*.deb \ | |
| src-tauri/target/${{ matrix.target }}/release/bundle/appimage/*.AppImage; do | |
| if [ -f "$f" ]; then | |
| gh release upload "${{ github.ref_name }}" "$f" --clobber | |
| echo "Uploaded $(basename "$f")" | |
| fi | |
| done | |
| fi | |
| # Upload Windows artifacts | |
| if [ "${{ matrix.platform }}" = "windows-latest" ]; then | |
| for f in src-tauri/target/${{ matrix.target }}/release/bundle/nsis/*.exe \ | |
| src-tauri/target/${{ matrix.target }}/release/bundle/msi/*.msi; do | |
| if [ -f "$f" ]; then | |
| gh release upload "${{ github.ref_name }}" "$f" --clobber | |
| echo "Uploaded $(basename "$f")" | |
| fi | |
| done | |
| fi | |
| shell: bash | |
| - name: Cleanup keychain | |
| if: matrix.platform == 'macos-latest' && always() | |
| run: | | |
| security delete-keychain $RUNNER_TEMP/app-signing.keychain-db || true |