feat: implement fetch pipeline and e2e coverage
This commit is contained in:
+22
-3
@@ -1,3 +1,4 @@
|
||||
use std::env;
|
||||
use std::path::Path;
|
||||
|
||||
use clap::Parser;
|
||||
@@ -11,6 +12,8 @@ pub mod output;
|
||||
pub mod render;
|
||||
|
||||
use crate::cli::{Cli, Commands, OutputFormat};
|
||||
use crate::gitea::client::GiteaClient;
|
||||
use crate::normalize::normalize_bundle;
|
||||
use crate::output::write_output;
|
||||
use crate::render::json::{parse_json, render_json};
|
||||
use crate::render::markdown::render_markdown;
|
||||
@@ -25,11 +28,27 @@ pub fn run() -> anyhow::Result<()> {
|
||||
let md = render_markdown(&doc);
|
||||
write_output(args.out.as_deref().map(Path::new), &md)?;
|
||||
}
|
||||
Commands::Fetch(_args) => {
|
||||
let _ = OutputFormat::Markdown;
|
||||
let _ = render_json;
|
||||
Commands::Fetch(args) => {
|
||||
let token = required_env("GITEA_PR_CLI_API_TOKEN")?;
|
||||
let base_url = required_env("GITEA_PR_CLI_URL")?;
|
||||
let repo = required_env("GITEA_PR_CLI_REPO")?;
|
||||
|
||||
let client = GiteaClient::new(base_url, token);
|
||||
let bundle = client.fetch_pr_bundle(&repo, args.pr_index)?;
|
||||
let doc = normalize_bundle(&repo, bundle);
|
||||
|
||||
let rendered = match args.format {
|
||||
OutputFormat::Markdown => render_markdown(&doc),
|
||||
OutputFormat::Json => render_json(&doc)?,
|
||||
};
|
||||
|
||||
write_output(args.out.as_deref().map(Path::new), &rendered)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn required_env(name: &'static str) -> anyhow::Result<String> {
|
||||
env::var(name).map_err(|_| anyhow::anyhow!("missing required environment variable: {name}"))
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use assert_cmd::Command;
|
||||
use mockito::Server;
|
||||
use tempfile::NamedTempFile;
|
||||
|
||||
#[test]
|
||||
@@ -92,3 +93,198 @@ fn render_md_writes_to_out_file_when_requested() {
|
||||
assert!(written.contains("# org/repo `#2` t2"));
|
||||
assert!(written.contains("## Metadata"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fetch_fails_when_required_env_is_missing() {
|
||||
let assert = Command::cargo_bin("gitea-pr-review")
|
||||
.unwrap()
|
||||
.args(["fetch", "1"])
|
||||
.env_remove("GITEA_PR_CLI_API_TOKEN")
|
||||
.env_remove("GITEA_PR_CLI_URL")
|
||||
.env_remove("GITEA_PR_CLI_REPO")
|
||||
.assert()
|
||||
.failure();
|
||||
|
||||
let stderr = String::from_utf8(assert.get_output().stderr.clone()).unwrap();
|
||||
assert!(
|
||||
stderr.contains("missing required environment variable: GITEA_PR_CLI_API_TOKEN"),
|
||||
"stderr was: {stderr}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fetch_writes_markdown_to_stdout_by_default() {
|
||||
let mut server = Server::new();
|
||||
let pull_path = "/api/v1/repos/org/repo/pulls/7";
|
||||
|
||||
server
|
||||
.mock("GET", pull_path)
|
||||
.with_status(200)
|
||||
.with_body(
|
||||
r#"{
|
||||
"number": 7,
|
||||
"title": "Fix parser",
|
||||
"state": "open",
|
||||
"body": "PR body",
|
||||
"user": { "login": "alice" },
|
||||
"base": { "ref": "main" },
|
||||
"head": { "ref": "feature/x" },
|
||||
"created_at": "2026-04-08T10:00:00Z",
|
||||
"updated_at": "2026-04-08T11:00:00Z",
|
||||
"merged_at": null,
|
||||
"additions": 3,
|
||||
"deletions": 1,
|
||||
"changed_files": 1
|
||||
}"#,
|
||||
)
|
||||
.create();
|
||||
server
|
||||
.mock("GET", "/api/v1/repos/org/repo/pulls/7/reviews")
|
||||
.with_status(200)
|
||||
.with_body(
|
||||
r#"[
|
||||
{
|
||||
"id": 55,
|
||||
"state": "COMMENT",
|
||||
"user": { "login": "bob" },
|
||||
"submitted_at": "2026-04-08T12:00:00Z"
|
||||
}
|
||||
]"#,
|
||||
)
|
||||
.create();
|
||||
server
|
||||
.mock("GET", "/api/v1/repos/org/repo/pulls/7/reviews/55/comments")
|
||||
.with_status(200)
|
||||
.with_body(
|
||||
r#"[
|
||||
{
|
||||
"id": 501,
|
||||
"body": "please fix",
|
||||
"created_at": "2026-04-08T12:01:00Z",
|
||||
"updated_at": null,
|
||||
"user": { "login": "bob" },
|
||||
"path": "src/main.rs",
|
||||
"line": 12,
|
||||
"pull_request_review_id": 55,
|
||||
"original_position": 1,
|
||||
"position": 1,
|
||||
"commit_id": "abcdef123456",
|
||||
"original_commit_id": "abcdef123456",
|
||||
"diff_hunk": "@@ -1,1 +1,1 @@"
|
||||
}
|
||||
]"#,
|
||||
)
|
||||
.create();
|
||||
server
|
||||
.mock("GET", "/api/v1/repos/org/repo/pulls/7/commits")
|
||||
.with_status(200)
|
||||
.with_body(
|
||||
r#"[
|
||||
{
|
||||
"sha": "abcdef1234567890",
|
||||
"commit": {
|
||||
"message": "fix: parser\n\nbody",
|
||||
"author": { "name": "alice", "date": "2026-04-08T10:30:00Z" }
|
||||
}
|
||||
}
|
||||
]"#,
|
||||
)
|
||||
.create();
|
||||
server
|
||||
.mock("GET", "/api/v1/repos/org/repo/pulls/7/files")
|
||||
.with_status(200)
|
||||
.with_body(
|
||||
r#"[
|
||||
{
|
||||
"filename": "src/main.rs",
|
||||
"additions": 3,
|
||||
"deletions": 1,
|
||||
"changes": 4,
|
||||
"status": "modified",
|
||||
"previous_filename": null
|
||||
}
|
||||
]"#,
|
||||
)
|
||||
.create();
|
||||
|
||||
let assert = Command::cargo_bin("gitea-pr-review")
|
||||
.unwrap()
|
||||
.args(["fetch", "7"])
|
||||
.env("GITEA_PR_CLI_API_TOKEN", "token")
|
||||
.env("GITEA_PR_CLI_URL", server.url())
|
||||
.env("GITEA_PR_CLI_REPO", "org/repo")
|
||||
.assert()
|
||||
.success();
|
||||
|
||||
let stdout = String::from_utf8(assert.get_output().stdout.clone()).unwrap();
|
||||
assert!(stdout.contains("# org/repo `#7` Fix parser"));
|
||||
assert!(stdout.contains("## Commits"));
|
||||
assert!(stdout.contains("## Diff Stat"));
|
||||
assert!(stdout.contains("## Review 1 (COMMENT)"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fetch_writes_json_to_out_file_when_requested() {
|
||||
let mut server = Server::new();
|
||||
let pull_path = "/api/v1/repos/org/repo/pulls/8";
|
||||
|
||||
server
|
||||
.mock("GET", pull_path)
|
||||
.with_status(200)
|
||||
.with_body(
|
||||
r#"{
|
||||
"number": 8,
|
||||
"title": "Add feature",
|
||||
"state": "open",
|
||||
"body": "PR body",
|
||||
"user": { "login": "alice" },
|
||||
"base": { "ref": "main" },
|
||||
"head": { "ref": "feature/y" },
|
||||
"created_at": "2026-04-08T10:00:00Z",
|
||||
"updated_at": "2026-04-08T11:00:00Z",
|
||||
"merged_at": null,
|
||||
"additions": 0,
|
||||
"deletions": 0,
|
||||
"changed_files": 0
|
||||
}"#,
|
||||
)
|
||||
.create();
|
||||
server
|
||||
.mock("GET", "/api/v1/repos/org/repo/pulls/8/reviews")
|
||||
.with_status(200)
|
||||
.with_body("[]")
|
||||
.create();
|
||||
server
|
||||
.mock("GET", "/api/v1/repos/org/repo/pulls/8/commits")
|
||||
.with_status(200)
|
||||
.with_body("[]")
|
||||
.create();
|
||||
server
|
||||
.mock("GET", "/api/v1/repos/org/repo/pulls/8/files")
|
||||
.with_status(200)
|
||||
.with_body("[]")
|
||||
.create();
|
||||
|
||||
let output = NamedTempFile::new().unwrap();
|
||||
|
||||
Command::cargo_bin("gitea-pr-review")
|
||||
.unwrap()
|
||||
.args([
|
||||
"fetch",
|
||||
"8",
|
||||
"--format",
|
||||
"json",
|
||||
"--out",
|
||||
output.path().to_str().unwrap(),
|
||||
])
|
||||
.env("GITEA_PR_CLI_API_TOKEN", "token")
|
||||
.env("GITEA_PR_CLI_URL", server.url())
|
||||
.env("GITEA_PR_CLI_REPO", "org/repo")
|
||||
.assert()
|
||||
.success();
|
||||
|
||||
let written = std::fs::read_to_string(output.path()).unwrap();
|
||||
assert!(written.contains("\"repo\": \"org/repo\""));
|
||||
assert!(written.contains("\"pr_index\": 8"));
|
||||
assert!(written.contains("\"head_branch\": \"feature/y\""));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user