1 Contributing
Vincent S. edited this page 2026-06-28 01:08:01 +02:00

Contributing

Pre-commit gate

The repo ships a .githooks/pre-commit hook that runs:

cargo clippy --all-targets -- -D warnings
cargo test

It must be activated per clone:

git config core.hooksPath .githooks

Bypass a single commit with git commit --no-verify.

CI mirrors this gate: a Forgejo Actions workflow (.forgejo/workflows/ci.yml) runs build + test + rustfmt --check on every push.

Testing

cargo test                           # workspace tests (parsers, alert engine, server routes via tower oneshot)
cargo test -p alfred-core            # one crate
cargo test parse_workspace_identifier  # one test by name substring
cargo clippy --all-targets

Conventions

  • Errors: anyhow in the daemon; control handlers return Result<String, String> mapped to HTTP status codes.
  • Config: structs use #[serde(deny_unknown_fields)] and a real Config::validate() (errors vs. warnings) — keep both in sync when adding fields.
  • Blocking work (subprocess calls, sysfs/statvfs, sqlite, NVML) belongs in tokio::task::spawn_blocking or on the automation thread, never inline in an async collect(). (Some existing modules predate this rule.)
  • Optional-dep modules get a default-on Cargo feature gating both dep:<crate> and pub mod <module>; + the spawn_if_enabled! line. ModuleKind is never gated. See Modules.

Adding a module

See the checklist in ModulesAdding a module. The short version: ModuleKind (+ Display/FromStr/all()), config struct (+ validate()), spawn_if_enabled!, and both capabilities() and client/list.rs::builtin_metadata.

Gotchas

  • Worker lifetime: WorkerClient must retain the tokio::process::Child (kill_on_drop); dropping the handle kills the worker.
  • alfred-ytm dep pin: pin alloc-no-stdlib to 2.0.4 in the lockfile, or brotli (pulled by reqwest) fails to compile.
  • Stdout discipline: client subcommands are waybar children — keep stdout pure JSON; logging is only initialised for serve.