Skip to content

Commit 5680cd8

Browse files
Alex Holmbergclaude
authored andcommitted
fix(11.3-01): derive dockerfile paths relative to repo root for Cloud Runner
Cloud Runner clones the GitHub repo and needs paths relative to the repo root, not relative to the analyzed subdirectory. When deploying from a monorepo subdirectory (e.g., services/contact-intelligence), the dockerfile_path and build_context must include the full path from repo root. Example for path="services/contact-intelligence": - Before: dockerfile="Dockerfile", context="." - After: dockerfile="services/contact-intelligence/Dockerfile", context="services/contact-intelligence" Co-Authored-By: Claude <noreply@anthropic.com>
1 parent d31a461 commit 5680cd8

1 file changed

Lines changed: 42 additions & 24 deletions

File tree

src/agent/tools/platform/deploy_service.rs

Lines changed: 42 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -562,21 +562,22 @@ User: "deploy this service"
562562
// Build deployment config request
563563
// Derive dockerfile path and build context from DockerfileInfo
564564
//
565-
// IMPORTANT: Paths are relative to the ANALYZED directory (args.path), NOT the project root.
566-
// This matches the manual wizard behavior when you run `sync-ctl deploy` from a subdirectory.
565+
// IMPORTANT: Paths must be relative to the REPO ROOT for Cloud Runner.
566+
// Cloud Runner clones the GitHub repo and builds from there.
567567
//
568-
// Example: User's local structure might be:
569-
// /local/project/services/contact-intelligence/Dockerfile
570-
// But the GitHub repo might have:
571-
// /Dockerfile (at root)
568+
// Example: User analyzes path="services/contact-intelligence" which has a Dockerfile.
569+
// The GitHub repo structure is:
570+
// repo-root/
571+
// services/
572+
// contact-intelligence/
573+
// Dockerfile
572574
//
573-
// When user specifies path="services/contact-intelligence", we analyze that dir and find
574-
// Dockerfile there. The paths sent to cloud runner should be:
575-
// dockerfile: "Dockerfile", context: "."
576-
// NOT:
577-
// dockerfile: "services/contact-intelligence/Dockerfile", context: "services/contact-intelligence"
575+
// Cloud Runner needs:
576+
// dockerfile: "services/contact-intelligence/Dockerfile"
577+
// context: "services/contact-intelligence"
578578
//
579-
// This is because the GitHub repo structure may differ from local structure.
579+
// NOT:
580+
// dockerfile: "Dockerfile", context: "." (would look at repo root)
580581
let (dockerfile_path, build_context) = analysis.docker_analysis
581582
.as_ref()
582583
.and_then(|d| d.dockerfiles.first())
@@ -587,27 +588,44 @@ User: "deploy this service"
587588
.unwrap_or_else(|| "Dockerfile".to_string());
588589

589590
// Derive dockerfile's directory relative to analysis_path
590-
// This gives us the path relative to what we analyzed, NOT the project root
591591
let analysis_relative_dir = df.path.parent()
592592
.and_then(|p| p.strip_prefix(&analysis_path).ok())
593593
.map(|p| p.to_string_lossy().to_string())
594594
.unwrap_or_default();
595595

596-
// Build paths relative to the analyzed directory
597-
// DO NOT prepend args.path - the repo structure may differ from local structure
598-
if analysis_relative_dir.is_empty() {
599-
// Dockerfile is at the root of the analyzed directory
600-
// dockerfile: "Dockerfile", context: "."
601-
(dockerfile_name, ".".to_string())
596+
// Build paths relative to REPO ROOT by prepending args.path (the subdirectory)
597+
// This ensures Cloud Runner finds the Dockerfile in the cloned repo
598+
let subpath = args.path.as_deref().unwrap_or("");
599+
600+
if subpath.is_empty() {
601+
// Analyzing repo root - use paths as-is
602+
if analysis_relative_dir.is_empty() {
603+
(dockerfile_name, ".".to_string())
604+
} else {
605+
(format!("{}/{}", analysis_relative_dir, dockerfile_name), analysis_relative_dir)
606+
}
602607
} else {
603-
// Dockerfile is in a subdirectory of the analyzed directory
604-
// dockerfile: "subdir/Dockerfile", context: "subdir"
605-
(format!("{}/{}", analysis_relative_dir, dockerfile_name), analysis_relative_dir)
608+
// Analyzing a subdirectory - prepend subpath to make repo-root-relative
609+
if analysis_relative_dir.is_empty() {
610+
// Dockerfile at root of analyzed subdir
611+
// e.g., subpath="services/contact-intelligence" -> dockerfile="services/contact-intelligence/Dockerfile"
612+
(format!("{}/{}", subpath, dockerfile_name), subpath.to_string())
613+
} else {
614+
// Dockerfile in nested dir within analyzed subdir
615+
// e.g., subpath="services", analysis_relative_dir="contact-intelligence"
616+
let full_context = format!("{}/{}", subpath, analysis_relative_dir);
617+
(format!("{}/{}", full_context, dockerfile_name), full_context)
618+
}
606619
}
607620
})
608621
.unwrap_or_else(|| {
609-
// No dockerfile found - default to root
610-
("Dockerfile".to_string(), ".".to_string())
622+
// No dockerfile found - use subpath as context if provided, else root
623+
let subpath = args.path.as_deref().unwrap_or("");
624+
if subpath.is_empty() {
625+
("Dockerfile".to_string(), ".".to_string())
626+
} else {
627+
(format!("{}/Dockerfile", subpath), subpath.to_string())
628+
}
611629
});
612630

613631
tracing::debug!(

0 commit comments

Comments
 (0)