* CLAUDE.md: project layout, key conventions, where to look first. Captures the non-obvious things a future session needs. * CONTRIBUTING.md: build/test workflow, how to add a subcommand (concrete walkthrough), code style. * CHANGELOG.md: history. 0.1.0 entry covers initial feature set; Unreleased captures stability + optimization batch. * docs/architecture.md: module graph, layering rules, the HTTP funnel, pager + SIGINT, repo resolution, test strategy. * docs/jq.md: --jq syntax cheatsheet (dot paths, brackets, negative indices, pipes, what's not supported). * docs/troubleshooting.md: keychain re-prompts, debug logging, pager opt-out, alias precedence, hook bypass, common 401s. * README.md: links into docs/ and updates binary size to 4 MB. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2.6 KiB
2.6 KiB
Contributing to fj
Setup
git clone ssh://git@rasterhub.com:2222/rasterstate/fj.git
cd fj
./scripts/install-hooks.sh # symlinks hooks/pre-push into .git/hooks
cargo build --release # 4 MB binary at target/release/fj
The hook gates every push on fmt, clippy (warnings as errors), the full
test suite, and a release build. Set FJ_E2E=1 to additionally run the
live API smoke (requires fj auth login already done).
Workflow
- Branch off
main. - Make changes. Keep commits focused.
cargo fmt --allbefore committing.- The pre-push hook runs the full bar; if it fails, fix the issue
rather than passing
FJ_SKIP_PREPUSH=1unless you genuinely need to bypass.
Testing
- 60 tests live in the source tree (51 unit + 9 wiremock integration).
- Unit tests stay close to the code they cover, in inline
#[cfg(test)]modules. - HTTP integration tests live in
src/client/integration_tests.rsand use a wiremock server. Construct test clients viaClient::for_base_url(base, token). - Live API tests live in
scripts/e2e-smoke.shand exercise read-only operations against the configured Forgejo. Toggle withFJ_E2E=1.
Adding a subcommand
Concrete example: adding fj sticker list.
src/api/sticker.rs— typed API wrappers and request/response structs. Use theserde_util::deserialize_null_to_defaulthelper for fields that Forgejo returns asnullwhen empty.src/cli/sticker.rs— clapArgs/Subcommanddefinitions and therundispatch.src/api/mod.rs—pub mod sticker;src/cli/mod.rs—pub mod sticker;, add toCommand, add the dispatch arm indispatch().src/main.rs— add"sticker"toKNOWN_SUBCOMMANDSso plugin discovery doesn't shadow it.- Add inline
#[cfg(test)] mod testsfor any non-trivial pure code. - If you touched HTTP behavior, add a wiremock test in
src/client/integration_tests.rs.
Code style
- See
CLAUDE.mdfor in-tree conventions. - One small line of comment max per non-obvious thing. Don't narrate what code does, only why.
- No
.unwrap()/.expect()in non-test code paths. Use?andanyhow::Error::contextto attach actionable messages. - Prefer
Resultover panics. The one exception isunreachable!()for genuinely impossible match arms, but flag it in review.
Releasing
cargo build --release
./target/release/fj completion zsh > ~/.zfunc/_fj
./target/release/fj man -o ./man
No cargo-dist or Homebrew tap yet. Binary lives at target/release/fj;
symlink into a user-level bin dir.
License
MIT. By contributing you agree to the same license.