fabro/lib/apps/fabro-cli/tests/it/cmd/pr_create.rs
2026-08-01 19:28:52 -04:00

203 lines
6.4 KiB
Rust
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#![allow(
clippy::absolute_paths,
reason = "This test module prefers explicit type paths over extra imports."
)]
use fabro_test::{fabro_snapshot, test_context};
use httpmock::MockServer;
use super::support::{mock_resolved_run, setup_seeded_completed_dry_run};
use crate::support::unique_run_id;
#[test]
fn help() {
let context = test_context!();
let mut cmd = context.command();
cmd.args(["pr", "create", "--help"]);
fabro_snapshot!(context.filters(), cmd, @"
success: true
exit_code: 0
----- stdout -----
Create a pull request from a completed run
Usage: fabro pr create [OPTIONS] <RUN_ID>
Arguments:
<RUN_ID> Run ID or prefix
Options:
--json Output as JSON [env: FABRO_JSON=]
--server <SERVER> Fabro server target: http(s) URL or absolute Unix socket path [env: FABRO_SERVER=]
--debug Enable DEBUG-level logging (default is INFO) [env: FABRO_DEBUG=]
--model <MODEL> LLM model for generating PR description
-f, --force Create PR even if the run status is not succeeded/partially_succeeded
--no-upgrade-check Disable automatic upgrade check [env: FABRO_NO_UPGRADE_CHECK=true]
--quiet Suppress non-essential output [env: FABRO_QUIET=]
--verbose Enable verbose output [env: FABRO_VERBOSE=]
-h, --help Print help
----- stderr -----
");
}
#[test]
fn pr_create_nongit_run_reports_missing_repo_origin() {
let context = test_context!();
let run = setup_seeded_completed_dry_run(&context);
let mut cmd = context.command();
cmd.args(["pr", "create", &run.run_id]);
fabro_snapshot!(context.filters(), cmd, @"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
× Run has no repo origin URL — pull request creation requires git metadata.
");
}
#[test]
fn pr_create_uses_server_endpoint_and_prints_url() {
let context = test_context!();
let server = MockServer::start();
let run_id = unique_run_id();
let resolve_mock = mock_resolved_run(&server, "nightly-build", &run_id);
let create_mock = server.mock(|when, then| {
when.method("POST")
.path(format!("/api/v1/runs/{run_id}/pull_request"))
.header("content-type", "application/json")
.json_body(serde_json::json!({
"force": false
}));
then.status(202)
.header("Content-Type", "application/json")
.json_body(serde_json::json!({
"id": "01KYYK70WTZT2E551P3H5P0059",
"status": "pending",
"model": "kimi-k3",
"force": false,
"requested_at": "2026-08-01T12:00:00Z",
"updated_at": "2026-08-01T12:00:00Z"
}));
});
let status_mock = server.mock(|when, then| {
when.method("GET")
.path(format!("/api/v1/runs/{run_id}/pull_request/creation"));
then.status(200)
.header("Content-Type", "application/json")
.json_body(serde_json::json!({
"id": "01KYYK70WTZT2E551P3H5P0059",
"status": "succeeded",
"model": "kimi-k3",
"force": false,
"requested_at": "2026-08-01T12:00:00Z",
"updated_at": "2026-08-01T12:00:15Z",
"pull_request": {
"owner": "fabro-sh",
"repo": "fabro",
"number": 123,
"html_url": "https://github.com/fabro-sh/fabro/pull/123"
}
}));
});
let mut cmd = context.command();
cmd.args([
"pr",
"create",
"--server",
&server.base_url(),
"nightly-build",
]);
fabro_snapshot!(context.filters(), cmd, @"
success: true
exit_code: 0
----- stdout -----
https://github.com/fabro-sh/fabro/pull/123
----- stderr -----
");
resolve_mock.assert();
create_mock.assert();
status_mock.assert();
}
#[test]
fn pr_create_passes_force_and_model_to_server() {
let context = test_context!();
let server = MockServer::start();
let run_id = unique_run_id();
let resolve_mock = mock_resolved_run(&server, "nightly-build", &run_id);
let create_mock = server.mock(|when, then| {
when.method("POST")
.path(format!("/api/v1/runs/{run_id}/pull_request"))
.header("content-type", "application/json")
.json_body(serde_json::json!({
"force": true,
"model": "gpt-5.2"
}));
then.status(202)
.header("Content-Type", "application/json")
.json_body(serde_json::json!({
"id": "01KYYK70WTZT2E551P3H5P0059",
"status": "pending",
"model": "gpt-5.2",
"force": true,
"requested_at": "2026-08-01T12:00:00Z",
"updated_at": "2026-08-01T12:00:00Z"
}));
});
let status_mock = server.mock(|when, then| {
when.method("GET")
.path(format!("/api/v1/runs/{run_id}/pull_request/creation"));
then.status(200)
.header("Content-Type", "application/json")
.json_body(serde_json::json!({
"id": "01KYYK70WTZT2E551P3H5P0059",
"status": "succeeded",
"model": "gpt-5.2",
"force": true,
"requested_at": "2026-08-01T12:00:00Z",
"updated_at": "2026-08-01T12:00:15Z",
"pull_request": {
"owner": "fabro-sh",
"repo": "fabro",
"number": 123,
"html_url": "https://github.com/fabro-sh/fabro/pull/123"
}
}));
});
let mut cmd = context.command();
cmd.args([
"pr",
"create",
"--json",
"--force",
"--model",
"gpt-5.2",
"--server",
&server.base_url(),
"nightly-build",
]);
fabro_snapshot!(context.filters(), cmd, @r#"
success: true
exit_code: 0
----- stdout -----
{
"owner": "fabro-sh",
"repo": "fabro",
"number": 123,
"html_url": "https://github.com/fabro-sh/fabro/pull/123"
}
----- stderr -----
"#);
resolve_mock.assert();
create_mock.assert();
status_mock.assert();
}