use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub struct PrIdentifier {
pub provider: String,
pub owner: String,
pub repo: String,
pub number: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct User {
pub login: String,
pub display_name: Option<String>,
pub avatar_url: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Reviewer {
pub user: User,
pub state: ReviewerState,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ReviewerState {
Pending,
Approved,
ChangesRequested,
Dismissed,
Commented,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum PrState {
Open,
Closed,
Merged,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ReviewStatus {
NeedsReview,
Approved,
ChangesRequested,
Mixed,
InReview,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum CiStatus {
Pending,
Running,
Success,
Failed,
Cancelled,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PullRequest {
pub id: PrIdentifier,
pub number: u64,
pub title: String,
pub url: String,
pub author: User,
pub reviewers: Vec<Reviewer>,
pub repo_full_name: String, pub provider: String,
pub head_branch: String,
pub base_branch: String,
pub state: PrState,
pub review_status: ReviewStatus,
pub ci_status: Option<CiStatus>, pub draft: bool,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
pub labels: Vec<String>,
pub comment_count: u32,
pub additions: Option<u32>, pub deletions: Option<u32>,
}
#[cfg(test)]
mod tests {
use super::*;
use chrono::Utc;
#[test]
fn models_round_trip() {
let pr = PullRequest {
id: PrIdentifier {
provider: "mock".to_string(),
owner: "acme".to_string(),
repo: "widget".to_string(),
number: 42,
},
number: 42,
title: "feat: round trip test".to_string(),
url: "https://github.com/acme/widget/pull/42".to_string(),
author: User {
login: "alice".to_string(),
display_name: None,
avatar_url: None,
},
reviewers: vec![],
repo_full_name: "acme/widget".to_string(),
provider: "mock".to_string(),
head_branch: "feat/test".to_string(),
base_branch: "main".to_string(),
state: PrState::Open,
review_status: ReviewStatus::NeedsReview,
ci_status: None,
draft: false,
created_at: Utc::now(),
updated_at: Utc::now(),
labels: vec![],
comment_count: 0,
additions: None,
deletions: None,
};
let json = serde_json::to_string(&pr).expect("serialization failed");
let deserialized: PullRequest = serde_json::from_str(&json).expect("deserialization failed");
assert_eq!(deserialized.number, 42);
}
}