From 34e1fc513e915ec103f6ea5a2eaa9de89b127251 Mon Sep 17 00:00:00 2001 From: bahdotsh Date: Wed, 30 Apr 2025 16:51:38 +0530 Subject: [PATCH] ix(executor): correct image selection and workspace mapping for run steps Previously, `run` steps in Docker jobs were failing due to several issues: - They were hardcoded to use `ubuntu:latest`, which often lacked necessary tools like `cargo`. - Even when the image was correct, the host workspace directory was not properly mapped into the container, preventing access to source files. This commit addresses these issues by: - Using the correct runner image specified by the job's `runs_on` field for `run` steps, instead of always defaulting to `ubuntu:latest`. - Updating the `get_runner_image` function to map `macos-latest` runners to `rust:latest` to ensure the Rust toolchain is available for relevant workflows. - Correctly mapping the host working directory to `/github/workspace` within the container for `run` steps. - Setting the container's working directory to `/github/workspace` when executing `run` steps. This allows commands like `cargo build` and `cargo test` within `run` steps to find both the necessary tools and the project source code inside the container. --- src/executor/docker.rs | 8 +++---- src/executor/engine.rs | 48 ++++++++++++++++++++++++------------------ 2 files changed, 32 insertions(+), 24 deletions(-) diff --git a/src/executor/docker.rs b/src/executor/docker.rs index 917aa4d..a73ad32 100644 --- a/src/executor/docker.rs +++ b/src/executor/docker.rs @@ -586,7 +586,7 @@ impl ContainerRuntime for DockerRuntime { logging::info(&format!("Docker: Running container with image: {}", image)); // Add a global timeout for all Docker operations to prevent freezing - let timeout_duration = std::time::Duration::from_secs(60); // 1 minute timeout + let timeout_duration = std::time::Duration::from_secs(360); // Increased outer timeout to 6 minutes // Run the entire container operation with a timeout match tokio::time::timeout( @@ -597,7 +597,7 @@ impl ContainerRuntime for DockerRuntime { { Ok(result) => result, Err(_) => { - logging::error("Docker operation timed out after 60 seconds"); + logging::error("Docker operation timed out after 360 seconds"); Err(ContainerError::ContainerExecution( "Operation timed out".to_string(), )) @@ -926,9 +926,9 @@ impl DockerRuntime { } } - // Wait for container to finish with a timeout (30 seconds) + // Wait for container to finish with a timeout (300 seconds) let wait_result = tokio::time::timeout( - std::time::Duration::from_secs(30), + std::time::Duration::from_secs(300), self.docker .wait_container::(&container.id, None) .collect::>(), diff --git a/src/executor/engine.rs b/src/executor/engine.rs index 2185712..6a50aae 100644 --- a/src/executor/engine.rs +++ b/src/executor/engine.rs @@ -607,7 +607,7 @@ async fn execute_job(ctx: JobExecutionContext<'_>) -> Result { working_dir: &'a Path, runtime: &'a dyn ContainerRuntime, workflow: &'a WorkflowDefinition, - job_runs_on: &'a str, + runner_image: &'a str, verbose: bool, #[allow(dead_code)] matrix_combination: &'a Option>, @@ -1016,7 +1016,7 @@ async fn execute_step(ctx: StepExecutionContext<'_>) -> Result) -> Result = - vec![(ctx.working_dir, Path::new("/github/workspace"))]; + // Define the standard workspace path inside the container + let container_workspace = Path::new("/github/workspace"); + + // Set up volume mapping from host working dir to container workspace + let volumes: Vec<(&Path, &Path)> = vec![(ctx.working_dir, container_workspace)]; let output = ctx .runtime .run_container( - &image, + ctx.runner_image, &cmd.to_vec(), &env_vars, - Path::new("/github/workspace"), + container_workspace, &volumes, ) .await @@ -1455,15 +1457,21 @@ async fn execute_step(ctx: StepExecutionContext<'_>) -> Result = vec![(ctx.working_dir, container_workspace)]; + // Execute the command match ctx .runtime .run_container( - "ubuntu:latest", // or appropriate runner image + ctx.runner_image, &cmd_parts, &env_vars, - ctx.working_dir, - &[], // Empty volumes for now, add if needed + container_workspace, + &volumes, ) .await { @@ -1606,11 +1614,11 @@ fn get_runner_image(runs_on: &str) -> String { "ubuntu-20.04-large" => "catthehacker/ubuntu:full-20.04", "ubuntu-18.04-large" => "catthehacker/ubuntu:full-18.04", - // macOS runners - use existing images for macOS compatibility layer - "macos-latest" => "catthehacker/ubuntu:act-latest", // Use Ubuntu with macOS compatibility - "macos-12" => "catthehacker/ubuntu:act-latest", // Monterey equivalent - "macos-11" => "catthehacker/ubuntu:act-latest", // Big Sur equivalent - "macos-10.15" => "catthehacker/ubuntu:act-latest", // Catalina equivalent + // macOS runners - use a standard Rust image for compatibility + "macos-latest" => "rust:latest", + "macos-12" => "rust:latest", // Monterey equivalent + "macos-11" => "rust:latest", // Big Sur equivalent + "macos-10.15" => "rust:latest", // Catalina equivalent // Windows runners - using servercore-based images "windows-latest" => "mcr.microsoft.com/windows/servercore:ltsc2022", @@ -1649,7 +1657,7 @@ fn get_runner_image(runs_on: &str) -> String { // Check for platform prefixes and provide appropriate images let runs_on_lower = runs_on.trim().to_lowercase(); if runs_on_lower.starts_with("macos") { - "catthehacker/ubuntu:act-latest" // Use Ubuntu with macOS compatibility + "rust:latest" // Use Rust image for macOS runners } else if runs_on_lower.starts_with("windows") { "mcr.microsoft.com/windows/servercore:ltsc2022" // Default Windows image } else if runs_on_lower.starts_with("python") { @@ -1727,7 +1735,7 @@ async fn execute_composite_action( job_env: &HashMap, working_dir: &Path, runtime: &dyn ContainerRuntime, - job_runs_on: &str, + runner_image: &str, verbose: bool, ) -> Result { // Find the action definition file @@ -1823,7 +1831,7 @@ async fn execute_composite_action( on_raw: serde_yaml::Value::Null, jobs: HashMap::new(), }, - job_runs_on, + runner_image, verbose, matrix_combination: &None, }))