Skip to content

Commit 409361e

Browse files
committed
Add tokio sync, replay cfg and code formatting
Enable the `sync` feature for tokio in cargo-rustapi and gate the Replay CLI subcommand/tests behind cfg(feature = "replay"). Additionally apply a series of small refactors and formatting fixes across the workspace: reflowed long expressions, added/removed trailing commas, normalized imports and multi-line signatures, and cleaned up test invocations and assertions. Changes touch cargo-rustapi, rustapi-core, rustapi-extras, rustapi-rs and related examples/tests; they are primarily stylistic and readability improvements (with the notable functional addition of the tokio `sync` feature and conditional replay wiring).
1 parent 2d69f73 commit 409361e

File tree

17 files changed

+346
-253
lines changed

17 files changed

+346
-253
lines changed

crates/cargo-rustapi/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ notify = "7.0"
3030
notify-debouncer-mini = "0.5"
3131

3232
# Async
33-
tokio = { workspace = true, features = ["process", "fs", "macros", "rt-multi-thread", "time", "signal"] }
33+
tokio = { workspace = true, features = ["process", "fs", "macros", "rt-multi-thread", "time", "signal", "sync"] }
3434

3535
# Serialization
3636
serde = { workspace = true }

crates/cargo-rustapi/src/cli.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
//! CLI argument parsing
22
3+
#[cfg(feature = "replay")]
4+
use crate::commands::ReplayArgs;
35
use crate::commands::{
46
self, AddArgs, BenchArgs, ClientArgs, DeployArgs, DoctorArgs, GenerateArgs, MigrateArgs,
57
NewArgs, ObservabilityArgs, RunArgs, WatchArgs,
68
};
7-
#[cfg(feature = "replay")]
8-
use crate::commands::ReplayArgs;
99
use clap::{Parser, Subcommand};
1010

1111
/// The official CLI tool for the RustAPI framework. Scaffold new projects, run development servers, and manage database migrations.
@@ -67,6 +67,7 @@ enum Commands {
6767
Deploy(DeployArgs),
6868

6969
/// Replay debugging commands (time-travel debugging)
70+
#[cfg(feature = "replay")]
7071
#[command(subcommand)]
7172
Replay(ReplayArgs),
7273
}
@@ -87,6 +88,7 @@ impl Cli {
8788
Commands::Docs { port } => commands::open_docs(port).await,
8889
Commands::Client(args) => commands::client(args).await,
8990
Commands::Deploy(args) => commands::deploy(args).await,
91+
#[cfg(feature = "replay")]
9092
Commands::Replay(args) => commands::replay(args).await,
9193
}
9294
}

crates/cargo-rustapi/src/commands/bench.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,10 @@ pub async fn bench(args: BenchArgs) -> Result<()> {
5656
command.env("RUSTAPI_PERF_ITERS", iterations.to_string());
5757
}
5858

59-
let status = command.status().await.context("Failed to launch benchmark workflow")?;
59+
let status = command
60+
.status()
61+
.await
62+
.context("Failed to launch benchmark workflow")?;
6063
if !status.success() {
6164
bail!("Benchmark workflow exited with status {}", status);
6265
}

crates/cargo-rustapi/src/commands/doctor.rs

Lines changed: 84 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -89,34 +89,34 @@ pub async fn doctor(args: DoctorArgs) -> Result<()> {
8989

9090
println!("{}", style("Toolchain").bold());
9191
checks.push(check_tool("rustc", &["--version"], "Rust compiler", true).await);
92-
checks.push(check_tool(
93-
"cargo",
94-
&["--version"],
95-
"Cargo package manager",
96-
true,
97-
)
98-
.await);
99-
checks.push(check_tool(
100-
"cargo",
101-
&["watch", "--version"],
102-
"cargo-watch (for hot reload)",
103-
false,
104-
)
105-
.await);
106-
checks.push(check_tool(
107-
"docker",
108-
&["--version"],
109-
"Docker (for containerization)",
110-
false,
111-
)
112-
.await);
113-
checks.push(check_tool(
114-
"sqlx",
115-
&["--version"],
116-
"sqlx-cli (for database migrations)",
117-
false,
118-
)
119-
.await);
92+
checks.push(check_tool("cargo", &["--version"], "Cargo package manager", true).await);
93+
checks.push(
94+
check_tool(
95+
"cargo",
96+
&["watch", "--version"],
97+
"cargo-watch (for hot reload)",
98+
false,
99+
)
100+
.await,
101+
);
102+
checks.push(
103+
check_tool(
104+
"docker",
105+
&["--version"],
106+
"Docker (for containerization)",
107+
false,
108+
)
109+
.await,
110+
);
111+
checks.push(
112+
check_tool(
113+
"sqlx",
114+
&["--version"],
115+
"sqlx-cli (for database migrations)",
116+
false,
117+
)
118+
.await,
119+
);
120120

121121
for check in &checks {
122122
print_check(check);
@@ -280,10 +280,7 @@ fn build_project_checks(workspace_root: &Path) -> Result<Vec<DoctorCheck>> {
280280
}
281281

282282
checks.push(if signals.production_defaults {
283-
DoctorCheck::pass(
284-
"Application baseline",
285-
"production_defaults usage detected",
286-
)
283+
DoctorCheck::pass("Application baseline", "production_defaults usage detected")
287284
} else {
288285
DoctorCheck::warn(
289286
"Application baseline",
@@ -327,17 +324,21 @@ fn build_project_checks(workspace_root: &Path) -> Result<Vec<DoctorCheck>> {
327324
)
328325
});
329326

330-
checks.push(if (signals.production_defaults || signals.request_id) && (signals.production_defaults || signals.tracing) {
331-
DoctorCheck::pass(
332-
"Request IDs and tracing",
333-
"Request ID and tracing signals detected",
334-
)
335-
} else {
336-
DoctorCheck::warn(
337-
"Request IDs and tracing",
338-
"RequestIdLayer/tracing signals were not clearly detected",
339-
)
340-
});
327+
checks.push(
328+
if (signals.production_defaults || signals.request_id)
329+
&& (signals.production_defaults || signals.tracing)
330+
{
331+
DoctorCheck::pass(
332+
"Request IDs and tracing",
333+
"Request ID and tracing signals detected",
334+
)
335+
} else {
336+
DoctorCheck::warn(
337+
"Request IDs and tracing",
338+
"RequestIdLayer/tracing signals were not clearly detected",
339+
)
340+
},
341+
);
341342

342343
checks.push(if signals.structured_logging || signals.otel {
343344
DoctorCheck::pass(
@@ -351,17 +352,19 @@ fn build_project_checks(workspace_root: &Path) -> Result<Vec<DoctorCheck>> {
351352
)
352353
});
353354

354-
checks.push(if signals.rate_limit || signals.security_headers || signals.timeout || signals.cors {
355-
DoctorCheck::pass(
356-
"Edge protections",
357-
"Detected timeout, rate limit, CORS, or security header configuration",
358-
)
359-
} else {
360-
DoctorCheck::warn(
361-
"Edge protections",
362-
"No timeout, rate limit, CORS, or security header configuration was detected",
363-
)
364-
});
355+
checks.push(
356+
if signals.rate_limit || signals.security_headers || signals.timeout || signals.cors {
357+
DoctorCheck::pass(
358+
"Edge protections",
359+
"Detected timeout, rate limit, CORS, or security header configuration",
360+
)
361+
} else {
362+
DoctorCheck::warn(
363+
"Edge protections",
364+
"No timeout, rate limit, CORS, or security header configuration was detected",
365+
)
366+
},
367+
);
365368

366369
checks.push(if signals.body_limit {
367370
DoctorCheck::pass(
@@ -401,7 +404,11 @@ fn scan_workspace_signals(workspace_root: &Path) -> Result<WorkspaceSignals> {
401404
);
402405
signals.health_endpoints |= contains_any(
403406
&contents,
404-
&[".health_endpoints(", ".health_endpoint_config(", "HealthEndpointConfig"],
407+
&[
408+
".health_endpoints(",
409+
".health_endpoint_config(",
410+
"HealthEndpointConfig",
411+
],
405412
);
406413
signals.health_checks |= contents.contains(".with_health_check(");
407414
signals.request_id |= contents.contains("RequestIdLayer");
@@ -414,10 +421,8 @@ fn scan_workspace_signals(workspace_root: &Path) -> Result<WorkspaceSignals> {
414421
);
415422
signals.otel |= contains_any(&contents, &["OtelLayer", "otel("]);
416423
signals.rate_limit |= contains_any(&contents, &["RateLimitLayer", "rate_limit("]);
417-
signals.security_headers |= contains_any(
418-
&contents,
419-
&["SecurityHeadersLayer", "security_headers("],
420-
);
424+
signals.security_headers |=
425+
contains_any(&contents, &["SecurityHeadersLayer", "security_headers("]);
421426
signals.timeout |= contains_any(&contents, &["TimeoutLayer", "timeout("]);
422427
signals.cors |= contains_any(&contents, &["CorsLayer", "cors("]);
423428
signals.body_limit |= contains_any(&contents, &["BodyLimitLayer", ".body_limit("]);
@@ -463,7 +468,10 @@ fn should_scan(path: &Path) -> bool {
463468
return true;
464469
};
465470

466-
!matches!(name, ".git" | "target" | "node_modules" | ".next" | "dist" | "build")
471+
!matches!(
472+
name,
473+
".git" | "target" | "node_modules" | ".next" | "dist" | "build"
474+
)
467475
}
468476

469477
fn is_scannable_file(path: &Path) -> bool {
@@ -500,7 +508,11 @@ mod tests {
500508
#[test]
501509
fn scan_workspace_signals_detects_production_patterns() {
502510
let dir = tempdir().unwrap();
503-
fs::write(dir.path().join("Cargo.toml"), "[package]\nname='demo'\nversion='0.1.0'\n").unwrap();
511+
fs::write(
512+
dir.path().join("Cargo.toml"),
513+
"[package]\nname='demo'\nversion='0.1.0'\n",
514+
)
515+
.unwrap();
504516
fs::write(dir.path().join(".env"), "RUSTAPI_ENV=production\n").unwrap();
505517

506518
let src_dir = dir.path().join("src");
@@ -536,12 +548,20 @@ mod tests {
536548
#[test]
537549
fn build_project_checks_warns_when_signals_are_missing() {
538550
let dir = tempdir().unwrap();
539-
fs::write(dir.path().join("Cargo.toml"), "[package]\nname='demo'\nversion='0.1.0'\n").unwrap();
551+
fs::write(
552+
dir.path().join("Cargo.toml"),
553+
"[package]\nname='demo'\nversion='0.1.0'\n",
554+
)
555+
.unwrap();
540556
fs::create_dir_all(dir.path().join("src")).unwrap();
541557
fs::write(dir.path().join("src").join("main.rs"), "fn main() {}\n").unwrap();
542558

543559
let checks = build_project_checks(dir.path()).unwrap();
544-
assert!(checks.iter().any(|check| check.status == DoctorStatus::Warn));
545-
assert!(checks.iter().any(|check| check.name == "Application baseline"));
560+
assert!(checks
561+
.iter()
562+
.any(|check| check.status == DoctorStatus::Warn));
563+
assert!(checks
564+
.iter()
565+
.any(|check| check.name == "Application baseline"));
546566
}
547567
}

crates/cargo-rustapi/src/commands/new.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,12 @@ pub async fn new_project(mut args: NewArgs) -> Result<()> {
118118

119119
// Get features
120120
let features = if let Some(features) = args.features {
121-
merge_unique_features(preset.map(ProjectPreset::recommended_features).unwrap_or_default(), features)
121+
merge_unique_features(
122+
preset
123+
.map(ProjectPreset::recommended_features)
124+
.unwrap_or_default(),
125+
features,
126+
)
122127
} else if args.yes {
123128
preset
124129
.map(ProjectPreset::recommended_features)
@@ -153,7 +158,12 @@ pub async fn new_project(mut args: NewArgs) -> Result<()> {
153158
let defaults = defaults
154159
.into_iter()
155160
.enumerate()
156-
.map(|(index, default)| default || preset_features.iter().any(|feature| feature == available[index]))
161+
.map(|(index, default)| {
162+
default
163+
|| preset_features
164+
.iter()
165+
.any(|feature| feature == available[index])
166+
})
157167
.collect::<Vec<_>>();
158168

159169
let selections = dialoguer::MultiSelect::with_theme(&theme)

crates/cargo-rustapi/tests/cli_tests.rs

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -112,13 +112,7 @@ mod new_command {
112112

113113
cargo_rustapi()
114114
.current_dir(dir.path())
115-
.args([
116-
"new",
117-
project_name,
118-
"--preset",
119-
"prod-api",
120-
"--yes",
121-
])
115+
.args(["new", project_name, "--preset", "prod-api", "--yes"])
122116
.assert()
123117
.success();
124118

@@ -140,13 +134,7 @@ mod new_command {
140134

141135
cargo_rustapi()
142136
.current_dir(dir.path())
143-
.args([
144-
"new",
145-
project_name,
146-
"--preset",
147-
"ai-api",
148-
"--yes",
149-
])
137+
.args(["new", project_name, "--preset", "ai-api", "--yes"])
150138
.assert()
151139
.success();
152140

@@ -166,13 +154,7 @@ mod new_command {
166154

167155
cargo_rustapi()
168156
.current_dir(dir.path())
169-
.args([
170-
"new",
171-
project_name,
172-
"--preset",
173-
"realtime-api",
174-
"--yes",
175-
])
157+
.args(["new", project_name, "--preset", "realtime-api", "--yes"])
176158
.assert()
177159
.success();
178160

@@ -282,6 +264,7 @@ mod observability_command {
282264
}
283265
}
284266

267+
#[cfg(feature = "replay")]
285268
mod replay_command {
286269
use super::*;
287270

0 commit comments

Comments
 (0)