pub mod bootstrap;
pub mod credentials;
pub mod deploy_target;
pub mod deployer;
use greentic_deploy_spec::CapabilitySlot;
use semver::VersionReq;
use super::slot::EnvPackHandler;
use crate::tool_check::ToolCheck;
pub use credentials::{AwsDeployerCredentials, AwsValidatorClient};
#[derive(Debug)]
pub struct AwsEcsDeployerHandler {
creds: AwsDeployerCredentials,
pub(crate) target: std::sync::Arc<dyn deploy_target::EcsDeployTarget>,
}
impl Default for AwsEcsDeployerHandler {
fn default() -> Self {
Self {
creds: AwsDeployerCredentials::default(),
target: std::sync::Arc::new(deploy_target::UnconfiguredEcsTarget),
}
}
}
impl AwsEcsDeployerHandler {
pub const DESCRIPTOR_PATH: &'static str = "greentic.deployer.aws-ecs";
pub const VERSION_REQ: &'static str = ">=1.0.0-dev, <2.0.0";
pub fn with_client(client: std::sync::Arc<dyn AwsValidatorClient>) -> Self {
Self {
creds: AwsDeployerCredentials::with_client(client),
target: std::sync::Arc::new(deploy_target::UnconfiguredEcsTarget),
}
}
pub fn with_target(target: std::sync::Arc<dyn deploy_target::EcsDeployTarget>) -> Self {
Self {
creds: AwsDeployerCredentials::default(),
target,
}
}
}
impl EnvPackHandler for AwsEcsDeployerHandler {
fn slot(&self) -> CapabilitySlot {
CapabilitySlot::Deployer
}
fn descriptor_path(&self) -> &str {
Self::DESCRIPTOR_PATH
}
fn supported_versions(&self) -> VersionReq {
Self::VERSION_REQ
.parse()
.expect("aws-ecs version-req is valid (guarded by tests)")
}
fn preflight(&self) -> Vec<ToolCheck> {
Vec::new()
}
fn deployer_credentials(&self) -> Option<&dyn crate::credentials::DeployerCredentials> {
Some(&self.creds)
}
fn wizard_qaspec_yaml(&self) -> Option<&'static str> {
Some(include_str!("wizard.qaspec.yaml"))
}
fn as_deployer(&self) -> Option<&dyn crate::env_packs::deployer::Deployer> {
Some(self)
}
}
#[cfg(test)]
mod tests {
use super::*;
use greentic_deploy_spec::PackDescriptor;
#[test]
fn handler_serves_deployer_slot_with_aws_ecs_path() {
let h = AwsEcsDeployerHandler::default();
assert_eq!(h.slot(), CapabilitySlot::Deployer);
assert_eq!(h.descriptor_path(), "greentic.deployer.aws-ecs");
let _ = h.supported_versions();
}
#[test]
fn version_req_accepts_ga_and_dev_releases() {
let h = AwsEcsDeployerHandler::default();
let req = h.supported_versions();
let ga = PackDescriptor::try_new("greentic.deployer.aws-ecs@1.0.0").unwrap();
assert!(req.matches(&ga.version().0), "{req} must accept 1.0.0");
let dev = PackDescriptor::try_new("greentic.deployer.aws-ecs@1.0.0-dev.1").unwrap();
assert!(
req.matches(&dev.version().0),
"{req} must accept dev pre-release"
);
let next_major = PackDescriptor::try_new("greentic.deployer.aws-ecs@2.0.0").unwrap();
assert!(
!req.matches(&next_major.version().0),
"{req} must reject 2.0.0 (breaking bump)"
);
}
#[test]
fn exposes_credentials_contract_and_deployer_impl() {
let h = AwsEcsDeployerHandler::default();
let creds = h
.deployer_credentials()
.expect("aws-ecs handler must expose credentials");
assert!(creds.requires_credentials_material());
assert!(
(&h as &dyn EnvPackHandler).as_deployer().is_some(),
"EnvPackHandler::as_deployer must surface the AWS-ECS Deployer impl"
);
assert!(
(&h as &dyn EnvPackHandler).as_manifest_renderer().is_none(),
"AWS-ECS is imperative; it must not expose a manifest renderer"
);
}
#[test]
fn wizard_qaspec_yaml_pins_id_and_requires_region() {
let yaml = AwsEcsDeployerHandler::default()
.wizard_qaspec_yaml()
.expect("aws-ecs handler ships a wizard QASpec");
let spec: qa_spec::FormSpec =
serde_yaml_bw::from_str(yaml).expect("wizard.qaspec.yaml parses as FormSpec");
assert_eq!(spec.id, "greentic.deployer.aws-ecs.wizard");
assert!(
spec.questions.iter().any(|q| q.id == "region"),
"aws-ecs wizard must collect the AWS region (no sensible default)",
);
}
}