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