1use std::path::PathBuf;
2
3use crate::config::{DeployerConfig, DeployerRequest, OutputFormat, Provider};
4use crate::contract::DeployerCapability;
5use crate::error::{DeployerError, Result};
6use crate::multi_target;
7use crate::plan::PlanContext;
8
9#[derive(Debug, Clone)]
11pub struct ServerlessRequest {
12 pub capability: DeployerCapability,
13 pub tenant: String,
14 pub pack_path: PathBuf,
15 pub provider_pack: Option<PathBuf>,
16 pub deploy_pack_id_override: Option<String>,
17 pub deploy_flow_id_override: Option<String>,
18 pub environment: Option<String>,
19 pub pack_id: Option<String>,
20 pub pack_version: Option<String>,
21 pub pack_digest: Option<String>,
22 pub distributor_url: Option<String>,
23 pub distributor_token: Option<String>,
24 pub preview: bool,
25 pub dry_run: bool,
26 pub execute_local: bool,
27 pub output: OutputFormat,
28 pub config_path: Option<PathBuf>,
29 pub allow_remote_in_offline: bool,
30 pub providers_dir: PathBuf,
31 pub packs_dir: PathBuf,
32}
33
34impl ServerlessRequest {
35 pub fn new(
36 capability: DeployerCapability,
37 tenant: impl Into<String>,
38 pack_path: PathBuf,
39 ) -> Self {
40 Self {
41 capability,
42 tenant: tenant.into(),
43 pack_path,
44 provider_pack: None,
45 deploy_pack_id_override: None,
46 deploy_flow_id_override: None,
47 environment: None,
48 pack_id: None,
49 pack_version: None,
50 pack_digest: None,
51 distributor_url: None,
52 distributor_token: None,
53 preview: false,
54 dry_run: false,
55 execute_local: false,
56 output: OutputFormat::Text,
57 config_path: None,
58 allow_remote_in_offline: false,
59 providers_dir: PathBuf::from("providers/deployer"),
60 packs_dir: PathBuf::from("packs"),
61 }
62 }
63
64 pub fn into_deployer_request(self) -> DeployerRequest {
65 DeployerRequest {
66 capability: self.capability,
67 provider: Provider::Generic,
68 strategy: "serverless-container".to_string(),
69 tenant: self.tenant,
70 environment: self.environment,
71 pack_path: self.pack_path,
72 bundle_root: None,
73 providers_dir: self.providers_dir,
74 packs_dir: self.packs_dir,
75 provider_pack: self.provider_pack,
76 pack_id: self.pack_id,
77 pack_version: self.pack_version,
78 pack_digest: self.pack_digest,
79 distributor_url: self.distributor_url,
80 distributor_token: self.distributor_token,
81 preview: self.preview,
82 dry_run: self.dry_run,
83 execute_local: self.execute_local,
84 output: self.output,
85 config_path: self.config_path,
86 allow_remote_in_offline: self.allow_remote_in_offline,
87 deploy_pack_id_override: self.deploy_pack_id_override,
88 deploy_flow_id_override: self.deploy_flow_id_override,
89 bundle_source: None,
90 bundle_digest: None,
91 repo_registry_base: None,
92 store_registry_base: None,
93 }
94 }
95}
96
97pub fn resolve_config(request: ServerlessRequest) -> Result<DeployerConfig> {
98 DeployerConfig::resolve(request.into_deployer_request())
99}
100
101pub fn ensure_serverless_config(config: &DeployerConfig) -> Result<()> {
102 if config.provider != Provider::Generic || config.strategy != "serverless-container" {
103 return Err(DeployerError::Config(format!(
104 "serverless adapter requires provider=generic strategy=serverless-container, got provider={} strategy={}",
105 config.provider.as_str(),
106 config.strategy
107 )));
108 }
109 Ok(())
110}
111
112pub async fn run(request: ServerlessRequest) -> Result<multi_target::OperationResult> {
113 let config = resolve_config(request)?;
114 run_config(config).await
115}
116
117pub async fn run_config(config: DeployerConfig) -> Result<multi_target::OperationResult> {
118 ensure_serverless_config(&config)?;
119 multi_target::run(config).await
120}
121
122pub async fn run_with_plan(
123 request: ServerlessRequest,
124 plan: PlanContext,
125) -> Result<multi_target::OperationResult> {
126 let config = resolve_config(request)?;
127 run_config_with_plan(config, plan).await
128}
129
130pub async fn run_config_with_plan(
131 config: DeployerConfig,
132 plan: PlanContext,
133) -> Result<multi_target::OperationResult> {
134 ensure_serverless_config(&config)?;
135 multi_target::run_with_plan(config, plan).await
136}
137
138#[cfg(test)]
139mod tests {
140 use super::*;
141
142 #[test]
143 fn serverless_request_defaults_to_generic_serverless_target() {
144 let request =
145 ServerlessRequest::new(DeployerCapability::Plan, "acme", PathBuf::from("pack-dir"))
146 .into_deployer_request();
147
148 assert_eq!(request.provider, Provider::Generic);
149 assert_eq!(request.strategy, "serverless-container");
150 assert_eq!(request.tenant, "acme");
151 }
152}