use crate::config_snapshot::ConfigSnapshot;
use crate::diagnostic_log::warn;
use crate::service_protocol::is_zero_object;
use crate::transaction_git::{GitContext, GitRequest, run_git_checked};
use std::path::Path;
const LAST_RESORT_LENGTH: usize = 7;
const ABBREVIATION_KEY: &str = "core.abbrev";
pub fn subject_of(message: &str) -> String {
let mut words: Vec<&str> = Vec::new();
for line in message.lines().skip_while(|line| { return line.trim().is_empty(); }) {
if line.trim().is_empty() {
break;
}
words.push(line.trim());
}
return words.join(" ");
}
pub fn summary_line(reference: &str, first_parent: &str, name: &str, subject: &str) -> String {
let branch: &str = if reference == "HEAD" { "detached HEAD" } else { reference.trim_start_matches("refs/heads/") };
let root: &str = if first_parent.is_empty() || is_zero_object(first_parent) { " (root-commit)" } else { "" };
return format!("[{branch}{root} {name}] {subject}");
}
fn configured(snapshot: &ConfigSnapshot) -> Option<Option<Vec<u8>>> {
return snapshot.entries().iter().rev().find(|entry| { return entry.key == ABBREVIATION_KEY; }).map(|entry| { return entry.value.clone(); });
}
fn asked_of_git(context: &GitContext, cwd: &Path, commit: &str) -> Option<String> {
let request: GitRequest = GitRequest::new(cwd, &["rev-parse", "--verify", "--short", commit]);
return match run_git_checked(context, &request) {
Ok(output) => Some(String::from_utf8_lossy(output.stdout.as_slice()).trim().to_string()).filter(|text| { return !text.is_empty(); }),
Err(failure) => {
warn("landedSummary", format!("asking Git for the abbreviated name failed: {failure}").as_str());
None
}
};
}
#[cfg(unix)]
pub fn short_name(context: &GitContext, cwd: &Path, object_directory: &Path, config: Option<&ConfigSnapshot>, commit: &str) -> String {
use crate::object_abbreviation::{Setting, abbreviate, setting_of};
let from_files: Option<String> = config.and_then(|snapshot| {
let setting: Setting = match configured(snapshot) {
Some(value) => setting_of(value.as_deref()),
None => Setting::Auto,
};
return abbreviate(object_directory, setting, commit);
});
return from_files
.or_else(|| { return asked_of_git(context, cwd, commit); })
.unwrap_or_else(|| { return commit.get(..LAST_RESORT_LENGTH).unwrap_or(commit).to_string(); });
}
#[cfg(not(unix))]
pub fn short_name(context: &GitContext, cwd: &Path, _object_directory: &Path, _config: Option<&ConfigSnapshot>, commit: &str) -> String {
return asked_of_git(context, cwd, commit).unwrap_or_else(|| { return commit.get(..LAST_RESORT_LENGTH).unwrap_or(commit).to_string(); });
}
pub fn rebuilt_note(unlanded: &[String], landed: &str) -> String {
let names: String = match unlanded.split_last() {
None => String::new(),
Some((only, [])) => only.clone(),
Some((last, front)) => format!("{} and {last}", front.join(", ")),
};
return format!("cli-git: the branch moved during the commit, so it was built again; {names} did not land, {landed} did.");
}
#[cfg(test)]
#[path = "landed_summary_tests.rs"]
mod tests;