139 lines
4.0 KiB
Rust
139 lines
4.0 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,
|
|
})
|
|
}
|