3 files changed
+28
-237
crates/cli/src/deploy/mod.rs
+1
-214
@@ -1,219 +1,6 @@
1
pub mod config;
2
mod detect_runner;
3
mod git;
4
+pub mod process_deploy;
5
mod remote_messages;
6
mod setup;
6
-
7
-use {
8
- crate::{
9
- account::{lib::is_logged_in, login::process_login},
10
- cli::CommandResult,
11
- deploy::config::check_project,
12
- deploy::detect_runner::detect_runner,
13
- token::get_smb_token,
14
- ui::{fail_message, succeed_message, succeed_symbol},
15
- },
16
- anyhow::{anyhow, Result},
17
- config::check_config,
18
- git::remote_deployment_setup,
19
- git2::{PushOptions, RemoteCallbacks, Repository},
20
- remote_messages::{build_next_app, start_server},
21
- smbcloud_model::project::{DeploymentPayload, DeploymentStatus},
22
- smbcloud_network::environment::Environment,
23
- smbcloud_networking_account::me::me,
24
- smbcloud_networking_project::{
25
- crud_project_deployment_create::create_deployment, crud_project_deployment_update::update,
26
- },
27
- spinners::Spinner,
28
- std::sync::{
29
- atomic::{AtomicBool, Ordering},
30
- Arc,
31
- },
32
-};
33
-
34
-pub async fn process_deploy(env: Environment) -> Result<CommandResult> {
35
- // Check credentials.
36
- if !is_logged_in(env) {
37
- let _ = process_login(env).await;
38
- }
39
-
40
- // Get current token
41
- let access_token = get_smb_token(env).await?;
42
-
43
- // Check config.
44
- let config = check_config(env).await?;
45
-
46
- // Check runner.
47
- let runner = detect_runner().await?;
48
-
49
- // Validate config with project.
50
- check_project(env, &access_token, config.project.id).await?;
51
-
52
- // Check remote repository setup.
53
- let repo = match Repository::open(".") {
54
- Ok(repo) => repo,
55
- Err(_) => {
56
- return Err(anyhow!(fail_message(
57
- "No git repository found. Init with `git init` command."
58
- )))
59
- }
60
- };
61
-
62
- // Get the current branch
63
- let head = match repo.head() {
64
- Ok(head) => head,
65
- Err(_) => {
66
- return Err(anyhow!(fail_message(
67
- "No HEAD reference found. Create a commit with `git commit` command."
68
- )))
69
- }
70
- };
71
-
72
- // Check if we're on the main branch
73
- let branch_name = match head.shorthand() {
74
- Some(name) => name,
75
- None => {
76
- return Err(anyhow!(fail_message(
77
- "Unable to determine current branch name."
78
- )))
79
- }
80
- };
81
-
82
- if branch_name != "main" && branch_name != "master" {
83
- return Err(anyhow!(fail_message(
84
- &format!("Not on main branch. Current branch: '{}'. Switch to main branch with `git checkout main` command.", branch_name)
85
- )));
86
- }
87
-
88
- let main_branch = head;
89
-
90
- let repository = match &config.project.repository {
91
- Some(repo) => repo,
92
- None => return Err(anyhow!(fail_message("Repository not found."))),
93
- };
94
-
95
- let mut origin = remote_deployment_setup(&runner, &repo, repository).await?;
96
-
97
- let commit_hash = match main_branch.resolve() {
98
- Ok(result) => match result.target() {
99
- Some(hash_id) => hash_id,
100
- None => return Err(anyhow!("Should have at least one commit.")),
101
- },
102
- Err(_) => return Err(anyhow!("Cannot resolve main branch.")),
103
- };
104
- let payload = DeploymentPayload {
105
- commit_hash: commit_hash.to_string(),
106
- status: DeploymentStatus::Started,
107
- };
108
-
109
- let created_deployment =
110
- create_deployment(env, &access_token, config.project.id, payload).await?;
111
- let user = me(env, &access_token).await?;
112
-
113
- let mut push_opts = PushOptions::new();
114
- let mut callbacks = RemoteCallbacks::new();
115
-
116
- // For updating status to failed
117
- let deployment_failed_flag = Arc::new(AtomicBool::new(false));
118
- let update_env = env; // Env is Copy
119
- let update_access_token = access_token.clone();
120
- let update_project_id = config.project.id;
121
- let update_deployment_id = created_deployment.id;
122
-
123
- // Set the credentials
124
- callbacks.credentials(config.credentials(user));
125
- callbacks.sideband_progress(|data| {
126
- // Convert bytes to string, print line by line
127
- if let Ok(text) = std::str::from_utf8(data) {
128
- for line in text.lines() {
129
- if line.contains(&build_next_app()) {
130
- println!("Building the app {}", succeed_symbol());
131
- }
132
- if line.contains(&start_server(repository)) {
133
- println!("App restart {}", succeed_symbol());
134
- }
135
- }
136
- }
137
- true // continue receiving.
138
- });
139
- callbacks.push_update_reference({
140
- let flag_clone = deployment_failed_flag.clone();
141
- let access_token_for_update_cb = update_access_token.clone();
142
- let project_id_for_update_cb = update_project_id;
143
- let deployment_id_for_update_cb = update_deployment_id;
144
-
145
- move |_refname, status_message| {
146
- if let Some(e) = status_message {
147
- // Try to set the flag. If it was already true, do nothing.
148
- if !flag_clone.swap(true, Ordering::SeqCst) {
149
- println!(
150
- "Deployment ref update failed: {}. Marking deployment as Failed.",
151
- e
152
- );
153
-
154
- let update_payload = DeploymentPayload {
155
- commit_hash: commit_hash.to_string(),
156
- status: DeploymentStatus::Failed,
157
- };
158
-
159
- // We are in a sync callback, so we need to block on the async task.
160
- let handle = tokio::runtime::Handle::current();
161
- let result = handle.block_on(async {
162
- update(
163
- update_env, // Env is Copy
164
- access_token_for_update_cb.clone(),
165
- project_id_for_update_cb,
166
- deployment_id_for_update_cb,
167
- update_payload,
168
- )
169
- .await
170
- });
171
-
172
- match result {
173
- Ok(_) => println!("Deployment status successfully updated to Failed."),
174
- Err(update_err) => {
175
- eprintln!("Error updating deployment status to Failed: {}", update_err)
176
- }
177
- }
178
- }
179
- }
180
- Ok(()) // Report success for the git callback itself, error is handled above.
181
- }
182
- });
183
- push_opts.remote_callbacks(callbacks);
184
-
185
- let spinner = Spinner::new(
186
- spinners::Spinners::Hamburger,
187
- succeed_message("Deploying > "),
188
- );
189
-
190
- match origin.push(&["refs/heads/main:refs/heads/main"], Some(&mut push_opts)) {
191
- Ok(_) => {
192
- // Update deployment status to Done
193
- let update_payload = DeploymentPayload {
194
- commit_hash: commit_hash.to_string(),
195
- status: DeploymentStatus::Done,
196
- };
197
- let result = update(
198
- env,
199
- access_token.clone(),
200
- config.project.id,
201
- created_deployment.id,
202
- update_payload,
203
- )
204
- .await;
205
- match result {
206
- Ok(_) => println!("App is running {}", succeed_symbol()),
207
- Err(update_err) => {
208
- eprintln!("Error updating deployment status to Done: {}", update_err)
209
- }
210
- }
211
- Ok(CommandResult {
212
- spinner,
213
- symbol: succeed_symbol(),
214
- msg: succeed_message("Deployment complete."),
215
- })
216
- }
217
- Err(e) => Err(anyhow!(fail_message(&e.to_string()))),
218
- }
219
-}
crates/cli/src/deploy/process_deploy.rs
+26
-22
@@ -1,26 +1,30 @@
1
-use crate::deploy::{
2
- account::{lib::is_logged_in, login::process_login},
3
- cli::CommandResult,
4
- config::check_config,
5
- deploy::config::check_project,
6
- detect_runner::detect_runner,
7
- git::remote_deployment_setup,
8
- remote_messages::{build_next_app, start_server},
9
- token::get_smb_token,
10
- ui::{fail_message, succeed_message, succeed_symbol},
11
-};
12
-use anyhow::{anyhow, Result};
13
-use git2::{PushOptions, RemoteCallbacks, Repository};
14
-use smbcloud_model::project::{DeploymentPayload, DeploymentStatus};
15
-use smbcloud_network::environment::Environment;
16
-use smbcloud_networking_account::me::me;
17
-use smbcloud_networking_project::{
18
- crud_project_deployment_create::create_deployment, crud_project_deployment_update::update,
1
+use {
2
+ crate::{
3
+ account::{lib::is_logged_in, login::process_login},
4
+ cli::CommandResult,
5
+ deploy::{
6
+ config::{check_config, check_project},
7
+ detect_runner::detect_runner,
8
+ git::remote_deployment_setup,
9
+ remote_messages::{build_next_app, start_server},
10
+ },
11
+ token::get_smb_token,
12
+ ui::{fail_message, succeed_message, succeed_symbol},
13
+ },
14
+ anyhow::{anyhow, Result},
15
+ git2::{PushOptions, RemoteCallbacks, Repository},
16
+ smbcloud_model::project::{DeploymentPayload, DeploymentStatus},
17
+ smbcloud_network::environment::Environment,
18
+ smbcloud_networking_account::me::me,
19
+ smbcloud_networking_project::{
20
+ crud_project_deployment_create::create_deployment, crud_project_deployment_update::update,
21
+ },
22
+ spinners::Spinner,
23
+ std::sync::{
24
+ atomic::{AtomicBool, Ordering},
25
+ Arc,
26
+ },
27
};
20
-use spinners::Spinner;
21
-use std::sync::atomic::AtomicBool;
22
-use std::sync::atomic::Ordering;
23
-use std::sync::Arc;
28
29
pub async fn process_deploy(env: Environment) -> Result<CommandResult> {
30
// Check credentials.
crates/cli/src/main.rs
+1
-1
@@ -5,12 +5,12 @@ use smbcloud_cli::account::login::process_login;
5
use smbcloud_cli::account::logout::process_logout;
6
use smbcloud_cli::account::me::process_me;
7
use smbcloud_cli::cli::CommandResult;
8
+use smbcloud_cli::deploy::process_deploy::process_deploy;
9
use smbcloud_cli::project::crud_create::process_project_init;
10
use smbcloud_cli::project::process::process_project;
11
use smbcloud_cli::{
12
account::process_account,
13
cli::{Cli, Commands},
13
- deploy::process_deploy,
14
};
15
use smbcloud_network::{environment::Environment, network::check_internet_connection};
16
use std::{