beet_cli/commands/
run_infra.rs

1use beet::prelude::*;
2use clap::Parser;
3use heck::ToKebabCase;
4use tokio::process::Command;
5
6
7
8/// A very light wrapper around sst, adapted to a few beet specific conventions
9/// like ensuring commands are run in the `infra` directory.
10#[derive(Parser)]
11pub struct RunInfra {
12	/// The subcommand to run (deploy or remove)
13	#[arg(value_enum, default_value = "deploy")]
14	subcommand: SstSubcommand,
15	/// Rusty convention, an alias for `--stage prod`
16	#[arg(long)]
17	release: bool,
18	/// The stage to use, defaults to `dev`
19	#[arg(long, default_value = "dev")]
20	stage: String,
21}
22
23/// Represents the available subcommands for the SST CLI.
24#[derive(clap::ValueEnum, Clone, Debug)]
25pub enum SstSubcommand {
26	/// Initialize a new project
27	Init,
28	/// Run in development mode
29	Dev,
30	/// Deploy your application
31	Deploy,
32	/// See what changes will be made
33	Diff,
34	/// Add a new provider
35	Add,
36	/// Install all the providers
37	Install,
38	/// Manage secrets
39	Secret,
40	/// Run a command with linked resources
41	Shell,
42	/// Remove your application
43	Remove,
44	/// Clear any locks on the app state
45	Unlock,
46	/// Print the version of the CLI
47	Version,
48	/// Upgrade the CLI
49	Upgrade,
50	/// Manage telemetry settings
51	Telemetry,
52	/// Refresh the local app state
53	Refresh,
54	/// Manage state of your app
55	State,
56	/// Generate certificate for the Console
57	Cert,
58	/// Start a tunnel
59	Tunnel,
60	/// Generates a diagnostic report
61	Diagnostic,
62}
63impl SstSubcommand {
64	/// Returns the name of the subcommand as a string.
65	pub fn as_str(&self) -> &str {
66		match self {
67			SstSubcommand::Init => "init",
68			SstSubcommand::Dev => "dev",
69			SstSubcommand::Deploy => "deploy",
70			SstSubcommand::Diff => "diff",
71			SstSubcommand::Add => "add",
72			SstSubcommand::Install => "install",
73			SstSubcommand::Secret => "secret",
74			SstSubcommand::Shell => "shell",
75			SstSubcommand::Remove => "remove",
76			SstSubcommand::Unlock => "unlock",
77			SstSubcommand::Version => "version",
78			SstSubcommand::Upgrade => "upgrade",
79			SstSubcommand::Telemetry => "telemetry",
80			SstSubcommand::Refresh => "refresh",
81			SstSubcommand::State => "state",
82			SstSubcommand::Cert => "cert",
83			SstSubcommand::Tunnel => "tunnel",
84			SstSubcommand::Diagnostic => "diagnostic",
85		}
86	}
87}
88
89impl RunInfra {
90	/// binary-resource-stage convention to match
91	/// sst.config.ts -> new sst.aws.Function(`..`, {name: `THIS_FIELD` }),
92	pub fn lambda_func_name(binary_name: &str, stage: &str) -> String {
93		format! {"{}-lambda-{}",binary_name.to_kebab_case(),stage}
94	}
95
96	pub async fn run(mut self) -> Result {
97		if self.release {
98			self.stage = "prod".to_string();
99		}
100
101		let mut args = vec!["sst", self.subcommand.as_str()];
102		args.push("--stage");
103		args.push(&self.stage);
104
105		let sst_dir = std::env::current_dir()?.join("infra").canonicalize()?;
106		let mut cmd = Command::new("npx");
107		cmd.current_dir(sst_dir).args(args);
108		// .arg("--config")
109		// .arg("infra/sst.config.ts")
110
111		println!(
112			"🌱 Running SST command: \n   {cmd:?}\n🌱 Interrupting this step may result in dangling resources"
113		);
114		cmd.status().await?.exit_ok()?.xok()
115	}
116}
117
118
119#[cfg(test)]
120mod test {
121	use crate::prelude::*;
122	use sweet::prelude::*;
123
124	#[test]
125	fn works() {
126		let binary_name = "test_binary";
127		RunInfra::lambda_func_name(binary_name, "dev")
128			.xpect()
129			.to_be("test-binary-lambda-dev");
130	}
131}