Skip to content

Commit d31a461

Browse files
Alex Holmbergclaude
authored andcommitted
fix(deploy): use paths relative to analyzed dir, not project root
When user specifies path="services/foo" to deploy a subdirectory, the dockerfile paths should be relative to THAT directory, not the project root. This matches the manual wizard behavior when you run `sync-ctl deploy` from within the service directory: - dockerfile: "Dockerfile" - context: "." The GitHub repo structure may differ from the local filesystem structure. For example, locally you might have: /project/services/contact-intelligence/Dockerfile But the GitHub repo might have: /Dockerfile (at root) Previously we were prepending args.path to make paths "repo-root-relative", but this broke deployments when the repo structure differed from local. Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 1dd0ee6 commit d31a461

1 file changed

Lines changed: 29 additions & 32 deletions

File tree

src/agent/tools/platform/deploy_service.rs

Lines changed: 29 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -561,8 +561,22 @@ User: "deploy this service"
561561

562562
// Build deployment config request
563563
// Derive dockerfile path and build context from DockerfileInfo
564-
// For monorepos: context = service folder, dockerfile = full path from repo root
565-
// This matches what the manual wizard sends when user selects the service folder
564+
//
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.
567+
//
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)
572+
//
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"
578+
//
579+
// This is because the GitHub repo structure may differ from local structure.
566580
let (dockerfile_path, build_context) = analysis.docker_analysis
567581
.as_ref()
568582
.and_then(|d| d.dockerfiles.first())
@@ -573,44 +587,27 @@ User: "deploy this service"
573587
.unwrap_or_else(|| "Dockerfile".to_string());
574588

575589
// Derive dockerfile's directory relative to analysis_path
590+
// This gives us the path relative to what we analyzed, NOT the project root
576591
let analysis_relative_dir = df.path.parent()
577592
.and_then(|p| p.strip_prefix(&analysis_path).ok())
578593
.map(|p| p.to_string_lossy().to_string())
579594
.unwrap_or_default();
580595

581-
// Build paths relative to repo root
582-
// If we analyzed a subdirectory (args.path), prepend it
583-
match (&args.path, analysis_relative_dir.as_str()) {
584-
(Some(subpath), "") | (Some(subpath), ".") => {
585-
// Dockerfile is at the root of the analyzed subpath
586-
// dockerfile: "services/foo/Dockerfile", context: "services/foo"
587-
(format!("{}/{}", subpath, dockerfile_name), subpath.clone())
588-
}
589-
(Some(subpath), rel_dir) => {
590-
// Dockerfile is nested within the analyzed subpath
591-
// dockerfile: "services/foo/nested/Dockerfile", context: "services/foo/nested"
592-
let context = format!("{}/{}", subpath, rel_dir);
593-
(format!("{}/{}", context, dockerfile_name), context)
594-
}
595-
(None, "") | (None, ".") => {
596-
// Dockerfile at repo root
597-
// dockerfile: "Dockerfile", context: "."
598-
(dockerfile_name, ".".to_string())
599-
}
600-
(None, rel_dir) => {
601-
// Dockerfile in subdirectory from repo root
602-
// dockerfile: "subdir/Dockerfile", context: "subdir"
603-
(format!("{}/{}", rel_dir, dockerfile_name), rel_dir.to_string())
604-
}
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())
602+
} 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)
605606
}
606607
})
607608
.unwrap_or_else(|| {
608-
// No dockerfile found - construct path from subpath if provided
609-
if let Some(ref subpath) = args.path {
610-
(format!("{}/Dockerfile", subpath), subpath.clone())
611-
} else {
612-
("Dockerfile".to_string(), ".".to_string())
613-
}
609+
// No dockerfile found - default to root
610+
("Dockerfile".to_string(), ".".to_string())
614611
});
615612

616613
tracing::debug!(

0 commit comments

Comments
 (0)