diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 86982517..88096344 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,8 +8,6 @@ on: workflow_dispatch: pull_request: types: [opened, synchronize] - paths-ignore: - - '**/*.md' push: branches: - main @@ -25,7 +23,25 @@ defaults: shell: bash jobs: + detect-changes: + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: read + outputs: + code-changed: ${{ steps.filter.outputs.code }} + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2 + id: filter + with: + filters: | + code: + - '!**/*.md' + test: + needs: detect-changes + if: needs.detect-changes.outputs.code-changed == 'true' name: Test strategy: fail-fast: false @@ -132,6 +148,7 @@ jobs: done: runs-on: ubuntu-latest + if: always() needs: - test - fmt diff --git a/CLAUDE.md b/CLAUDE.md index caa85995..ab2c26be 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,10 +1,28 @@ -# CLAUDE.md - -## Project Overview - -A monorepo task runner (like nx/turbo) with intelligent caching and dependency resolution. - -## Build Commands +# Vite Task + +A monorepo task runner (like Nx/Turbo) with intelligent caching and dependency resolution, distributed as the `vp run` command in [Vite+](https://github.com/voidzero-dev/vite-plus). + +## Repository Structure + +- `crates/vite_task` — Task execution engine with caching and session management +- `crates/vite_task_bin` — Internal dev CLI binary (`vt`) and task synthesizer +- `crates/vite_task_graph` — Task dependency graph construction and config loading +- `crates/vite_task_plan` — Execution planning (resolves env vars, working dirs, commands) +- `crates/vite_workspace` — Workspace detection and package dependency graph +- `crates/fspy*` — File system access tracing (9 crates: supervisor, preload libs, platform backends) +- `crates/pty_terminal*` — Cross-platform headless terminal emulator (3 crates) +- `crates/vite_path` — Type-safe absolute/relative path system +- `crates/vite_str` — Stack-allocated compact string type +- `crates/vite_glob` — Glob pattern matching +- `crates/vite_shell` — Shell command parsing +- `crates/vite_select` — Interactive fuzzy selection UI +- `crates/vite_tui` — Terminal UI components (WIP, unfinished) +- `crates/vite_graph_ser` — Graph serialization utilities +- `crates/subprocess_test` — Subprocess testing framework +- `packages/tools` — Node.js test utilities (print, json-edit, check-tty, etc.) +- `docs/` — Documentation (inputs configuration guide) + +## Development Commands ```bash just init # Install build tools and dependencies @@ -30,96 +48,37 @@ INSTA_UPDATE=always cargo test # Update snapshots Integration tests (e2e, plan, fspy) require `pnpm install` in `packages/tools` first. You don't need `pnpm install` in test fixture directories. -Test fixtures and snapshots: +### Test Fixtures -- **Plan**: `crates/vite_task_plan/tests/plan_snapshots/fixtures/` - quicker, sufficient for testing behaviour before actual execution: - - task graph - - resolved configurations - - resolved program paths, cwd, and env vars -- **E2E**: `crates/vite_task_bin/tests/e2e_snapshots/fixtures/` - needed for testing execution and beyond: caching, output styling +- **Plan**: `crates/vite_task_plan/tests/plan_snapshots/fixtures/` — quicker, sufficient for testing task graph, resolved configs, program paths, cwd, and env vars +- **E2E**: `crates/vite_task_bin/tests/e2e_snapshots/fixtures/` — needed for testing execution, caching, output styling ### Cross-Platform Testing -**CRITICAL**: This project must work on both Unix (macOS/Linux) and Windows. For any cross-platform features: - -1. **No Platform Skipping**: Skipping tests on either platform is **UNACCEPTABLE** - - Use `#[cfg(unix)]` and `#[cfg(windows)]` for platform-specific code within tests - - Both platforms must execute the test and verify the feature works correctly - - If a feature can't work on a platform, it shouldn't be added +**CRITICAL**: This project must work on both Unix (macOS/Linux) and Windows. Skipping tests on either platform is **UNACCEPTABLE**. -2. **Windows Cross-Testing from macOS**: - `cargo xtest` cross-compiles the test binary and runs it on a real remote Windows environment (not emulation). The filesystem is bridged so the test can access local fixture files. - ```bash - cargo xtest --builder cargo-xwin --target aarch64-pc-windows-msvc -p --test +- Use `#[cfg(unix)]` and `#[cfg(windows)]` for platform-specific code within tests +- Both platforms must execute the test and verify the feature works correctly +- Use cross-platform libraries for common operations (e.g., `terminal_size` for terminal dimensions) - # Examples: - cargo xtest --builder cargo-xwin --target aarch64-pc-windows-msvc -p pty_terminal --test terminal - cargo xtest --builder cargo-xwin --target aarch64-pc-windows-msvc -p pty_terminal --test terminal -- resize_terminal - ``` +## Architecture -3. **Cross-Platform Test Design Patterns**: - - Use conditional compilation for platform-specific setup/assertions - - Use cross-platform libraries for common operations (e.g., `terminal_size` for terminal dimensions) - - Verify platform-specific behavior works as expected: - - **Unix**: SIGWINCH signals, ioctl, /dev/null, etc. - - **Windows**: ConPTY, GetConsoleScreenBufferInfo, NUL, etc. +### Task Execution Pipeline -4. **Example**: The `pty_terminal::resize_terminal` test demonstrates proper cross-platform testing: - - Unix: Installs SIGWINCH handler to verify signal delivery - - Windows: Acknowledges synchronous ConPTY resize behavior - - Both: Query terminal size using cross-platform `terminal_size` crate - - Both: Verify resize actually works and returns correct dimensions - -## CLI Usage - -```bash -# Run a task defined in vite-task.json -vt run # run task in current package -vt run # # run task in specific package -vt run -r # run task in all packages (recursive) -vt run -t # run task in current package + transitive deps -vt run -- --extra --args # pass extra args to the task command -vt run # interactive task selector (fuzzy search) - -# Built-in commands (run tools from node_modules/.bin) -vt test [args...] # run vitest -vt lint [args...] # run oxlint - -# Cache management -vt cache clean # remove the cache database - -# Package selection flags --r, --recursive # select all packages in the workspace --t, --transitive # select current package + transitive deps --w, --workspace-root # select the workspace root package --F, --filter # pnpm-style filter (repeatable, see below) - -# Run flags ---ignore-depends-on # skip explicit dependsOn dependencies --v, --verbose # show full detailed summary after execution ---cache # force caching on for all tasks and scripts ---no-cache # force caching off for all tasks and scripts ---last-details # show detailed summary of the last run - -# Filter patterns (pnpm-style) --F # select by package name --F '@scope/*' # select by glob pattern --F ./ # select packages under a directory --F '...' # select package and its dependencies --F '...' # select package and its dependents --F '!' # exclude packages matching pattern +``` +CLI (vite_task_bin) → Task Graph (vite_task_graph) → Plan (vite_task_plan) → Execution (vite_task) + ↑ ↓ + vite_workspace fspy (file tracing) ``` -## Key Architecture +### Task Dependencies -- **vite_task** - Main task runner with caching and session management -- **vite_task_bin** - CLI binary (`vt` command) and task synthesizer -- **vite_task_graph** - Task dependency graph construction and config loading -- **vite_task_plan** - Execution planning (resolves env vars, working dirs, commands) -- **vite_workspace** - Workspace detection and package dependency graph -- **fspy** - File system access tracking for precise cache invalidation +1. **Explicit**: Defined via `dependsOn` in `vite-task.json` (skip with `--ignore-depends-on`) +2. **Topological**: Based on package.json dependencies + - With `-r/--recursive`: runs task across all packages in dependency order + - With `-t/--transitive`: runs task in current package and its dependencies -## Task Configuration +### Task Configuration Tasks are defined in `vite-task.json`: @@ -140,37 +99,11 @@ Tasks are defined in `vite-task.json`: } ``` -- `cache` (root): workspace-wide cache toggle. Default: `{ "scripts": false, "tasks": true }` -- `command`: shell command to run (required) -- `cwd`: working directory relative to the package root -- `dependsOn`: explicit task dependencies (`taskName` or `package#task`) -- `cache` (task): enable/disable caching for this task (default: `true`) -- `env`: env var names to fingerprint and pass to the task -- `untrackedEnv`: env var names to pass without fingerprinting -- `input`: files for cache fingerprinting (globs, `{ "auto": true }`, negation patterns) - -## Task Dependencies - -1. **Explicit**: Defined via `dependsOn` in `vite-task.json` (skip with `--ignore-depends-on`) -2. **Topological**: Based on package.json dependencies - - With `-r/--recursive`: runs task across all packages in dependency order - - With `-t/--transitive`: runs task in current package and its dependencies - -## Cross-Platform Linting - -After major changes (especially to `fspy*` or platform-specific crates), run cross-platform clippy before pushing: - -```bash -just lint # native (host platform) -just lint-linux # Linux via cargo-zigbuild -just lint-windows # Windows via cargo-xwin -``` - ## Code Constraints ### Required Patterns -These patterns are enforced by `.clippy.toml`: +Enforced by `.clippy.toml`: | Instead of | Use | | ----------------------------------- | ---------------------------------------- | @@ -181,28 +114,23 @@ These patterns are enforced by `.clippy.toml`: | `std::env::current_dir` | `vite_path::current_dir` | | `.to_lowercase()`/`.to_uppercase()` | `cow_utils` methods | +### Path Type System + +- Use `AbsolutePath` for internal data flow; only convert to `RelativePath` when saving to cache +- Use methods like `strip_prefix`/`join` from `vite_path` instead of converting to std paths +- Only convert to std paths when interfacing with std library functions +- Add necessary methods in `vite_path` instead of falling back to std path types + ### Cross-Platform Requirements -**All code must work on both Unix and Windows without platform skipping:** +All code must work on both Unix and Windows without platform skipping: - Use `#[cfg(unix)]` / `#[cfg(windows)]` for platform-specific implementations -- Always test on both platforms (use `cargo xtest` for Windows cross-compilation) - Platform differences should be handled gracefully, not skipped -- Document platform-specific behavior in code comments - -## Path Type System - -- **Type Safety**: All paths use typed `vite_path` instead of `std::path` - - **Absolute Paths**: `vite_path::AbsolutePath` / `AbsolutePathBuf` - - **Relative Paths**: `vite_path::RelativePath` / `RelativePathBuf` - -- **Usage Guidelines**: - - Use `AbsolutePath` for internal data flow; only convert to `RelativePath` when saving to cache - - Use methods like `strip_prefix`/`join` from `vite_path` instead of converting to std paths - - Only convert to std paths when interfacing with std library functions - - Add necessary methods in `vite_path` instead of falling back to std path types +- After major changes to `fspy*` or platform-specific crates, run `just lint-linux` and `just lint-windows` ## Quick Reference - **Task Format**: `package#task` (e.g., `app#build`, `@test/utils#lint`) - **Config File**: `vite-task.json` in each package +- **Rust Edition**: 2024, MSRV 1.88.0 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..e4b1d087 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,101 @@ +# Contributing to Vite Task + +## Prerequisites + +- [Rust](https://rustup.rs/) (see [rust-toolchain.toml](rust-toolchain.toml) for the required version) +- [Node.js](https://nodejs.org/) (^20.19.0 || >=22.12.0) +- [pnpm](https://pnpm.io/) (10.x) +- [just](https://just.systems/) — task runner for build commands +- [cargo-binstall](https://github.com/cargo-bins/cargo-binstall) — for installing Rust tools + +## Initial Setup + +```bash +just init +``` + +This installs all required Rust tools (`cargo-insta`, `typos-cli`, `cargo-shear`, `dprint`, `taplo-cli`) and bootstraps the Node.js tooling. + +## Development Workflow + +Officially, Vite Task is distributed as part of Vite+ and invoked via `vp run`. The `vt` binary (`vite_task_bin` crate) is an internal development CLI for working on this repo in pure Rust without building the full Vite+ stack. Use `cargo run --bin vt` to build and run locally during development. Don't reference `vt` in user-facing documentation — it's not a public interface. + +| | `vp run` (Vite+) | `vt run` (this repo) | +| ------------ | -------------------------------------------- | -------------------- | +| Purpose | End-user CLI | Internal dev/testing | +| Config | `vite.config.ts` (`run` block) | `vite-task.json` | +| Distribution | Bundled in Vite+ | `cargo run --bin vt` | +| Scope | Full toolchain (dev, build, test, lint, ...) | Task runner only | + +```bash +just ready # Full quality check: typos, fmt, check, test, lint, doc +just fmt # Format code (cargo fmt + cargo shear + dprint) +just check # Check compilation with all features +just test # Run all tests +just lint # Clippy linting +just doc # Generate documentation +``` + +### Running Specific Tests + +```bash +cargo test # All tests +cargo test -p vite_task_bin --test e2e_snapshots # E2E snapshot tests +cargo test -p vite_task_plan --test plan_snapshots # Plan snapshot tests +cargo test --test e2e_snapshots -- stdin # Filter by test name +INSTA_UPDATE=always cargo test # Update snapshots +``` + +Integration tests (e2e, plan, fspy) require `pnpm install` in `packages/tools` first. You don't need `pnpm install` in test fixture directories. + +### Test Fixtures + +- **Plan snapshots** — `crates/vite_task_plan/tests/plan_snapshots/fixtures/` — quicker, sufficient for testing task graph, resolved configs, program paths, cwd, and env vars +- **E2E snapshots** — `crates/vite_task_bin/tests/e2e_snapshots/fixtures/` — needed for testing actual execution, caching behavior, and output styling + +See individual crate READMEs for crate-specific testing details. + +## Cross-Platform Development + +This project must work on macOS, Linux, and Windows. Skipping tests on any platform is not acceptable. + +- Use `#[cfg(unix)]` / `#[cfg(windows)]` for platform-specific code +- Use cross-platform libraries where possible (e.g., `terminal_size` instead of raw ioctl/ConPTY) + +### Cross-Platform Linting + +After changes to `fspy*` or platform-specific crates, run cross-platform clippy: + +```bash +just lint # Native (host platform) +just lint-linux # Linux via cargo-zigbuild +just lint-windows # Windows via cargo-xwin +``` + +## Code Conventions + +### Required Patterns + +These are enforced by `.clippy.toml`: + +| Instead of | Use | +| ------------------------------------- | ------------------------------------------ | +| `HashMap` / `HashSet` | `FxHashMap` / `FxHashSet` from rustc-hash | +| `std::path::Path` / `PathBuf` | `vite_path::AbsolutePath` / `RelativePath` | +| `std::format!` | `vite_str::format!` | +| `String` (for small strings) | `vite_str::Str` | +| `std::env::current_dir` | `vite_path::current_dir` | +| `.to_lowercase()` / `.to_uppercase()` | `cow_utils` methods | + +### Path Type System + +All paths use `vite_path` for type safety: + +- **`AbsolutePath` / `AbsolutePathBuf`** — for internal data flow +- **`RelativePath` / `RelativePathBuf`** — for cache storage and display + +Use `vite_path` methods (`strip_prefix`, `join`, etc.) instead of converting to `std::path`. Only convert to std paths when interfacing with std library functions. Add necessary methods to `vite_path` rather than falling back. + +## macOS Performance Tip + +Add your terminal app to the approved "Developer Tools" in System Settings > Privacy & Security. Your Rust builds will be ~30% faster. diff --git a/README.md b/README.md index b3b73129..144eeab2 100644 --- a/README.md +++ b/README.md @@ -1 +1,20 @@ # Vite Task + +Monorepo task runner with intelligent caching and dependency-aware scheduling, powering [`vp run`](https://github.com/voidzero-dev/vite-plus) in [Vite+](https://viteplus.dev). + +## Getting Started + +Install [Vite+](https://viteplus.dev), then run tasks from your workspace. See the [documentation](https://viteplus.dev/guide/run) for full usage. + +```bash +vp run build # run a task in the current package +vp run build -r # run across all packages in dependency order +vp run @my/app#build -t # run in a package and its transitive dependencies +vp run --cache build # run with caching enabled +``` + +## License + +[MIT](LICENSE) + +Copyright (c) 2026-present [VoidZero Inc.](https://voidzero.dev/)