use super::RestApiClient;
use crate::{OutputVariable, RestClientError as ClientError, ReviewOptions, ThreadCommentOptions};
#[cfg(feature = "file-changes")]
use crate::{FileDiffLines, FileFilter, LinesChangedOnly, parse_diff};
#[cfg(feature = "file-changes")]
use std::{collections::HashMap, process::Command};
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct LocalClient;
#[async_trait::async_trait]
impl RestApiClient for LocalClient {
#[cfg(feature = "file-changes")]
async fn get_list_of_changed_files(
&self,
file_filter: &FileFilter,
lines_changed_only: &LinesChangedOnly,
base_diff: Option<String>,
ignore_index: bool,
) -> Result<HashMap<String, FileDiffLines>, ClientError> {
let git_status = if ignore_index {
0
} else {
match Command::new("git").args(["status", "--short"]).output() {
Err(e) => {
return Err(ClientError::io("invoke `git status`", e));
}
Ok(output) => {
if output.status.success() {
String::from_utf8_lossy(&output.stdout)
.to_string()
.trim_end_matches('\n')
.lines()
.filter(|l| !l.starts_with(' '))
.count()
} else {
let err_msg = String::from_utf8_lossy(&output.stderr).to_string();
return Err(ClientError::GitCommand(err_msg));
}
}
}
};
let mut diff_args = vec!["diff".to_string()];
if git_status != 0 {
diff_args.push("--staged".to_string());
}
if let Some(base) = base_diff {
match Command::new("git")
.args(["rev-parse", base.as_str()])
.output()
{
Err(e) => {
return Err(ClientError::Io {
task: format!("invoke `git rev-parse {base}` to validate reference"),
source: e,
});
}
Ok(output) => {
if output.status.success() {
diff_args.push(base);
} else if base.chars().all(|c| c.is_ascii_digit()) {
diff_args.push(format!("HEAD~{base}"));
} else {
let err_msg = String::from_utf8_lossy(&output.stderr).to_string();
return Err(ClientError::GitCommand(err_msg));
}
}
}
} else if git_status == 0 {
diff_args.push("HEAD~1".to_string());
}
match Command::new("git").args(&diff_args).output() {
Err(e) => Err(ClientError::Io {
task: format!("invoke `git {}`", diff_args.join(" ")),
source: e,
}),
Ok(output) => {
if output.status.success() {
let diff_str = String::from_utf8_lossy(&output.stdout).to_string();
let files = parse_diff(&diff_str, file_filter, lines_changed_only)?;
Ok(files)
} else {
let err_msg = String::from_utf8_lossy(&output.stderr).to_string();
Err(ClientError::GitCommand(err_msg))
}
}
}
}
fn is_pr_event(&self) -> bool {
false
}
fn set_user_agent(&mut self, _user_agent: &str) -> Result<(), ClientError> {
Ok(())
}
async fn post_thread_comment(&self, _options: ThreadCommentOptions) -> Result<(), ClientError> {
Ok(())
}
async fn cull_pr_reviews(&mut self, _options: &mut ReviewOptions) -> Result<(), ClientError> {
Ok(())
}
async fn post_pr_review(&mut self, _options: &ReviewOptions) -> Result<(), ClientError> {
Ok(())
}
fn write_output_variables(&self, vars: &[OutputVariable]) -> Result<(), ClientError> {
for var in vars {
log::info!("{}: {}", var.name, var.value);
}
Ok(())
}
}