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, me::me},
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    let user = me(env).await?;
70
71    let mut push_opts = PushOptions::new();
72    let mut callbacks = RemoteCallbacks::new();
73    // Set the credentials
74    callbacks.credentials(config.credentials(user));
75    callbacks.sideband_progress(|data| {
76        // Convert bytes to string, print line by line
77        if let Ok(text) = std::str::from_utf8(data) {
78            for line in text.lines() {
79                if line.contains(&build_next_app()) {
80                    println!("Building the app {}", succeed_symbol());
81                }
82                if line.contains(&start_server(&config.project.repository)) {
83                    println!("App restart {}", succeed_symbol());
84                }
85            }
86        }
87        true // continue receiving.
88    });
89    callbacks.push_update_reference(|_x, status_message| match status_message {
90        Some(e) => {
91            println!("Deployment fail: {}", e);
92            Ok(())
93        }
94        None => Ok(()),
95    });
96    push_opts.remote_callbacks(callbacks);
97
98    let spinner = Spinner::new(
99        spinners::Spinners::Hamburger,
100        succeed_message("Deploying > "),
101    );
102
103    match origin.push(&["refs/heads/main:refs/heads/main"], Some(&mut push_opts)) {
104        Ok(_) => Ok(CommandResult {
105            spinner,
106            symbol: succeed_symbol(),
107            msg: succeed_message("Deployment complete."),
108        }),
109        Err(e) => Err(anyhow!(fail_message(&e.to_string()))),
110    }
111}