fix(desktop): let attachment links open existing folders, not just files #21
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: Native Platform CI | |
| on: | |
| pull_request: | |
| branches: [main, master] | |
| paths: | |
| - ".github/workflows/native-platform-ci.yml" | |
| - "apps/desktop/src-tauri/**" | |
| - "apps/mobile/modules/**/android/**" | |
| - "apps/mobile/ios-app-intents/**" | |
| - "apps/mobile/widgets-ios/**" | |
| - "apps/mobile/modules/**/ios/**" | |
| - "apps/mobile/plugins/**" | |
| - "apps/mobile/app.config.ts" | |
| - "apps/mobile/app.json" | |
| - "apps/mobile/package.json" | |
| - "packages/core/src/**" | |
| - "scripts/check-synced-field-parity.ts" | |
| - "scripts/ci/setup-android-sdk.sh" | |
| - "scripts/ci/setup-ruby.sh" | |
| - "package.json" | |
| - "bun.lock" | |
| push: | |
| branches: [main, master] | |
| paths: | |
| - ".github/workflows/native-platform-ci.yml" | |
| - "apps/desktop/src-tauri/**" | |
| - "apps/mobile/modules/**/android/**" | |
| - "apps/mobile/ios-app-intents/**" | |
| - "apps/mobile/widgets-ios/**" | |
| - "apps/mobile/modules/**/ios/**" | |
| - "apps/mobile/plugins/**" | |
| - "apps/mobile/app.config.ts" | |
| - "apps/mobile/app.json" | |
| - "apps/mobile/package.json" | |
| - "packages/core/src/**" | |
| - "scripts/check-synced-field-parity.ts" | |
| - "scripts/ci/setup-android-sdk.sh" | |
| - "scripts/ci/setup-ruby.sh" | |
| - "package.json" | |
| - "bun.lock" | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| env: | |
| FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" | |
| jobs: | |
| changes: | |
| runs-on: ubuntu-latest | |
| name: Detect native changes | |
| outputs: | |
| android: ${{ steps.filter.outputs.android }} | |
| ios: ${{ steps.filter.outputs.ios }} | |
| macos: ${{ steps.filter.outputs.macos }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 | |
| with: | |
| fetch-depth: 0 | |
| - name: Filter changed paths | |
| id: filter | |
| env: | |
| BASE_SHA: ${{ github.event.pull_request.base.sha || github.event.before }} | |
| EVENT_NAME: ${{ github.event_name }} | |
| HEAD_SHA: ${{ github.sha }} | |
| run: | | |
| set -euo pipefail | |
| if [ "$EVENT_NAME" = "workflow_dispatch" ]; then | |
| echo "android=true" >> "$GITHUB_OUTPUT" | |
| echo "ios=true" >> "$GITHUB_OUTPUT" | |
| echo "macos=true" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| if [ -z "${BASE_SHA:-}" ] || [[ "$BASE_SHA" =~ ^0+$ ]]; then | |
| BASE_SHA="$(git rev-parse "${HEAD_SHA}^")" | |
| fi | |
| git diff --name-only "$BASE_SHA" "$HEAD_SHA" > "$RUNNER_TEMP/native-changed-paths.txt" | |
| android=false | |
| ios=false | |
| macos=false | |
| while IFS= read -r path; do | |
| case "$path" in | |
| apps/desktop/src-tauri/*|packages/core/src/*|scripts/check-synced-field-parity.ts|package.json|bun.lock|.github/workflows/native-platform-ci.yml) | |
| macos=true | |
| ;; | |
| esac | |
| case "$path" in | |
| apps/mobile/modules/*/android/*|apps/mobile/plugins/*|apps/mobile/app.config.ts|apps/mobile/app.json|apps/mobile/package.json|scripts/ci/setup-android-sdk.sh|package.json|bun.lock|.github/workflows/native-platform-ci.yml) | |
| android=true | |
| ;; | |
| esac | |
| case "$path" in | |
| apps/mobile/ios-app-intents/*|apps/mobile/widgets-ios/*|apps/mobile/modules/*/ios/*|apps/mobile/plugins/*|apps/mobile/app.config.ts|apps/mobile/app.json|apps/mobile/package.json|scripts/ci/setup-ruby.sh|package.json|bun.lock|.github/workflows/native-platform-ci.yml) | |
| ios=true | |
| ;; | |
| esac | |
| done < "$RUNNER_TEMP/native-changed-paths.txt" | |
| echo "android=$android" >> "$GITHUB_OUTPUT" | |
| echo "ios=$ios" >> "$GITHUB_OUTPUT" | |
| echo "macos=$macos" >> "$GITHUB_OUTPUT" | |
| macos-rust: | |
| if: needs.changes.outputs.macos == 'true' | |
| needs: changes | |
| runs-on: macos-15 | |
| name: macOS Rust check and tests | |
| timeout-minutes: 35 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 | |
| - name: Setup Rust | |
| uses: dtolnay/rust-toolchain@631a55b12751854ce901bb631d5902ceb48146f7 # stable | |
| - name: Cache Rust artifacts | |
| uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 | |
| with: | |
| workspaces: apps/desktop/src-tauri | |
| - name: Check macOS Rust and Objective-C bridge | |
| run: cargo check --locked --manifest-path apps/desktop/src-tauri/Cargo.toml | |
| - name: Run macOS native library tests | |
| run: cargo test --locked --manifest-path apps/desktop/src-tauri/Cargo.toml --lib | |
| android-native: | |
| if: needs.changes.outputs.android == 'true' | |
| needs: changes | |
| runs-on: ubuntu-latest | |
| name: Android native compile | |
| timeout-minutes: 45 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 | |
| with: | |
| node-version: 22 | |
| - name: Setup Java | |
| uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 | |
| with: | |
| distribution: temurin | |
| java-version: 17 | |
| - name: Setup Android SDK | |
| run: bash scripts/ci/setup-android-sdk.sh | |
| - name: Setup Bun | |
| uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 | |
| with: | |
| bun-version-file: ".bun-version" | |
| - name: Cache Bun dependencies | |
| uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 | |
| with: | |
| path: ~/.bun/install/cache | |
| key: ${{ runner.os }}-bun-${{ hashFiles('bun.lock') }} | |
| restore-keys: | | |
| ${{ runner.os }}-bun- | |
| - name: Install dependencies | |
| run: bun install --frozen-lockfile | |
| - name: Generate Android native project | |
| working-directory: apps/mobile | |
| env: | |
| CI: "1" | |
| EXPO_NO_TELEMETRY: "1" | |
| NODE_ENV: development | |
| run: | | |
| "$GITHUB_WORKSPACE/node_modules/.bin/expo" prebuild \ | |
| --clean \ | |
| --platform android \ | |
| --no-install | |
| - name: Compile Android Java and Kotlin sources | |
| working-directory: apps/mobile/android | |
| env: | |
| CI: "1" | |
| EXPO_NO_TELEMETRY: "1" | |
| NODE_ENV: development | |
| run: | | |
| ./gradlew \ | |
| :app:compileDebugKotlin \ | |
| :app:compileDebugJavaWithJavac \ | |
| --no-daemon \ | |
| -PreactNativeArchitectures=arm64-v8a | |
| ios-native: | |
| if: needs.changes.outputs.ios == 'true' | |
| needs: changes | |
| runs-on: macos-15 | |
| name: iOS Swift compile | |
| timeout-minutes: 45 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 | |
| with: | |
| node-version: 22 | |
| - name: Setup Bun | |
| uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 | |
| with: | |
| bun-version-file: ".bun-version" | |
| - name: Cache Bun dependencies | |
| uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 | |
| with: | |
| path: ~/.bun/install/cache | |
| key: ${{ runner.os }}-bun-${{ hashFiles('bun.lock') }} | |
| restore-keys: | | |
| ${{ runner.os }}-bun- | |
| - name: Install dependencies | |
| run: bun install --frozen-lockfile | |
| - name: Setup Ruby | |
| run: bash scripts/ci/setup-ruby.sh 3.3 | |
| - name: Install pinned CocoaPods | |
| run: gem install cocoapods --version 1.16.2 --no-document | |
| - name: Select Xcode (iOS 26 SDK required) | |
| run: | | |
| set -euo pipefail | |
| XCODE_26_PATH="$(ls -d /Applications/Xcode_26*.app 2>/dev/null | sort -V | tail -n 1 || true)" | |
| if [ -n "${XCODE_26_PATH:-}" ]; then | |
| sudo xcode-select -s "$XCODE_26_PATH" | |
| else | |
| XCODE_FALLBACK_PATH="$(ls -d /Applications/Xcode*.app 2>/dev/null | sort -V | tail -n 1 || true)" | |
| if [ -n "${XCODE_FALLBACK_PATH:-}" ]; then | |
| echo "::warning::No Xcode_26*.app found; falling back to latest available: ${XCODE_FALLBACK_PATH}" | |
| sudo xcode-select -s "$XCODE_FALLBACK_PATH" | |
| else | |
| echo "::warning::No explicit Xcode*.app found; using runner default Xcode." | |
| fi | |
| fi | |
| echo "Selected DEVELOPER_DIR: $(xcode-select -p)" | |
| xcodebuild -version | |
| IOS_SDK_VERSION="$(xcodebuild -showsdks | awk '/-sdk iphoneos/{gsub(/iphoneos/, "", $NF); ver=$NF} END{print ver}')" | |
| if [ -z "${IOS_SDK_VERSION:-}" ]; then | |
| echo "::error::No iPhoneOS SDK found on runner. Current SDKs:" | |
| xcodebuild -showsdks | |
| exit 1 | |
| fi | |
| IOS_SDK_MAJOR="${IOS_SDK_VERSION%%.*}" | |
| if ! [[ "${IOS_SDK_MAJOR}" =~ ^[0-9]+$ ]]; then | |
| echo "::error::Unable to parse iPhoneOS SDK version: ${IOS_SDK_VERSION}" | |
| xcodebuild -showsdks | |
| exit 1 | |
| fi | |
| if [ "${IOS_SDK_MAJOR}" -lt 26 ]; then | |
| echo "::error::Detected iPhoneOS SDK ${IOS_SDK_VERSION}. The App Intents source (IntentModes/supportedModes) needs the iOS 26 SDK, matching the release build." | |
| echo "::error::Install/select Xcode 26+ on the runner." | |
| exit 1 | |
| fi | |
| echo "Using iPhoneOS SDK ${IOS_SDK_VERSION}" | |
| - name: Generate iOS native project | |
| working-directory: apps/mobile | |
| env: | |
| EXPO_NO_TELEMETRY: "1" | |
| NODE_ENV: development | |
| run: | | |
| "$GITHUB_WORKSPACE/node_modules/.bin/expo" prebuild \ | |
| --clean \ | |
| --platform ios \ | |
| --no-install | |
| - name: Install CocoaPods dependencies | |
| working-directory: apps/mobile/ios | |
| run: pod install | |
| - name: Compile iOS app and native Swift modules | |
| run: | | |
| xcodebuild \ | |
| -workspace apps/mobile/ios/Mindwtr.xcworkspace \ | |
| -scheme Mindwtr \ | |
| -configuration Debug \ | |
| -sdk iphonesimulator \ | |
| -destination 'generic/platform=iOS Simulator' \ | |
| CODE_SIGNING_ALLOWED=NO \ | |
| CODE_SIGNING_REQUIRED=NO \ | |
| build |