diff --git a/.github/actions/setup-rust/action.yml b/.github/actions/setup-rust/action.yml new file mode 100644 index 00000000..8d3cc24b --- /dev/null +++ b/.github/actions/setup-rust/action.yml @@ -0,0 +1,63 @@ +name: Setup Rust toolchain +description: >- + Installs the Rust toolchain, sets up cargo caching, and installs the minimal + Linux build dependencies required for the workspace (gpui in particular). +inputs: + toolchain: + description: Rust toolchain to install (e.g. stable, 1.79.0) + required: false + default: stable + target: + description: Optional rustup target triple to add (e.g. x86_64-unknown-linux-gnu) + required: false + default: "" + components: + description: Comma-separated list of rustup components (e.g. rustfmt,clippy) + required: false + default: "" + cache-key: + description: Shared cache key used by Swatinem/rust-cache + required: false + default: default + cache-save-if: + description: Whether to write back to the cache (set to "false" on PRs to avoid bloat) + required: false + default: "true" + +runs: + using: composite + steps: + - name: Install Rust toolchain + uses: actions-rs/toolchain@16499b5e05bf2e26879000db0c1d13f7e13fa3af # v1.0.7 + with: + toolchain: ${{ inputs.toolchain }} + target: ${{ inputs.target }} + components: ${{ inputs.components }} + override: true + + - name: Cache cargo registry and target + uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0 + with: + shared-key: ${{ inputs.cache-key }} + save-if: ${{ inputs.cache-save-if }} + + # Minimal set of system libraries required to build the workspace on + # Linux. Mirrors the dependencies gpui pulls in (Wayland, X11/XCB, + # xkbcommon, fontconfig, alsa, vulkan loader) plus the few generic + # libraries used by other crates in the workspace (openssl, zstd). + - name: Install Linux dependencies + if: runner.os == 'Linux' + shell: bash + run: | + sudo apt-get update + sudo apt-get install -y --no-install-recommends \ + pkg-config \ + build-essential \ + libssl-dev \ + libzstd-dev \ + libfontconfig-dev \ + libwayland-dev \ + libx11-xcb-dev \ + libxkbcommon-x11-dev \ + libasound2-dev \ + libvulkan1 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index adc35641..ee7b41b3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,12 +3,71 @@ name: Build on: push: branches: [main] + pull_request: + branches: [main] env: CARGO_TERM_COLOR: always jobs: + test-linux: + name: Test workspace (Linux, excl. ui_gpui) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + + - name: Setup Rust + uses: ./.github/actions/setup-rust + with: + components: rustfmt,clippy + cache-key: workspace-linux + cache-save-if: ${{ github.event_name != 'pull_request' }} + + - name: cargo fmt --check + run: cargo fmt --all -- --check + + # We exclude ui_gpui here because gpui is exercised separately on every + # supported platform in the `test-gpui` job. Linting / testing the rest + # of the workspace on Linux is sufficient. + - name: cargo clippy (workspace, excl. ui_gpui) + run: | + cargo clippy \ + --workspace --exclude ui_gpui --all-targets --locked \ + -- -D warnings + + - name: cargo test (workspace, excl. ui_gpui) + run: cargo test --workspace --exclude ui_gpui --locked + + test-gpui: + name: Test ui_gpui (${{ matrix.name }}) + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-latest + name: linux-x86_64 + - os: macos-latest + name: macos-aarch64 + - os: windows-latest + name: windows-x86_64 + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + + - name: Setup Rust + uses: ./.github/actions/setup-rust + with: + cache-key: ui-gpui-${{ matrix.name }} + cache-save-if: ${{ github.event_name != 'pull_request' }} + + - name: cargo test -p ui_gpui + run: cargo test -p ui_gpui --locked + build: + needs: [test-linux, test-gpui] + # Skip the full release-build matrix for pull requests; running tests is + # enough to gate PRs and the cross-platform build matrix is expensive. + if: github.event_name != 'pull_request' strategy: fail-fast: false # Don't cancel other builds if one fails matrix: @@ -36,60 +95,13 @@ jobs: - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Setup Rust - uses: actions-rs/toolchain@16499b5e05bf2e26879000db0c1d13f7e13fa3af # v1.0.7 + uses: ./.github/actions/setup-rust with: - toolchain: stable target: ${{ matrix.target }} - override: true - - - name: Install Linux dependencies - if: matrix.os == 'ubuntu-latest' - run: | - sudo apt-get update - - # Install X11 and XCB development libraries - sudo apt-get install -y \ - build-essential \ - pkg-config \ - libx11-dev \ - libx11-xcb-dev \ - libxcb1-dev \ - libxcb-shape0-dev \ - libxcb-xfixes0-dev \ - libxcb-render0-dev \ - libxcb-render-util0-dev \ - libxcb-randr0-dev \ - libxcb-image0-dev \ - libxcb-util-dev \ - libxcb-cursor-dev \ - libxcb-keysyms1-dev \ - libxcb-icccm4-dev \ - libxkbcommon-dev \ - libxkbcommon-x11-dev \ - libgl1-mesa-dev \ - libglu1-mesa-dev \ - libxrandr-dev \ - libxinerama-dev \ - libxcursor-dev \ - libxi-dev - - # Debug output - echo "=== Checking X11-xcb availability ===" - pkg-config --exists x11-xcb && echo "✓ x11-xcb pkg-config found" || echo "✗ x11-xcb pkg-config missing" - pkg-config --libs x11-xcb 2>/dev/null && echo "✓ x11-xcb libs available" || echo "✗ x11-xcb libs not found" - - echo "=== Library search ===" - find /usr -name "*X11-xcb*" 2>/dev/null | head -5 || echo "No X11-xcb files found" - ldconfig -p | grep -i x11 | grep -i xcb || echo "X11-xcb not in ldconfig" - - echo "=== Environment for build ===" - export PKG_CONFIG_PATH="/usr/lib/x86_64-linux-gnu/pkgconfig:/usr/share/pkgconfig:$PKG_CONFIG_PATH" - echo "PKG_CONFIG_PATH=$PKG_CONFIG_PATH" + cache-key: build-${{ matrix.name }} - name: Build uses: actions-rs/cargo@844f36862e911db73fe0815f00a4a2602c279505 # v1.0.3 - env: - PKG_CONFIG_PATH: /usr/lib/x86_64-linux-gnu/pkgconfig:/usr/share/pkgconfig with: command: build args: --locked --release --target ${{ matrix.target }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 776796c8..ce37fd90 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,7 +12,56 @@ env: CARGO_TERM_COLOR: always jobs: + test-linux: + name: Test workspace (Linux, excl. ui_gpui) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + + - name: Setup Rust + uses: ./.github/actions/setup-rust + with: + components: rustfmt,clippy + cache-key: workspace-linux + + - name: cargo fmt --check + run: cargo fmt --all -- --check + + - name: cargo clippy (workspace, excl. ui_gpui) + run: | + cargo clippy \ + --workspace --exclude ui_gpui --all-targets --locked \ + -- -D warnings + + - name: cargo test (workspace, excl. ui_gpui) + run: cargo test --workspace --exclude ui_gpui --locked + + test-gpui: + name: Test ui_gpui (${{ matrix.name }}) + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-latest + name: linux-x86_64 + - os: macos-latest + name: macos-aarch64 + - os: windows-latest + name: windows-x86_64 + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + + - name: Setup Rust + uses: ./.github/actions/setup-rust + with: + cache-key: ui-gpui-${{ matrix.name }} + + - name: cargo test -p ui_gpui + run: cargo test -p ui_gpui --locked + prepare-version: + needs: [test-linux, test-gpui] runs-on: ubuntu-latest permissions: contents: write @@ -165,60 +214,13 @@ jobs: - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Setup Rust - uses: actions-rs/toolchain@16499b5e05bf2e26879000db0c1d13f7e13fa3af # v1.0.7 + uses: ./.github/actions/setup-rust with: - toolchain: stable target: ${{ matrix.target }} - override: true - - - name: Install Linux dependencies - if: matrix.os == 'ubuntu-latest' - run: | - sudo apt-get update - - # Install X11 and XCB development libraries - sudo apt-get install -y \ - build-essential \ - pkg-config \ - libx11-dev \ - libx11-xcb-dev \ - libxcb1-dev \ - libxcb-shape0-dev \ - libxcb-xfixes0-dev \ - libxcb-render0-dev \ - libxcb-render-util0-dev \ - libxcb-randr0-dev \ - libxcb-image0-dev \ - libxcb-util-dev \ - libxcb-cursor-dev \ - libxcb-keysyms1-dev \ - libxcb-icccm4-dev \ - libxkbcommon-dev \ - libxkbcommon-x11-dev \ - libgl1-mesa-dev \ - libglu1-mesa-dev \ - libxrandr-dev \ - libxinerama-dev \ - libxcursor-dev \ - libxi-dev - - # Debug output - echo "=== Checking X11-xcb availability ===" - pkg-config --exists x11-xcb && echo "✓ x11-xcb pkg-config found" || echo "✗ x11-xcb pkg-config missing" - pkg-config --libs x11-xcb 2>/dev/null && echo "✓ x11-xcb libs available" || echo "✗ x11-xcb libs not found" - - echo "=== Library search ===" - find /usr -name "*X11-xcb*" 2>/dev/null | head -5 || echo "No X11-xcb files found" - ldconfig -p | grep -i x11 | grep -i xcb || echo "X11-xcb not in ldconfig" - - echo "=== Environment for build ===" - export PKG_CONFIG_PATH="/usr/lib/x86_64-linux-gnu/pkgconfig:/usr/share/pkgconfig:$PKG_CONFIG_PATH" - echo "PKG_CONFIG_PATH=$PKG_CONFIG_PATH" + cache-key: build-${{ matrix.name }} - name: Build uses: actions-rs/cargo@844f36862e911db73fe0815f00a4a2602c279505 # v1.0.3 - env: - PKG_CONFIG_PATH: /usr/lib/x86_64-linux-gnu/pkgconfig:/usr/share/pkgconfig with: command: build args: --locked --release --target ${{ matrix.target }} diff --git a/crates/code_assistant_core/src/tests/sandbox_tests.rs b/crates/code_assistant_core/src/tests/sandbox_tests.rs index 7a717c28..cc74597e 100644 --- a/crates/code_assistant_core/src/tests/sandbox_tests.rs +++ b/crates/code_assistant_core/src/tests/sandbox_tests.rs @@ -90,6 +90,6 @@ mod sandbox_tests_placeholder { #[test] fn sandbox_tests_skip_on_non_macos() { // Seatbelt enforcement is macOS-specific, so these tests are skipped elsewhere. - assert!(true); + // Intentionally empty body; presence of this test documents the platform skip. } } diff --git a/crates/command_executor/src/sandboxed_executor.rs b/crates/command_executor/src/sandboxed_executor.rs index 671f2d9d..1dcb177e 100644 --- a/crates/command_executor/src/sandboxed_executor.rs +++ b/crates/command_executor/src/sandboxed_executor.rs @@ -1,7 +1,9 @@ use std::path::PathBuf; use std::sync::Arc; -use anyhow::{Result, bail}; +use anyhow::Result; +#[cfg(target_os = "macos")] +use anyhow::bail; use async_trait::async_trait; use sandbox::{SandboxContext, SandboxPolicy}; #[cfg(not(target_os = "macos"))] @@ -325,34 +327,20 @@ impl SandboxedCommandExecutor { } } +#[cfg(target_os = "macos")] fn shell_command(command_line: &str, redirect_stderr: bool) -> (String, Vec) { - #[cfg(target_family = "unix")] - { - let shell = std::env::var("SHELL").unwrap_or_else(|_| "/bin/bash".to_string()); - let mut args = Vec::new(); - args.push("-c".to_string()); - if redirect_stderr { - args.push(format!("{command_line} 2>&1")); - } else { - args.push(command_line.to_string()); - } - (shell, args) - } - - #[cfg(target_family = "windows")] - { - let shell = "cmd".to_string(); - let mut args = Vec::new(); - args.push("/C".to_string()); - if redirect_stderr { - args.push(format!("{command_line} 2>&1")); - } else { - args.push(command_line.to_string()); - } - (shell, args) + let shell = std::env::var("SHELL").unwrap_or_else(|_| "/bin/bash".to_string()); + let mut args = Vec::new(); + args.push("-c".to_string()); + if redirect_stderr { + args.push(format!("{command_line} 2>&1")); + } else { + args.push(command_line.to_string()); } + (shell, args) } +#[cfg(target_os = "macos")] fn canonical_working_dir(working_dir: Option<&PathBuf>) -> Result { match working_dir { Some(dir) => {