gerenuk 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gerenuk-0.1.0/.claude/settings.json +2 -0
- gerenuk-0.1.0/.claude/skills/rust-review/SKILL.md +95 -0
- gerenuk-0.1.0/.github/dependabot.yml +38 -0
- gerenuk-0.1.0/.github/workflows/audit.yml +29 -0
- gerenuk-0.1.0/.github/workflows/cargo-deny.yml +35 -0
- gerenuk-0.1.0/.github/workflows/codeql.yml +42 -0
- gerenuk-0.1.0/.github/workflows/docs.yml +57 -0
- gerenuk-0.1.0/.github/workflows/release.yml +114 -0
- gerenuk-0.1.0/.github/workflows/review.yml +84 -0
- gerenuk-0.1.0/.gitignore +81 -0
- gerenuk-0.1.0/CLAUDE.md +105 -0
- gerenuk-0.1.0/Cargo.lock +817 -0
- gerenuk-0.1.0/Cargo.toml +86 -0
- gerenuk-0.1.0/LICENSE +21 -0
- gerenuk-0.1.0/Makefile +76 -0
- gerenuk-0.1.0/PKG-INFO +161 -0
- gerenuk-0.1.0/README.md +133 -0
- gerenuk-0.1.0/clippy.toml +10 -0
- gerenuk-0.1.0/deny.toml +27 -0
- gerenuk-0.1.0/docs/book.toml +23 -0
- gerenuk-0.1.0/docs/custom.css +260 -0
- gerenuk-0.1.0/docs/dev/ARCHITECTURE.md +103 -0
- gerenuk-0.1.0/docs/gen-version.sh +34 -0
- gerenuk-0.1.0/docs/generate-llms-txt.sh +56 -0
- gerenuk-0.1.0/docs/inject-shared.sh +100 -0
- gerenuk-0.1.0/docs/lint-mermaid.mjs +76 -0
- gerenuk-0.1.0/docs/mermaid-init.js +45 -0
- gerenuk-0.1.0/docs/mermaid.min.js +2609 -0
- gerenuk-0.1.0/docs/package-lock.json +173 -0
- gerenuk-0.1.0/docs/package.json +10 -0
- gerenuk-0.1.0/docs/plans/gerenuk-pitch-phase1-diff-to-symbols.md +180 -0
- gerenuk-0.1.0/docs/plans/phase1-implementation-plan.md +191 -0
- gerenuk-0.1.0/docs/shared/claude-snippet.md +15 -0
- gerenuk-0.1.0/docs/src/SUMMARY.md +11 -0
- gerenuk-0.1.0/docs/src/commands/audit.md +83 -0
- gerenuk-0.1.0/docs/src/commands/changed-symbols.md +168 -0
- gerenuk-0.1.0/docs/src/commands/doctor.md +26 -0
- gerenuk-0.1.0/docs/src/commands/overview.md +35 -0
- gerenuk-0.1.0/docs/src/how-it-works.md +83 -0
- gerenuk-0.1.0/docs/src/index.md +39 -0
- gerenuk-0.1.0/docs/src/setup.md +71 -0
- gerenuk-0.1.0/docs/src/troubleshooting.md +74 -0
- gerenuk-0.1.0/docs/theme/head.hbs +3 -0
- gerenuk-0.1.0/docs/version.js +24 -0
- gerenuk-0.1.0/prek.toml +38 -0
- gerenuk-0.1.0/pyproject.toml +44 -0
- gerenuk-0.1.0/release.toml +25 -0
- gerenuk-0.1.0/rust-toolchain.toml +3 -0
- gerenuk-0.1.0/rustfmt.toml +3 -0
- gerenuk-0.1.0/src/analyze.rs +367 -0
- gerenuk-0.1.0/src/changed.rs +1176 -0
- gerenuk-0.1.0/src/cli.rs +300 -0
- gerenuk-0.1.0/src/config.rs +192 -0
- gerenuk-0.1.0/src/diff.rs +432 -0
- gerenuk-0.1.0/src/git.rs +447 -0
- gerenuk-0.1.0/src/lib.rs +26 -0
- gerenuk-0.1.0/src/main.rs +42 -0
- gerenuk-0.1.0/src/model.rs +310 -0
- gerenuk-0.1.0/src/modpath.rs +207 -0
- gerenuk-0.1.0/src/pysource.rs +462 -0
- gerenuk-0.1.0/src/report.rs +187 -0
- gerenuk-0.1.0/src/tyf.rs +228 -0
- gerenuk-0.1.0/src/workspace.rs +163 -0
- gerenuk-0.1.0/tests/audit.rs +206 -0
- gerenuk-0.1.0/tests/changed_symbols.rs +521 -0
- gerenuk-0.1.0/tests/cli.rs +115 -0
- gerenuk-0.1.0/tests/common/mod.rs +223 -0
- gerenuk-0.1.0/tests/fixtures/sample_pkg/pyproject.toml +16 -0
- gerenuk-0.1.0/tests/fixtures/sample_pkg/sample_pkg/__init__.py +12 -0
- gerenuk-0.1.0/tests/fixtures/sample_pkg/sample_pkg/cli.py +28 -0
- gerenuk-0.1.0/tests/fixtures/sample_pkg/sample_pkg/models.py +38 -0
- gerenuk-0.1.0/tests/fixtures/sample_pkg/sample_pkg/service.py +45 -0
- gerenuk-0.1.0/tests/fixtures/sample_pkg/tests/__init__.py +0 -0
- gerenuk-0.1.0/tests/fixtures/sample_pkg/tests/test_models.py +34 -0
- gerenuk-0.1.0/tests/fixtures/sample_pkg/tests/test_service.py +32 -0
- gerenuk-0.1.0/tests/fixtures/sample_pkg/uv.lock +155 -0
- gerenuk-0.1.0/tests/snapshots/changed_symbols__the_full_json_report_matches_its_snapshot.snap +31 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rust-review
|
|
3
|
+
context: fork
|
|
4
|
+
description: Deep Rust code quality review. Auto-invoke when finishing a task, before marking work complete, when the user asks to review code, or when preparing a PR. Covers error handling, async correctness, duplicated logic, test quality, performance patterns, idiomatic Rust, docs-code alignment, and API design beyond what clippy catches.
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Deep Code Review for gerenuk
|
|
8
|
+
|
|
9
|
+
Perform a thorough code quality review of the changes in this project. Go beyond what clippy and rustfmt catch. Focus on the areas below and report findings grouped by severity: 🔴 Must Fix, 🟡 Should Fix, 🟢 Suggestion.
|
|
10
|
+
|
|
11
|
+
First, run `cargo fmt --all -- --check` and `cargo clippy --all-targets --all-features -- -D warnings` to confirm the automated checks pass. If they don't, fix those first before proceeding with the deep review.
|
|
12
|
+
|
|
13
|
+
## 1. Error Handling Quality
|
|
14
|
+
|
|
15
|
+
- `.unwrap()` outside tests is forbidden. Flag any instance.
|
|
16
|
+
- Check that `.context("message")` is used when propagating errors from external crates with `?` — bare `?` loses context about what operation failed.
|
|
17
|
+
- Flag `Result` return types where the function never actually returns `Err` (remove the wrapper — clippy catches this as `unnecessary_wraps` but double-check).
|
|
18
|
+
- Flag `.map_err(|_| ...)` that silently discards error information.
|
|
19
|
+
- Verify error types are specific enough — no `String` as error type, no `anyhow::Error` leaking into library-style modules.
|
|
20
|
+
- Check that `thiserror` error variants have `#[from]` or manual `From` impls for their sources.
|
|
21
|
+
|
|
22
|
+
## 2. Async / Tokio Correctness
|
|
23
|
+
|
|
24
|
+
- Flag any `MutexGuard` or `RwLockGuard` held across an `.await` point — this can deadlock or prevent `Send` futures.
|
|
25
|
+
- Flag blocking operations (std::fs, std::process::Command, heavy computation) running directly in async context without `spawn_blocking`.
|
|
26
|
+
- Check that spawned tasks (`tokio::spawn`) have their `JoinHandle` either awaited or explicitly dropped with a comment explaining why.
|
|
27
|
+
- Verify `tokio::select!` branches handle cancellation correctly (partially completed work).
|
|
28
|
+
- Check for unbounded channels or queues that could cause memory issues under load.
|
|
29
|
+
|
|
30
|
+
## 3. Duplicated Logic
|
|
31
|
+
|
|
32
|
+
- Search for functions or code blocks that do substantially the same thing with minor variations. Flag them and suggest extraction into a shared function, trait, or generic.
|
|
33
|
+
- Pay special attention to:
|
|
34
|
+
- LSP message construction patterns (likely repeated across commands)
|
|
35
|
+
- Error handling boilerplate that could be a helper
|
|
36
|
+
- Serialization/deserialization patterns
|
|
37
|
+
- Similar match arms across different functions
|
|
38
|
+
- Suggest concrete refactoring: which function to extract, what parameters it should take.
|
|
39
|
+
|
|
40
|
+
## 4. Test Quality
|
|
41
|
+
|
|
42
|
+
- **Tests that don't assert**: Flag any test that just calls code without asserting on the result. Running without panicking is not a test.
|
|
43
|
+
- **Tests that assert too little**: `assert!(result.is_ok())` without checking the value inside is weak. Suggest asserting on the actual content.
|
|
44
|
+
- **Overly verbose tests**: Tests with excessive setup that obscure what's actually being tested. Suggest extracting test helpers or fixtures.
|
|
45
|
+
- **Missing edge cases**: For each public function, check if tests cover: empty input, error paths, boundary conditions.
|
|
46
|
+
- **Test naming**: Test names should describe the behavior being tested, not the implementation (`test_returns_error_on_missing_file` not `test_function_xyz`).
|
|
47
|
+
- **Integration vs unit**: Verify that unit tests (in `#[cfg(test)] mod tests`) test internal logic, while `tests/integration/` tests exercise the public CLI interface.
|
|
48
|
+
- Suggest adding `proptest` for any function that transforms data (roundtrip properties).
|
|
49
|
+
|
|
50
|
+
## 5. Performance Patterns
|
|
51
|
+
|
|
52
|
+
- Flag unnecessary `.clone()` — suggest borrowing or restructuring ownership.
|
|
53
|
+
- Flag `.collect::<Vec<_>>()` immediately followed by `.iter()` — the intermediate collection is usually unnecessary.
|
|
54
|
+
- Prefer `&str` over `String`, `&[T]` over `Vec<T>`, `&Path` over `PathBuf` in function parameters when ownership isn't needed.
|
|
55
|
+
- Flag large structs being passed by value instead of reference.
|
|
56
|
+
- Check for `Arc::clone(&x)` vs `x.clone()` — the former is required by our lint config for clarity.
|
|
57
|
+
- In async code, flag futures that capture large amounts of data across await points.
|
|
58
|
+
|
|
59
|
+
## 6. Idiomatic Rust
|
|
60
|
+
|
|
61
|
+
- Prefer iterator chains over manual `for` loops with `push`.
|
|
62
|
+
- Use `if let` / `let else` instead of `match` with a single interesting arm and a wildcard.
|
|
63
|
+
- Suggest `impl From<X> for Y` instead of standalone conversion functions.
|
|
64
|
+
- Suggest `Display` implementations instead of `to_string()` methods.
|
|
65
|
+
- Flag `&String`, `&Vec<T>`, `&Box<T>` in function signatures — use `&str`, `&[T]`, `&T` instead.
|
|
66
|
+
- Check doc comments on all public types and functions.
|
|
67
|
+
|
|
68
|
+
## 7. Documentation ↔ Code Alignment
|
|
69
|
+
|
|
70
|
+
- **Check that `docs/src/how-it-works.md` still matches the actual architecture.** In particular:
|
|
71
|
+
- Do the diagrams (daemon layers, request lifecycle, client pool flow) reflect the current code paths in `src/daemon/` and `src/lsp/`?
|
|
72
|
+
- Are the RPC method names listed in the "Available RPC methods" table still accurate? Cross-check against the actual enum/dispatch in the daemon server code.
|
|
73
|
+
- Do the described concurrency patterns (single-pipe, batch processing, sequential LSP requests) still hold?
|
|
74
|
+
- Are timeouts, retry counts, and backoff intervals mentioned in prose consistent with the constants in the code?
|
|
75
|
+
- **Check that `docs/src/commands/*.md` describe the current CLI interface.** Compare the documented flags and subcommands against the `clap` definitions in `src/cli/`.
|
|
76
|
+
- **Check that `docs/src/performance.md` benchmarks and claims are not contradicted by recent changes.**
|
|
77
|
+
- Flag any mismatch as 🔴 Must Fix — stale docs are worse than no docs.
|
|
78
|
+
|
|
79
|
+
## 8. API and Module Design
|
|
80
|
+
|
|
81
|
+
- Is `main.rs` thin? It should just parse args and call into library code.
|
|
82
|
+
- Are module boundaries clean? Each module should have a clear responsibility.
|
|
83
|
+
- Check for any `pub` items that don't need to be public.
|
|
84
|
+
- Flag circular dependencies between modules.
|
|
85
|
+
|
|
86
|
+
## Output Format
|
|
87
|
+
|
|
88
|
+
Group all findings by severity, then by area. For each finding:
|
|
89
|
+
- State **what** the issue is and **where** (file:line or function name)
|
|
90
|
+
- Explain **why** it matters
|
|
91
|
+
- Suggest a **concrete fix** (not just "improve this")
|
|
92
|
+
|
|
93
|
+
End with a summary: X must-fix, Y should-fix, Z suggestions.
|
|
94
|
+
|
|
95
|
+
$ARGUMENTS
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
# Rust (Cargo) dependencies
|
|
4
|
+
- package-ecosystem: "cargo"
|
|
5
|
+
directory: "/"
|
|
6
|
+
schedule:
|
|
7
|
+
interval: "weekly"
|
|
8
|
+
day: "monday"
|
|
9
|
+
open-pull-requests-limit: 10
|
|
10
|
+
labels:
|
|
11
|
+
- "dependencies"
|
|
12
|
+
- "rust"
|
|
13
|
+
groups:
|
|
14
|
+
minor-and-patch:
|
|
15
|
+
update-types:
|
|
16
|
+
- "minor"
|
|
17
|
+
- "patch"
|
|
18
|
+
|
|
19
|
+
# GitHub Actions
|
|
20
|
+
- package-ecosystem: "github-actions"
|
|
21
|
+
directory: "/"
|
|
22
|
+
schedule:
|
|
23
|
+
interval: "weekly"
|
|
24
|
+
labels:
|
|
25
|
+
- "dependencies"
|
|
26
|
+
- "ci"
|
|
27
|
+
|
|
28
|
+
# Python dependencies. `ty-find` is a runtime dependency in pyproject.toml,
|
|
29
|
+
# and it is the project gerenuk drives, so a new release matters here.
|
|
30
|
+
# Weekly is enough — there is no lockfile at the root to keep in step.
|
|
31
|
+
- package-ecosystem: "pip"
|
|
32
|
+
directory: "/"
|
|
33
|
+
schedule:
|
|
34
|
+
interval: "weekly"
|
|
35
|
+
open-pull-requests-limit: 10
|
|
36
|
+
labels:
|
|
37
|
+
- "dependencies"
|
|
38
|
+
- "python"
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
name: "Cargo Audit"
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
paths:
|
|
6
|
+
- "Cargo.toml"
|
|
7
|
+
- "Cargo.lock"
|
|
8
|
+
pull_request:
|
|
9
|
+
paths:
|
|
10
|
+
- "Cargo.toml"
|
|
11
|
+
- "Cargo.lock"
|
|
12
|
+
schedule:
|
|
13
|
+
- cron: "0 0 * * *" # Daily at midnight UTC
|
|
14
|
+
workflow_dispatch:
|
|
15
|
+
|
|
16
|
+
permissions:
|
|
17
|
+
contents: read
|
|
18
|
+
issues: write
|
|
19
|
+
|
|
20
|
+
jobs:
|
|
21
|
+
audit:
|
|
22
|
+
name: Security Audit
|
|
23
|
+
runs-on: ubuntu-latest
|
|
24
|
+
steps:
|
|
25
|
+
- name: Checkout repository
|
|
26
|
+
uses: actions/checkout@v7
|
|
27
|
+
|
|
28
|
+
- name: Run cargo-audit
|
|
29
|
+
uses: actions-rust-lang/audit@v1
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
name: "Cargo Deny"
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: ["main"]
|
|
6
|
+
paths:
|
|
7
|
+
- "Cargo.lock"
|
|
8
|
+
- "Cargo.toml"
|
|
9
|
+
- "deny.toml"
|
|
10
|
+
pull_request:
|
|
11
|
+
paths:
|
|
12
|
+
- "Cargo.lock"
|
|
13
|
+
- "Cargo.toml"
|
|
14
|
+
- "deny.toml"
|
|
15
|
+
|
|
16
|
+
permissions:
|
|
17
|
+
contents: read
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
deny:
|
|
21
|
+
name: ${{ matrix.check }}
|
|
22
|
+
runs-on: ubuntu-latest
|
|
23
|
+
strategy:
|
|
24
|
+
fail-fast: false
|
|
25
|
+
matrix:
|
|
26
|
+
check: [bans, licenses, sources]
|
|
27
|
+
steps:
|
|
28
|
+
- name: Checkout repository
|
|
29
|
+
uses: actions/checkout@v7
|
|
30
|
+
|
|
31
|
+
- name: Run cargo-deny (${{ matrix.check }})
|
|
32
|
+
uses: EmbarkStudios/cargo-deny-action@v2
|
|
33
|
+
with:
|
|
34
|
+
command: check ${{ matrix.check }}
|
|
35
|
+
arguments: --all-features
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
name: "CodeQL"
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: ["main"]
|
|
6
|
+
paths:
|
|
7
|
+
- "src/**"
|
|
8
|
+
- "Cargo.toml"
|
|
9
|
+
- "Cargo.lock"
|
|
10
|
+
pull_request:
|
|
11
|
+
branches: ["main"]
|
|
12
|
+
paths:
|
|
13
|
+
- "src/**"
|
|
14
|
+
- "Cargo.toml"
|
|
15
|
+
- "Cargo.lock"
|
|
16
|
+
schedule:
|
|
17
|
+
- cron: "0 6 * * 1" # Weekly on Monday at 06:00 UTC
|
|
18
|
+
|
|
19
|
+
permissions:
|
|
20
|
+
security-events: write
|
|
21
|
+
packages: read
|
|
22
|
+
actions: read
|
|
23
|
+
contents: read
|
|
24
|
+
|
|
25
|
+
jobs:
|
|
26
|
+
analyze:
|
|
27
|
+
name: Analyze Rust
|
|
28
|
+
runs-on: ubuntu-latest
|
|
29
|
+
steps:
|
|
30
|
+
- name: Checkout repository
|
|
31
|
+
uses: actions/checkout@v7
|
|
32
|
+
|
|
33
|
+
- name: Initialize CodeQL
|
|
34
|
+
uses: github/codeql-action/init@v4
|
|
35
|
+
with:
|
|
36
|
+
languages: rust
|
|
37
|
+
build-mode: none
|
|
38
|
+
|
|
39
|
+
- name: Perform CodeQL Analysis
|
|
40
|
+
uses: github/codeql-action/analyze@v4
|
|
41
|
+
with:
|
|
42
|
+
category: "/language:rust"
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
name: Deploy docs
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
branches: ["main"]
|
|
5
|
+
paths:
|
|
6
|
+
- "docs/**"
|
|
7
|
+
- "src/**" # rebuild when CLI changes (help text may change)
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
pages: write
|
|
12
|
+
id-token: write
|
|
13
|
+
|
|
14
|
+
concurrency:
|
|
15
|
+
group: "pages"
|
|
16
|
+
cancel-in-progress: false
|
|
17
|
+
|
|
18
|
+
jobs:
|
|
19
|
+
deploy:
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
environment:
|
|
22
|
+
name: github-pages
|
|
23
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
|
24
|
+
steps:
|
|
25
|
+
- uses: actions/checkout@v7
|
|
26
|
+
|
|
27
|
+
- uses: actions/setup-node@v6
|
|
28
|
+
with:
|
|
29
|
+
node-version: "22"
|
|
30
|
+
|
|
31
|
+
- name: Lint mermaid diagrams
|
|
32
|
+
run: |
|
|
33
|
+
cd docs && npm ci --silent
|
|
34
|
+
cd .. && node docs/lint-mermaid.mjs
|
|
35
|
+
|
|
36
|
+
- name: Install mdBook and preprocessors
|
|
37
|
+
run: |
|
|
38
|
+
mkdir -p bin
|
|
39
|
+
curl -sSL https://github.com/rust-lang/mdBook/releases/download/v0.5.2/mdbook-v0.5.2-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=bin
|
|
40
|
+
curl -sSL https://github.com/badboy/mdbook-mermaid/releases/download/v0.17.0/mdbook-mermaid-v0.17.0-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=bin
|
|
41
|
+
echo "$PWD/bin" >> $GITHUB_PATH
|
|
42
|
+
|
|
43
|
+
- name: Sync docs version badge with Cargo.toml
|
|
44
|
+
run: bash docs/gen-version.sh
|
|
45
|
+
|
|
46
|
+
- name: Build book
|
|
47
|
+
run: mdbook build docs
|
|
48
|
+
|
|
49
|
+
- name: Generate llms.txt
|
|
50
|
+
run: bash docs/generate-llms-txt.sh
|
|
51
|
+
|
|
52
|
+
- uses: actions/upload-pages-artifact@v5
|
|
53
|
+
with:
|
|
54
|
+
path: docs/book/html
|
|
55
|
+
|
|
56
|
+
- uses: actions/deploy-pages@v5
|
|
57
|
+
id: deployment
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- 'v*'
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: write
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
build-wheels:
|
|
14
|
+
name: Build wheels on ${{ matrix.os }}
|
|
15
|
+
runs-on: ${{ matrix.os }}
|
|
16
|
+
strategy:
|
|
17
|
+
matrix:
|
|
18
|
+
os: [ubuntu-latest, macos-14, windows-latest]
|
|
19
|
+
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v7
|
|
22
|
+
|
|
23
|
+
- name: Build wheels
|
|
24
|
+
uses: PyO3/maturin-action@v1
|
|
25
|
+
with:
|
|
26
|
+
args: --release --strip
|
|
27
|
+
manylinux: 2_28
|
|
28
|
+
|
|
29
|
+
- name: Upload wheels
|
|
30
|
+
uses: actions/upload-artifact@v7
|
|
31
|
+
with:
|
|
32
|
+
name: wheels-${{ matrix.os }}
|
|
33
|
+
path: target/wheels/*.whl
|
|
34
|
+
|
|
35
|
+
build-sdist:
|
|
36
|
+
name: Build source distribution
|
|
37
|
+
runs-on: ubuntu-latest
|
|
38
|
+
steps:
|
|
39
|
+
- uses: actions/checkout@v7
|
|
40
|
+
|
|
41
|
+
- name: Set up Rust
|
|
42
|
+
uses: dtolnay/rust-toolchain@stable
|
|
43
|
+
|
|
44
|
+
- name: Set up Python
|
|
45
|
+
uses: actions/setup-python@v6
|
|
46
|
+
with:
|
|
47
|
+
python-version: '3.11'
|
|
48
|
+
|
|
49
|
+
- name: Install maturin
|
|
50
|
+
run: pip install maturin
|
|
51
|
+
|
|
52
|
+
- name: Build sdist
|
|
53
|
+
run: maturin sdist
|
|
54
|
+
|
|
55
|
+
- name: Upload sdist
|
|
56
|
+
uses: actions/upload-artifact@v7
|
|
57
|
+
with:
|
|
58
|
+
name: sdist
|
|
59
|
+
path: target/wheels/*.tar.gz
|
|
60
|
+
|
|
61
|
+
create-release:
|
|
62
|
+
name: Create GitHub Release
|
|
63
|
+
needs: [build-wheels, build-sdist]
|
|
64
|
+
runs-on: ubuntu-latest
|
|
65
|
+
if: startsWith(github.ref, 'refs/tags/')
|
|
66
|
+
steps:
|
|
67
|
+
- uses: actions/checkout@v7
|
|
68
|
+
|
|
69
|
+
- name: Download all artifacts
|
|
70
|
+
uses: actions/download-artifact@v8
|
|
71
|
+
with:
|
|
72
|
+
path: dist
|
|
73
|
+
|
|
74
|
+
- name: Flatten artifacts
|
|
75
|
+
run: |
|
|
76
|
+
mkdir -p wheels
|
|
77
|
+
find dist -name '*.whl' -exec cp {} wheels/ \;
|
|
78
|
+
find dist -name '*.tar.gz' -exec cp {} wheels/ \;
|
|
79
|
+
|
|
80
|
+
- name: Create Release
|
|
81
|
+
uses: softprops/action-gh-release@v3
|
|
82
|
+
with:
|
|
83
|
+
files: wheels/*
|
|
84
|
+
generate_release_notes: true
|
|
85
|
+
draft: false
|
|
86
|
+
prerelease: false
|
|
87
|
+
|
|
88
|
+
publish-to-pypi:
|
|
89
|
+
name: Publish to PyPI
|
|
90
|
+
needs: [build-wheels, build-sdist, create-release]
|
|
91
|
+
runs-on: ubuntu-latest
|
|
92
|
+
if: startsWith(github.ref, 'refs/tags/') && github.event_name == 'push'
|
|
93
|
+
environment:
|
|
94
|
+
name: pypi
|
|
95
|
+
url: https://pypi.org/p/gerenuk
|
|
96
|
+
permissions:
|
|
97
|
+
id-token: write
|
|
98
|
+
steps:
|
|
99
|
+
- name: Download all artifacts
|
|
100
|
+
uses: actions/download-artifact@v8
|
|
101
|
+
with:
|
|
102
|
+
path: dist
|
|
103
|
+
|
|
104
|
+
- name: Flatten artifacts
|
|
105
|
+
run: |
|
|
106
|
+
mkdir -p wheels
|
|
107
|
+
find dist -name '*.whl' -exec cp {} wheels/ \;
|
|
108
|
+
find dist -name '*.tar.gz' -exec cp {} wheels/ \;
|
|
109
|
+
|
|
110
|
+
- name: Publish to PyPI
|
|
111
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
112
|
+
with:
|
|
113
|
+
packages-dir: wheels/
|
|
114
|
+
skip-existing: true
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
name: Code Review
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
paths:
|
|
7
|
+
- "src/**"
|
|
8
|
+
- "tests/**"
|
|
9
|
+
- "docs/**"
|
|
10
|
+
- "Cargo.toml"
|
|
11
|
+
- "Cargo.lock"
|
|
12
|
+
- "rust-toolchain.toml"
|
|
13
|
+
- "clippy.toml"
|
|
14
|
+
- "rustfmt.toml"
|
|
15
|
+
pull_request:
|
|
16
|
+
paths:
|
|
17
|
+
- "src/**"
|
|
18
|
+
- "tests/**"
|
|
19
|
+
- "docs/**"
|
|
20
|
+
- "Cargo.toml"
|
|
21
|
+
- "Cargo.lock"
|
|
22
|
+
- "rust-toolchain.toml"
|
|
23
|
+
- "clippy.toml"
|
|
24
|
+
- "rustfmt.toml"
|
|
25
|
+
|
|
26
|
+
concurrency:
|
|
27
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
28
|
+
cancel-in-progress: true
|
|
29
|
+
|
|
30
|
+
env:
|
|
31
|
+
CARGO_TERM_COLOR: always
|
|
32
|
+
|
|
33
|
+
jobs:
|
|
34
|
+
fmt:
|
|
35
|
+
name: Formatting
|
|
36
|
+
runs-on: ubuntu-latest
|
|
37
|
+
steps:
|
|
38
|
+
- uses: actions/checkout@v7
|
|
39
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
40
|
+
with:
|
|
41
|
+
components: rustfmt
|
|
42
|
+
- run: cargo fmt --all --check
|
|
43
|
+
|
|
44
|
+
clippy:
|
|
45
|
+
name: Clippy
|
|
46
|
+
runs-on: ubuntu-latest
|
|
47
|
+
steps:
|
|
48
|
+
- uses: actions/checkout@v7
|
|
49
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
50
|
+
with:
|
|
51
|
+
components: clippy
|
|
52
|
+
- uses: Swatinem/rust-cache@v2
|
|
53
|
+
- run: cargo clippy --all-targets --all-features -- -D warnings
|
|
54
|
+
|
|
55
|
+
test:
|
|
56
|
+
name: Tests
|
|
57
|
+
runs-on: ubuntu-latest
|
|
58
|
+
steps:
|
|
59
|
+
- uses: actions/checkout@v7
|
|
60
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
61
|
+
- uses: Swatinem/rust-cache@v2
|
|
62
|
+
# The suite stubs `tyf` via GERENUK_TYF, so neither ty-find nor ty is
|
|
63
|
+
# needed here. See tests/common/mod.rs.
|
|
64
|
+
- run: cargo test --all-features
|
|
65
|
+
|
|
66
|
+
fixture:
|
|
67
|
+
name: Fixture package tests
|
|
68
|
+
runs-on: ubuntu-latest
|
|
69
|
+
steps:
|
|
70
|
+
- uses: actions/checkout@v7
|
|
71
|
+
- uses: astral-sh/setup-uv@v7
|
|
72
|
+
- name: Run the fixture package's pytest suite
|
|
73
|
+
working-directory: tests/fixtures/sample_pkg
|
|
74
|
+
run: uv run --with pytest --with hatchling python -m pytest -q
|
|
75
|
+
|
|
76
|
+
docs:
|
|
77
|
+
name: Docs are in sync
|
|
78
|
+
runs-on: ubuntu-latest
|
|
79
|
+
steps:
|
|
80
|
+
- uses: actions/checkout@v7
|
|
81
|
+
- name: Version badge matches Cargo.toml
|
|
82
|
+
run: bash docs/gen-version.sh --check
|
|
83
|
+
- name: Shared snippets are injected
|
|
84
|
+
run: bash docs/inject-shared.sh --check
|
gerenuk-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Rust
|
|
2
|
+
/target/
|
|
3
|
+
**/*.rs.bk
|
|
4
|
+
|
|
5
|
+
# Python
|
|
6
|
+
__pycache__/
|
|
7
|
+
*.py[cod]
|
|
8
|
+
*$py.class
|
|
9
|
+
*.so
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
pip-wheel-metadata/
|
|
24
|
+
share/python-wheels/
|
|
25
|
+
*.egg-info/
|
|
26
|
+
.installed.cfg
|
|
27
|
+
*.egg
|
|
28
|
+
MANIFEST
|
|
29
|
+
cf/
|
|
30
|
+
# Virtual environments
|
|
31
|
+
.env
|
|
32
|
+
.venv
|
|
33
|
+
env/
|
|
34
|
+
venv/
|
|
35
|
+
ENV/
|
|
36
|
+
env.bak/
|
|
37
|
+
venv.bak/
|
|
38
|
+
|
|
39
|
+
# Claude Code
|
|
40
|
+
.claude/worktrees/
|
|
41
|
+
|
|
42
|
+
# IDE
|
|
43
|
+
.vscode/
|
|
44
|
+
.idea/
|
|
45
|
+
*.swp
|
|
46
|
+
*.swo
|
|
47
|
+
*~
|
|
48
|
+
|
|
49
|
+
# OS
|
|
50
|
+
.DS_Store
|
|
51
|
+
.DS_Store?
|
|
52
|
+
._*
|
|
53
|
+
.Spotlight-V100
|
|
54
|
+
.Trashes
|
|
55
|
+
ehthumbs.db
|
|
56
|
+
Thumbs.db
|
|
57
|
+
|
|
58
|
+
# Logs
|
|
59
|
+
*.log
|
|
60
|
+
|
|
61
|
+
# Temporary files
|
|
62
|
+
*.tmp
|
|
63
|
+
*.temp
|
|
64
|
+
.cache/
|
|
65
|
+
|
|
66
|
+
# maturin / PyO3
|
|
67
|
+
*.so
|
|
68
|
+
*.pyd
|
|
69
|
+
.eggs/
|
|
70
|
+
|
|
71
|
+
# Testing
|
|
72
|
+
.pytest_cache/
|
|
73
|
+
.coverage
|
|
74
|
+
htmlcov/
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
# Fixture package virtualenvs
|
|
78
|
+
tests/fixtures/**/.venv/
|
|
79
|
+
|
|
80
|
+
# mdBook build output (docs/book.toml build-dir)
|
|
81
|
+
docs/book/
|
gerenuk-0.1.0/CLAUDE.md
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with
|
|
4
|
+
code in this repository.
|
|
5
|
+
|
|
6
|
+
## Project Overview
|
|
7
|
+
|
|
8
|
+
`gerenuk` is a CLI that audits Python symbols by driving `tyf` (from
|
|
9
|
+
[ty-find](https://github.com/mojzis/ty-find)). It is a hybrid Rust/Python
|
|
10
|
+
project: a Rust binary packaged as a Python wheel via maturin.
|
|
11
|
+
|
|
12
|
+
It reports two things per file: symbols nothing references, and symbols only
|
|
13
|
+
tests reach. A second command, `changed-symbols`, maps the working tree's git
|
|
14
|
+
diff to the Python symbols it changed — the first stage of impact-based pytest
|
|
15
|
+
selection, and the one part of the crate that needs `git` rather than `tyf`.
|
|
16
|
+
Architecture details: `docs/dev/ARCHITECTURE.md`.
|
|
17
|
+
|
|
18
|
+
## Prerequisites
|
|
19
|
+
|
|
20
|
+
- **`tyf`** on `PATH` for `audit`/`doctor` (`uv add --dev ty ty-find`). Not
|
|
21
|
+
needed for the test suite — the tests stub it.
|
|
22
|
+
- **`git`** on `PATH` for `changed-symbols` and its tests, or `GERENUK_GIT`
|
|
23
|
+
pointing at it. That is all it needs.
|
|
24
|
+
- **`uv`** for the fixture package's pytest suite.
|
|
25
|
+
|
|
26
|
+
## Common Commands
|
|
27
|
+
|
|
28
|
+
```sh
|
|
29
|
+
# Pre-commit checks (always run before committing)
|
|
30
|
+
cargo fmt --all -- --check && cargo clippy --all-targets --all-features -- -D warnings && cargo test --all-features
|
|
31
|
+
|
|
32
|
+
make review # the above, plus the fixture pytest suite, audit and deny
|
|
33
|
+
make review-quick # skip the network checks
|
|
34
|
+
make test-fixture # just the Python fixture package's pytest suite
|
|
35
|
+
make docs # build the mdBook site + llms.txt
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
If formatting fails, fix it with `cargo fmt --all` and re-run.
|
|
39
|
+
|
|
40
|
+
## Development Workflow
|
|
41
|
+
|
|
42
|
+
All features and bug fixes follow TDD (red-green-refactor). No implementation
|
|
43
|
+
code without a failing test first. Bug fixes must include a regression test that
|
|
44
|
+
fails without the fix.
|
|
45
|
+
|
|
46
|
+
## Test Changes Require Deliberation
|
|
47
|
+
|
|
48
|
+
When a test fails during implementation:
|
|
49
|
+
|
|
50
|
+
1. **Stop and diagnose.** Understand WHY it fails before changing anything. Is
|
|
51
|
+
the test wrong, or is the implementation wrong?
|
|
52
|
+
2. **Default assumption: the test is right.** Fix the implementation first.
|
|
53
|
+
3. **If the test genuinely needs updating** (requirements changed, API evolved),
|
|
54
|
+
explain what changed and why the old assertion is no longer correct before
|
|
55
|
+
modifying it.
|
|
56
|
+
4. **Never weaken an assertion just to make it pass.** Making a test more
|
|
57
|
+
permissive without understanding the failure is not a fix.
|
|
58
|
+
5. **If uncertain, ask.** A 2-line question is cheaper than a silent wrong
|
|
59
|
+
decision.
|
|
60
|
+
|
|
61
|
+
## Key Invariants
|
|
62
|
+
|
|
63
|
+
- **`tyf::Runner::run` and `git::Git::run` are the only functions that spawn a
|
|
64
|
+
process.** Everything downstream takes parsed data. Keep it that way — it is
|
|
65
|
+
what makes `analyze`, `changed` and `report` testable with no `tyf`, no `ty`,
|
|
66
|
+
no `git` and no Python. Adding a third seam needs a very good reason.
|
|
67
|
+
- **`changed-symbols` must never construct a `tyf::Runner`.** Discovery happens
|
|
68
|
+
inside the `Audit` and `Doctor` arms of `Cli::run`, not before the match. A
|
|
69
|
+
test in `tests/changed_symbols.rs` runs with an empty `PATH` to enforce this.
|
|
70
|
+
- **`changed::Sources` is the seam the classification is tested through.** New
|
|
71
|
+
inputs go behind that trait, not into `changed::analyze` directly, or the unit
|
|
72
|
+
tests stop being able to run without a repository.
|
|
73
|
+
- **`main.rs` stays thin.** Argument parsing, tracing setup, exit-code mapping.
|
|
74
|
+
Command bodies belong in `cli.rs`.
|
|
75
|
+
- **Exit codes are part of the contract.** `0` clean, `1` findings, `2` the run
|
|
76
|
+
could not complete. Do not collapse `1` and `2`. `changed-symbols` is an
|
|
77
|
+
inventory rather than a verdict, so it returns `0` or `2` and never `1`.
|
|
78
|
+
- **The fixture package and the canned payloads must agree.** Changing the call
|
|
79
|
+
graph in `tests/fixtures/sample_pkg` means updating both its pytest suite and
|
|
80
|
+
the stub payloads in `tests/audit.rs`.
|
|
81
|
+
- **`clippy::unwrap_used` / `expect_used` are denied outside tests.** Use
|
|
82
|
+
`anyhow::Context` on every `?` that crosses an I/O or parsing boundary.
|
|
83
|
+
- **A symbol's `added`/`modified`/`deleted` verdict comes from whether it exists
|
|
84
|
+
on each side of the diff, not from which side the hunk touched.** Deleting
|
|
85
|
+
lines from a function that still exists is a modification; its callers were
|
|
86
|
+
never orphaned. Renames are deliberately *not* paired — a moved module is a
|
|
87
|
+
new module, so the old path's symbols are `deleted` and the new path's
|
|
88
|
+
`added`.
|
|
89
|
+
- **Do not trust `tyf`'s production/test split.** Its heuristic reads the whole
|
|
90
|
+
absolute path, so a project under a `tests/` directory has every reference
|
|
91
|
+
filed as a test. `analyze::split_refs` re-derives the buckets from paths
|
|
92
|
+
relative to the workspace root, and drops the symbol's own definition. The
|
|
93
|
+
stub payloads in `tests/audit.rs` reproduce both quirks — keep them that way.
|
|
94
|
+
|
|
95
|
+
## Docs
|
|
96
|
+
|
|
97
|
+
The mdBook site under `docs/` deploys to GitHub Pages on push to `main`
|
|
98
|
+
(`.github/workflows/docs.yml`), along with `llms.txt` and `llms-full.txt`.
|
|
99
|
+
|
|
100
|
+
- Shared prose lives in `docs/shared/` and is injected into `README.md` and
|
|
101
|
+
`docs/src/setup.md` by `docs/inject-shared.sh`. Edit the shared file, then run
|
|
102
|
+
the script — never edit between the `<!-- BEGIN SHARED:... -->` markers.
|
|
103
|
+
- `docs/gen-version.sh` syncs the docs version badge with `Cargo.toml`.
|
|
104
|
+
- Adding a page means adding it to `docs/src/SUMMARY.md`; the `llms.txt`
|
|
105
|
+
generator reads that file.
|