smbcloud_cli/deploy/
mod.rs

1pub mod config;
2mod git;
3mod remote_messages;
4mod setup;
5
6use crate::{
7    account::{lib::is_logged_in, login::process_login},
8    cli::CommandResult,
9    deploy::config::check_project,
10    ui::{fail_message, succeed_message, succeed_symbol},
11};
12use anyhow::{anyhow, Result};
13use config::check_config;
14use git::remote_deployment_setup;
15use git2::{PushOptions, RemoteCallbacks, Repository};
16use remote_messages::{build_next_app, start_server};
17use smbcloud_model::project::DeploymentPayload;
18use smbcloud_model::project::DeploymentStatus;
19use smbcloud_networking::environment::Environment;
20use smbcloud_networking_project::crud_project_deployment_create::create;
21use spinners::Spinner;
22
23pub async fn process_deploy(env: Environment) -> Result<CommandResult> {
24    // Check credentials.
25    if !is_logged_in(env) {
26        let _ = process_login(env).await;
27    }
28
29    // Check config.
30    let config = check_config(env).await?;
31
32    // Validate config with project.
33    check_project(env, config.project.id).await?;
34
35    // Check remote repository setup.
36    let repo = match Repository::open(".") {
37        Ok(repo) => repo,
38        Err(_) => {
39            return Err(anyhow!(fail_message(
40                "No git repository found. Init with `git init` command."
41            )))
42        }
43    };
44
45    let main_branch = match repo.head() {
46        Ok(branch) => branch,
47        Err(_) => {
48            return Err(anyhow!(fail_message(
49                "No main branch found. Create with `git checkout -b <branch>` command."
50            )))
51        }
52    };
53
54    let mut origin = remote_deployment_setup(&repo, &config.project.repository).await?;
55
56    let commit_hash = match main_branch.resolve() {
57        Ok(result) => match result.target() {
58            Some(hash_id) => hash_id,
59            None => todo!(),
60        },
61        Err(_) => todo!(),
62    };
63    let payload = DeploymentPayload {
64        commit_hash: commit_hash.to_string(),
65        status: DeploymentStatus::Started,
66    };
67
68    let _deployment = create(env, config.project.id, payload).await?;
69
70    let mut push_opts = PushOptions::new();
71    let mut callbacks = RemoteCallbacks::new();
72    // Set the credentials
73    callbacks.credentials(config.credentials());
74    callbacks.sideband_progress(|data| {
75        // Convert bytes to string, print line by line
76        if let Ok(text) = std::str::from_utf8(data) {
77            for line in text.lines() {
78                if line.contains(&build_next_app()) {
79                    println!("Building the app {}", succeed_symbol());
80                }
81                if line.contains(&start_server(&config.project.repository)) {
82                    println!("App restart {}", succeed_symbol());
83                }
84            }
85        }
86        true // continue receiving.
87    });
88    callbacks.push_update_reference(|_x, status_message| match status_message {
89        Some(e) => {
90            println!("Deployment fail: {}", e);
91            Ok(())
92        }
93        None => Ok(()),
94    });
95    push_opts.remote_callbacks(callbacks);
96
97    let spinner = Spinner::new(
98        spinners::Spinners::Hamburger,
99        succeed_message("Deploying > "),
100    );
101
102    match origin.push(&["refs/heads/main:refs/heads/main"], Some(&mut push_opts)) {
103        Ok(_) => Ok(CommandResult {
104            spinner,
105            symbol: succeed_symbol(),
106            msg: succeed_message("Deployment complete."),
107        }),
108        Err(e) => Err(anyhow!(fail_message(&e.to_string()))),
109    }
110}