brush: vendor the source tree (un-ignore) to complete the local fork
The prior commit switched the recipe to `[source] path = "source"`, but .gitignore:77 still listed `local/recipes/shells/brush/source` (a leftover from when brush was a transient upstream git fetch), so the vendored tree was not tracked — a fresh clone would have no brush source and the build would fail. Drop that ignore line and commit the vendored working tree (reubeno/brush @ 897b373e, with the Redox port patches pre-applied). brush is now a durable local fork like the other path=source recipes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+86
@@ -0,0 +1,86 @@
|
||||
name: Compatibility Bug Report
|
||||
description: Report a case where brush behaves differently from bash
|
||||
labels: ["bug", "area: compat"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for helping improve brush's compatibility!
|
||||
|
||||
This template is for reporting cases where brush produces different behavior than bash for the same input. Before submitting, please [search existing issues](https://github.com/reubeno/brush/issues) to check if this has already been reported.
|
||||
|
||||
- type: input
|
||||
id: brush-version
|
||||
attributes:
|
||||
label: brush version
|
||||
description: The version of brush you're using. You can find this with `brush --version`.
|
||||
placeholder: "e.g., brush 0.2.9"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: bash-version
|
||||
attributes:
|
||||
label: bash version (for comparison)
|
||||
description: The version of bash you compared against, if applicable. You can find this with `bash --version`.
|
||||
placeholder: "e.g., GNU bash, version 5.2.21(1)-release"
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: dropdown
|
||||
id: platform
|
||||
attributes:
|
||||
label: Platform / OS
|
||||
options:
|
||||
- Linux
|
||||
- macOS
|
||||
- WSL
|
||||
- Windows
|
||||
- Other
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: reproduction
|
||||
attributes:
|
||||
label: Steps to reproduce
|
||||
description: >
|
||||
Provide the shell commands, script, or other usage details that
|
||||
reproduced the issue. If you can narrow it down to a minimal
|
||||
reproducing example, that's very helpful but not required.
|
||||
placeholder: |
|
||||
# Example:
|
||||
brush -c 'some command'
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: actual-behavior
|
||||
attributes:
|
||||
label: Actual behavior (brush)
|
||||
description: What did brush do in this case?
|
||||
placeholder: Describe or paste the brush output...
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: expected-behavior
|
||||
attributes:
|
||||
label: Expected behavior
|
||||
description: >
|
||||
What did you expect to happen? If relevant, what does bash or another
|
||||
comparable shell do in this case?
|
||||
placeholder: Describe or paste the expected output or behavior
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: additional-context
|
||||
attributes:
|
||||
label: Additional context
|
||||
description: >
|
||||
Is there anything else you think is important to share? You might consider
|
||||
including additional environment specifics (e.g., relevant .bashrc config),
|
||||
workarounds, related issues, any additional debugging you've performed, etc.
|
||||
validations:
|
||||
required: false
|
||||
@@ -0,0 +1,5 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Questions & Discussion
|
||||
url: https://github.com/reubeno/brush/discussions
|
||||
about: Ask questions, share ideas, or discuss brush in GitHub Discussions.
|
||||
@@ -0,0 +1,52 @@
|
||||
name: Feature Request
|
||||
description: Suggest a new feature or enhancement for brush
|
||||
labels: ["enhancement"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for taking the time to suggest an improvement to brush! We welcome and appreciate all input and feedback. While we can't commit to prioritizing or implementing all such requests, we'd rather you make the suggestion than not.
|
||||
|
||||
Our only requests: (1) please ensure you follow our project's [Code of Conduct](https://github.com/reubeno/brush#coc-ov-file), and (2) before submitting, please [search existing issues](https://github.com/reubeno/brush/issues) to check if a similar request already exists. If it does, feel free to add a comment to the existing issue instead.
|
||||
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Feature description
|
||||
description: A clear and concise description of the feature or enhancement you'd like.
|
||||
placeholder: Describe the feature...
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: use-case
|
||||
attributes:
|
||||
label: Use case / motivation
|
||||
description: |
|
||||
Why is this feature important to you? What problem does it solve? How would you use it?
|
||||
|
||||
Providing context helps us understand the value and prioritize accordingly.
|
||||
placeholder: Explain why this feature would be useful...
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: proposed-solution
|
||||
attributes:
|
||||
label: Proposed solution
|
||||
description: >
|
||||
If you have ideas on how this could be implemented or how it should work,
|
||||
share them here. Note that this is purely optional.
|
||||
placeholder: Describe how you think this could work...
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: textarea
|
||||
id: additional-context
|
||||
attributes:
|
||||
label: Additional context
|
||||
description: >
|
||||
Any other context, references, or screenshots that would help us understand your request.
|
||||
For example, links to relevant documentation, other shells that implement this, etc.
|
||||
validations:
|
||||
required: false
|
||||
@@ -0,0 +1,19 @@
|
||||
name: Other Issue
|
||||
description: "Report an issue that doesn't fit the other templates"
|
||||
labels: ["state: triage"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
If your issue is a **feature request**, please use the [Feature Request](https://github.com/reubeno/brush/issues/new?template=feature-request.yml) template instead. If it's about **brush behaving differently from bash** or another compatibility issue, please use the [Compatibility Bug Report](https://github.com/reubeno/brush/issues/new?template=compatibility-bug.yml) template instead.
|
||||
|
||||
For general questions or discussion, consider using [GitHub Discussions](https://github.com/reubeno/brush/discussions).
|
||||
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Description
|
||||
description: Please describe the issue in detail.
|
||||
placeholder: Describe the issue...
|
||||
validations:
|
||||
required: true
|
||||
@@ -0,0 +1,394 @@
|
||||
# GitHub Copilot Coding Agent Instructions for brush
|
||||
|
||||
## Project Overview
|
||||
|
||||
**brush** (Bourne Rusty Shell) is a POSIX- and bash-compatible shell implemented in Rust. It's a multi-crate workspace (~60K lines of Rust code) targeting Linux, macOS, and WSL, with experimental Windows and WASM support. The project emphasizes compatibility testing against bash as an oracle.
|
||||
|
||||
**Key Stats:** Rust 2024 edition, MSRV 1.88.0, 5 main crates, 1500+ compatibility test cases, published to crates.io.
|
||||
|
||||
## Critical: Read AGENTS.md First
|
||||
|
||||
**BEFORE making any changes, read `/AGENTS.md`.** It contains detailed architecture patterns, testing workflows, and development guidelines specific to this project. The information below supplements (not replaces) AGENTS.md.
|
||||
|
||||
## Code Review Checklist
|
||||
|
||||
When reviewing PRs, verify:
|
||||
|
||||
- [ ] **Documentation**: All exported APIs have rustdoc comments (missing docs = CI failure)
|
||||
- [ ] **Forbidden patterns**: No `panic`, `unwrap_in_result`, `expect_used`, or `todo` (all denied by clippy)
|
||||
- [ ] **Error handling**: Uses `thiserror` for crate errors; `anyhow` only in tests
|
||||
- [ ] **Logging**: Uses `tracing::debug!(target: trace_categories::CATEGORY, "msg")` pattern
|
||||
- [ ] **Testing**: Compatibility fixes include YAML test cases in `brush-shell/tests/cases/`
|
||||
- [ ] **Testing**: Builtin changes have tests in `brush-shell/tests/cases/builtin/`
|
||||
- [ ] **Testing**: Unit tests expected for new public APIs (when feasible) (see AGENTS.md section 2)
|
||||
- [ ] **Platform code**: Platform-specific code is in `brush-core/src/sys/` modules
|
||||
- [ ] **Breaking changes**: Public API changes are clearly highlighted and documented
|
||||
- [ ] **Builder pattern**: Configuration uses builder pattern (see `Shell::builder()`)
|
||||
- [ ] **Code quality**: Passes `cargo fmt --check` and `cargo clippy` without warnings
|
||||
- [ ] **Commit format**: Follows [Conventional Commits](https://www.conventionalcommits.org/) (feat:, fix:, docs:, test:)
|
||||
- [ ] **Dependencies**: No unnecessary cloning (use references when possible)
|
||||
- [ ] **Cross-platform**: Uses appropriate `cfg(unix)`, `cfg(windows)`, `cfg(target_family = "wasm")`
|
||||
|
||||
## Workspace Structure
|
||||
|
||||
```
|
||||
brush/
|
||||
├── brush-shell/ # CLI application & main entry point
|
||||
├── brush-interactive/ # Interactive shell (readline, completion)
|
||||
├── brush-core/ # Core shell runtime & builtins
|
||||
├── brush-builtins/ # Shell builtin implementations
|
||||
├── brush-parser/ # AST generation & parsing
|
||||
├── xtask/ # Build automation tasks
|
||||
└── docs/ # Diátaxis-structured documentation
|
||||
```
|
||||
|
||||
**Dependency flow:** brush-shell → brush-interactive → brush-core → brush-parser
|
||||
↘ brush-builtins ↗
|
||||
|
||||
## Build & Validation Commands
|
||||
|
||||
### Terminal Command Execution
|
||||
|
||||
When running commands that may take more than a few seconds (cargo build, cargo check, cargo test, cargo clippy, cargo xtask, etc.), **run them in background mode and poll for results** rather than blocking. This prevents commands from being cancelled due to timeouts. Use `isBackground: true` with `run_in_terminal`, then use `get_terminal_output` to check results.
|
||||
|
||||
### Using xtask (Recommended)
|
||||
|
||||
The project provides a `cargo xtask` command that centralizes common development tasks. This is the recommended approach for running checks and tests.
|
||||
|
||||
#### Quick Development Cycle
|
||||
|
||||
```bash
|
||||
# Run quick inner-loop checks (~7s warm): fmt, build, lint, unit tests
|
||||
cargo xtask ci quick
|
||||
|
||||
# Run full pre-commit checks (~45s warm): quick + deps, schemas, integration tests
|
||||
cargo xtask ci pre-commit
|
||||
|
||||
# Run with --continue-on-error to see all failures at once
|
||||
cargo xtask ci pre-commit -k
|
||||
|
||||
# Add -v for verbose output showing exact commands being run
|
||||
cargo xtask -v ci pre-commit
|
||||
```
|
||||
|
||||
#### Individual Checks
|
||||
|
||||
```bash
|
||||
# Format check
|
||||
cargo xtask check fmt
|
||||
|
||||
# Lint check (clippy)
|
||||
cargo xtask check lint
|
||||
|
||||
# Dependency check (cargo-deny)
|
||||
cargo xtask check deps
|
||||
|
||||
# Build check
|
||||
cargo xtask check build
|
||||
|
||||
# Schema check (regenerates and diffs)
|
||||
cargo xtask check schemas
|
||||
```
|
||||
|
||||
#### Running Tests
|
||||
|
||||
```bash
|
||||
# Run unit tests (fast tests excluding integration binaries)
|
||||
cargo xtask test unit
|
||||
|
||||
# Run integration tests (all workspace tests including compat tests)
|
||||
cargo xtask test integration
|
||||
|
||||
# Run tests with coverage
|
||||
cargo xtask test integration --coverage --coverage-output codecov.xml
|
||||
```
|
||||
|
||||
### Manual Approach (Alternate)
|
||||
|
||||
For finer-grained control or when xtask isn't available:
|
||||
|
||||
#### Quick Development Cycle (Use These Frequently)
|
||||
|
||||
```bash
|
||||
# Fast syntax/type checking (< 5 seconds)
|
||||
cargo check --workspace
|
||||
|
||||
# Package-specific checking (even faster)
|
||||
cargo check --package brush-core
|
||||
|
||||
# Format code (ALWAYS run before committing)
|
||||
cargo fmt --all
|
||||
|
||||
# Lint code (ALWAYS run before committing)
|
||||
cargo clippy --workspace --all-features --all-targets
|
||||
|
||||
# Run package-specific tests (fast iteration)
|
||||
cargo test --package brush-parser
|
||||
cargo test --package brush-core
|
||||
```
|
||||
|
||||
**Note:** `cargo fmt --check` may show warnings about unstable rustfmt features (`wrap_comments`, `comment_width`) on stable Rust. These are harmless and expected.
|
||||
|
||||
### Comprehensive Testing Workflow
|
||||
|
||||
Follow this **exact order** for efficient testing:
|
||||
|
||||
1. **Inner loop** (during development):
|
||||
```bash
|
||||
cargo check --package <changed-package>
|
||||
cargo test --package <changed-package>
|
||||
```
|
||||
|
||||
2. **Compatibility tests** (critical for shell behavior):
|
||||
```bash
|
||||
cargo test --test brush-compat-tests
|
||||
|
||||
# Run specific test case:
|
||||
cargo test --test brush-compat-tests -- 'builtin/echo'
|
||||
```
|
||||
|
||||
3. **Full workspace tests** (before considering work complete):
|
||||
```bash
|
||||
cargo test --workspace
|
||||
```
|
||||
|
||||
**Test timing:** Package tests: 3-20 seconds. Compat tests: ~18 seconds build + test time. Full workspace: several minutes.
|
||||
|
||||
### Pre-Commit Validation (Before Every Commit)
|
||||
|
||||
**Recommended:** Run the xtask pre-commit workflow:
|
||||
|
||||
```bash
|
||||
cargo xtask ci pre-commit
|
||||
```
|
||||
|
||||
**Manual approach:** Run these before every commit:
|
||||
|
||||
```bash
|
||||
cargo fmt --check --all
|
||||
cargo clippy --workspace --all-features --all-targets
|
||||
```
|
||||
|
||||
### Pre-PR Validation (Before Opening Pull Request)
|
||||
|
||||
**Recommended:** Run pre-commit checks which includes full test suite:
|
||||
|
||||
```bash
|
||||
cargo xtask ci pre-commit
|
||||
```
|
||||
|
||||
**Manual approach:** In addition to pre-commit checks, also run:
|
||||
|
||||
```bash
|
||||
cargo test --workspace
|
||||
```
|
||||
|
||||
### Pre-Finish Quality Gates (Run Before Completing Task)
|
||||
|
||||
**Recommended:** Run the xtask pre-commit workflow which covers all essential checks:
|
||||
|
||||
```bash
|
||||
cargo xtask ci pre-commit
|
||||
```
|
||||
|
||||
**Manual approach:**
|
||||
|
||||
```bash
|
||||
cargo test --test brush-compat-tests
|
||||
cargo deny check all # License/security audit (run LAST, not frequently)
|
||||
cargo clippy --workspace --all-features --all-targets
|
||||
cargo fmt --check --all
|
||||
cargo test --workspace
|
||||
```
|
||||
|
||||
**Timing note:** `cargo deny check all` takes ~1-5 seconds. Only run as final validation step.
|
||||
|
||||
### Build Variants
|
||||
|
||||
```bash
|
||||
# Standard debug build
|
||||
cargo build
|
||||
|
||||
# Release build (takes ~2+ minutes, avoid during iteration)
|
||||
cargo build --release
|
||||
|
||||
# Check all targets and features
|
||||
cargo check --all-features --all-targets
|
||||
```
|
||||
|
||||
## Testing Philosophy
|
||||
|
||||
**Test-driven approach:** When fixing bugs or adding features, write test cases in `brush-shell/tests/cases/*.yaml` BEFORE implementation. Use these to validate your changes.
|
||||
|
||||
**Integration test structure:** Tests are YAML-based, run shell commands, compare stdout/stderr/exit codes against bash oracle. See `docs/reference/integration-testing.md` and AGENTS.md section 2 for detailed testing strategy.
|
||||
|
||||
**Test categories:**
|
||||
- Unit tests: In-file with `#[cfg(test)]`
|
||||
- Integration tests: `brush-shell/tests/` directory
|
||||
- Compatibility tests: YAML cases in `brush-shell/tests/cases/`
|
||||
- Benchmarks: `brush-shell/benches/` and crate-level `benches/`
|
||||
|
||||
## Common Pitfalls & Solutions
|
||||
|
||||
### ❌ Don't Do This
|
||||
- Run full test suite on every change (too slow)
|
||||
- Skip `cargo fmt` and `cargo clippy` before committing
|
||||
- Use `cargo deny check` during development iteration
|
||||
- Clone values unnecessarily (use references)
|
||||
- Add breaking changes to public APIs without highlighting them
|
||||
- Forget to add compat test cases for compatibility fixes
|
||||
|
||||
### ✅ Do This
|
||||
- Target specific packages/tests during development
|
||||
- Run fmt/clippy before every commit
|
||||
- Follow builder pattern for configuration (see `Shell::builder()`)
|
||||
- Keep platform-specific code in `brush-core/src/sys/`
|
||||
- Document all exported APIs with rustdoc
|
||||
- Use `tracing::debug!(target: trace_categories::CATEGORY, "msg")` for logging
|
||||
- Add test cases to `brush-shell/tests/cases/` for compatibility changes
|
||||
|
||||
## Error Handling & Logging
|
||||
|
||||
```rust
|
||||
// Use thiserror for crate-specific errors
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum MyError { ... }
|
||||
|
||||
// Use anyhow ONLY in tests
|
||||
#[cfg(test)]
|
||||
use anyhow::Result;
|
||||
|
||||
// Logging with trace categories
|
||||
use crate::trace_categories;
|
||||
tracing::debug!(target: trace_categories::COMMANDS, "executing: {}", cmd);
|
||||
```
|
||||
|
||||
**Available trace categories:** COMMANDS, COMPLETION, EXPANSION, FUNCTIONS, INPUT, JOBS, PARSE, PATTERN, UNIMPLEMENTED
|
||||
|
||||
## Linting Configuration
|
||||
|
||||
The project uses **extremely strict** linting (workspace-level in `Cargo.toml`):
|
||||
- All Rust warnings denied
|
||||
- All clippy warnings denied (pedantic, cargo, nursery, perf)
|
||||
- `expect_used`, `panic`, `todo`, `unwrap_in_result` are **forbidden**
|
||||
- Missing docs on exported items are errors
|
||||
|
||||
**Your code MUST pass `cargo clippy` without warnings.**
|
||||
|
||||
## Cross-Platform Considerations
|
||||
|
||||
- Primary targets: Linux (x86_64, aarch64), macOS (aarch64)
|
||||
- Secondary: Windows (x86_64), WASM (wasm32-unknown-unknown, wasm32-wasip2)
|
||||
- Platform-specific code goes in `brush-core/src/sys/` modules
|
||||
- Use `cfg(unix)`, `cfg(windows)`, `cfg(target_family = "wasm")` appropriately
|
||||
- See `.cargo/config.toml` for target-specific configurations
|
||||
|
||||
## CI Pipeline (What Will Run on Your PR)
|
||||
|
||||
GitHub Actions runs these checks (from `.github/workflows/ci.yaml`):
|
||||
|
||||
1. **Build** on multiple platforms (x86_64/aarch64 Linux, macOS, Windows, WASM)
|
||||
2. **Tests** on Linux x86_64, Linux aarch64, macOS
|
||||
3. **Static checks** (format, clippy, cargo-deny) on stable + MSRV (1.88.0)
|
||||
4. **Compatibility tests** with bash as oracle
|
||||
5. **Code coverage** reports (70% overall threshold, no 5% negative delta)
|
||||
6. **External test suites** (bash-completion test suite)
|
||||
7. **OS compatibility** (Arch, Debian, Fedora, NixOS, openSUSE)
|
||||
8. **Benchmarks** (performance regression detection on PRs)
|
||||
9. **Public API analysis** (breaking change detection)
|
||||
|
||||
**All of these must pass for PR to merge.**
|
||||
|
||||
## Making Changes
|
||||
|
||||
### Editing Core Shell Behavior
|
||||
1. Check `brush-core/src/shell.rs` for `Shell` struct
|
||||
2. Use `Shell::builder()` for construction
|
||||
3. Update `brush-shell/src/main.rs` if CLI changes needed
|
||||
|
||||
### Adding/Modifying Builtins
|
||||
1. Edit files in `brush-builtins/src/`
|
||||
2. Register in `brush-builtins/src/factory.rs`
|
||||
3. Add test cases in `brush-shell/tests/cases/builtin/`
|
||||
|
||||
### Parser Changes
|
||||
1. Modify `brush-parser/src/`
|
||||
2. Update AST definitions
|
||||
3. Test with `cargo test --package brush-parser`
|
||||
|
||||
### Breaking Changes Policy
|
||||
- Avoid breaking public APIs (all crate exports are public)
|
||||
- If unavoidable, highlight clearly and document thoroughly
|
||||
- New optional fields on public structs are OK if struct implements `Default`
|
||||
- See AGENTS.md section 3 for complete breaking change policy
|
||||
|
||||
## Performance & Benchmarking
|
||||
|
||||
```bash
|
||||
# Run benchmarks (using xtask)
|
||||
cargo xtask analyze bench
|
||||
|
||||
# Run benchmarks with output file
|
||||
cargo xtask analyze bench --output benchmarks.txt
|
||||
|
||||
# Run benchmarks (manual)
|
||||
cargo bench --workspace --benches
|
||||
|
||||
# Collect flamegraphs (10 second profiling)
|
||||
cargo bench --workspace --benches -- --profile-time 10
|
||||
# Output: target/criterion/<benchmark_name>/profile/*.svg
|
||||
```
|
||||
|
||||
**Note:** Performance regression testing runs automatically on PRs. Don't worry about it unless working on performance-specific features.
|
||||
|
||||
## Documentation Standards
|
||||
|
||||
**Rustdoc:** REQUIRED for all exported types, functions, traits, modules. Missing docs = CI failure.
|
||||
**Examples:** Only needed for major feature additions.
|
||||
**Style:** Follow Rust documentation best practices.
|
||||
|
||||
## Commit Messages
|
||||
|
||||
Use [Conventional Commits](https://www.conventionalcommits.org/):
|
||||
```
|
||||
feat: add support for X
|
||||
fix: correct behavior of Y
|
||||
docs: update Z documentation
|
||||
test: add test cases for W
|
||||
```
|
||||
|
||||
## AI-Assisted Contributions
|
||||
|
||||
If using AI assistance significantly, add to PR description or commit message:
|
||||
```
|
||||
Assisted-by: GitHub Copilot
|
||||
```
|
||||
|
||||
## When Something Fails
|
||||
|
||||
1. **Test failures:** Focus on affected area first, check if new tests are needed
|
||||
2. **Format/clippy failures:** Fix immediately before proceeding
|
||||
3. **Compat test failures:** Indicates shell behavior change, may need test updates
|
||||
4. **Build failures:** Check dependencies, verify Rust version (1.88.0+)
|
||||
5. **Timeout issues:** Build from scratch can take 2+ minutes
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Command | When | Time |
|
||||
|---------|------|------|
|
||||
| `cargo xtask ci quick` | Rapid iteration (inner loop) | ~7s |
|
||||
| `cargo xtask ci pre-commit` | Before commit (comprehensive) | ~45s |
|
||||
| `cargo xtask ci pre-commit -k` | See all failures at once | ~45s |
|
||||
| `cargo check` | Constantly during dev | ~3-5s |
|
||||
| `cargo test --package X` | After each change | 3-20s |
|
||||
| `cargo xtask test unit` | Fast unit tests | ~4.5s |
|
||||
| `cargo xtask test integration` | All workspace tests | ~36s |
|
||||
| `cargo xtask check fmt` | Before every commit | <1s |
|
||||
| `cargo xtask check lint` | Before commit | ~5-10s |
|
||||
| `cargo xtask check deps` | Final validation only | ~1-5s |
|
||||
|
||||
## Trust These Instructions
|
||||
|
||||
Only search the codebase if information here or in AGENTS.md is incomplete, contradictory, or proven incorrect. These instructions are validated against the actual working repository.
|
||||
@@ -0,0 +1,23 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
cooldown:
|
||||
default-days: 7
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
groups:
|
||||
github-actions:
|
||||
patterns:
|
||||
- "*"
|
||||
|
||||
- package-ecosystem: "cargo"
|
||||
cooldown:
|
||||
default-days: 7
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
groups:
|
||||
cargo:
|
||||
patterns:
|
||||
- "*"
|
||||
@@ -0,0 +1,203 @@
|
||||
#
|
||||
# Based on https://github.com/release-plz/release-plz/blob/a5043c478d46d051c00e4fbc85036ac22510f07e/.github/workflows/cd.yml
|
||||
#
|
||||
|
||||
name: CD # Continuous Deployment
|
||||
run-name: CD${{ github.event_name == 'release' && ' (release)' || ' (dry run)' }}
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
# Manual triggers don't actually publish but dry-run the builds.
|
||||
workflow_dispatch: null
|
||||
|
||||
# Run on PR in dry-run mode to make sure this workflow is still generally
|
||||
# working.
|
||||
pull_request:
|
||||
branches: ["main"]
|
||||
|
||||
# Run on pushes into `main` as a way to have "nightly"-ish binaries.
|
||||
push:
|
||||
branches: ["main"]
|
||||
|
||||
# Only allow one run of the workflow per branch / PR at a time.
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
CARGO_INCREMENTAL: 0
|
||||
CARGO_NET_GIT_FETCH_WITH_CLI: true
|
||||
CARGO_NET_RETRY: 10
|
||||
CARGO_TERM_COLOR: always
|
||||
RUST_BACKTRACE: 1
|
||||
RUSTFLAGS: -D warnings
|
||||
RUSTUP_MAX_RETRIES: 10
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
upload-docs:
|
||||
name: "Generate and upload documentation"
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
id-token: write
|
||||
attestations: write
|
||||
|
||||
if: github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request' || github.event_name == 'push' || (github.event_name == 'release' && github.repository_owner == 'reubeno' && startsWith(github.event.release.tag_name, 'brush-shell-v'))
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 30
|
||||
|
||||
steps:
|
||||
- name: "Checkout repository"
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: "Install Rust toolchain"
|
||||
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # v1
|
||||
with:
|
||||
toolchain: stable
|
||||
|
||||
- name: "Enable cargo cache"
|
||||
uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
|
||||
|
||||
- name: "Generate documentation distribution"
|
||||
run: cargo xtask gen docs dist --out brush-docs.tar.gz
|
||||
|
||||
- name: "Upload documentation to release"
|
||||
if: github.event_name == 'release'
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GITHUB_RELEASE_TAG: ${{ github.event.release.tag_name }}
|
||||
run: |
|
||||
gh release upload ${GITHUB_RELEASE_TAG} \
|
||||
brush-docs.tar.gz \
|
||||
brush-docs.tar.gz.sha256 \
|
||||
brush-docs.tar.gz.sha512
|
||||
|
||||
- name: "Generate artifact attestation"
|
||||
if: github.event_name == 'release'
|
||||
uses: actions/attest-build-provenance@0f67c3f4856b2e3261c31976d6725780e5e4c373 # v4.1.1
|
||||
with:
|
||||
subject-path: "brush-docs.tar.gz*"
|
||||
|
||||
- name: "Upload documentation artifact (dry-run)"
|
||||
if: github.event_name != 'release'
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: brush-docs
|
||||
path: |
|
||||
brush-docs.tar.gz
|
||||
brush-docs.tar.gz.sha256
|
||||
brush-docs.tar.gz.sha512
|
||||
|
||||
upload-assets:
|
||||
name: ${{ matrix.target }}
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
id-token: write
|
||||
attestations: write
|
||||
|
||||
if: github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request' || github.event_name == 'push' || (github.event_name == 'release' && github.repository_owner == 'reubeno' && startsWith(github.event.release.tag_name, 'brush-shell-v'))
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
# Run all jobs to completion regardless of errors.
|
||||
# This is useful because sometimes we fail to compile for a certain target.
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- target: aarch64-pc-windows-msvc
|
||||
os: windows-2025
|
||||
force_dry_run: true
|
||||
- target: x86_64-unknown-linux-gnu
|
||||
os: ubuntu-22.04
|
||||
force_dry_run: false
|
||||
- target: x86_64-apple-darwin
|
||||
os: macos-15-intel
|
||||
force_dry_run: false
|
||||
- target: x86_64-pc-windows-msvc
|
||||
os: windows-2025
|
||||
force_dry_run: true
|
||||
- target: x86_64-unknown-linux-musl
|
||||
os: ubuntu-22.04
|
||||
force_dry_run: false
|
||||
- target: aarch64-unknown-linux-gnu
|
||||
os: ubuntu-22.04
|
||||
force_dry_run: false
|
||||
- target: aarch64-unknown-linux-musl
|
||||
os: ubuntu-22.04
|
||||
force_dry_run: false
|
||||
- target: aarch64-apple-darwin
|
||||
os: macos-14
|
||||
force_dry_run: false
|
||||
timeout-minutes: 60
|
||||
|
||||
steps:
|
||||
- name: "Checkout repository"
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: "Install Rust toolchain"
|
||||
uses: actions-rust-lang/setup-rust-toolchain@166cdcfd11aee3cb47222f9ddb555ce30ddb9659 # v1.17.0
|
||||
|
||||
- name: "Setup cross-compiling toolchain"
|
||||
if: startsWith(matrix.os, 'ubuntu') && !contains(matrix.target, '-musl')
|
||||
uses: taiki-e/setup-cross-toolchain-action@3d9770ce98eb7dbcf378563182a5e8031165f75b # v1.41.0
|
||||
with:
|
||||
target: ${{ matrix.target }}
|
||||
|
||||
- name: "Install musl cross tools"
|
||||
if: contains(matrix.target, '-musl')
|
||||
uses: taiki-e/install-action@43aecc8d72668fbcfe75c31400bc4f890f1c5853 # v2.83.2
|
||||
with:
|
||||
tool: cross
|
||||
|
||||
- name: "Workaround: clean cache"
|
||||
run: cargo clean
|
||||
|
||||
- name: "Install cargo-about"
|
||||
run: cargo install cargo-about --locked --features cli
|
||||
|
||||
- name: "Generate license notices"
|
||||
working-directory: brush-shell
|
||||
run: cargo about generate -o ../THIRD_PARTY_LICENSES.html about.hbs
|
||||
|
||||
- name: "Update build flags"
|
||||
if: endsWith(matrix.target, 'windows-msvc')
|
||||
run: echo "RUSTFLAGS=${RUSTFLAGS} -C target-feature=+crt-static" >> "${GITHUB_ENV}"
|
||||
|
||||
- name: "Build and upload binaries to release"
|
||||
uses: taiki-e/upload-rust-binary-action@f0d45ae91ee7b8ee928de7a9d04d893a08bcbec6 # v1.30.2
|
||||
id: upload-release
|
||||
with:
|
||||
dry-run: ${{ github.event_name != 'release' || matrix.force_dry_run }}
|
||||
bin: brush
|
||||
locked: true
|
||||
target: ${{ matrix.target }}
|
||||
tar: unix
|
||||
zip: windows
|
||||
checksum: sha256,sha512
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
include: "LICENSE,THIRD_PARTY_LICENSES.html"
|
||||
|
||||
- name: "Generate artifact attestation"
|
||||
if: github.event_name == 'release' && !matrix.force_dry_run
|
||||
uses: actions/attest-build-provenance@0f67c3f4856b2e3261c31976d6725780e5e4c373 # v4.1.1
|
||||
with:
|
||||
subject-path: "${{ steps.upload-release.outputs.archive }}.*"
|
||||
|
||||
- name: "Upload artifacts (dry-run)"
|
||||
if: github.event_name != 'release' || matrix.force_dry_run
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: brush-${{ matrix.target }}
|
||||
path: "${{ steps.upload-release.outputs.archive }}.*"
|
||||
@@ -0,0 +1,138 @@
|
||||
name: "PR Reports"
|
||||
on:
|
||||
# We intentionally run this workflow in the context of the target of a PR; we are careful
|
||||
# an intentional about how we handle the data coming from the PR.
|
||||
workflow_run: # zizmor: ignore[dangerous-triggers]
|
||||
workflows: ["CI"]
|
||||
types:
|
||||
- completed
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
report:
|
||||
name: "Report"
|
||||
|
||||
permissions:
|
||||
actions: read
|
||||
checks: write
|
||||
contents: read
|
||||
pull-requests: write
|
||||
|
||||
runs-on: ubuntu-24.04
|
||||
|
||||
# We only run this job if the workflow run that completed was triggered by a pull request.
|
||||
if: github.event.workflow_run.event == 'pull_request'
|
||||
|
||||
steps:
|
||||
- name: Extract PR number and create event file
|
||||
id: get-pr
|
||||
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
const fs = require('fs');
|
||||
|
||||
// Find the workflow run that triggered this job.
|
||||
const workflowRun = await github.rest.actions.getWorkflowRun({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
run_id: context.payload.workflow_run.id,
|
||||
});
|
||||
|
||||
// Extract the source commit info.
|
||||
const { head_branch, head_sha, head_repository } = workflowRun.data;
|
||||
const head_repo_owner = head_repository.owner.login;
|
||||
core.setOutput('head_branch', head_branch);
|
||||
core.setOutput('head_sha', head_sha);
|
||||
core.setOutput('head_repo', head_repository.full_name);
|
||||
|
||||
// Try to find all PRs from that source.
|
||||
const { data: prs } = await github.rest.pulls.list({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
state: 'open',
|
||||
head: `${head_repo_owner}:${head_branch}`,
|
||||
per_page: 20
|
||||
});
|
||||
|
||||
// Filter PRs to find the one that targets the main branch.
|
||||
// NOTE: This only supports a target branch of 'main'.
|
||||
const filtered_prs = prs.filter(pr => pr.base.ref === 'main');
|
||||
|
||||
if (filtered_prs.length > 0) {
|
||||
const pr = filtered_prs[0];
|
||||
core.setOutput('pr_number', pr.number);
|
||||
|
||||
// Write out a mostly-stubbed event file.
|
||||
const eventData = {
|
||||
pull_request: {
|
||||
head: {
|
||||
sha: head_sha,
|
||||
repo: {
|
||||
full_name: head_repository.full_name
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
fs.writeFileSync('event-file.json', JSON.stringify(eventData), 'utf-8');
|
||||
} else {
|
||||
core.setOutput('pr_number', '');
|
||||
}
|
||||
|
||||
- name: Download code coverage reports
|
||||
if: steps.get-pr.outputs.pr_number != ''
|
||||
continue-on-error: true
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
pattern: codecov-reports*
|
||||
merge-multiple: true
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
run-id: ${{ github.event.workflow_run.id }}
|
||||
path: reports/
|
||||
|
||||
- name: Download performance reports
|
||||
if: steps.get-pr.outputs.pr_number != ''
|
||||
continue-on-error: true
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
pattern: perf-reports*
|
||||
merge-multiple: true
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
run-id: ${{ github.event.workflow_run.id }}
|
||||
path: reports/
|
||||
|
||||
- name: Download test results
|
||||
if: steps.get-pr.outputs.pr_number != ''
|
||||
continue-on-error: true
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
pattern: test-reports*
|
||||
merge-multiple: true
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
run-id: ${{ github.event.workflow_run.id }}
|
||||
path: reports/
|
||||
|
||||
- name: Show published reports
|
||||
continue-on-error: true
|
||||
if: steps.get-pr.outputs.pr_number != ''
|
||||
run: |
|
||||
ls -lR reports/
|
||||
|
||||
- name: "Publish test results"
|
||||
uses: EnricoMi/publish-unit-test-result-action@d0a4676d0e0b938bc201470d88276b7c74c712b3 # v2.24.0
|
||||
if: steps.get-pr.outputs.pr_number != ''
|
||||
continue-on-error: true
|
||||
with:
|
||||
commit: ${{ github.event.workflow_run.head_sha }}
|
||||
event_file: event-file.json
|
||||
event_name: ${{ github.event.workflow_run.event }}
|
||||
files: reports/test-results-*.xml
|
||||
|
||||
- name: "Publish available .md reports to PR"
|
||||
uses: marocchino/sticky-pull-request-comment@5770ad5eb8f42dd2c4f34da00c94c5381e49af88 # v3.0.5
|
||||
if: steps.get-pr.outputs.pr_number != ''
|
||||
with:
|
||||
path: reports/*.md
|
||||
number: ${{ steps.get-pr.outputs.pr_number }}
|
||||
@@ -0,0 +1,764 @@
|
||||
name: "CI"
|
||||
on:
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- "release-plz.toml"
|
||||
push:
|
||||
paths-ignore:
|
||||
- "docs/**"
|
||||
- "**.md"
|
||||
- "LICENSE"
|
||||
- "release-plz.toml"
|
||||
branches:
|
||||
- main
|
||||
|
||||
env:
|
||||
RUST_BACKTRACE: 1
|
||||
CARGO_TERM_COLOR: always
|
||||
CLICOLOR: 1
|
||||
CLICOLOR_FORCE: 1
|
||||
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
|
||||
# Only allow one run of the workflow per branch / PR at a time.
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
# Build and upload release binaries for all relevant architectures.
|
||||
build:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
# Build for x86_64/linux target on native host.
|
||||
# N.B. We intentionally pin to Ubuntu 22.04 for now to increase
|
||||
# the range of distros that will be able to run the produced binaries.
|
||||
# Newer release of Ubuntu upgrade glibc to a point not yet supported
|
||||
# by some latest stable versions of distros.
|
||||
- host: "ubuntu-22.04"
|
||||
target: ""
|
||||
cross_command: ""
|
||||
cross_tool_to_install: ""
|
||||
os: "linux"
|
||||
arch: "x86_64"
|
||||
binary_name: "brush"
|
||||
extra_build_args: ""
|
||||
# Build for x86_64/linux using musl as target C runtime.
|
||||
# We don't bother pinning to an ealier version of Ubuntu because
|
||||
# the produced binary will statically link the C runtime anyhow.
|
||||
- host: "ubuntu-24.04"
|
||||
target: "x86_64-unknown-linux-musl"
|
||||
cross_command: "cross"
|
||||
cross_tool_to_install: "cross"
|
||||
os: "linux-musl"
|
||||
arch: "x86_64"
|
||||
binary_name: "brush"
|
||||
extra_build_args: ""
|
||||
# Build for aarch64/macos target on native host.
|
||||
- host: "macos-latest"
|
||||
target: ""
|
||||
cross_command: ""
|
||||
cross_tool_to_install: ""
|
||||
os: "macos"
|
||||
arch: "aarch64"
|
||||
required_tools: ""
|
||||
binary_name: "brush"
|
||||
extra_build_args: ""
|
||||
# Build for aarch64/linux target on x86_64/Linux host.
|
||||
- host: "ubuntu-24.04"
|
||||
target: "aarch64-unknown-linux-gnu"
|
||||
cross_command: "cross"
|
||||
cross_tool_to_install: "cross"
|
||||
os: "linux"
|
||||
arch: "aarch64"
|
||||
required_tools: "gcc-aarch64-linux-gnu"
|
||||
binary_name: "brush"
|
||||
extra_build_args: ""
|
||||
# Build for wasm32 target on x86_64/linux host.
|
||||
- host: "ubuntu-24.04"
|
||||
target: "wasm32-unknown-unknown"
|
||||
cross_command: "cross"
|
||||
cross_tool_to_install: "cross"
|
||||
os: "unknown"
|
||||
arch: "wasm32"
|
||||
required_tools: ""
|
||||
binary_name: "brush.wasm"
|
||||
extra_build_args: "--no-default-features --features minimal"
|
||||
# Build for WASI-0.2 target on x86_64/linux host.
|
||||
- host: "ubuntu-24.04"
|
||||
target: "wasm32-wasip2"
|
||||
cross_command: "cross"
|
||||
cross_tool_to_install: "cross"
|
||||
os: "wasi-0.2"
|
||||
arch: "wasm32"
|
||||
required_tools: ""
|
||||
binary_name: "brush.wasm"
|
||||
extra_build_args: "--no-default-features --features minimal"
|
||||
# Build for x86_64/windows target on x86_64/linux host.
|
||||
- host: "ubuntu-24.04"
|
||||
target: "x86_64-pc-windows-gnu"
|
||||
cross_command: "cross"
|
||||
cross_tool_to_install: "cross"
|
||||
os: "windows"
|
||||
arch: "x86_64"
|
||||
required_tools: ""
|
||||
binary_name: "brush.exe"
|
||||
extra_build_args: ""
|
||||
# Build for x86_64/android target on x86_64/linux host.
|
||||
- host: "ubuntu-24.04"
|
||||
target: "x86_64-linux-android"
|
||||
cross_command: "cargo ndk"
|
||||
cross_tool_to_install: "cargo-ndk"
|
||||
os: "android"
|
||||
arch: "x86_64"
|
||||
required_tools: ""
|
||||
binary_name: "brush"
|
||||
extra_build_args: ""
|
||||
# x86_64/FreeBSD target on x86_64/linux host, via cross. Compile-check
|
||||
# only (check_only): cross's curated sysroot omits some base-system
|
||||
# libraries (libgeom/libkvm/...) that `sysinfo` links against, so the
|
||||
# final link of a real binary fails. Checking still validates that the
|
||||
# shell compiles for the target; producing a binary is a TODO (would
|
||||
# need a full sysroot with those libraries present).
|
||||
- host: "ubuntu-24.04"
|
||||
target: "x86_64-unknown-freebsd"
|
||||
cross_command: "cross"
|
||||
cross_tool_to_install: "cross"
|
||||
os: "freebsd"
|
||||
arch: "x86_64"
|
||||
required_tools: ""
|
||||
binary_name: "brush"
|
||||
extra_build_args: ""
|
||||
check_only: true
|
||||
# x86_64/NetBSD target on x86_64/linux host, via cross. Compile-check
|
||||
# only for the same reason as FreeBSD above.
|
||||
- host: "ubuntu-24.04"
|
||||
target: "x86_64-unknown-netbsd"
|
||||
cross_command: "cross"
|
||||
cross_tool_to_install: "cross"
|
||||
os: "netbsd"
|
||||
arch: "x86_64"
|
||||
required_tools: ""
|
||||
binary_name: "brush"
|
||||
extra_build_args: ""
|
||||
check_only: true
|
||||
# OpenBSD is tier-3 with no prebuilt std, so even compile-checking it
|
||||
# requires building std from source (-Zbuild-std, hence nightly +
|
||||
# rust-src + no rustup target). panic_abort is built explicitly because
|
||||
# our release profile sets panic = "abort" (plain -Zbuild-std only
|
||||
# builds std + panic_unwind). Compile-check only, like the other BSDs;
|
||||
# check links nothing, so no C cross-compiler/sysroot/linker is needed
|
||||
# (none of the workspace's C-compiling deps are in this default graph).
|
||||
- host: "ubuntu-24.04"
|
||||
target: "x86_64-unknown-openbsd"
|
||||
cross_command: "cargo"
|
||||
cross_tool_to_install: ""
|
||||
os: "openbsd"
|
||||
arch: "x86_64"
|
||||
required_tools: ""
|
||||
binary_name: "brush"
|
||||
extra_build_args: "-Zbuild-std=std,panic_abort"
|
||||
toolchain: "nightly"
|
||||
components: "rust-src"
|
||||
# std is built from source, so there's no prebuilt target to install.
|
||||
skip_rustup_target: true
|
||||
check_only: true
|
||||
|
||||
name: "${{ matrix.check_only && 'Check' || 'Build' }} (${{ matrix.arch }}/${{ matrix.os }})"
|
||||
runs-on: ${{ matrix.host }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up rust toolchain
|
||||
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # v1
|
||||
with:
|
||||
toolchain: ${{ matrix.toolchain || 'stable' }}
|
||||
targets: ${{ !matrix.skip_rustup_target && matrix.target || '' }}
|
||||
components: ${{ matrix.components || '' }}
|
||||
|
||||
- name: Enable cargo cache
|
||||
uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
|
||||
with:
|
||||
key: "${{ matrix.target }}"
|
||||
|
||||
- name: Install additional prerequisite tools
|
||||
if: ${{ matrix.required_tools != '' }}
|
||||
env:
|
||||
REQUIRED_TOOLS: ${{ matrix.required_tools }}
|
||||
run: sudo apt-get update -y && sudo apt-get install -y ${REQUIRED_TOOLS}
|
||||
|
||||
- name: Install cross-compilation toolchain
|
||||
if: ${{ matrix.cross_tool_to_install != '' }}
|
||||
uses: taiki-e/install-action@43aecc8d72668fbcfe75c31400bc4f890f1c5853 # v2.83.2
|
||||
with:
|
||||
tool: ${{ matrix.cross_tool_to_install }}
|
||||
|
||||
- name: "Build (native)"
|
||||
if: ${{ matrix.target == '' }}
|
||||
env:
|
||||
EXTRA_BUILD_ARGS: ${{ matrix.extra_build_args }}
|
||||
run: cargo build --release --all-targets ${EXTRA_BUILD_ARGS}
|
||||
|
||||
- name: "${{ matrix.check_only && 'Check' || 'Build' }} (cross)"
|
||||
if: ${{ matrix.target != '' }}
|
||||
env:
|
||||
CROSS_COMMAND: ${{ matrix.cross_command }}
|
||||
CARGO_SUBCOMMAND: ${{ matrix.check_only && 'check' || 'build' }}
|
||||
TARGET: ${{ matrix.target }}
|
||||
EXTRA_BUILD_ARGS: ${{ matrix.extra_build_args }}
|
||||
CARGO_NDK_PLATFORM: 24
|
||||
run: ${CROSS_COMMAND} ${CARGO_SUBCOMMAND} --release --target=${TARGET} ${EXTRA_BUILD_ARGS}
|
||||
|
||||
- name: "Upload binaries"
|
||||
# check_only targets don't produce a binary to upload.
|
||||
if: ${{ !matrix.check_only }}
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: binaries-${{ matrix.arch }}-${{ matrix.os }}
|
||||
path: target/${{ matrix.target }}/release/${{ matrix.binary_name }}
|
||||
|
||||
- name: "Upload integration test binaries"
|
||||
if: ${{ matrix.target == '' }}
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: integration-tests-${{ matrix.arch }}-${{ matrix.os }}
|
||||
path: |
|
||||
target/${{ matrix.target }}/release/deps/brush_*_tests-*
|
||||
!**/*.d
|
||||
|
||||
# Test functional correctness
|
||||
test:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- host: "ubuntu-24.04"
|
||||
variant: "linux-x86_64"
|
||||
artifact_suffix: "linux-x86_64"
|
||||
name_suffix: "(linux/x86_64)"
|
||||
homebrew_supported: true
|
||||
coverage: true
|
||||
coverage_min_percent: 70
|
||||
|
||||
- host: "ubuntu-24.04-arm"
|
||||
variant: "linux-aarch64"
|
||||
artifact_suffix: "linux-aarch64"
|
||||
name_suffix: "(linux/aarch64)"
|
||||
homebrew_supported: false
|
||||
coverage: true
|
||||
coverage_min_percent: 70
|
||||
|
||||
- host: "macos-latest"
|
||||
variant: "macos"
|
||||
artifact_suffix: "-macos"
|
||||
name_suffix: "(macOS)"
|
||||
homebrew_supported: true
|
||||
coverage: true
|
||||
coverage_min_percent: 70
|
||||
|
||||
- host: "windows-2025"
|
||||
variant: "windows"
|
||||
artifact_suffix: "-windows"
|
||||
name_suffix: "(windows)"
|
||||
homebrew_supported: false
|
||||
coverage: true
|
||||
coverage_min_percent: 20
|
||||
|
||||
- host: "ubuntu-24.04"
|
||||
variant: "wasi"
|
||||
artifact_suffix: "-wasi"
|
||||
name_suffix: "(wasm32/wasi-0.2)"
|
||||
homebrew_supported: false
|
||||
coverage: false
|
||||
extra_rust_targets: "wasm32-wasip2"
|
||||
wasi_runtime: "wasmtime"
|
||||
xtask_test_args: "--wasi"
|
||||
|
||||
name: "Test ${{ matrix.name_suffix }}"
|
||||
runs-on: ${{ matrix.host }}
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up rust toolchain
|
||||
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # v1
|
||||
with:
|
||||
toolchain: stable
|
||||
targets: ${{ matrix.extra_rust_targets || '' }}
|
||||
components: llvm-tools-preview
|
||||
|
||||
- name: Enable cargo cache
|
||||
uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
|
||||
with:
|
||||
# Needed to make sure cargo-deny is correctly cached.
|
||||
cache-all-crates: true
|
||||
|
||||
- name: Install cargo-nextest
|
||||
uses: taiki-e/install-action@43aecc8d72668fbcfe75c31400bc4f890f1c5853 # v2.83.2
|
||||
with:
|
||||
tool: cargo-nextest
|
||||
|
||||
- name: Install cargo-llvm-cov
|
||||
if: ${{ matrix.coverage }}
|
||||
uses: taiki-e/install-action@43aecc8d72668fbcfe75c31400bc4f890f1c5853 # v2.83.2
|
||||
with:
|
||||
tool: cargo-llvm-cov
|
||||
|
||||
- name: Install WASI runtime
|
||||
if: ${{ matrix.wasi_runtime }}
|
||||
uses: taiki-e/install-action@43aecc8d72668fbcfe75c31400bc4f890f1c5853 # v2.83.2
|
||||
with:
|
||||
tool: ${{ matrix.wasi_runtime }}
|
||||
|
||||
- name: Set up Homebrew
|
||||
if: ${{ matrix.homebrew_supported }}
|
||||
id: set-up-homebrew
|
||||
# We ignore the stale-action-refs check because this action does not have any releases or tags.
|
||||
# We're forced to pick a specific commit.
|
||||
uses: Homebrew/actions/setup-homebrew@df4b09108a1de9d6f995fe68f302b3f68bd6d2ef # zizmor: ignore[stale-action-refs]
|
||||
with:
|
||||
stable: true
|
||||
|
||||
- name: "Install recent bash for tests"
|
||||
if: ${{ matrix.homebrew_supported }}
|
||||
run: |
|
||||
set -x
|
||||
|
||||
# Install it
|
||||
brew install bash
|
||||
|
||||
# Find the path
|
||||
BASH_PATH="$(brew --prefix bash)/bin/bash"
|
||||
|
||||
# Log what we're using
|
||||
echo "Using bash from: ${BASH_PATH}"
|
||||
echo "bash version:"
|
||||
${BASH_PATH} --version
|
||||
echo "BASH_PATH=${BASH_PATH}">>$GITHUB_ENV
|
||||
|
||||
- name: "Download recent bash-completion sources for tests"
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
repository: "scop/bash-completion"
|
||||
ref: "2.17.0"
|
||||
path: "bash-completion"
|
||||
|
||||
- name: "Setup bash-completion"
|
||||
run: echo "BASH_COMPLETION_PATH=${GITHUB_WORKSPACE}/bash-completion/bash_completion">>$GITHUB_ENV
|
||||
|
||||
- name: Test
|
||||
env:
|
||||
VARIANT: ${{ matrix.variant }}
|
||||
run: |
|
||||
args="${{ matrix.xtask_test_args || '' }}"
|
||||
args="${args} --results-output ./test-results-${VARIANT}.xml"
|
||||
if [[ "${{ matrix.coverage }}" == "true" ]]; then
|
||||
args="${args} --coverage --coverage-output ./codecov-${VARIANT}.xml"
|
||||
fi
|
||||
cargo xtask test integration ${args}
|
||||
|
||||
- name: "Upload test results"
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
if: always()
|
||||
with:
|
||||
name: test-reports${{ matrix.artifact_suffix }}
|
||||
path: test-results-*.xml
|
||||
|
||||
- name: "Generate code coverage report"
|
||||
uses: clearlyip/code-coverage-report-action@110af9d4ec87b6706f182fd90e3102af9e5203bf # v7.0.0
|
||||
if: ${{ always() && matrix.coverage }}
|
||||
id: "code_coverage_report"
|
||||
with:
|
||||
artifact_download_workflow_names: "CI"
|
||||
artifact_name: coverage-%name%${{ matrix.artifact_suffix }}
|
||||
filename: codecov-${{ matrix.variant }}.xml
|
||||
overall_coverage_fail_threshold: ${{ matrix.coverage_min_percent }}
|
||||
only_list_changed_files: ${{ github.event_name == 'pull_request' }}
|
||||
fail_on_negative_difference: true
|
||||
negative_difference_by: "overall"
|
||||
negative_difference_threshold: 5
|
||||
|
||||
- name: "Upload code coverage report"
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
if: always()
|
||||
with:
|
||||
name: codecov-reports${{ matrix.artifact_suffix }}
|
||||
path: code-coverage-results.md
|
||||
|
||||
# Static analysis of the code.
|
||||
check:
|
||||
name: "Source code checks"
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
# Test latest stable as well as MSRV.
|
||||
rust-version: ["stable", "1.88.0"]
|
||||
# Run checks on Linux, Windows, and macOS.
|
||||
os: ["ubuntu-24.04", "windows-2025", "macos-latest"]
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up rust toolchain (${{ matrix.rust-version }})
|
||||
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # v1
|
||||
with:
|
||||
toolchain: ${{ matrix.rust-version }}
|
||||
components: clippy, rustfmt
|
||||
|
||||
- name: Enable cargo cache
|
||||
uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
|
||||
with:
|
||||
# Needed to make sure cargo-deny is correctly cached.
|
||||
cache-all-crates: true
|
||||
|
||||
- name: Format check
|
||||
run: cargo xtask check fmt
|
||||
|
||||
- name: Check
|
||||
run: cargo xtask check build
|
||||
|
||||
- name: Install cargo-deny
|
||||
if: runner.os == 'Linux'
|
||||
uses: taiki-e/install-action@43aecc8d72668fbcfe75c31400bc4f890f1c5853 # v2.83.2
|
||||
with:
|
||||
tool: cargo-deny
|
||||
|
||||
# NOTE: Only run on Linux. cargo-deny checks (advisories, licenses, bans,
|
||||
# sources) are platform-independent, so running on one OS is sufficient.
|
||||
# Also works around a cargo-deny 0.19.x bug where its advisory DB parser
|
||||
# panics on Windows due to CRLF line endings (hardcoded LF-only matching).
|
||||
- name: Deny check
|
||||
if: runner.os == 'Linux'
|
||||
run: cargo xtask check deps
|
||||
|
||||
- name: Clippy check
|
||||
if: matrix.rust-version == 'stable'
|
||||
run: cargo xtask check lint
|
||||
|
||||
# Check for unneeded dependencies.
|
||||
check-deps:
|
||||
name: "Check for unneeded dependencies"
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up nightly rust toolchain
|
||||
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # v1
|
||||
with:
|
||||
toolchain: nightly
|
||||
|
||||
- name: Install cargo-udeps
|
||||
uses: taiki-e/install-action@43aecc8d72668fbcfe75c31400bc4f890f1c5853 # v2.83.2
|
||||
with:
|
||||
tool: cargo-udeps
|
||||
|
||||
- name: Check for unused dependencies
|
||||
run: cargo xtask check unused-deps
|
||||
|
||||
# Check that generated schemas are up-to-date
|
||||
check-schemas:
|
||||
name: "Check generated schemas"
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up rust toolchain
|
||||
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # v1
|
||||
with:
|
||||
toolchain: stable
|
||||
|
||||
- name: Enable cargo cache
|
||||
uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
|
||||
|
||||
- name: Check generated schemas
|
||||
run: cargo xtask check schemas
|
||||
|
||||
# Analyze public API surface
|
||||
analyze-public-api:
|
||||
if: github.event_name == 'pull_request'
|
||||
name: "Analyze public API"
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up nightly rust toolchain
|
||||
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # v1
|
||||
with:
|
||||
toolchain: nightly
|
||||
|
||||
- name: Install cargo-public-api
|
||||
uses: taiki-e/install-action@43aecc8d72668fbcfe75c31400bc4f890f1c5853 # v2.83.2
|
||||
with:
|
||||
tool: cargo-public-api
|
||||
|
||||
- name: Set up branches
|
||||
run: |
|
||||
set -euo pipefail
|
||||
git fetch origin main
|
||||
|
||||
- name: Compare public APIs with main
|
||||
run: cargo xtask analyze public-api --base origin/main --output-dir reports
|
||||
|
||||
- name: Upload test report
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: test-reports-public-api
|
||||
path: reports/*.md
|
||||
|
||||
# Performance analysis of the code.
|
||||
benchmark:
|
||||
if: github.event_name == 'pull_request'
|
||||
name: "Benchmarks"
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Checkout PR sources
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
path: pr
|
||||
|
||||
- name: Checkout main sources
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
path: main
|
||||
ref: main
|
||||
|
||||
- name: Set up rust toolchain
|
||||
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # v1
|
||||
with:
|
||||
toolchain: stable
|
||||
|
||||
- name: Enable cargo cache
|
||||
uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
|
||||
with:
|
||||
workspaces: |
|
||||
./pr
|
||||
./main
|
||||
|
||||
- name: Performance analysis on PR
|
||||
run: cargo xtask analyze bench --output benchmarks.txt
|
||||
working-directory: pr
|
||||
|
||||
- name: Performance analysis on main
|
||||
run: cargo bench --workspace --benches -- --output-format bencher | tee benchmarks.txt
|
||||
working-directory: main
|
||||
|
||||
- name: Compare benchmark results
|
||||
run: |
|
||||
./pr/scripts/compare-benchmark-results.py -b main/benchmarks.txt -t pr/benchmarks.txt >benchmark-results.md
|
||||
|
||||
- name: Upload performance results
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: perf-reports
|
||||
path: |
|
||||
pr/benchmarks.txt
|
||||
main/benchmarks.txt
|
||||
benchmark-results.md
|
||||
|
||||
# Run bash-completion test suite
|
||||
bash-completion-tests:
|
||||
name: "External tests / bash-completion test suite"
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
steps:
|
||||
- name: Checkout brush
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
path: "brush"
|
||||
|
||||
- name: Checkout bash-completion
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
repository: "scop/bash-completion"
|
||||
ref: "2.16.0"
|
||||
path: "bash-completion"
|
||||
|
||||
- name: Download prebuilt brush binaries
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
name: "binaries-x86_64-linux"
|
||||
path: "binaries"
|
||||
|
||||
- name: Setup downloads
|
||||
run: |
|
||||
chmod +x binaries/*
|
||||
ls -l binaries
|
||||
|
||||
- name: Install prerequisites for running tests
|
||||
run: |
|
||||
set -x
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y python3
|
||||
python3 -m pip install --user pytest pytest-xdist pytest-md-report pytest-json-report
|
||||
|
||||
- name: "Run test suite (brush)"
|
||||
working-directory: brush
|
||||
run: |
|
||||
cargo xtask test \
|
||||
--brush-path $GITHUB_WORKSPACE/binaries/brush \
|
||||
external bash-completion \
|
||||
--bash-completion-path $GITHUB_WORKSPACE/bash-completion \
|
||||
--output $GITHUB_WORKSPACE/test-results-bash-completion.json \
|
||||
--summary-output $GITHUB_WORKSPACE/test-results-bash-completion.md || true
|
||||
|
||||
- name: Upload test report
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: test-reports-bash-completion
|
||||
path: |
|
||||
test-results-bash-completion.md
|
||||
|
||||
# Test release binary on a variety of OS platforms.
|
||||
os-tests:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
# N.B. We don't include Ubuntu because it's already covered by the initial test job.
|
||||
- container: "archlinux:latest"
|
||||
description: "Arch Linux/latest"
|
||||
prereqs_command: "pacman -Sy --noconfirm bash-completion iputils grep less sed util-linux which"
|
||||
|
||||
- container: "mcr.microsoft.com/azurelinux-beta/base/core:4.0"
|
||||
description: "Azure Linux/4.0"
|
||||
prereqs_command: "dnf install -y bash-completion ca-certificates git iputils grep less sed util-linux which"
|
||||
|
||||
- container: "debian:testing"
|
||||
description: "Debian/testing"
|
||||
prereqs_command: "apt-get update -y && apt-get install -y bash-completion bsdmainutils iputils-ping grep less sed which"
|
||||
|
||||
- container: "fedora:latest"
|
||||
description: "Fedora/latest"
|
||||
prereqs_command: "dnf install -y bash-completion iputils grep less sed util-linux which"
|
||||
|
||||
- container: "nixos/nix:latest"
|
||||
description: "NixOS/latest"
|
||||
prereqs_command: "nix --extra-experimental-features nix-command --extra-experimental-features flakes profile install nixpkgs#gnused nixpkgs#hexdump nixpkgs#bash-completion"
|
||||
|
||||
# NOTE: We use Tumbleweed to make sure we get a recent enough version of bash.
|
||||
- container: "opensuse/tumbleweed:latest"
|
||||
description: "openSUSE Tumbleweed/latest"
|
||||
prereqs_command: "zypper install -y bash-completion git which"
|
||||
|
||||
name: "OS target tests (${{ matrix.description }})"
|
||||
runs-on: ubuntu-24.04
|
||||
container: ${{ matrix.container }}
|
||||
needs: build
|
||||
env:
|
||||
# Reference: https://github.com/Azure/azure-cli/issues/29835
|
||||
GNUPGHOME: /root/.gnupg
|
||||
steps:
|
||||
# Install prerequisites *first*; may need some of them for checkout itself.
|
||||
- name: Install prerequisites
|
||||
if: ${{ matrix.prereqs_command != '' }}
|
||||
env:
|
||||
PREREQS_COMMAND: ${{ matrix.prereqs_command }}
|
||||
run: bash -c "${PREREQS_COMMAND}"
|
||||
|
||||
# Workaround path issues on NixOS
|
||||
- name: "Apply workarounds: NixOS"
|
||||
if: ${{ matrix.container == 'nixos/nix:latest' }}
|
||||
run: |
|
||||
set -x
|
||||
|
||||
# Allow use of experimental features to avoid nix from complaining.
|
||||
export NIX_CONFIG="extra-experimental-features = nix-command flakes"
|
||||
|
||||
# The nixos/nix image ships no /etc/os-release (unlike a full NixOS install
|
||||
# and every other container we test against). Provide one so the test harness
|
||||
# can identify the OS, which it relies on for tests' `incompatible_os` tags.
|
||||
printf 'NAME=NixOS\nID=nixos\nPRETTY_NAME="NixOS (nix container)"\n' > /etc/os-release
|
||||
|
||||
# Hacks to get the mounted nodejs by github actions work as it's dynamically linked
|
||||
# https://github.com/actions/checkout/issues/334#issuecomment-716068696
|
||||
nix build --no-link --max-jobs 2 --cores 0 'nixpkgs#stdenv.cc.cc.lib' 'nixpkgs#glibc'
|
||||
echo "LD_LIBRARY_PATH=$(nix path-info 'nixpkgs#stdenv.cc.cc.lib')/lib" >> "$GITHUB_ENV"
|
||||
ln -s "$(nix path-info 'nixpkgs#glibc' --recursive | grep glibc | grep -v bin)/lib64" /lib64
|
||||
|
||||
# Provide alternate path for bash-completion
|
||||
echo "BASH_COMPLETION_PATH=$(nix path-info 'nixpkgs#bash-completion')/share/bash-completion/bash_completion">>"$GITHUB_ENV"
|
||||
|
||||
# Forcibly add system paths
|
||||
echo "BRUSH_TEST_PATH_VAR=$PATH">>"$GITHUB_ENV"
|
||||
|
||||
# Checkout sources for YAML-based test cases
|
||||
- name: Checkout
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
path: sources
|
||||
|
||||
- name: Download prebuilt brush binaries
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
name: binaries-x86_64-linux
|
||||
path: binaries
|
||||
|
||||
- name: Download integration test binaries
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
name: integration-tests-x86_64-linux
|
||||
path: binaries
|
||||
|
||||
- name: Setup downloads
|
||||
run: |
|
||||
# N.B. Can't use -o pipefail because it's not supported on Debian.
|
||||
set -eux
|
||||
chmod +x binaries/*
|
||||
ls -l -R sources/brush-shell/tests
|
||||
ls -l binaries
|
||||
|
||||
- name: Run tests
|
||||
shell: bash
|
||||
run: |
|
||||
export BRUSH_PATH=$PWD/binaries/brush
|
||||
export BRUSH_VERBOSE=true
|
||||
|
||||
result=0
|
||||
for test_name in binaries/*tests*; do
|
||||
if [[ ${test_name} == *compat* ]]; then
|
||||
export BRUSH_TEST_CASES=$PWD/sources/brush-shell/tests/cases/compat
|
||||
elif [[ ${test_name} == *integration* ]]; then
|
||||
export BRUSH_TEST_CASES=$PWD/sources/brush-shell/tests/cases/brush
|
||||
elif [[ ${test_name} == *interactive* || ${test_name} == *version* ]]; then
|
||||
# TODO(tests): Re-enable these tests.
|
||||
echo "WARNING: skipping test: ${test_name}"
|
||||
continue
|
||||
fi
|
||||
|
||||
echo "Running test: ${test_name}"
|
||||
chmod +x ${test_name}
|
||||
${test_name} || result=$?
|
||||
done
|
||||
|
||||
exit ${result}
|
||||
@@ -0,0 +1,69 @@
|
||||
name: "CodeQL Advanced"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["main"]
|
||||
pull_request:
|
||||
branches: ["main"]
|
||||
schedule:
|
||||
- cron: "35 1 * * 3"
|
||||
|
||||
permissions: {}
|
||||
|
||||
# Only allow one run of the workflow per branch / PR at a time.
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze (${{ matrix.language }})
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
# required for all workflows
|
||||
security-events: write
|
||||
# required to fetch internal or private CodeQL packs
|
||||
packages: read
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- language: actions
|
||||
build-mode: none
|
||||
- language: python
|
||||
build-mode: none
|
||||
- language: rust
|
||||
build-mode: none
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4.37.0
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
build-mode: ${{ matrix.build-mode }}
|
||||
queries: security-extended,security-and-quality
|
||||
|
||||
# - name: Set up rust toolchain
|
||||
# if: ${{ matrix.language == 'rust' }}
|
||||
# uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # v1
|
||||
# with:
|
||||
# toolchain: stable
|
||||
|
||||
# - name: Enable cargo cache
|
||||
# if: ${{ matrix.language == 'rust' }}
|
||||
# uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
|
||||
|
||||
# - name: Build Rust code
|
||||
# if: ${{ matrix.language == 'rust' }}
|
||||
# run: cargo build --all-targets --all-features
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4.37.0
|
||||
with:
|
||||
category: "/language:${{matrix.language}}"
|
||||
@@ -0,0 +1,72 @@
|
||||
name: "Devcontainer"
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
paths:
|
||||
- ".devcontainer/**"
|
||||
|
||||
permissions: {}
|
||||
|
||||
# Only allow one run of the workflow per branch / PR at a time.
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: "Build devcontainer"
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
contents: read
|
||||
packages: read
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Pre-build dev container image
|
||||
uses: devcontainers/ci@513af61f4de4f75d37e4438f184ba4358f0fc1ca # v0.3.1900000450
|
||||
with:
|
||||
imageName: ghcr.io/reubeno/brush/devcontainer
|
||||
imageTag: latest
|
||||
cacheFrom: ghcr.io/reubeno/brush/devcontainer
|
||||
push: never
|
||||
|
||||
build_and_publish:
|
||||
name: "Build and publish devcontainer"
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Pre-build dev container image
|
||||
uses: devcontainers/ci@513af61f4de4f75d37e4438f184ba4358f0fc1ca # v0.3.1900000450
|
||||
with:
|
||||
imageName: ghcr.io/reubeno/brush/devcontainer
|
||||
imageTag: latest
|
||||
cacheFrom: ghcr.io/reubeno/brush/devcontainer
|
||||
push: filter
|
||||
refFilterForPush: refs/heads/main
|
||||
eventFilterForPush: push
|
||||
@@ -0,0 +1,77 @@
|
||||
name: "Docs"
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
env:
|
||||
RUST_BACKTRACE: 1
|
||||
CARGO_TERM_COLOR: always
|
||||
CLICOLOR: 1
|
||||
CLICOLOR_FORCE: 1
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
# Only allow one run of the workflow per branch / PR at a time.
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
# Check links in docs
|
||||
check-links:
|
||||
name: "Check links"
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Check repo-local links
|
||||
uses: lycheeverse/lychee-action@e7477775783ea5526144ba13e8db5eec57747ce8 # v2.9.0
|
||||
with:
|
||||
args: ". --offline --verbose --no-progress"
|
||||
fail: true
|
||||
|
||||
# Generate docs content
|
||||
generate-docs:
|
||||
name: "Generate usage docs"
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up rust toolchain
|
||||
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # v1
|
||||
with:
|
||||
toolchain: stable
|
||||
|
||||
- name: Enable cargo cache
|
||||
uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
|
||||
|
||||
- name: Create dirs
|
||||
run: mkdir -p ./md ./man
|
||||
|
||||
- name: Build markdown info
|
||||
run: cargo xtask gen docs markdown --out ./md/brush.md
|
||||
|
||||
- name: Upload markdown docs
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: docs-markdown
|
||||
path: md
|
||||
|
||||
- name: Build man pages
|
||||
run: cargo xtask gen docs man --output-dir ./man
|
||||
|
||||
- name: Upload man pages
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: docs-man
|
||||
path: man
|
||||
@@ -0,0 +1,29 @@
|
||||
name: Spelling
|
||||
on: [pull_request]
|
||||
|
||||
env:
|
||||
RUST_BACKTRACE: 1
|
||||
CARGO_TERM_COLOR: always
|
||||
CLICOLOR: 1
|
||||
CLICOLOR_FORCE: 1
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
# Only allow one run of the workflow per branch / PR at a time.
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
spelling:
|
||||
name: spell-check
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout brush
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Spell check repo
|
||||
uses: crate-ci/typos@bee27e3a4fd1ea2111cf90ab89cd076c870fce14 # v1.48.0
|
||||
@@ -0,0 +1,46 @@
|
||||
#
|
||||
# This workflow was based on https://docs.zizmor.sh/usage/#use-in-github-actions
|
||||
#
|
||||
|
||||
name: GitHub Actions Security Analysis with zizmor 🌈
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["main"]
|
||||
pull_request:
|
||||
branches: ["**"]
|
||||
|
||||
permissions: {}
|
||||
|
||||
# Only allow one run of the workflow per branch / PR at a time.
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
zizmor:
|
||||
name: zizmor latest via PyPI
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
security-events: write # needed for SARIF uploads
|
||||
contents: read # only needed for private repos
|
||||
actions: read # only needed for private repos
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Install the latest version of uv
|
||||
uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
|
||||
|
||||
- name: Run zizmor 🌈
|
||||
run: uvx zizmor --format=sarif . > results.sarif
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Upload SARIF file
|
||||
uses: github/codeql-action/upload-sarif@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4.37.0
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
category: zizmor
|
||||
Reference in New Issue
Block a user