greentic_setup/cli_commands/
lifecycle.rs1use anyhow::{Context, Result, bail};
4
5use crate::cli_args::*;
6use crate::cli_helpers::resolve_bundle_dir;
7use crate::cli_i18n::CliI18n;
8use crate::engine::{SetupConfig, SetupRequest};
9use crate::plan::TenantSelection;
10use crate::{SetupEngine, SetupMode, bundle};
11
12pub fn init(args: BundleInitArgs, i18n: &CliI18n) -> Result<()> {
14 let bundle_dir = args.path.unwrap_or_else(|| std::path::PathBuf::from("."));
15 let bundle_path = bundle_dir.display().to_string();
16
17 if bundle::is_bundle_root(&bundle_dir) {
18 println!("{}", i18n.tf("cli.bundle.init.exists", &[&bundle_path]));
19 return Ok(());
20 }
21
22 println!("{}", i18n.tf("cli.bundle.init.creating", &[&bundle_path]));
23
24 bundle::create_demo_bundle_structure(&bundle_dir, args.name.as_deref())
25 .context(i18n.t("cli.error.failed_create_bundle"))?;
26
27 println!("{}", i18n.tf("cli.bundle.init.created", &[&bundle_path]));
28 println!("\n{}", i18n.t("cli.bundle.init.next_steps"));
29 println!("{}", i18n.tf("cli.bundle.init.step_add", &[&bundle_path]));
30 println!("{}", i18n.tf("cli.bundle.init.step_setup", &[&bundle_path]));
31
32 Ok(())
33}
34
35pub fn add(args: BundleAddArgs, i18n: &CliI18n) -> Result<()> {
37 let bundle_dir = resolve_bundle_dir(args.bundle)?;
38 let bundle_path = bundle_dir.display().to_string();
39
40 println!("{}", i18n.t("cli.bundle.add.adding"));
41 println!("{}", i18n.tf("cli.bundle.add.pack_ref", &[&args.pack_ref]));
42 println!("{}", i18n.tf("cli.bundle.add.bundle", &[&bundle_path]));
43 println!("{}", i18n.tf("cli.bundle.add.tenant", &[&args.tenant]));
44 println!(
45 "{}",
46 i18n.tf(
47 "cli.bundle.add.team",
48 &[args.team.as_deref().unwrap_or("default")]
49 )
50 );
51 println!("{}", i18n.tf("cli.bundle.add.env", &[&args.env]));
52
53 if !bundle::is_bundle_root(&bundle_dir) {
54 bundle::create_demo_bundle_structure(&bundle_dir, None)
55 .context(i18n.t("cli.error.failed_create_bundle"))?;
56 println!(
57 "{}",
58 i18n.tf("cli.bundle.add.created_structure", &[&bundle_path])
59 );
60 }
61
62 let request = SetupRequest {
63 bundle: bundle_dir.clone(),
64 pack_refs: vec![args.pack_ref.clone()],
65 tenants: vec![TenantSelection {
66 tenant: args.tenant.clone(),
67 team: args.team.clone(),
68 allow_paths: Vec::new(),
69 }],
70 ..Default::default()
71 };
72
73 let config = SetupConfig {
74 tenant: args.tenant,
75 team: args.team,
76 env: args.env,
77 offline: false,
78 verbose: true,
79 };
80 let engine = SetupEngine::new(config);
81 let plan = engine
82 .plan(SetupMode::Create, &request, args.dry_run)
83 .context(i18n.t("cli.error.failed_build_plan"))?;
84
85 engine.print_plan(&plan);
86
87 if args.dry_run {
88 println!("\n{}", i18n.t("cli.bundle.add.dry_run"));
89 return Ok(());
90 }
91
92 let report = engine
93 .execute(&plan)
94 .context(i18n.t("cli.error.failed_execute_plan"))?;
95
96 println!("\n{}", i18n.t("cli.bundle.add.success"));
97 println!(
98 "{}",
99 i18n.tf(
100 "cli.bundle.add.resolved",
101 &[&report.resolved_packs.len().to_string()]
102 )
103 );
104
105 Ok(())
106}
107
108pub fn remove(args: BundleRemoveArgs, i18n: &CliI18n) -> Result<()> {
110 let bundle_dir = resolve_bundle_dir(args.bundle)?;
111
112 bundle::validate_bundle_exists(&bundle_dir).context(i18n.t("cli.error.invalid_bundle"))?;
113
114 println!("{}", i18n.t("cli.bundle.remove.removing"));
115 println!(
116 "{}",
117 i18n.tf("cli.bundle.setup.provider", &[&args.provider_id])
118 );
119 println!(
120 "{}",
121 i18n.tf(
122 "cli.bundle.add.bundle",
123 &[&bundle_dir.display().to_string()]
124 )
125 );
126
127 if !args.force {
128 println!("\n{}", i18n.t("cli.bundle.remove.confirm"));
129 println!("{}", i18n.t("cli.bundle.remove.use_force"));
130 bail!("{}", i18n.t("cli.bundle.remove.cancelled"));
131 }
132
133 let request = SetupRequest {
134 bundle: bundle_dir.clone(),
135 providers_remove: vec![args.provider_id.clone()],
136 tenants: vec![TenantSelection {
137 tenant: args.tenant.clone(),
138 team: args.team.clone(),
139 allow_paths: Vec::new(),
140 }],
141 ..Default::default()
142 };
143
144 let config = SetupConfig {
145 tenant: args.tenant,
146 team: args.team,
147 env: "dev".to_string(),
148 offline: false,
149 verbose: true,
150 };
151 let engine = SetupEngine::new(config);
152 let plan = engine
153 .plan(SetupMode::Remove, &request, false)
154 .context(i18n.t("cli.error.failed_build_plan"))?;
155
156 engine.print_plan(&plan);
157 engine
158 .execute(&plan)
159 .context(i18n.t("cli.error.failed_execute_plan"))?;
160
161 println!(
162 "\n{}",
163 i18n.tf("cli.bundle.remove.complete", &[&args.provider_id])
164 );
165
166 Ok(())
167}