Skip to content

Commit 150d708

Browse files
committed
Add requirement/condition.
1 parent 1bfbe0c commit 150d708

3 files changed

Lines changed: 359 additions & 3 deletions

File tree

crates/task-runner/src/task_runner.rs

Lines changed: 105 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -443,7 +443,7 @@ impl<'task> TaskRunner<'task> {
443443
return Err(TaskRunnerError::FingerprintCheckFailed {
444444
target: self.task.target.clone(),
445445
script: check_result.check.get_script().into(),
446-
error: Box::new(output.to_error("<check>", true)),
446+
error: Box::new(output.to_error("<fingerprint>", true)),
447447
}
448448
.into());
449449
}
@@ -472,6 +472,8 @@ impl<'task> TaskRunner<'task> {
472472
info.stderr = None;
473473
}
474474
};
475+
} else {
476+
unreachable!();
475477
}
476478

477479
fingerprint
@@ -501,7 +503,11 @@ impl<'task> TaskRunner<'task> {
501503
}
502504

503505
// Execute the task checks first, if any, and exit early if they fail
504-
// self.execute_checks().await?;
506+
if self.execute_checks().await? {
507+
self.skip()?;
508+
509+
return Ok(());
510+
}
505511

506512
debug!(
507513
task_target = self.task.target.as_str(),
@@ -584,6 +590,103 @@ impl<'task> TaskRunner<'task> {
584590
Ok(())
585591
}
586592

593+
#[instrument(skip(self))]
594+
pub async fn execute_checks(&mut self) -> miette::Result<bool> {
595+
let checks = ChecksRunner::new(self.app_context, self.project, self.task)?
596+
.execute(vec![TaskCheckType::Condition, TaskCheckType::Requirement])
597+
.await?;
598+
599+
if checks.is_empty() {
600+
return Ok(false);
601+
}
602+
603+
let mut has_conditions = false;
604+
let mut all_conditions_met = true;
605+
606+
for check_result in checks {
607+
// If a hard failure, we should abort the runner
608+
if let Some(error) = check_result.error {
609+
return Err(error);
610+
}
611+
612+
self.operations.push(check_result.attempt);
613+
614+
match check_result.check {
615+
// Success: Track the skipped state. If all conditions pass, skip running the task.
616+
// Failure: Do not return an error, as the task itself will run instead.
617+
TaskCheck::Condition(condition) => {
618+
let passed = check_result
619+
.output
620+
.as_ref()
621+
.is_some_and(|output| output.success());
622+
623+
trace!(
624+
task_target = self.task.target.as_str(),
625+
check = condition.script,
626+
passed,
627+
exit_code = check_result
628+
.output
629+
.as_ref()
630+
.and_then(|output| output.code()),
631+
"Checking condition"
632+
);
633+
634+
has_conditions = true;
635+
636+
if !passed {
637+
all_conditions_met = false;
638+
}
639+
}
640+
// Success: Continue on to the next check.
641+
// Failure: Return an error, as the task itself should not run.
642+
TaskCheck::Requirement(requirement) => {
643+
trace!(
644+
task_target = self.task.target.as_str(),
645+
check = requirement.script,
646+
exit_code = check_result
647+
.output
648+
.as_ref()
649+
.and_then(|output| output.code()),
650+
"Checking requirement"
651+
);
652+
653+
if let Some(output) = check_result.output
654+
&& !output.success()
655+
{
656+
return Err(TaskRunnerError::RequirementCheckFailed {
657+
target: self.task.target.clone(),
658+
script: requirement.script,
659+
error: Box::new(output.to_error("<requirement>", true)),
660+
}
661+
.into());
662+
}
663+
}
664+
TaskCheck::Fingerprint(_) => {
665+
unreachable!();
666+
}
667+
};
668+
}
669+
670+
// Only skip if all conditions pass, otherwise we should run the task as normal
671+
if has_conditions {
672+
if all_conditions_met {
673+
debug!(
674+
task_target = self.task.target.as_str(),
675+
"Skipping task as all conditional checks have passed"
676+
);
677+
678+
return Ok(true);
679+
}
680+
681+
debug!(
682+
task_target = self.task.target.as_str(),
683+
"Will continue to run the task as not all conditional checks have passed"
684+
);
685+
}
686+
687+
Ok(false)
688+
}
689+
587690
#[instrument(skip(self))]
588691
pub fn skip(&mut self) -> miette::Result<()> {
589692
debug!(task_target = self.task.target.as_str(), "Skipping task");

crates/task-runner/src/task_runner_error.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,19 @@ pub enum TaskRunnerError {
3131
error: Box<ProcessError>,
3232
},
3333

34+
#[diagnostic(code(task_runner::requirement_check_failed))]
35+
#[error(
36+
"Task {} is unable to run as the requirement check {} failed.",
37+
.target.style(Style::Label),
38+
.script.style(Style::Shell),
39+
)]
40+
RequirementCheckFailed {
41+
target: Target,
42+
script: String,
43+
#[source]
44+
error: Box<ProcessError>,
45+
},
46+
3447
#[diagnostic(code(task_runner::missing_dependency_hash))]
3548
#[error(
3649
"Encountered a missing hash for task {}, which is a dependency of {}.\nThis either means the dependency hasn't ran, has failed, or there's a misconfiguration.\n\nTry disabling the task's cache, or marking it as local.",

0 commit comments

Comments
 (0)