feat: add gitea API client and DTO bundle fetch
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
use anyhow::{Context, Result};
|
||||
use reqwest::blocking::Client;
|
||||
|
||||
use crate::gitea::dto::{
|
||||
ChangedFileDto, CommitDto, PullBundleDto, PullDto, ReviewCommentDto, ReviewDto,
|
||||
};
|
||||
|
||||
pub struct GiteaClient {
|
||||
base_url: String,
|
||||
token: String,
|
||||
http: Client,
|
||||
}
|
||||
|
||||
impl GiteaClient {
|
||||
pub fn new(base_url: String, token: String) -> Self {
|
||||
Self {
|
||||
base_url,
|
||||
token,
|
||||
http: Client::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn endpoint(&self, path: &str) -> String {
|
||||
format!(
|
||||
"{}/{}",
|
||||
self.base_url.trim_end_matches('/'),
|
||||
path.trim_start_matches('/')
|
||||
)
|
||||
}
|
||||
|
||||
fn get_json<T: serde::de::DeserializeOwned>(&self, path: &str) -> Result<T> {
|
||||
let response = self
|
||||
.http
|
||||
.get(self.endpoint(path))
|
||||
.header("Authorization", format!("token {}", self.token))
|
||||
.send()
|
||||
.with_context(|| format!("request failed for {path}"))?
|
||||
.error_for_status()
|
||||
.with_context(|| format!("gitea api returned error for {path}"))?;
|
||||
|
||||
response
|
||||
.json::<T>()
|
||||
.with_context(|| format!("decode gitea response failed for {path}"))
|
||||
}
|
||||
|
||||
pub fn fetch_pr_bundle(&self, repo: &str, pr_index: i64) -> Result<PullBundleDto> {
|
||||
let pull_path = format!("/api/v1/repos/{repo}/pulls/{pr_index}");
|
||||
let reviews_path = format!("{pull_path}/reviews");
|
||||
let commits_path = format!("{pull_path}/commits");
|
||||
let files_path = format!("{pull_path}/files");
|
||||
|
||||
let pull: PullDto = self.get_json(&pull_path)?;
|
||||
let reviews: Vec<ReviewDto> = self.get_json(&reviews_path)?;
|
||||
let mut comments = Vec::new();
|
||||
for review in &reviews {
|
||||
let review_comments_path = format!("{pull_path}/reviews/{}/comments", review.id);
|
||||
let mut review_comments: Vec<ReviewCommentDto> =
|
||||
self.get_json(&review_comments_path)?;
|
||||
comments.append(&mut review_comments);
|
||||
}
|
||||
let commits: Vec<CommitDto> = self.get_json(&commits_path)?;
|
||||
let files: Vec<ChangedFileDto> = self.get_json(&files_path)?;
|
||||
|
||||
Ok(PullBundleDto {
|
||||
pull,
|
||||
reviews,
|
||||
comments,
|
||||
commits,
|
||||
files,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct UserDto {
|
||||
pub login: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct PullBranchDto {
|
||||
#[serde(rename = "ref")]
|
||||
pub ref_name: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct PullDto {
|
||||
pub number: i64,
|
||||
pub title: String,
|
||||
pub state: String,
|
||||
pub body: Option<String>,
|
||||
pub user: UserDto,
|
||||
pub base: PullBranchDto,
|
||||
pub head: PullBranchDto,
|
||||
pub created_at: String,
|
||||
pub updated_at: String,
|
||||
pub merged_at: Option<String>,
|
||||
pub additions: Option<i64>,
|
||||
pub deletions: Option<i64>,
|
||||
pub changed_files: Option<i64>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct ReviewDto {
|
||||
pub id: i64,
|
||||
pub state: String,
|
||||
pub user: UserDto,
|
||||
pub submitted_at: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct ReviewCommentDto {
|
||||
pub id: i64,
|
||||
pub body: String,
|
||||
pub created_at: String,
|
||||
pub updated_at: Option<String>,
|
||||
pub user: UserDto,
|
||||
pub path: Option<String>,
|
||||
pub line: Option<i64>,
|
||||
pub pull_request_review_id: Option<i64>,
|
||||
pub original_position: Option<u64>,
|
||||
pub position: Option<u64>,
|
||||
pub commit_id: Option<String>,
|
||||
pub original_commit_id: Option<String>,
|
||||
pub diff_hunk: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct CommitUserDto {
|
||||
pub name: String,
|
||||
pub date: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct RepoCommitDto {
|
||||
pub message: String,
|
||||
pub author: Option<CommitUserDto>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct CommitDto {
|
||||
pub sha: String,
|
||||
pub commit: RepoCommitDto,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct ChangedFileDto {
|
||||
pub filename: String,
|
||||
pub additions: i64,
|
||||
pub deletions: i64,
|
||||
pub changes: Option<i64>,
|
||||
pub status: Option<String>,
|
||||
pub previous_filename: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PullBundleDto {
|
||||
pub pull: PullDto,
|
||||
pub reviews: Vec<ReviewDto>,
|
||||
pub comments: Vec<ReviewCommentDto>,
|
||||
pub commits: Vec<CommitDto>,
|
||||
pub files: Vec<ChangedFileDto>,
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
pub mod client;
|
||||
pub mod dto;
|
||||
@@ -4,6 +4,7 @@ use clap::Parser;
|
||||
|
||||
pub mod cli;
|
||||
pub mod error;
|
||||
pub mod gitea;
|
||||
pub mod model;
|
||||
pub mod output;
|
||||
pub mod render;
|
||||
|
||||
Reference in New Issue
Block a user