use super::standards_review_append::spool_directory;
use super::standards_review_input::has_shadow_log;
use super::standards_review_run::{ReviewOptions, ReviewOutcome, options_from_environment, review_landed, run_within};
use super::standards_review_source::{read_landed_commit, read_message, read_names};
use super::standards_review_text::commit_subject;
use super::service_work::Verdict;
use super::transaction_git::GitContext;
use super::work_item::WorkItem;
use std::path::{Path, PathBuf};
use std::time::Duration;
pub const CALL_DEADLINE: Duration = Duration::from_secs(10);
pub const BUDGET: Duration = Duration::from_secs(20);
pub fn options_for(item: &WorkItem, variable: &dyn Fn(&str) -> Option<String>) -> ReviewOptions {
let mut options: ReviewOptions = options_from_environment(Path::new(item.repository.as_str()), variable);
options.deadline = CALL_DEADLINE;
options.spool = Some(spool_directory(Path::new(item.git_dir.as_str()), item.repository.as_str()));
return options;
}
fn run_review(context: &GitContext, item: &WorkItem, options: &ReviewOptions, now_millis: &dyn Fn() -> u64) -> ReviewOutcome {
let cwd: PathBuf = PathBuf::from(item.repository.as_str());
let names: Vec<String> = match read_names(context, cwd.as_path(), item.oid.as_str()) {
Ok(found) => found,
Err(message) => return ReviewOutcome::Unread(message),
};
let subject: String = match read_message(context, cwd.as_path(), item.oid.as_str()) {
Ok(message) => commit_subject(message.as_str()),
Err(message) => return ReviewOutcome::Unread(message),
};
let read = |files: &[String]| { return read_landed_commit(context, cwd.as_path(), item.oid.as_str(), subject.as_str(), files); };
return review_landed(names.as_slice(), item.oid.as_str(), subject.as_str(), &read, options, now_millis);
}
fn wall_clock_millis() -> u64 {
return std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).map_or(0, |elapsed| { return u64::try_from(elapsed.as_millis()).unwrap_or(u64::MAX); });
}
pub fn review_item(context: &GitContext, item: &WorkItem, options: ReviewOptions, budget: Duration) -> Verdict {
if !has_shadow_log(Path::new(item.repository.as_str())) {
return Verdict::Done;
}
let owned_context: GitContext = context.clone();
let owned: WorkItem = item.clone();
let outcome: Option<ReviewOutcome> = run_within(budget, move || { return run_review(&owned_context, &owned, &options, &wall_clock_millis); });
return match outcome {
None => Verdict::Failed(format!("the review of {} did not finish within {} s", item.oid, budget.as_secs())),
Some(ReviewOutcome::Unread(message) | ReviewOutcome::Unwritable(message)) => Verdict::Failed(message),
Some(ReviewOutcome::NoEntry | ReviewOutcome::Skipped | ReviewOutcome::Reviewed(_) | ReviewOutcome::AlreadyLogged) => Verdict::Done,
};
}
#[cfg(test)]
#[path = "service_review_tests.rs"]
mod tests;