From f876facfa77c583a6b7b5facaf5755bc3eafb784 Mon Sep 17 00:00:00 2001 From: mbecker20 Date: Sun, 19 Oct 2025 21:47:29 -0700 Subject: [PATCH] improve git status message / failure propogation --- bin/core/src/api/write/build.rs | 80 ++++++++++++++++----------- bin/core/src/stack/remote.rs | 18 +++++- bin/core/src/sync/remote.rs | 21 +++++-- client/core/rs/src/entities/update.rs | 8 +-- 4 files changed, 84 insertions(+), 43 deletions(-) diff --git a/bin/core/src/api/write/build.rs b/bin/core/src/api/write/build.rs index dc8a2427c..99a94c195 100644 --- a/bin/core/src/api/write/build.rs +++ b/bin/core/src/api/write/build.rs @@ -390,23 +390,28 @@ impl Resolve for RefreshBuildCache { None }; - let ( - remote_path, - remote_contents, - remote_error, - latest_hash, - latest_message, - ) = if build.config.files_on_host { + let RemoteDockerfileContents { + path, + contents, + error, + hash, + message, + } = if build.config.files_on_host { // ============= // FILES ON HOST // ============= match get_on_host_dockerfile(&build).await { Ok(FileContents { path, contents }) => { - (Some(path), Some(contents), None, None, None) - } - Err(e) => { - (None, None, Some(format_serror(&e.into())), None, None) + RemoteDockerfileContents { + path: Some(path), + contents: Some(contents), + ..Default::default() + } } + Err(e) => RemoteDockerfileContents { + error: Some(format_serror(&e.into())), + ..Default::default() + }, } } else if let Some(repo) = &repo { let Some(res) = get_git_remote(&build, repo.into()).await? @@ -426,7 +431,7 @@ impl Resolve for RefreshBuildCache { // ============= // UI BASED FILE // ============= - (None, None, None, None, None) + RemoteDockerfileContents::default() }; let info = BuildInfo { @@ -434,11 +439,11 @@ impl Resolve for RefreshBuildCache { built_hash: build.info.built_hash, built_message: build.info.built_message, built_contents: build.info.built_contents, - remote_path, - remote_contents, - remote_error, - latest_hash, - latest_message, + remote_path: path, + remote_contents: contents, + remote_error: error, + latest_hash: hash, + latest_message: message, }; let info = to_document(&info) @@ -530,15 +535,7 @@ async fn get_on_host_dockerfile( async fn get_git_remote( build: &Build, mut clone_args: RepoExecutionArgs, -) -> anyhow::Result< - Option<( - Option, - Option, - Option, - Option, - Option, - )>, -> { +) -> anyhow::Result> { if clone_args.provider.is_empty() { // Nothing to do here return Ok(None); @@ -565,7 +562,17 @@ async fn get_git_remote( access_token, ) .await - .context("failed to clone build repo")?; + .context("Failed to clone Build repo")?; + + // Ensure clone / pull successful, + // propogate error log -> 'errored' and return. + if let Some(failure) = res.logs.iter().find(|log| !log.success) { + return Ok(Some(RemoteDockerfileContents { + path: Some(format!("Failed at: {}", failure.stage)), + error: Some(failure.combined()), + ..Default::default() + })); + } let relative_path = PathBuf::from(&build.config.build_path) .join(&build.config.dockerfile_path); @@ -578,11 +585,20 @@ async fn get_git_remote( Ok(contents) => (Some(contents), None), Err(e) => (None, Some(format_serror(&e.into()))), }; - Ok(Some(( - Some(relative_path.display().to_string()), + Ok(Some(RemoteDockerfileContents { + path: Some(relative_path.display().to_string()), contents, error, - res.commit_hash, - res.commit_message, - ))) + hash: res.commit_hash, + message: res.commit_message, + })) +} + +#[derive(Default)] +pub struct RemoteDockerfileContents { + pub path: Option, + pub contents: Option, + pub error: Option, + pub hash: Option, + pub message: Option, } diff --git a/bin/core/src/stack/remote.rs b/bin/core/src/stack/remote.rs index a6c012f6f..41cf6b6e9 100644 --- a/bin/core/src/stack/remote.rs +++ b/bin/core/src/stack/remote.rs @@ -11,12 +11,13 @@ use komodo_client::entities::{ use crate::{config::core_config, helpers::git_token}; +#[derive(Default)] pub struct RemoteComposeContents { pub successful: Vec, pub errored: Vec, pub hash: Option, pub message: Option, - pub _logs: Vec, + // pub logs: Vec, } /// Returns Result<(read paths, error paths, logs, short hash, commit message)> @@ -28,11 +29,23 @@ pub async fn get_repo_compose_contents( ) -> anyhow::Result { let clone_args: RepoExecutionArgs = repo.map(Into::into).unwrap_or(stack.into()); - let (repo_path, _logs, hash, message) = + let (repo_path, logs, hash, message) = ensure_remote_repo(clone_args) .await .context("Failed to clone stack repo")?; + // Ensure clone / pull successful, + // propogate error log -> 'errored' and return. + if let Some(failure) = logs.iter().find(|log| !log.success) { + return Ok(RemoteComposeContents { + errored: vec![FileContents { + path: format!("Failed at: {}", failure.stage), + contents: failure.combined(), + }], + ..Default::default() + }); + } + let run_directory = repo_path.join(&stack.config.run_directory); // This will remove any intermediate '/./' which can be a problem for some OS. let run_directory = run_directory.components().collect::(); @@ -69,7 +82,6 @@ pub async fn get_repo_compose_contents( errored, hash, message, - _logs, }) } diff --git a/bin/core/src/sync/remote.rs b/bin/core/src/sync/remote.rs index 194095065..688798880 100644 --- a/bin/core/src/sync/remote.rs +++ b/bin/core/src/sync/remote.rs @@ -1,4 +1,4 @@ -use anyhow::Context; +use anyhow::{Context, anyhow}; use komodo_client::entities::{ RepoExecutionArgs, RepoExecutionResponse, repo::Repo, @@ -99,9 +99,22 @@ async fn get_repo( format!("Failed to update resource repo at {repo_path:?}") })?; - // let hash = hash.context("failed to get commit hash")?; - // let message = - // message.context("failed to get commit hash message")?; + // Ensure clone / pull successful, + // propogate error log -> 'errored' and return. + if let Some(failure) = logs.iter().find(|log| !log.success) { + return Ok(RemoteResources { + resources: Err(anyhow!("Repo clone / pull failed")), + files: Vec::new(), + file_errors: vec![SyncFileContents { + resource_path: String::from("Repo error"), + path: format!("Failed at: {}", failure.stage), + contents: failure.combined(), + }], + logs, + hash: None, + message: None, + }); + } let (mut files, mut file_errors) = (Vec::new(), Vec::new()); let resources = super::file::read_resources( diff --git a/client/core/rs/src/entities/update.rs b/client/core/rs/src/entities/update.rs index 7e25a9640..8c17967c4 100644 --- a/client/core/rs/src/entities/update.rs +++ b/client/core/rs/src/entities/update.rs @@ -192,12 +192,12 @@ impl Log { /// Combines stdout / stderr into one log pub fn combined(&self) -> String { match (self.stdout.is_empty(), self.stderr.is_empty()) { - (true, true) => { + (false, false) => { format!("stdout: {}\n\nstderr: {}", self.stdout, self.stderr) } - (true, false) => self.stdout.to_string(), - (false, true) => self.stderr.to_string(), - (false, false) => String::from("No log"), + (false, true) => self.stdout.to_string(), + (true, false) => self.stderr.to_string(), + (true, true) => String::from("No log"), } } }