evaluation: use ? to handle errors
This commit is contained in:
parent
0b936ea1cc
commit
a8eb1743b0
1 changed files with 103 additions and 84 deletions
|
@ -23,7 +23,6 @@ use std::path::Path;
|
||||||
use std::sync::RwLock;
|
use std::sync::RwLock;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
use tasks::eval;
|
use tasks::eval;
|
||||||
use tasks::eval::StepResult;
|
|
||||||
|
|
||||||
pub struct EvaluationWorker<E> {
|
pub struct EvaluationWorker<E> {
|
||||||
cloner: checkout::CachedCloner,
|
cloner: checkout::CachedCloner,
|
||||||
|
@ -107,20 +106,23 @@ impl<E: stats::SysEvents + 'static> worker::SimpleWorker for EvaluationWorker<E>
|
||||||
&self.identity,
|
&self.identity,
|
||||||
&self.tag_paths,
|
&self.tag_paths,
|
||||||
&self.cloner,
|
&self.cloner,
|
||||||
|
job,
|
||||||
)
|
)
|
||||||
.evaluate_job(job)
|
.worker_actions()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct OneEval<'a, E> {
|
struct OneEval<'a, E> {
|
||||||
client_app: &'a hubcaps::Github,
|
client_app: &'a hubcaps::Github,
|
||||||
client_legacy: &'a hubcaps::Github,
|
repo: hubcaps::repositories::Repository<'a>,
|
||||||
|
gists: Gists<'a>,
|
||||||
nix: &'a nix::Nix,
|
nix: &'a nix::Nix,
|
||||||
acl: &'a ACL,
|
acl: &'a ACL,
|
||||||
events: &'a mut E,
|
events: &'a mut E,
|
||||||
identity: &'a str,
|
identity: &'a str,
|
||||||
tag_paths: &'a HashMap<String, Vec<String>>,
|
tag_paths: &'a HashMap<String, Vec<String>>,
|
||||||
cloner: &'a checkout::CachedCloner,
|
cloner: &'a checkout::CachedCloner,
|
||||||
|
job: &'a evaluationjob::EvaluationJob,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, E: stats::SysEvents + 'static> OneEval<'a, E> {
|
impl<'a, E: stats::SysEvents + 'static> OneEval<'a, E> {
|
||||||
|
@ -133,16 +135,23 @@ impl<'a, E: stats::SysEvents + 'static> OneEval<'a, E> {
|
||||||
identity: &'a str,
|
identity: &'a str,
|
||||||
tag_paths: &'a HashMap<String, Vec<String>>,
|
tag_paths: &'a HashMap<String, Vec<String>>,
|
||||||
cloner: &'a checkout::CachedCloner,
|
cloner: &'a checkout::CachedCloner,
|
||||||
|
job: &'a evaluationjob::EvaluationJob,
|
||||||
) -> OneEval<'a, E> {
|
) -> OneEval<'a, E> {
|
||||||
|
let gists = client_legacy.gists();
|
||||||
|
|
||||||
|
let repo = client_app.repo(job.repo.owner.clone(), job.repo.name.clone());
|
||||||
|
|
||||||
OneEval {
|
OneEval {
|
||||||
client_app,
|
client_app,
|
||||||
client_legacy,
|
repo,
|
||||||
|
gists,
|
||||||
nix,
|
nix,
|
||||||
acl,
|
acl,
|
||||||
events,
|
events,
|
||||||
identity,
|
identity,
|
||||||
tag_paths,
|
tag_paths,
|
||||||
cloner,
|
cloner,
|
||||||
|
job,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,31 +159,76 @@ impl<'a, E: stats::SysEvents + 'static> OneEval<'a, E> {
|
||||||
evaluationjob::Actions {}
|
evaluationjob::Actions {}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_strategy_err(
|
fn update_status(
|
||||||
&self,
|
&self,
|
||||||
ret: StepResult<()>,
|
description: String,
|
||||||
gists: &Gists<'_>,
|
url: Option<String>,
|
||||||
status: &mut CommitStatus,
|
state: hubcaps::statuses::State,
|
||||||
) -> Result<(), ()> {
|
) -> Result<(), hubcaps::Error> {
|
||||||
match ret {
|
let description = if description.len() >= 140 {
|
||||||
Ok(()) => Ok(()),
|
eprintln!(
|
||||||
Err(eval::Error::Fail(msg)) => {
|
"Warning: description is over 140 char; truncating: {:?}",
|
||||||
status.set_with_description(&msg, hubcaps::statuses::State::Failure);
|
&description
|
||||||
Err(())
|
);
|
||||||
|
description.chars().take(140).collect()
|
||||||
|
} else {
|
||||||
|
description
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut builder = hubcaps::statuses::StatusOptions::builder(state);
|
||||||
|
builder.context("grahamcofborg-eval");
|
||||||
|
builder.description(description);
|
||||||
|
|
||||||
|
if let Some(url) = url {
|
||||||
|
builder.target_url(url);
|
||||||
}
|
}
|
||||||
Err(eval::Error::FailWithGist(msg, filename, content)) => {
|
|
||||||
status.set_url(make_gist(&gists, &filename, Some("".to_owned()), content));
|
self.repo
|
||||||
status.set_with_description(&msg, hubcaps::statuses::State::Failure);
|
.statuses()
|
||||||
Err(())
|
.create(&self.job.pr.head_sha, &builder.build())
|
||||||
|
.map(|_| ())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn make_gist(
|
||||||
|
&self,
|
||||||
|
filename: &str,
|
||||||
|
description: Option<String>,
|
||||||
|
content: String,
|
||||||
|
) -> Option<String> {
|
||||||
|
make_gist(&self.gists, filename, description, content)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn worker_actions(&mut self) -> worker::Actions {
|
||||||
|
let eval_result = self.evaluate_job();
|
||||||
|
if let Ok(actions) = eval_result {
|
||||||
|
return actions;
|
||||||
|
}
|
||||||
|
let eval_result =
|
||||||
|
eval_result.expect_err("We have an OK, but just checked for an Ok before");
|
||||||
|
|
||||||
|
match eval_result {
|
||||||
|
EvalWorkerError::EvalError(eval::Error::Fail(msg)) => {
|
||||||
|
self.update_status(msg, None, hubcaps::statuses::State::Failure)
|
||||||
|
.expect("Failed to set status");
|
||||||
|
}
|
||||||
|
EvalWorkerError::EvalError(eval::Error::FailWithGist(msg, filename, content)) => {
|
||||||
|
self.update_status(
|
||||||
|
msg,
|
||||||
|
self.make_gist(&filename, Some("".to_owned()), content),
|
||||||
|
hubcaps::statuses::State::Failure,
|
||||||
|
)
|
||||||
|
.expect("Failed to set status");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn evaluate_job(&mut self, job: &evaluationjob::EvaluationJob) -> worker::Actions {
|
return self.actions().skip(&self.job);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn evaluate_job(&mut self) -> Result<worker::Actions, EvalWorkerError> {
|
||||||
|
let job = self.job;
|
||||||
let repo = self
|
let repo = self
|
||||||
.client_app
|
.client_app
|
||||||
.repo(job.repo.owner.clone(), job.repo.name.clone());
|
.repo(self.job.repo.owner.clone(), self.job.repo.name.clone());
|
||||||
let gists = self.client_legacy.gists();
|
|
||||||
let pulls = repo.pulls();
|
let pulls = repo.pulls();
|
||||||
let pull = pulls.get(job.pr.number);
|
let pull = pulls.get(job.pr.number);
|
||||||
let issue_ref = repo.issue(job.pr.number);
|
let issue_ref = repo.issue(job.pr.number);
|
||||||
|
@ -186,7 +240,7 @@ impl<'a, E: stats::SysEvents + 'static> OneEval<'a, E> {
|
||||||
if iss.state == "closed" {
|
if iss.state == "closed" {
|
||||||
self.events.notify(Event::IssueAlreadyClosed);
|
self.events.notify(Event::IssueAlreadyClosed);
|
||||||
info!("Skipping {} because it is closed", job.pr.number);
|
info!("Skipping {} because it is closed", job.pr.number);
|
||||||
return self.actions().skip(&job);
|
return Ok(self.actions().skip(&job));
|
||||||
}
|
}
|
||||||
|
|
||||||
if issue_is_wip(&iss) {
|
if issue_is_wip(&iss) {
|
||||||
|
@ -205,7 +259,7 @@ impl<'a, E: stats::SysEvents + 'static> OneEval<'a, E> {
|
||||||
self.events.notify(Event::IssueFetchFailed);
|
self.events.notify(Event::IssueFetchFailed);
|
||||||
info!("Error fetching {}!", job.pr.number);
|
info!("Error fetching {}!", job.pr.number);
|
||||||
info!("E: {:?}", e);
|
info!("E: {:?}", e);
|
||||||
return self.actions().skip(&job);
|
return Ok(self.actions().skip(&job));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -216,7 +270,7 @@ impl<'a, E: stats::SysEvents + 'static> OneEval<'a, E> {
|
||||||
&issue,
|
&issue,
|
||||||
&issue_ref,
|
&issue_ref,
|
||||||
&repo,
|
&repo,
|
||||||
&gists,
|
&self.gists,
|
||||||
self.nix.clone(),
|
self.nix.clone(),
|
||||||
&self.tag_paths,
|
&self.tag_paths,
|
||||||
))
|
))
|
||||||
|
@ -234,12 +288,7 @@ impl<'a, E: stats::SysEvents + 'static> OneEval<'a, E> {
|
||||||
|
|
||||||
overall_status.set_with_description("Starting", hubcaps::statuses::State::Pending);
|
overall_status.set_with_description("Starting", hubcaps::statuses::State::Pending);
|
||||||
|
|
||||||
if self
|
evaluation_strategy.pre_clone()?;
|
||||||
.handle_strategy_err(evaluation_strategy.pre_clone(), &gists, &mut overall_status)
|
|
||||||
.is_err()
|
|
||||||
{
|
|
||||||
return self.actions().skip(&job);
|
|
||||||
}
|
|
||||||
|
|
||||||
let project = self
|
let project = self
|
||||||
.cloner
|
.cloner
|
||||||
|
@ -264,16 +313,7 @@ impl<'a, E: stats::SysEvents + 'static> OneEval<'a, E> {
|
||||||
info!("Checking out target branch {}", &target_branch);
|
info!("Checking out target branch {}", &target_branch);
|
||||||
let refpath = co.checkout_origin_ref(target_branch.as_ref()).unwrap();
|
let refpath = co.checkout_origin_ref(target_branch.as_ref()).unwrap();
|
||||||
|
|
||||||
if self
|
evaluation_strategy.on_target_branch(&Path::new(&refpath), &mut overall_status)?;
|
||||||
.handle_strategy_err(
|
|
||||||
evaluation_strategy.on_target_branch(&Path::new(&refpath), &mut overall_status),
|
|
||||||
&gists,
|
|
||||||
&mut overall_status,
|
|
||||||
)
|
|
||||||
.is_err()
|
|
||||||
{
|
|
||||||
return self.actions().skip(&job);
|
|
||||||
}
|
|
||||||
|
|
||||||
let target_branch_rebuild_sniff_start = Instant::now();
|
let target_branch_rebuild_sniff_start = Instant::now();
|
||||||
|
|
||||||
|
@ -293,19 +333,10 @@ impl<'a, E: stats::SysEvents + 'static> OneEval<'a, E> {
|
||||||
.set_with_description("Commit not found", hubcaps::statuses::State::Error);
|
.set_with_description("Commit not found", hubcaps::statuses::State::Error);
|
||||||
|
|
||||||
info!("Commit {} doesn't exist", job.pr.head_sha);
|
info!("Commit {} doesn't exist", job.pr.head_sha);
|
||||||
return self.actions().skip(&job);
|
return Ok(self.actions().skip(&job));
|
||||||
}
|
}
|
||||||
|
|
||||||
if self
|
evaluation_strategy.after_fetch(&co)?;
|
||||||
.handle_strategy_err(
|
|
||||||
evaluation_strategy.after_fetch(&co),
|
|
||||||
&gists,
|
|
||||||
&mut overall_status,
|
|
||||||
)
|
|
||||||
.is_err()
|
|
||||||
{
|
|
||||||
return self.actions().skip(&job);
|
|
||||||
}
|
|
||||||
|
|
||||||
overall_status.set_with_description("Merging PR", hubcaps::statuses::State::Pending);
|
overall_status.set_with_description("Merging PR", hubcaps::statuses::State::Pending);
|
||||||
|
|
||||||
|
@ -317,19 +348,10 @@ impl<'a, E: stats::SysEvents + 'static> OneEval<'a, E> {
|
||||||
|
|
||||||
evaluation_strategy.merge_conflict();
|
evaluation_strategy.merge_conflict();
|
||||||
|
|
||||||
return self.actions().skip(&job);
|
return Ok(self.actions().skip(&job));
|
||||||
}
|
}
|
||||||
|
|
||||||
if self
|
evaluation_strategy.after_merge(&mut overall_status)?;
|
||||||
.handle_strategy_err(
|
|
||||||
evaluation_strategy.after_merge(&mut overall_status),
|
|
||||||
&gists,
|
|
||||||
&mut overall_status,
|
|
||||||
)
|
|
||||||
.is_err()
|
|
||||||
{
|
|
||||||
return self.actions().skip(&job);
|
|
||||||
}
|
|
||||||
|
|
||||||
println!("Got path: {:?}, building", refpath);
|
println!("Got path: {:?}, building", refpath);
|
||||||
overall_status
|
overall_status
|
||||||
|
@ -358,8 +380,7 @@ impl<'a, E: stats::SysEvents + 'static> OneEval<'a, E> {
|
||||||
}
|
}
|
||||||
Err(mut out) => {
|
Err(mut out) => {
|
||||||
state = hubcaps::statuses::State::Failure;
|
state = hubcaps::statuses::State::Failure;
|
||||||
gist_url = make_gist(
|
gist_url = self.make_gist(
|
||||||
&gists,
|
|
||||||
&check.name(),
|
&check.name(),
|
||||||
Some(format!("{:?}", state)),
|
Some(format!("{:?}", state)),
|
||||||
file_to_str(&mut out),
|
file_to_str(&mut out),
|
||||||
|
@ -382,23 +403,11 @@ impl<'a, E: stats::SysEvents + 'static> OneEval<'a, E> {
|
||||||
let mut response: worker::Actions = vec![];
|
let mut response: worker::Actions = vec![];
|
||||||
|
|
||||||
if eval_results {
|
if eval_results {
|
||||||
let ret = evaluation_strategy
|
let complete = evaluation_strategy
|
||||||
.all_evaluations_passed(&Path::new(&refpath), &mut overall_status);
|
.all_evaluations_passed(&Path::new(&refpath), &mut overall_status)?;
|
||||||
match ret {
|
|
||||||
Ok(complete) => {
|
|
||||||
send_check_statuses(complete.checks, &repo);
|
send_check_statuses(complete.checks, &repo);
|
||||||
response.extend(schedule_builds(complete.builds, auto_schedule_build_archs));
|
response.extend(schedule_builds(complete.builds, auto_schedule_build_archs));
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
info!("Failed after all the evaluations passed");
|
|
||||||
if self
|
|
||||||
.handle_strategy_err(Err(e), &gists, &mut overall_status)
|
|
||||||
.is_err()
|
|
||||||
{
|
|
||||||
return self.actions().skip(&job);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
info!("Just about done...");
|
info!("Just about done...");
|
||||||
|
|
||||||
|
@ -411,7 +420,7 @@ impl<'a, E: stats::SysEvents + 'static> OneEval<'a, E> {
|
||||||
self.events.notify(Event::TaskEvaluationCheckComplete);
|
self.events.notify(Event::TaskEvaluationCheckComplete);
|
||||||
|
|
||||||
info!("done!");
|
info!("done!");
|
||||||
self.actions().done(&job, response)
|
Ok(self.actions().done(&job, response))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -540,3 +549,13 @@ fn indicates_wip(text: &str) -> bool {
|
||||||
|
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum EvalWorkerError {
|
||||||
|
EvalError(eval::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<eval::Error> for EvalWorkerError {
|
||||||
|
fn from(e: eval::Error) -> EvalWorkerError {
|
||||||
|
EvalWorkerError::EvalError(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue