Skip to content

Build cmd#3

Merged
Bechma merged 4 commits intocyberfabric:mainfrom
Bechma:build-cmd
Feb 23, 2026
Merged

Build cmd#3
Bechma merged 4 commits intocyberfabric:mainfrom
Bechma:build-cmd

Conversation

@Bechma
Copy link
Copy Markdown
Collaborator

@Bechma Bechma commented Feb 23, 2026

Summary by CodeRabbit

  • New Features
    • Automatic server scaffolding and an integrated build command that runs the project build.
  • Refactor
    • Unified CLI arguments and centralized scaffolding logic so build and run share common options and behavior, reducing duplication.
  • Bug Fixes
    • Clearer path/config canonicalization errors and improved reporting when builds fail.

Signed-off-by: Bechma <19294519+Bechma@users.noreply.github.com>
Signed-off-by: Bechma <19294519+Bechma@users.noreply.github.com>
Signed-off-by: Bechma <19294519+Bechma@users.noreply.github.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Feb 23, 2026

📝 Walkthrough

Walkthrough

Rewires CLI build/run plumbing: introduces BuildRunArgs and centralizes scaffolding, config loading, and cargo invocation in crates/cli/src/common.rs; updates build and run commands to flatten BuildRunArgs and CommonArgs, canonicalize paths, generate server structure, and invoke cargo with error handling.

Changes

Cohort / File(s) Summary
Build command
crates/cli/src/build/mod.rs
Replaced release: bool with #[command(flatten)] build_run_args: BuildRunArgs and #[command(flatten)] common_args: CommonArgs. Added BuildArgs::run to canonicalize paths, load config, generate server scaffold, and run cargo build with proper error context and non-success handling.
Run command wiring
crates/cli/src/run/mod.rs
Changed RunArgs to flatten BuildRunArgs and CommonArgs, updated imports and canonicalization to use build_run_args/common_args, and adjusted OTEL/RELEASE usage to come from BuildRunArgs.
Shared CLI/common module
crates/cli/src/common.rs
Added BuildRunArgs, BASE_PATH, cargo_command, get_config, generate_server_structure, and internal helpers/templates to centralize config loading, dependency derivation, server scaffolding, and cargo command construction.
Run loop refactor
crates/cli/src/run/run_loop.rs
Delegated config/scaffold generation and cargo invocation to common APIs; removed many local helpers; replaced OTEL flag with RELEASE: AtomicBool; updated cargo run/watch flows to call common::cargo_command, common::get_config, and common::generate_server_structure.
Template relocation/removal
crates/cli/src/run/templates.rs
Removed CARGO_CONFIG_TOML, CARGO_SERVER_MAIN, and prepare_cargo_server_main — templates and helper logic moved into common.rs.

Sequence Diagram(s)

sequenceDiagram
    participant CLI as CLI (build/run)
    participant Common as common.rs
    participant FS as Filesystem
    participant Cargo as Cargo

    CLI->>Common: start build/run with BuildRunArgs
    Common->>FS: canonicalize workspace & config paths
    Common->>FS: load config (get_config)
    Common->>Common: derive dependencies & generate_server_structure
    Common->>Cargo: run cargo via cargo_command (build/run, otel/release)
    Cargo-->>Common: exit status
    Common-->>CLI: return success or bail with error
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐇 I hop through paths and scaffolded trees,

Merging configs with nimble ease,
A common burrow for build and run—
Now crates compile beneath the sun. 🥕

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 6.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Build cmd' is vague and generic, using abbreviated terminology that doesn't clearly convey what was actually changed or implemented. Consider using a more descriptive title that captures the main change, such as 'Refactor BuildArgs to use flattened composition' or 'Extract shared build configuration logic to common module'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
crates/cli/src/common.rs (2)

97-108: Silent metadata mismatch: modules in config but not in the workspace are left with empty metadata.

get_config only merges metadata for modules that exist in both the config and the workspace members. If a module is listed in the config but not found in the workspace (e.g., typo in the config, or the crate hasn't been added yet), there's no warning. This could lead to confusing downstream errors.

Consider logging a warning for config modules that don't have a matching workspace member.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/cli/src/common.rs` around lines 97 - 108, get_config currently skips
modules present in the config but missing from workspace members, leaving their
metadata empty without any notice. Modify get_config (which calls
get_config_from_path and get_module_name_from_crate and iterates over
config.modules) so when members.remove(module.0.as_str()) returns None you emit
a warning (e.g., via log::warn or the project's logger) that the config module
(use module.0) has no matching workspace member and therefore no metadata
merged; keep existing behavior otherwise. Ensure the warning message includes
the module name and concise context to aid debugging.

122-167: Avoid cloning the dependencies map; take &mut instead.

insert_required_deps takes the map by value, forcing a .clone() at the call site (line 177). Accepting &mut HashMap avoids the allocation.

♻️ Proposed refactor
-fn insert_required_deps(
-    mut dependencies: HashMap<String, ConfigModuleMetadata>,
-) -> HashMap<String, ConfigModuleMetadata> {
+fn insert_required_deps(
+    dependencies: &mut HashMap<String, ConfigModuleMetadata>,
+) {
     dependencies.insert(
         "modkit".to_owned(),
         // ...
     );
     // ... other inserts ...
-    dependencies
 }

Then update the call site:

+    let mut deps = dependencies.clone();
+    insert_required_deps(&mut deps);
     let cargo_toml = toml::to_string(&CargoToml {
-        dependencies: insert_required_deps(dependencies.clone()),
+        dependencies: deps,
         features,
         ..Default::default()
     })

Actually, since generate_server_structure takes dependencies by shared reference (&HashMap), the clone is still needed to avoid mutating the caller's data. So the clone cannot be eliminated without a broader signature change. The current approach is acceptable.

Also applies to: 176-177

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/cli/src/common.rs` around lines 122 - 167, insert_required_deps
currently takes ownership of the HashMap causing callers to clone; change its
signature to fn insert_required_deps(dependencies: &mut HashMap<String,
ConfigModuleMetadata>) and update its body to mutate the passed-in map (remove
the final return), then update the caller(s) that currently call
insert_required_deps(dependencies.clone()) to pass a mutable reference (&mut
dependencies) instead so the extra clone/allocation is eliminated; ensure you
update any imports/usages referencing insert_required_deps accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@crates/cli/src/common.rs`:
- Around line 200-202: The error message passed to path.parent().context(...)
contains a typo ("unreacheable"); update the string to "this should be
unreachable, the parent for the file structure always exists" by editing the
context call used with path.parent() so the message reads "unreachable" instead
of "unreacheable".

---

Nitpick comments:
In `@crates/cli/src/common.rs`:
- Around line 97-108: get_config currently skips modules present in the config
but missing from workspace members, leaving their metadata empty without any
notice. Modify get_config (which calls get_config_from_path and
get_module_name_from_crate and iterates over config.modules) so when
members.remove(module.0.as_str()) returns None you emit a warning (e.g., via
log::warn or the project's logger) that the config module (use module.0) has no
matching workspace member and therefore no metadata merged; keep existing
behavior otherwise. Ensure the warning message includes the module name and
concise context to aid debugging.
- Around line 122-167: insert_required_deps currently takes ownership of the
HashMap causing callers to clone; change its signature to fn
insert_required_deps(dependencies: &mut HashMap<String, ConfigModuleMetadata>)
and update its body to mutate the passed-in map (remove the final return), then
update the caller(s) that currently call
insert_required_deps(dependencies.clone()) to pass a mutable reference (&mut
dependencies) instead so the extra clone/allocation is eliminated; ensure you
update any imports/usages referencing insert_required_deps accordingly.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f875a7f and 180591e.

📒 Files selected for processing (5)
  • crates/cli/src/build/mod.rs
  • crates/cli/src/common.rs
  • crates/cli/src/run/mod.rs
  • crates/cli/src/run/run_loop.rs
  • crates/cli/src/run/templates.rs
💤 Files with no reviewable changes (1)
  • crates/cli/src/run/templates.rs

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
crates/cli/src/common.rs (2)

127-128: insert_required_deps signature forces an avoidable clone at the call site.

The function takes ownership, inserts entries, and returns the map — but line 182 must call dependencies.clone() just to satisfy this. Changing to &mut HashMap<...> eliminates the allocation.

♻️ Proposed refactor
 fn insert_required_deps(
-    mut dependencies: HashMap<String, ConfigModuleMetadata>,
-) -> HashMap<String, ConfigModuleMetadata> {
+    dependencies: &mut HashMap<String, ConfigModuleMetadata>,
+) {
     dependencies.insert( /* ... */ );
     // ... other inserts ...
-    dependencies
 }

And at the call site (line 181–186):

+    let mut cargo_toml_deps = dependencies.clone();
+    insert_required_deps(&mut cargo_toml_deps);
     let cargo_toml = toml::to_string(&CargoToml {
-        dependencies: insert_required_deps(dependencies.clone()),
+        dependencies: cargo_toml_deps,
         features,
         ..Default::default()
     })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/cli/src/common.rs` around lines 127 - 128, The function
insert_required_deps currently takes ownership of a HashMap<String,
ConfigModuleMetadata>, forcing callers to clone the map; change its signature to
take a mutable reference (&mut HashMap<String, ConfigModuleMetadata>) and mutate
it in place, updating its internals to use the borrowed map instead of returning
a new one, and update all call sites (remove dependencies.clone() and pass &mut
dependencies) so no extra allocation is needed; ensure types reference
ConfigModuleMetadata consistently and adjust any return values or uses
accordingly.

202-203: PathBuf::from(path) is redundant — Path::join already returns a PathBuf.

♻️ Proposed simplification
-    let path = PathBuf::from(path).join(BASE_PATH).join(relative_path);
+    let path = path.join(BASE_PATH).join(relative_path);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/cli/src/common.rs` around lines 202 - 203, In create_file_structure,
remove the redundant PathBuf::from(path) call and use the &Path parameter's join
method directly so the intermediate PathBuf is produced via
path.join(BASE_PATH).join(relative_path); update the let binding (still named
path) to use path.join(...) to produce a PathBuf and leave BASE_PATH and
relative_path usage unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@crates/cli/src/common.rs`:
- Around line 36-81: The generated CARGO_SERVER_MAIN uses serde_json only inside
#[cfg(feature = "otel")] blocks but insert_required_deps currently always
injects serde_json into Cargo.toml, causing unused dependency errors; update
insert_required_deps to either (A) add serde_json to the generated Cargo.toml
only when the otel flag is enabled, or (B) add serde_json as an optional
dependency and include it under the otel feature in the features table so
serde_json is only enabled when feature "otel" is active (reference function
insert_required_deps and constant CARGO_SERVER_MAIN and ensure Cargo.toml
feature wiring reflects this).
- Around line 225-228: The generated `use` lines embed HashMap keys directly
(the `dependencies.keys().map(|name| format!("use {name} as _;\n"))`
expression), which fails for hyphenated crate names; sanitize the identifier by
replacing hyphens with underscores before formatting (e.g. compute let ident =
name.replace('-', "_") inside the map and use format!("use {ident} as _;\n")),
so generated Rust identifiers are valid.

---

Nitpick comments:
In `@crates/cli/src/common.rs`:
- Around line 127-128: The function insert_required_deps currently takes
ownership of a HashMap<String, ConfigModuleMetadata>, forcing callers to clone
the map; change its signature to take a mutable reference (&mut HashMap<String,
ConfigModuleMetadata>) and mutate it in place, updating its internals to use the
borrowed map instead of returning a new one, and update all call sites (remove
dependencies.clone() and pass &mut dependencies) so no extra allocation is
needed; ensure types reference ConfigModuleMetadata consistently and adjust any
return values or uses accordingly.
- Around line 202-203: In create_file_structure, remove the redundant
PathBuf::from(path) call and use the &Path parameter's join method directly so
the intermediate PathBuf is produced via
path.join(BASE_PATH).join(relative_path); update the let binding (still named
path) to use path.join(...) to produce a PathBuf and leave BASE_PATH and
relative_path usage unchanged.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 180591e and f96cda0.

📒 Files selected for processing (1)
  • crates/cli/src/common.rs

Signed-off-by: Bechma <19294519+Bechma@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
crates/cli/src/common.rs (1)

213-215: Hyphenated crate names produce invalid Rust identifiers in generated use statements.

name is taken directly from the HashMap key. A module like "my-service" would emit use my-service as _;, which is a syntax error. This was raised in a previous review and remains unresolved.

🐛 Proposed fix
-        .map(|name| format!("use {name} as _;\n"))
+        .map(|name| format!("use {} as _;\n", name.replace('-', "_")))
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/cli/src/common.rs` around lines 213 - 215, The generated use
statements use raw crate keys which may contain hyphens (e.g., "my-service") and
produce invalid Rust identifiers; update the mapping in the
dependencies.keys().map(...) closure to convert crate names to valid Rust
identifiers (at minimum replace '-' with '_', e.g. let ident = name.replace('-',
"_")) and use that ident in the format!("use {ident} as _;\n") so hyphenated
crate names emit valid use statements; ensure the change is applied where the
dependencies mapping occurs in common.rs.
🧹 Nitpick comments (1)
crates/cli/src/common.rs (1)

175-177: Consider caching the parsed Liquid template with OnceLock.

CARGO_SERVER_MAIN is a compile-time constant, but generate_server_structure re-parses it on every invocation. A std::sync::OnceLock or once_cell::sync::Lazy would parse the template once.

♻️ Suggested approach
+use std::sync::OnceLock;
+
+fn server_main_template() -> &'static liquid::Template {
+    static TEMPLATE: OnceLock<liquid::Template> = OnceLock::new();
+    TEMPLATE.get_or_init(|| {
+        liquid::ParserBuilder::with_stdlib()
+            .build()
+            .expect("liquid stdlib build failed")
+            .parse(CARGO_SERVER_MAIN)
+            .expect("CARGO_SERVER_MAIN template is invalid")
+    })
+}

 pub fn generate_server_structure(...) -> anyhow::Result<()> {
     ...
-    let main_template = liquid::ParserBuilder::with_stdlib()
-        .build()?
-        .parse(CARGO_SERVER_MAIN)?;
+    let main_template = server_main_template();
     ...
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/cli/src/common.rs` around lines 175 - 177, The code reparses the
compile-time constant CARGO_SERVER_MAIN on every call to
generate_server_structure; change this by creating a static std::sync::OnceLock
(or once_cell::sync::Lazy) to hold the parsed liquid::Template and initialize it
once, then replace the local main_template creation in generate_server_structure
with a lookup from that static (e.g., TEMPLATE_ONCE.get_or_init(||
ParserBuilder::with_stdlib().build()?.parse(CARGO_SERVER_MAIN))). Ensure error
handling matches the current return type so failures to parse propagate
correctly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@crates/cli/src/common.rs`:
- Around line 213-215: The generated use statements use raw crate keys which may
contain hyphens (e.g., "my-service") and produce invalid Rust identifiers;
update the mapping in the dependencies.keys().map(...) closure to convert crate
names to valid Rust identifiers (at minimum replace '-' with '_', e.g. let ident
= name.replace('-', "_")) and use that ident in the format!("use {ident} as
_;\n") so hyphenated crate names emit valid use statements; ensure the change is
applied where the dependencies mapping occurs in common.rs.

---

Nitpick comments:
In `@crates/cli/src/common.rs`:
- Around line 175-177: The code reparses the compile-time constant
CARGO_SERVER_MAIN on every call to generate_server_structure; change this by
creating a static std::sync::OnceLock (or once_cell::sync::Lazy) to hold the
parsed liquid::Template and initialize it once, then replace the local
main_template creation in generate_server_structure with a lookup from that
static (e.g., TEMPLATE_ONCE.get_or_init(||
ParserBuilder::with_stdlib().build()?.parse(CARGO_SERVER_MAIN))). Ensure error
handling matches the current return type so failures to parse propagate
correctly.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f96cda0 and 7910d96.

📒 Files selected for processing (1)
  • crates/cli/src/common.rs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant