beet_cli/commands/
run_deploy.rs

1use crate::prelude::*;
2use beet::prelude::*;
3use clap::Parser;
4use tokio::process::Command;
5
6/// Deploy to AWS Lambda in release mode.
7#[derive(Debug, Parser)]
8pub struct RunDeploy {
9	#[command(flatten)]
10	pub build: RunBuild,
11	/// Specify the region to deploy the lambda function to
12	#[arg(long)]
13	pub region: Option<String>,
14	/// use a specificed name for the lambda function,
15	/// defaults to the package name. This must match sst.aws.Function(..,{name: THIS_FIELD })
16	/// Specify the IAM role that the lambda function should use
17	#[arg(long)]
18	pub iam_role: Option<String>,
19	/// Build but do not deploy
20	#[arg(long)]
21	pub dry_run: bool,
22	/// Optionally specify the stage name used to match the lambda function name with
23	/// the sst configuration. By default this is `dev` for debug builds and `prod` for release builds.
24	#[arg(long)]
25	pub stage: Option<String>,
26}
27
28
29impl RunDeploy {
30	/// Builds all required files and runs:
31	/// - Build template map used by the binary
32	/// - Build static files
33
34	pub async fn run(self) -> Result {
35		// we need to build the native and wasm binaries,
36		// and export the html
37		let mut build = self.build.clone();
38		build.build_cmd.release = true; // force release build
39		build.run(RunMode::Once).await?;
40
41		let config = BeetConfigFile::try_load_or_default::<BuildConfig>(
42			self.build.beet_config.as_deref(),
43		)
44		.unwrap_or_exit();
45
46		self.lambda_build().await?;
47		if !self.dry_run {
48			self.lambda_deploy(&config).await?;
49		}
50		Ok(())
51	}
52
53	async fn lambda_build(&self) -> Result<()> {
54		let mut cmd = Command::new("cargo");
55		// TODO we should support all lambda build featire
56		cmd.arg("lambda")
57			.arg("build")
58			// beet binaries should default to 'server' with 'openssl' but we need
59			// to disable that to specify 'deploy' feature
60			.arg("--no-default-features")
61			// force release, debug builds are generally way to big for lambda (450 MB / 65 MB)
62			.arg("--release")
63			.arg("--features")
64			.arg("deploy")
65			.arg("--lambda-dir")
66			.arg("target/lambda/crates");
67
68		// if self.build.build_cmd.release {
69		// 	cmd.arg("--release");
70		// }
71		if self.build.build_cmd.all_features {
72			cmd.arg("--all-features");
73		}
74		if self.build.build_cmd.no_default_features {
75			cmd.arg("--no-default-features");
76		}
77		if let Some(features) = &self.build.build_cmd.features {
78			cmd.arg("--features").arg(features);
79		}
80		if let Some(pkg) = &self.build.build_cmd.package {
81			cmd.arg("--package").arg(pkg);
82		}
83		if let Some(bin) = &self.build.build_cmd.bin {
84			cmd.arg("--bin").arg(bin);
85		}
86		if let Some(example) = &self.build.build_cmd.example {
87			cmd.arg("--example").arg(example);
88		}
89		if let Some(test) = &self.build.build_cmd.test {
90			cmd.arg("--test").arg(test);
91		}
92
93		println!("🌱 Compiling lambda binary");
94		cmd.status().await?.exit_ok()?.xok()
95	}
96
97	/// Deploy to lambda, using best effort to determine the binary name
98	#[allow(unused)]
99	async fn lambda_deploy(&self, config: &BuildConfig) -> Result {
100		let mut cmd = Command::new("cargo");
101
102		let binary_name = self.build.load_binary_name()?;
103
104		let html_dir = config
105			.template_config
106			.workspace
107			.html_dir
108			// .into_abs()
109			.to_string();
110		let snippets_dir = config
111			.template_config
112			.workspace
113			.snippets_dir()
114			// .into_abs()
115			.to_string();
116
117
118		cmd.arg("lambda")
119			.arg("deploy")
120			.arg("--enable-function-url")
121			.arg("--include")
122			.arg(&html_dir)
123			.arg("--include")
124			.arg(&snippets_dir)
125			.arg("--lambda-dir")
126			.arg("target/lambda/crates")
127			.arg("--binary-name")
128			.arg(&binary_name);
129
130		if let Some(iam_role) = &self.iam_role {
131			cmd.arg("--iam-role").arg(iam_role);
132		}
133		if let Some(region) = &self.region {
134			cmd.arg("--region").arg(region);
135		};
136
137		let stage = self
138			.stage
139			.as_ref()
140			.map(|stage| stage.as_str())
141			.unwrap_or_else(|| {
142				if self.build.build_cmd.release {
143					"prod"
144				} else {
145					"dev"
146				}
147			});
148
149		let function_name = RunInfra::lambda_func_name(&binary_name, stage);
150		cmd.arg(&function_name);
151
152		// Print the full command before executing
153		println!("🌱 Deploying Lambda Binary to {function_name}\n   {cmd:?}");
154
155		cmd.status().await?.exit_ok()?.xok()
156	}
157}