Skip to content

Commit 0c0811d

Browse files
committed
Fix CI coverage: exclude cargo-rustapi from tarpaulin, gate mcp_tools example
1 parent 6e84889 commit 0c0811d

4 files changed

Lines changed: 40 additions & 1 deletion

File tree

.github/workflows/ci.yml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,14 @@ jobs:
211211
uses: taiki-e/install-action@cargo-tarpaulin
212212

213213
- name: Run coverage
214-
run: cargo tarpaulin --workspace --out Html --output-dir coverage
214+
run: |
215+
# cargo-rustapi spawns nested `cargo` builds in integration tests;
216+
# tarpaulin cannot instrument those subprocesses reliably.
217+
cargo tarpaulin --workspace \
218+
--exclude cargo-rustapi \
219+
--timeout 900 \
220+
--out Html \
221+
--output-dir coverage
215222
216223
- name: Upload coverage report
217224
uses: actions/upload-artifact@v4

crates/cargo-rustapi/tests/cli_tests.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ fn cargo_rustapi() -> Command {
1010
assert_cmd::cargo::cargo_bin_cmd!("cargo-rustapi")
1111
}
1212

13+
/// Tarpaulin sets `TARPAULIN` when instrumenting tests; nested `cargo` builds are unreliable there.
14+
fn running_under_tarpaulin() -> bool {
15+
std::env::var_os("TARPAULIN").is_some()
16+
}
17+
1318
mod new_command {
1419
use super::*;
1520

@@ -320,6 +325,11 @@ mod generate_command {
320325

321326
#[test]
322327
fn test_generate_crud_sqlx_compiles() {
328+
if running_under_tarpaulin() {
329+
eprintln!("skipping nested cargo e2e under tarpaulin");
330+
return;
331+
}
332+
323333
let dir = tempdir().expect("Failed to create temp dir");
324334
let project_name = "test-crud-sqlx";
325335
let project_path = dir.path().join(project_name);

crates/rustapi-rs/Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ rustapi-openapi = { workspace = true, default-features = false }
3737
name = "file_upload"
3838
path = "examples/file_upload.rs"
3939

40+
[[example]]
41+
name = "mcp_tools"
42+
path = "examples/mcp_tools.rs"
43+
required-features = ["protocol-mcp"]
44+
4045
[dev-dependencies]
4146
rustapi-core = { workspace = true }
4247
rustapi-macros = { workspace = true }

crates/rustapi-rs/examples/mcp_tools.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,31 +28,45 @@
2828
//! -H 'content-type: application/json' \
2929
//! -d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"get_agent_weather_city","arguments":{"city":"Istanbul"}}}'
3030
31+
#[cfg(not(any(feature = "protocol-mcp", feature = "mcp")))]
32+
fn main() {
33+
eprintln!(
34+
"Run this example with MCP support enabled:\n cargo run -p rustapi-rs --example mcp_tools --features protocol-mcp"
35+
);
36+
}
37+
38+
#[cfg(any(feature = "protocol-mcp", feature = "mcp"))]
3139
use rustapi_rs::prelude::*;
40+
#[cfg(any(feature = "protocol-mcp", feature = "mcp"))]
3241
use rustapi_rs::protocol::mcp::{
3342
run_rustapi_and_mcp_with_shutdown, InvocationMode, McpConfig, McpServer,
3443
};
44+
#[cfg(any(feature = "protocol-mcp", feature = "mcp"))]
3545
use serde::{Deserialize, Serialize};
3646

47+
#[cfg(any(feature = "protocol-mcp", feature = "mcp"))]
3748
#[derive(Serialize, Schema)]
3849
struct Weather {
3950
city: String,
4051
temperature: i32,
4152
unit: &'static str,
4253
}
4354

55+
#[cfg(any(feature = "protocol-mcp", feature = "mcp"))]
4456
#[derive(Deserialize, Serialize, Schema)]
4557
struct SumRequest {
4658
a: i32,
4759
b: i32,
4860
}
4961

62+
#[cfg(any(feature = "protocol-mcp", feature = "mcp"))]
5063
#[derive(Serialize, Schema)]
5164
struct SumResponse {
5265
sum: i32,
5366
}
5467

5568
/// This route will be exposed as an MCP tool because of the "agent" tag.
69+
#[cfg(any(feature = "protocol-mcp", feature = "mcp"))]
5670
#[rustapi_rs::get("/agent/weather/{city}")]
5771
#[rustapi_rs::tag("agent")]
5872
#[rustapi_rs::summary("Get weather information for a city")]
@@ -65,6 +79,7 @@ async fn get_weather(Path(city): Path<String>) -> Json<Weather> {
6579
}
6680

6781
/// Another exposed tool (POST with JSON body).
82+
#[cfg(any(feature = "protocol-mcp", feature = "mcp"))]
6883
#[rustapi_rs::post("/agent/sum")]
6984
#[rustapi_rs::tag("agent")]
7085
#[rustapi_rs::summary("Add two integers and return the result")]
@@ -73,11 +88,13 @@ async fn sum(Json(req): Json<SumRequest>) -> Json<SumResponse> {
7388
}
7489

7590
/// This route is deliberately NOT tagged — it will NOT appear in MCP discovery.
91+
#[cfg(any(feature = "protocol-mcp", feature = "mcp"))]
7692
#[rustapi_rs::get("/admin/internal-config")]
7793
async fn internal_only() -> &'static str {
7894
"this-should-never-be-visible-to-agents"
7995
}
8096

97+
#[cfg(any(feature = "protocol-mcp", feature = "mcp"))]
8198
#[tokio::main]
8299
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
83100
let app = RustApi::auto();

0 commit comments

Comments
 (0)