115 lines
3.7 KiB
Rust
115 lines
3.7 KiB
Rust
use git::rpc::{proto as p, proto::commit_service_client::CommitServiceClient};
|
|
use session::Session;
|
|
|
|
use crate::{AppService, error::AppError, git::rpc_err};
|
|
|
|
#[derive(Debug, Clone, serde::Serialize, utoipa::ToSchema)]
|
|
pub struct CompareResponse {
|
|
pub base_commit: CompareCommit,
|
|
pub head_commit: CompareCommit,
|
|
pub ahead_by: i32,
|
|
pub behind_by: i32,
|
|
pub total_commits: i32,
|
|
pub commits: Vec<CompareCommit>,
|
|
pub files_changed: u64,
|
|
pub insertions: u64,
|
|
pub deletions: u64,
|
|
}
|
|
|
|
#[derive(Debug, Clone, serde::Serialize, utoipa::ToSchema)]
|
|
pub struct CompareCommit {
|
|
pub sha: String,
|
|
pub message: String,
|
|
pub author_name: Option<String>,
|
|
pub author_email: Option<String>,
|
|
}
|
|
|
|
impl AppService {
|
|
pub async fn git_compare(
|
|
&self,
|
|
ctx: &Session,
|
|
wk_name: &str,
|
|
repo_name: &str,
|
|
base: &str,
|
|
head: &str,
|
|
) -> Result<CompareResponse, AppError> {
|
|
let repo = self.git_require_member(ctx, wk_name, repo_name).await?;
|
|
let mut client = CommitServiceClient::new(self.git.clone());
|
|
|
|
fn oid(s: &str) -> p::ObjectId {
|
|
p::ObjectId { value: s.to_string() }
|
|
}
|
|
|
|
let base_info = client
|
|
.commit_info(tonic::Request::new(p::CommitInfoRequest {
|
|
repo_id: repo.id.to_string(),
|
|
oid: Some(oid(base)),
|
|
}))
|
|
.await.map_err(rpc_err)?.into_inner();
|
|
|
|
let head_info = client
|
|
.commit_info(tonic::Request::new(p::CommitInfoRequest {
|
|
repo_id: repo.id.to_string(),
|
|
oid: Some(oid(head)),
|
|
}))
|
|
.await.map_err(rpc_err)?.into_inner();
|
|
|
|
let history = client
|
|
.commit_history(tonic::Request::new(p::CommitHistoryRequest {
|
|
repo_id: repo.id.to_string(),
|
|
limit: 250, skip: 0, sort: 0,
|
|
branch: Some(format!("{base}..{head}")),
|
|
}))
|
|
.await.map_err(rpc_err)?.into_inner();
|
|
|
|
let commits: Vec<CompareCommit> = history.commits.into_iter().map(|c| {
|
|
let author_name = c.author.as_ref().map(|a| a.name.clone());
|
|
let author_email = c.author.as_ref().map(|a| a.email.clone());
|
|
CompareCommit {
|
|
sha: c.oid.map(|o| o.value).unwrap_or_default(),
|
|
message: c.summary,
|
|
author_name,
|
|
author_email,
|
|
}
|
|
}).collect();
|
|
|
|
let diff = crate::AppService::git_diff_stats(
|
|
self, ctx, wk_name, repo_name,
|
|
base.to_string(), head.to_string(), None,
|
|
).await?;
|
|
|
|
let stats = diff.result.and_then(|r| r.stats);
|
|
let files_changed = stats.as_ref().map(|s| s.files_changed).unwrap_or(0);
|
|
let insertions = stats.as_ref().map(|s| s.insertions).unwrap_or(0);
|
|
let deletions = stats.as_ref().map(|s| s.deletions).unwrap_or(0);
|
|
|
|
Ok(CompareResponse {
|
|
base_commit: cmt(base_info.commit),
|
|
head_commit: cmt(head_info.commit),
|
|
ahead_by: commits.len() as i32,
|
|
behind_by: 0,
|
|
total_commits: commits.len() as i32,
|
|
commits,
|
|
files_changed,
|
|
insertions,
|
|
deletions,
|
|
})
|
|
}
|
|
}
|
|
|
|
fn cmt(c: Option<p::CommitMeta>) -> CompareCommit {
|
|
c.map(|c| {
|
|
let author_name = c.author.as_ref().map(|a| a.name.clone());
|
|
let author_email = c.author.as_ref().map(|a| a.email.clone());
|
|
CompareCommit {
|
|
sha: c.oid.map(|o| o.value).unwrap_or_default(),
|
|
message: c.message,
|
|
author_name,
|
|
author_email,
|
|
}
|
|
}).unwrap_or_else(|| CompareCommit {
|
|
sha: String::new(), message: String::new(),
|
|
author_name: None, author_email: None,
|
|
})
|
|
}
|