|
82 | 82 |
|
83 | 83 | # Runnable stub bodies per language: bare FROM+COPY exits immediately (base-image |
84 | 84 | # CMD is a no-op), crash-looping the task until every health probe times out. |
| 85 | +# Include health-file shims so the ALB target group probe (/health, /healthz, |
| 86 | +# /actuator/health etc.) succeeds even when the terraform default differs from |
| 87 | +# the stub's "/" root. http.server and http-server serve plain files at those |
| 88 | +# exact paths, so create them at build time. |
85 | 89 | _STUB_RUN: Final[dict[str, str]] = { |
86 | | - "javascript": 'EXPOSE 3000\nENV PORT=3000\nCMD ["npx", "-y", "http-server", "-p", "3000", "."]', |
87 | | - "typescript": 'EXPOSE 3000\nENV PORT=3000\nCMD ["npx", "-y", "http-server", "-p", "3000", "."]', |
88 | | - "python": 'EXPOSE 8080\nCMD ["python", "-m", "http.server", "8080", "--bind", "0.0.0.0"]', |
89 | | - "ruby": 'EXPOSE 8080\nCMD ["ruby", "-run", "-e", "httpd", ".", "-p", "8080"]', |
90 | | - "php": 'EXPOSE 8080\nCMD ["php", "-S", "0.0.0.0:8080", "-t", "."]', |
| 90 | + "javascript": 'RUN echo ok > health && echo ok > healthz && echo ok > status && mkdir -p api && echo ok > api/health\n' |
| 91 | + 'EXPOSE 3000\nENV PORT=3000\nCMD ["npx", "-y", "http-server", "-p", "3000", ".", "--cors"]', |
| 92 | + "typescript": 'RUN echo ok > health && echo ok > healthz && echo ok > status && mkdir -p api && echo ok > api/health\n' |
| 93 | + 'EXPOSE 3000\nENV PORT=3000\nCMD ["npx", "-y", "http-server", "-p", "3000", ".", "--cors"]', |
| 94 | + "python": 'RUN echo ok > health && echo ok > healthz && echo ok > status && mkdir -p api && echo ok > api/health\n' |
| 95 | + 'EXPOSE 8080\nCMD ["python", "-m", "http.server", "8080", "--bind", "0.0.0.0"]', |
| 96 | + "ruby": 'RUN echo ok > health && echo ok > healthz\nEXPOSE 8080\nCMD ["ruby", "-run", "-e", "httpd", ".", "-p", "8080"]', |
| 97 | + "php": 'RUN echo ok > health && echo ok > healthz\nEXPOSE 8080\nCMD ["php", "-S", "0.0.0.0:8080", "-t", "."]', |
91 | 98 | } |
92 | 99 |
|
93 | 100 |
|
@@ -188,10 +195,36 @@ def resolve_docker_artifacts( |
188 | 195 | containers = analysis.stack_detection.containers or [ |
189 | 196 | analysis.stack_detection.container |
190 | 197 | ] |
191 | | - # Language-aware base image for repos without a Dockerfile. |
192 | 198 | fallback_base = _FALLBACK_BASE_IMAGES.get( |
193 | 199 | analysis.stack_detection.primary_language, "python:3.12-slim" |
194 | 200 | ) |
| 201 | + # Monorepo packaging artifacts: pnpm and similar tool repos carry internal |
| 202 | + # Dockerfiles under docker/, __patches__, pnpr/, fixtures/, .github/ etc. |
| 203 | + # Treating those as separate ECS images creates a multi-image service that |
| 204 | + # always fails its build (version-mismatch, missing release tarball). Keep |
| 205 | + # only root-proximate Dockerfiles unless docker-compose explicitly declared |
| 206 | + # a multi-service primary; otherwise collapse to the primary entrypoint. |
| 207 | + if len(containers) > 1: |
| 208 | + shallow = [ |
| 209 | + c for c in containers |
| 210 | + if c.dockerfile_path and Path(c.dockerfile_path).parts[0].lower() not in ( |
| 211 | + "docker", "__patches__", "fixtures", "pnpr", ".github", "scripts", "tools" |
| 212 | + ) and c.dockerfile_path.count("/") <= 1 |
| 213 | + ] |
| 214 | + if shallow: |
| 215 | + containers = shallow |
| 216 | + elif not any(c.dockerfile_path == "Dockerfile" for c in containers): |
| 217 | + logger.info("Monorepo tool images filtered out; collapsing to single stub") |
| 218 | + containers = [] |
| 219 | + if not containers: |
| 220 | + # No Dockerfile at all (common for libraries/CLIs): synthesize one so |
| 221 | + # the pipeline still produces a runnable artifact for health probing. |
| 222 | + containers = [analysis.stack_detection.container] if analysis.stack_detection.container else [] |
| 223 | + if not containers or not containers[0].dockerfile_content: |
| 224 | + if containers and containers[0]: |
| 225 | + containers[0].dockerfile_content = None # type: ignore |
| 226 | + else: |
| 227 | + containers = [type("C", (), {"dockerfile_path": None, "dockerfile_content": None, "base_image": fallback_base})()] # type: ignore |
195 | 228 | images: list[DockerImage] = [] |
196 | 229 | for index, container in enumerate(containers): |
197 | 230 | base_image = container.base_image or fallback_base |
|
0 commit comments