feat: add normalized document model and output writer
This commit is contained in:
Generated
+84
@@ -110,6 +110,9 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"clap",
|
"clap",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -124,6 +127,18 @@ version = "1.70.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
|
checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itoa"
|
||||||
|
version = "1.0.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell_polyfill"
|
name = "once_cell_polyfill"
|
||||||
version = "1.70.2"
|
version = "1.70.2"
|
||||||
@@ -148,6 +163,49 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde"
|
||||||
|
version = "1.0.228"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
|
||||||
|
dependencies = [
|
||||||
|
"serde_core",
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_core"
|
||||||
|
version = "1.0.228"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
|
||||||
|
dependencies = [
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_derive"
|
||||||
|
version = "1.0.228"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_json"
|
||||||
|
version = "1.0.149"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
|
||||||
|
dependencies = [
|
||||||
|
"itoa",
|
||||||
|
"memchr",
|
||||||
|
"serde",
|
||||||
|
"serde_core",
|
||||||
|
"zmij",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
version = "0.11.1"
|
version = "0.11.1"
|
||||||
@@ -165,6 +223,26 @@ dependencies = [
|
|||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror"
|
||||||
|
version = "1.0.69"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
|
||||||
|
dependencies = [
|
||||||
|
"thiserror-impl",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror-impl"
|
||||||
|
version = "1.0.69"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.24"
|
version = "1.0.24"
|
||||||
@@ -191,3 +269,9 @@ checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-link",
|
"windows-link",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zmij"
|
||||||
|
version = "1.0.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
|
||||||
|
|||||||
@@ -6,3 +6,6 @@ edition = "2024"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
clap = { version = "4.5", features = ["derive"] }
|
clap = { version = "4.5", features = ["derive"] }
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
serde_json = "1.0"
|
||||||
|
thiserror = "1.0"
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum AppError {
|
||||||
|
#[error("missing required environment variable: {0}")]
|
||||||
|
MissingEnv(&'static str),
|
||||||
|
#[error("api error: {0}")]
|
||||||
|
Api(String),
|
||||||
|
#[error("invalid input json: {0}")]
|
||||||
|
InvalidInputJson(String),
|
||||||
|
}
|
||||||
@@ -1,4 +1,7 @@
|
|||||||
pub mod cli;
|
pub mod cli;
|
||||||
|
pub mod error;
|
||||||
|
pub mod model;
|
||||||
|
pub mod output;
|
||||||
|
|
||||||
pub fn run() -> anyhow::Result<()> {
|
pub fn run() -> anyhow::Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct PrReviewDocument {
|
||||||
|
pub meta: PrMeta,
|
||||||
|
pub commits: Vec<CommitItem>,
|
||||||
|
pub diff_stat: DiffStat,
|
||||||
|
pub reviews: Vec<ReviewItem>,
|
||||||
|
pub threads: Vec<CommentThread>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct PrMeta {
|
||||||
|
pub repo: String,
|
||||||
|
pub pr_index: i64,
|
||||||
|
pub title: String,
|
||||||
|
pub state: String,
|
||||||
|
pub author: String,
|
||||||
|
pub base_branch: String,
|
||||||
|
pub head_branch: String,
|
||||||
|
pub created_at: String,
|
||||||
|
pub updated_at: String,
|
||||||
|
pub merged_at: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct CommitItem {
|
||||||
|
pub sha: String,
|
||||||
|
pub short_sha: String,
|
||||||
|
pub title: String,
|
||||||
|
pub author: String,
|
||||||
|
pub date: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct DiffStat {
|
||||||
|
pub files_changed: usize,
|
||||||
|
pub additions: i64,
|
||||||
|
pub deletions: i64,
|
||||||
|
pub files: Vec<FileStat>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct FileStat {
|
||||||
|
pub path: String,
|
||||||
|
pub additions: i64,
|
||||||
|
pub deletions: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct ReviewItem {
|
||||||
|
pub id: i64,
|
||||||
|
pub state: String,
|
||||||
|
pub reviewer: String,
|
||||||
|
pub submitted_at: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct CommentThread {
|
||||||
|
pub thread_id: String,
|
||||||
|
pub file_path: Option<String>,
|
||||||
|
pub line: Option<i64>,
|
||||||
|
pub root_comment: CommentItem,
|
||||||
|
pub replies: Vec<CommentItem>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct CommentItem {
|
||||||
|
pub id: i64,
|
||||||
|
pub user: String,
|
||||||
|
pub created_at: String,
|
||||||
|
pub body: String,
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
use std::io::Write;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
pub fn write_output(out: Option<&Path>, content: &str) -> anyhow::Result<()> {
|
||||||
|
if let Some(path) = out {
|
||||||
|
std::fs::write(path, content)?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut stdout = std::io::stdout().lock();
|
||||||
|
stdout.write_all(content.as_bytes())?;
|
||||||
|
stdout.flush()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
use gitea_pr_review::model::{CommentItem, CommentThread, DiffStat, FileStat, PrMeta, PrReviewDocument};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn model_json_roundtrip() {
|
||||||
|
let doc = PrReviewDocument {
|
||||||
|
meta: PrMeta {
|
||||||
|
repo: "org/repo".into(),
|
||||||
|
pr_index: 9,
|
||||||
|
title: "feat: x".into(),
|
||||||
|
state: "open".into(),
|
||||||
|
author: "alice".into(),
|
||||||
|
base_branch: "main".into(),
|
||||||
|
head_branch: "feature/x".into(),
|
||||||
|
created_at: "2026-04-08T10:00:00Z".into(),
|
||||||
|
updated_at: "2026-04-08T11:00:00Z".into(),
|
||||||
|
merged_at: None,
|
||||||
|
},
|
||||||
|
commits: vec![],
|
||||||
|
diff_stat: DiffStat {
|
||||||
|
files_changed: 1,
|
||||||
|
additions: 2,
|
||||||
|
deletions: 1,
|
||||||
|
files: vec![FileStat {
|
||||||
|
path: "src/main.rs".into(),
|
||||||
|
additions: 2,
|
||||||
|
deletions: 1,
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
reviews: vec![],
|
||||||
|
threads: vec![CommentThread {
|
||||||
|
thread_id: "t1".into(),
|
||||||
|
file_path: Some("src/main.rs".into()),
|
||||||
|
line: Some(10),
|
||||||
|
root_comment: CommentItem {
|
||||||
|
id: 100,
|
||||||
|
user: "reviewer".into(),
|
||||||
|
created_at: "2026-04-08T12:00:00Z".into(),
|
||||||
|
body: "hello".into(),
|
||||||
|
},
|
||||||
|
replies: vec![],
|
||||||
|
}],
|
||||||
|
};
|
||||||
|
|
||||||
|
let encoded = serde_json::to_string(&doc).unwrap();
|
||||||
|
let decoded: PrReviewDocument = serde_json::from_str(&encoded).unwrap();
|
||||||
|
assert_eq!(decoded.meta.repo, "org/repo");
|
||||||
|
assert_eq!(decoded.threads[0].root_comment.body, "hello");
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user