use super::App;
use crate::aws::Environment;
use crate::lint::inputs::{EnvLintInputs, Platforms, ProbeOutcome};
pub(crate) enum WorkerDlq {
Depth(i64),
NoDlq,
Unknown(String),
}
impl WorkerDlq {
pub(crate) fn depth(&self) -> Option<i64> {
match self {
Self::Depth(d) => Some(*d),
_ => None,
}
}
}
pub(crate) fn worker_dlq(depth: Option<i64>, absent: bool, stale: bool) -> WorkerDlq {
match (depth, absent, stale) {
(_, _, true) => WorkerDlq::Unknown("the last worker-queue check failed".into()),
(Some(d), _, false) => WorkerDlq::Depth(d),
(None, true, false) => WorkerDlq::NoDlq,
(None, false, false) => {
WorkerDlq::Unknown("no worker-queue check has completed yet".into())
}
}
}
pub(crate) fn dlq_depth_gap(
env: &Environment,
disabled: &[String],
dlq: &WorkerDlq,
) -> Option<String> {
let WorkerDlq::Unknown(why) = dlq else {
return None;
};
if !env.tier.eq_ignore_ascii_case("Worker") || disabled.iter().any(|d| d == "EBL011") {
return None;
}
ProbeOutcome::Unknown(why.clone()).coverage_warning("EBL011", &env.name)
}
pub(crate) fn platforms_from_cache(
latest: &std::collections::HashMap<String, String>,
failed: Option<&str>,
home_region: &str,
env_region: &str,
) -> Platforms {
if env_region != home_region {
return Platforms::Unavailable(format!(
"the platform-version list is loaded for {home_region} only, and this env is \
in {env_region}"
));
}
match failed {
Some(e) if latest.is_empty() => Platforms::Unavailable(e.to_string()),
_ if latest.is_empty() => {
Platforms::Unavailable("the platform-version list has not loaded yet".into())
}
_ => Platforms::Loaded(latest.clone()),
}
}
pub(crate) struct LintSnapshot {
pub(crate) env: Environment,
user_disables: Vec<String>,
pub(crate) required_tags: Vec<String>,
pub(crate) platforms: Platforms,
pub(crate) dlq: WorkerDlq,
}
impl App {
pub(crate) fn lint_snapshot(&self, env: &Environment) -> LintSnapshot {
LintSnapshot {
env: env.clone(),
user_disables: self.cfg.lint_disable.clone(),
required_tags: self.cfg.required_tags.clone(),
platforms: platforms_from_cache(
&self.latest_stacks,
self.latest_stacks_error.as_deref(),
&self.context.region,
&self.region_for(env),
),
dlq: worker_dlq(
self.worker_dlq_depths.get(&env.name).copied(),
self.worker_dlq_absent.contains(&env.name),
self.worker_dlq_stale.contains(&env.name),
),
}
}
}
impl LintSnapshot {
pub(crate) fn disabled(&self) -> Vec<String> {
let mut disabled = self.user_disables.clone();
disabled.extend(crate::project::load_lint_disables_from_cwd());
disabled
}
pub(crate) fn finish(&self, mut inputs: EnvLintInputs, disabled: &[String]) -> LintRun {
inputs.dlq_depth = self.dlq.depth();
inputs
.coverage_warnings
.extend(dlq_depth_gap(&self.env, disabled, &self.dlq));
let rules = crate::lint::default_rules(disabled);
let issues =
crate::lint::inputs::run_rules_for_env(&rules, &self.env, &inputs, &self.required_tags);
LintRun {
issues,
coverage_warnings: inputs.coverage_warnings,
}
}
pub(crate) fn finish_fetched(
&self,
options: Vec<(String, String, String)>,
tags: Option<Result<Vec<String>, String>>,
health: Result<i64, String>,
disabled: &[String],
) -> LintRun {
let inputs = crate::lint::inputs::assemble(
&self.env,
options,
tags,
health,
&self.platforms,
disabled,
&self.required_tags,
);
self.finish(inputs, disabled)
}
}
pub(crate) struct LintRun {
pub(crate) issues: Vec<crate::lint::Issue>,
pub(crate) coverage_warnings: Vec<String>,
}
pub(crate) async fn run_tui_lint(
aws: &crate::aws::AwsClient,
snap: &LintSnapshot,
) -> Result<LintRun, String> {
let disabled = snap.disabled();
let inputs = crate::lint::inputs::fetch_env_lint_inputs(
aws,
&snap.env,
&snap.platforms,
false,
&disabled,
&snap.required_tags,
)
.await?;
Ok(snap.finish(inputs, &disabled))
}