Add container-lifecycle error variants
Introduce typed variants for the per-run container lifecycle
(WorkspaceMaterializationFailed, ImageBuildFailed,
ContainerStartFailed) and route the materialize_workspace
non-success exit through the dedicated variant. The other two
variants land now even without producers so the error surface
change is atomic.
Assisted-by: Claude Opus 4.7 via Claude Code
diff --git a/src/ci/run.rs b/src/ci/run.rs
index 5834e35..b10bbe4 100644
--- a/src/ci/run.rs
+++ b/src/ci/run.rs
@@ -466,11 +466,11 @@ pub fn materialize_workspace(
let tar_status = tar.wait()?;
let archive_status = archive.wait()?;
if !archive_status.success() || !tar_status.success() {
- // Task 3 introduces Error::WorkspaceMaterializationFailed; for
- // now use std::io::Error wrapped as Error::Io. Task 3 swaps it.
- return Err(Error::Io(std::io::Error::other(format!(
- "materialize_workspace: git archive exited {archive_status}, tar exited {tar_status}"
- ))));
+ return Err(Error::WorkspaceMaterializationFailed {
+ source: std::io::Error::other(format!(
+ "git archive exited {archive_status}, tar exited {tar_status}"
+ )),
+ });
}
Ok(())
}
@@ -590,6 +590,41 @@ mod tests {
);
}
+ #[test]
+ fn materialize_workspace_errors_on_unknown_sha() {
+ let dir = tempfile::tempdir().expect("tempdir");
+ let src_repo = dir.path().join("src");
+ fs_err::create_dir_all(&src_repo).expect("mkdir src");
+
+ let env_vars: [(&str, &str); 6] = [
+ ("GIT_AUTHOR_NAME", "test"),
+ ("GIT_AUTHOR_EMAIL", "test@test"),
+ ("GIT_COMMITTER_NAME", "test"),
+ ("GIT_COMMITTER_EMAIL", "test@test"),
+ ("GIT_CONFIG_GLOBAL", "/dev/null"),
+ ("GIT_CONFIG_SYSTEM", "/dev/null"),
+ ];
+ let out = std::process::Command::new("git")
+ .args(["init", "-b", "main"])
+ .current_dir(&src_repo)
+ .envs(env_vars)
+ .output()
+ .expect("git init");
+ assert!(out.status.success());
+
+ let workspace = dir.path().join("ws");
+ let err = materialize_workspace(
+ &src_repo.join(".git"),
+ "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef",
+ &workspace,
+ )
+ .expect_err("expected failure on unknown SHA");
+ assert!(
+ matches!(err, Error::WorkspaceMaterializationFailed { .. }),
+ "expected WorkspaceMaterializationFailed, got: {err:?}"
+ );
+ }
+
#[test]
fn run_state_dir_name() {
assert_eq!(RunState::Pending.dir_name(), "pending");
diff --git a/src/error.rs b/src/error.rs
index 5533a63..80478b1 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -40,6 +40,24 @@ pub enum Error {
source: Box<Error>,
},
+ #[error("workspace materialization failed")]
+ WorkspaceMaterializationFailed {
+ #[source]
+ source: std::io::Error,
+ },
+
+ #[error("image build failed")]
+ ImageBuildFailed {
+ #[source]
+ source: std::io::Error,
+ },
+
+ #[error("container start failed")]
+ ContainerStartFailed {
+ #[source]
+ source: std::io::Error,
+ },
+
#[error("git error: {0}")]
Git(String),