prevent duplicate parallel builds

This commit is contained in:
Reinier van der Leer
2026-02-12 15:20:11 +01:00
parent 39b821da94
commit 66be27f6da

View File

@@ -46,17 +46,66 @@ def main():
# Get project name from compose file or default
project_name = compose.get("name", "autogpt_platform")
def get_image_name(dockerfile: str, target: str) -> str:
"""Generate image name based on Dockerfile folder and build target."""
dockerfile_parts = dockerfile.replace("\\", "/").split("/")
if len(dockerfile_parts) >= 2:
folder_name = dockerfile_parts[-2] # e.g., "backend" or "frontend"
else:
folder_name = "app"
return f"{project_name}-{folder_name}:{target}"
def get_build_key(dockerfile: str, target: str) -> str:
"""Generate a unique key for a Dockerfile+target combination."""
return f"{dockerfile}:{target}"
# First pass: collect all services with build configs and identify duplicates
# Track which (dockerfile, target) combinations we've seen
build_key_to_first_service: dict[str, str] = {}
services_to_build: list[str] = []
services_to_dedupe: list[str] = []
for service_name, service_config in compose.get("services", {}).items():
if "build" not in service_config:
continue
build_config = service_config["build"]
dockerfile = build_config.get("dockerfile", "Dockerfile")
target = build_config.get("target", "default")
build_key = get_build_key(dockerfile, target)
if build_key not in build_key_to_first_service:
# First service with this build config - it will do the actual build
build_key_to_first_service[build_key] = service_name
services_to_build.append(service_name)
else:
# Duplicate - will just use the image from the first service
services_to_dedupe.append(service_name)
# Second pass: configure builds and deduplicate
modified_services = []
for service_name, service_config in compose.get("services", {}).items():
if "build" not in service_config:
continue
build_config = service_config["build"]
dockerfile = build_config.get("dockerfile", "Dockerfile")
target = build_config.get("target", "default")
image_name = get_image_name(dockerfile, target)
# Set image name for all services (needed for both builders and deduped)
service_config["image"] = image_name
if service_name in services_to_dedupe:
# Remove build config - this service will use the pre-built image
del service_config["build"]
continue
# This service will do the actual build - add cache config
cache_from = args.cache_from
cache_to = args.cache_to
# Determine scope based on Dockerfile path
dockerfile = build_config.get("dockerfile", "Dockerfile")
if "type=gha" in args.cache_from or "type=gha" in args.cache_to:
if "frontend" in dockerfile:
scope = args.frontend_scope
@@ -74,20 +123,6 @@ def main():
build_config["cache_from"] = [cache_from]
build_config["cache_to"] = [cache_to]
# Set image name based on Dockerfile folder and build target
# This ensures services with the same Dockerfile+target share an image
if "image" not in service_config:
# Extract folder name from dockerfile path (e.g., "backend" from "autogpt_platform/backend/Dockerfile")
dockerfile_parts = dockerfile.replace("\\", "/").split("/")
if len(dockerfile_parts) >= 2:
folder_name = dockerfile_parts[-2] # e.g., "backend" or "frontend"
else:
folder_name = "app"
target = build_config.get("target", "default")
service_config["image"] = f"{project_name}-{folder_name}:{target}"
modified_services.append(service_name)
# Write back to the same file
@@ -97,6 +132,12 @@ def main():
print(f"Added cache config to {len(modified_services)} services in {args.source}:")
for svc in modified_services:
print(f" - {svc}")
if services_to_dedupe:
print(
f"Deduplicated {len(services_to_dedupe)} services (will use pre-built images):"
)
for svc in services_to_dedupe:
print(f" - {svc}")
if __name__ == "__main__":