use ingest::LossyImportEntry;
use objects::object::{State, Status};
use sley::ObjectId as GitObjectId;
use super::git_core::GitBridge;
impl<'a> GitBridge<'a> {
pub(crate) fn build_commit_message(state: &State) -> String {
let _ = Status::Draft;
state
.intent
.clone()
.unwrap_or_else(|| "No intent specified".to_string())
}
pub(crate) fn build_commit_message_with_footer(
state: &State,
hosted_url: Option<&str>,
annotations_omitted: u32,
) -> String {
let body = Self::build_commit_message(state);
Self::build_commit_message_with_footer_with_body(
state,
&body,
hosted_url,
annotations_omitted,
)
}
pub(crate) fn build_commit_message_with_footer_with_body(
state: &State,
body: &str,
hosted_url: Option<&str>,
annotations_omitted: u32,
) -> String {
let mut out = body.to_string();
if !out.ends_with('\n') {
out.push('\n');
}
out.push('\n');
out.push_str(&format!(
"Heddle-State: {}\n",
state.change_id.to_string_full()
));
if let Some(url) = hosted_url
&& !url.is_empty()
{
let trimmed = url.trim_end_matches('/');
out.push_str(&format!(
"Heddle-URL: {trimmed}/state/{}\n",
state.change_id.to_string_full()
));
}
out.push_str(&format!(
"Heddle-Annotations-Omitted: {annotations_omitted}\n"
));
out
}
}
#[derive(Debug, Default)]
pub struct ExportStats {
pub states_exported: usize,
pub commits_total: usize,
pub threads_synced: usize,
pub markers_synced: usize,
pub branches: Vec<ExportedRef>,
pub tags: Vec<ExportedRef>,
}
#[derive(Debug, Clone)]
pub struct ExportedRef {
pub name: String,
pub tip: GitObjectId,
}
#[derive(Debug, Default)]
pub struct ImportStats {
pub commits_imported: usize,
pub states_created: usize,
pub branches_synced: usize,
pub tags_synced: usize,
pub skipped_non_commit_refs: usize,
pub lossy_entries: Vec<LossyImportEntry>,
}
#[cfg(test)]
mod tests {
use objects::object::{Attribution, ChangeId, ContentHash, Principal};
use super::*;
fn sample_state() -> State {
State::new_snapshot(
ContentHash::compute(b"tree"),
vec![],
Attribution::human(Principal::new("Alice", "alice@example.com")),
)
.with_intent("ship the auth rewrite")
}
#[test]
fn footer_emits_state_id_and_zero_omitted_when_no_url() {
let state = sample_state();
let msg = GitBridge::build_commit_message_with_footer(&state, None, 0);
assert!(msg.contains(&format!(
"Heddle-State: {}",
state.change_id.to_string_full()
)));
assert!(msg.contains("Heddle-Annotations-Omitted: 0"));
assert!(!msg.contains("Heddle-URL:"));
}
#[test]
fn footer_emits_url_when_hosted_configured() {
let state = sample_state();
let msg =
GitBridge::build_commit_message_with_footer(&state, Some("https://heddle.test/"), 3);
assert!(msg.contains(&format!(
"Heddle-URL: https://heddle.test/state/{}",
state.change_id.to_string_full()
)));
assert!(msg.contains("Heddle-Annotations-Omitted: 3"));
}
#[test]
fn change_id_round_trips_through_footer() {
let state = sample_state();
let id_str = state.change_id.to_string_full();
let _: ChangeId = ChangeId::parse(&id_str).expect("round-trip parse");
}
}