use crate::auto_push_single_flight::{
PushAttempt, PushGit, SingleFlightError, git_command, git_output, run_query,
};
use crate::bounded_push::{STOP_GRACE, run_bounded_push};
use crate::push_deadline_and_patience_settings::push_patience;
use crate::journald_native::{CLIENT_IDENTIFIER, IDENTIFIER};
use crate::inner_git_words::record_text;
use std::ffi::OsString;
use crate::auto_push_destination::Destination;
pub(crate) const TAG: &str = "monochromatic-git-policy-cli";
pub const RECONCILE_LINE_PREFIX: &str = "monochromatic-git-policy-cli: auto-push: ";
pub const RECONCILE_FAILED_PREFIX: &str = "monochromatic-git-policy-cli: auto-push: not published: ";
pub const MAX_RECONCILE_ATTEMPTS: u32 = 10;
pub(crate) const REJECTED_MARKER: &str = "[rejected]";
pub(crate) const REMOTE_REJECTED_MARKER: &str = "[remote rejected]";
pub fn was_rejected_as_stale(output: &str) -> bool {
return output.contains(REJECTED_MARKER) || output.contains(REMOTE_REJECTED_MARKER);
}
pub(crate) fn unpublished(failed_prefix: &str, previous: &str, exit_code: i64, reason: &str) -> PushAttempt {
return PushAttempt {
exit_code: if exit_code == 0 { 1 } else { exit_code },
output: format!("{previous}\n{failed_prefix}{reason}"),
};
}
pub(crate) fn argv(parts: &[&str]) -> Vec<OsString> {
return parts.iter().map(OsString::from).collect();
}
pub(crate) fn is_ancestor(
git: &PushGit,
ancestor: &str,
descendant: &str,
) -> Result<Option<bool>, SingleFlightError> {
let output = run_query(
git,
&argv(&["merge-base", "--is-ancestor", ancestor, descendant]),
)?;
return Ok(match output.code {
Some(0) => Some(true),
Some(1) => Some(false),
_ => None,
});
}
pub(crate) fn fetch_remote_tip(
git: &PushGit,
destination: &Destination,
) -> Result<Result<String, PushAttempt>, SingleFlightError> {
let private_ref = format!("refs/cli-git/auto-push/fetch-{}", std::process::id());
let refspec = format!("+{}:{private_ref}", destination.merge_ref);
let arguments = argv(&[
"fetch",
"--no-tags",
&destination.remote,
&refspec,
]);
let command = git_command(git, &arguments);
let fetched = run_bounded_push(command, push_patience(&git.environment), STOP_GRACE, git.environment.as_slice())?;
if fetched.exit_code != 0 {
return Ok(Err(fetched));
}
record_text(&["fetch", "--no-tags", destination.remote.as_str(), refspec.as_str()], fetched.output.as_str());
let tip = git_output(
git,
&argv(&[
"rev-parse",
"--verify",
&format!("{private_ref}^{{commit}}"),
]),
);
let _deleted = run_query(git, &argv(&["update-ref", "-d", &private_ref]));
return Ok(Ok(tip?));
}
pub fn journal_identifier(explicit: bool) -> &'static str {
return if explicit { CLIENT_IDENTIFIER } else { IDENTIFIER };
}