common-python-tasks 0.11.0__tar.gz → 0.12.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/PKG-INFO +2 -2
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/README.md +1 -1
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/docs/configuration.md +2 -1
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/docs/tasks/container-images.md +66 -11
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/docs/tasks/reference/build-image.md +4 -3
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/docs/tasks/reference/build.md +2 -1
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/docs/tasks/reference/release.md +2 -1
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/scripts/docs_tasks_reference.py +0 -40
- common_python_tasks-0.12.0/src/common_python_tasks/data/dockerfile_extensions/docker-in-docker/Dockerfile +27 -0
- common_python_tasks-0.12.0/src/common_python_tasks/data/dockerfile_extensions/docker-in-docker/install.sh +39 -0
- common_python_tasks-0.12.0/src/common_python_tasks/data/dockerfile_extensions/docker-in-docker/supervisor.sh +116 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/src/common_python_tasks/data/generic/Dockerfile.j2 +6 -5
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/src/common_python_tasks/env.py +108 -37
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/src/common_python_tasks/tasks.py +97 -26
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/.gitignore +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/.poetry/plugins/poetry_dynamic_versioning-1.10.0.dist-info/licenses/LICENSE +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/.poetry/plugins/poetry_plugin_export-1.10.0.dist-info/licenses/LICENSE +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/LICENSE +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/docs/documentation-workflows.md +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/docs/getting-started.md +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/docs/index.md +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/docs/tasks/daily-development.md +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/docs/tasks/development-stacks.md +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/docs/tasks/documentation.md +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/docs/tasks/index.md +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/docs/tasks/packaging-and-releases.md +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/docs/tasks/reference/build-deps-image.md +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/docs/tasks/reference/build-package.md +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/docs/tasks/reference/bump-version.md +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/docs/tasks/reference/changelog.md +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/docs/tasks/reference/clean.md +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/docs/tasks/reference/container-shell.md +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/docs/tasks/reference/db-shell.md +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/docs/tasks/reference/docs-build.md +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/docs/tasks/reference/docs-serve.md +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/docs/tasks/reference/format.md +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/docs/tasks/reference/lint.md +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/docs/tasks/reference/publish-github-release.md +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/docs/tasks/reference/publish-package.md +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/docs/tasks/reference/push-image.md +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/docs/tasks/reference/reset-db.md +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/docs/tasks/reference/run-container.md +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/docs/tasks/reference/run-db-migrations.md +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/docs/tasks/reference/stack-down.md +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/docs/tasks/reference/stack-up.md +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/docs/tasks/reference/test.md +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/docs/tasks/reference/update-dependencies.md +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/pyproject.toml +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/scripts/__init__.py +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/scripts/add_common_python_tasks.py +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/scripts/release_script.py +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/scripts/update_docs_tasks_reference.py +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/scripts/utils.py +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/src/common_python_tasks/__init__.py +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/src/common_python_tasks/__main__.py +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/src/common_python_tasks/data/dockerfile_extensions/.gitkeep +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/src/common_python_tasks/data/fastapi/alembic.ini.j2 +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/src/common_python_tasks/data/fastapi/compose-base.yml.j2 +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/src/common_python_tasks/data/fastapi/compose-db-debug.yml.j2 +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/src/common_python_tasks/data/fastapi/compose-db.yml.j2 +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/src/common_python_tasks/data/fastapi/compose-debug.yml.j2 +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/src/common_python_tasks/data/generic/.coveragerc +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/src/common_python_tasks/data/generic/.dockerignore +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/src/common_python_tasks/data/generic/Dockerfile.deps.j2 +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/src/common_python_tasks/data/generic/cliff.toml +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/src/common_python_tasks/data/generic/pytest.ini +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/src/common_python_tasks/data/generic/ruff.toml +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/src/common_python_tasks/docker.py +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/src/common_python_tasks/docker_compose.py +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/src/common_python_tasks/git.py +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/src/common_python_tasks/github.py +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/src/common_python_tasks/project.py +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/src/common_python_tasks/utils.py +0 -0
- {common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/zensical.toml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: common-python-tasks
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.12.0
|
|
4
4
|
Summary: Opinionated Poe the Poet tasks for Python package development.
|
|
5
5
|
Project-URL: Homepage, http://github.com/ci-sourcerer/common-python-tasks
|
|
6
6
|
Project-URL: Source, http://github.com/ci-sourcerer/common-python-tasks.git
|
|
@@ -42,7 +42,7 @@ Read the [complete documentation](https://ci-sourcerer.github.io/common-python-t
|
|
|
42
42
|
Add the package as a development dependency.
|
|
43
43
|
|
|
44
44
|
```shell
|
|
45
|
-
uv add --dev common-python-tasks==0.
|
|
45
|
+
uv add --dev common-python-tasks==0.12.0
|
|
46
46
|
```
|
|
47
47
|
|
|
48
48
|
Expose the default task set in `pyproject.toml`.
|
|
@@ -9,7 +9,7 @@ Read the [complete documentation](https://ci-sourcerer.github.io/common-python-t
|
|
|
9
9
|
Add the package as a development dependency.
|
|
10
10
|
|
|
11
11
|
```shell
|
|
12
|
-
uv add --dev common-python-tasks==0.
|
|
12
|
+
uv add --dev common-python-tasks==0.12.0
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
Expose the default task set in `pyproject.toml`.
|
|
@@ -44,7 +44,8 @@ Container variables are read by the host-side tasks unless their description exp
|
|
|
44
44
|
| `CONTAINER_APT_PACKAGES` | Space-delimited APT packages installed in the runtime stage |
|
|
45
45
|
| `CONTAINER_CUSTOM_ENTRYPOINT` | `[project.scripts]` key selected as the image entrypoint command |
|
|
46
46
|
| `CONTAINER_DOCKER_BUILD_ARGS` | Shell-tokenized arguments passed directly to `docker build`; task arguments after `--` take precedence |
|
|
47
|
-
| `
|
|
47
|
+
| `CONTAINER_DOCKERFILE_PATH` | Project-owned application Dockerfile used by `build-image`, `build`, and `release` instead of the bundled template |
|
|
48
|
+
| `CONTAINER_DOCKERFILE_HOOK_PATH` | Executable host script that modifies the selected Dockerfile before the build |
|
|
48
49
|
| `CONTAINER_PRUNE_KEEP` | Prior images kept after a build; `-1` disables pruning, `0` keeps only the latest, and `N` keeps the latest plus `N` prior images |
|
|
49
50
|
|
|
50
51
|
### Environment and extension settings
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Container images
|
|
2
2
|
|
|
3
|
-
Container tasks are selected with the optional `containers` tag.
|
|
3
|
+
Container tasks are selected with the optional `containers` tag. By default, they generate a multi-stage Dockerfile from the project metadata and container settings, build the application wheel, and install it in a non-root runtime image. A project can instead select a complete application Dockerfile that it owns.
|
|
4
4
|
|
|
5
5
|
```toml
|
|
6
6
|
[tool.poe]
|
|
@@ -77,7 +77,7 @@ COPY . /tmp/build/
|
|
|
77
77
|
# Export debug requirements when the project defines a debug dependency group
|
|
78
78
|
RUN --mount=type=cache,target=/root/.cache/uv,id=uv-cache{{ CACHE_ID_SUFFIX }}{% for mount in UV_INDEX_SECRET_MOUNTS %} \
|
|
79
79
|
--mount={{ mount }}{% endfor %} \
|
|
80
|
-
uv export --group debug --no-hashes --format requirements-txt --output-file requirements-debug.txt
|
|
80
|
+
uv export --frozen --only-group debug --no-hashes --format requirements-txt --output-file requirements-debug.txt
|
|
81
81
|
{% endif %}
|
|
82
82
|
|
|
83
83
|
# Build the wheel, caching the uv cache directory to speed up subsequent builds.
|
|
@@ -172,10 +172,11 @@ LABEL git.commit=${GIT_COMMIT}
|
|
|
172
172
|
# current package does not provide a console script, the entrypoint will default to `python`
|
|
173
173
|
RUN echo "#!/bin/sh
|
|
174
174
|
|
|
175
|
-
{{ ENTRYPOINT_COMMAND|default('python') }} \"\$@\"" >/pkg/entrypoint.sh \
|
|
175
|
+
exec {{ ENTRYPOINT_COMMAND|default('python') }} \"\$@\"" >/pkg/entrypoint.sh \
|
|
176
176
|
&& chmod +x /pkg/entrypoint.sh
|
|
177
177
|
|
|
178
|
-
|
|
178
|
+
ARG RUNTIME_USER=py
|
|
179
|
+
USER ${RUNTIME_USER}
|
|
179
180
|
|
|
180
181
|
{% if EXTENSION_CONTENT %}
|
|
181
182
|
{{ EXTENSION_CONTENT }}
|
|
@@ -193,13 +194,13 @@ COPY --from=builder /tmp/build /tmp/build
|
|
|
193
194
|
|
|
194
195
|
RUN --mount=type=cache,target=/root/.cache/pip,id=pip-cache{{ CACHE_ID_SUFFIX }} pip install --root-user-action=ignore -r /tmp/build/requirements-debug.txt
|
|
195
196
|
|
|
196
|
-
USER
|
|
197
|
+
USER ${RUNTIME_USER}
|
|
197
198
|
{% endif %}
|
|
198
199
|
|
|
199
200
|
# Final (default) image: explicitly use runtime as the final target so debug is not used unless requested
|
|
200
201
|
FROM runtime AS final
|
|
201
202
|
|
|
202
|
-
USER
|
|
203
|
+
USER ${RUNTIME_USER}
|
|
203
204
|
```
|
|
204
205
|
|
|
205
206
|
### Dependency image template
|
|
@@ -277,7 +278,28 @@ Do not use these declarations for secrets because their values persist in the im
|
|
|
277
278
|
|
|
278
279
|
The `--env` and `--envfile` options on `run-container` and `container-shell` have ordinary `docker run` semantics. They affect only that container invocation and can override environment values embedded during the build.
|
|
279
280
|
|
|
280
|
-
##
|
|
281
|
+
## Using a project-owned Dockerfile
|
|
282
|
+
|
|
283
|
+
Set `CONTAINER_DOCKERFILE_PATH` when a project owns its complete application Dockerfile. `build-image` and every aggregate task that invokes it, including `build` and `release`, use the same file instead of rendering the bundled template.
|
|
284
|
+
|
|
285
|
+
```toml
|
|
286
|
+
[tool.poe.env]
|
|
287
|
+
CONTAINER_DOCKERFILE_PATH = "docker/Dockerfile"
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
The `--dockerfile-path` option overrides the environment setting for one invocation. The option is available on both the individual and aggregate tasks.
|
|
291
|
+
|
|
292
|
+
```shell
|
|
293
|
+
poe build-image --dockerfile-path docker/Dockerfile.ci
|
|
294
|
+
poe build --dockerfile-path docker/Dockerfile.ci
|
|
295
|
+
poe release --dockerfile-path docker/Dockerfile.release
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
The project root remains the Docker build context. Standard image naming, version and commit tags, metadata build arguments, `CONTAINER_DOCKER_BUILD_ARGS`, Dockerfile hooks, image pruning, and release-time image pushing continue to work. A normal custom build does not select a target stage, so the Dockerfile does not need the bundled `runtime` stage. A custom debug build selects a stage named `debug`.
|
|
299
|
+
|
|
300
|
+
Settings that render content into the bundled template do not alter a project-owned Dockerfile. This includes `CONTAINER_APT_PACKAGES`, `CONTAINER_CUSTOM_ENTRYPOINT`, `CONTAINER_ENV`, extensions, and dependency-image mappings. Declare equivalent instructions in the project-owned Dockerfile when they are needed. BuildKit secrets derived from `UV_INDEX_*` credentials remain available as Docker build secrets, but the custom Dockerfile must mount them explicitly.
|
|
301
|
+
|
|
302
|
+
## Extending the generated runtime image
|
|
281
303
|
|
|
282
304
|
Use `CONTAINER_EXTENSION_FILES` to append project-owned Dockerfile fragments without replacing the generic Dockerfile. Its value is a colon-delimited list of paths, such as `Dockerfile.system:docker/Dockerfile.browser`.
|
|
283
305
|
|
|
@@ -289,23 +311,56 @@ RUN apt-get update \
|
|
|
289
311
|
USER py
|
|
290
312
|
```
|
|
291
313
|
|
|
292
|
-
Extension files are concatenated in their configured order and inserted near the end of `runtime`, after the entrypoint is created and after `USER py
|
|
314
|
+
Extension files are concatenated in their configured order and inserted near the end of `runtime`, after the entrypoint is created and after `USER ${RUNTIME_USER}` (which defaults to `py`). An extension that needs elevated permissions must switch to `USER root`; it should normally restore `USER ${RUNTIME_USER}` for the instructions that follow. Extensions that need to start as another user can redeclare `ARG RUNTIME_USER=root`; both the final and debug stages honor this argument. `COPY` paths remain relative to the project-root build context.
|
|
293
315
|
|
|
294
316
|
Extension content is treated as raw Dockerfile syntax, not as a Jinja template. This keeps project extensions independent of private template variables used by `common-python-tasks`.
|
|
295
317
|
|
|
296
318
|
`CONTAINER_EXTENSIONS` selects extension bundles shipped in the installed package's `data/dockerfile_extensions/` directory. Bundle names are colon-delimited and are applied after local extension files. A bundle may accept one value with `bundle=value`; that value is passed to the first `ARG` declared by the bundle that has not already been assigned to another extension. Arguments are ignored with a warning when the bundle declares no `ARG`.
|
|
297
319
|
|
|
298
|
-
|
|
320
|
+
A bundled extension can keep scripts and other supporting files beside its `Dockerfile`. The image builder exposes that directory as a BuildKit named context called `cpt-extension-<bundle-name>`, with unsupported characters normalized to hyphens. The bundle can copy an asset with `COPY --from=cpt-extension-example script.sh /usr/local/bin/script` without embedding it in a heredoc. These managed contexts are added only to the application image build.
|
|
321
|
+
|
|
322
|
+
Use an extension for additive runtime instructions. Use `CONTAINER_DOCKERFILE_HOOK_PATH` only when a change must rewrite another part of the selected Dockerfile. The hook must be an executable host-side script; it receives a temporary copy of the selected Dockerfile as its first argument and must edit that file in place. The hook also receives the following context variables.
|
|
299
323
|
|
|
300
324
|
| Variable | Meaning |
|
|
301
325
|
| - | - |
|
|
302
|
-
| `COMMON_PYTHON_TASKS_DOCKERFILE_PATH` |
|
|
326
|
+
| `COMMON_PYTHON_TASKS_DOCKERFILE_PATH` | Temporary selected Dockerfile path, matching the first script argument |
|
|
303
327
|
| `COMMON_PYTHON_TASKS_DOCKER_CONTEXT` | Docker build context path |
|
|
304
328
|
| `COMMON_PYTHON_TASKS_DOCKER_DEBUG` | `1` for a debug build, otherwise `0` |
|
|
305
329
|
| `COMMON_PYTHON_TASKS_DOCKER_NO_CACHE` | `1` when `--no-cache` is active, otherwise `0` |
|
|
306
330
|
| `COMMON_PYTHON_TASKS_DOCKER_PLAIN` | `1` when plain progress output is active, otherwise `0` |
|
|
307
331
|
| `COMMON_PYTHON_TASKS_DOCKER_SINGLE_ARCH` | `1` for a single-architecture build, otherwise `0` |
|
|
308
332
|
|
|
333
|
+
### Docker-in-Docker
|
|
334
|
+
|
|
335
|
+
The bundled `docker-in-docker` extension installs Docker CE, containerd, Buildx, and Compose from Docker's signed APT repository. Its installation and supervisor scripts are separate packaged files copied through the extension's named build context; image builds do not download scripts from the devcontainer feature repository.
|
|
336
|
+
|
|
337
|
+
Initial support is limited to Debian Bookworm variants (`slim-bookworm` and `bookworm`) on `amd64` and `arm64`. The extension checks the actual distribution and architecture during the build and rejects everything else, including Alpine and Trixie. Select extensions independently for each image build; other images do not need to enable Docker-in-Docker.
|
|
338
|
+
|
|
339
|
+
```sh
|
|
340
|
+
CONTAINER_PYTHON_VARIANT=slim-bookworm \
|
|
341
|
+
CONTAINER_EXTENSIONS=docker-in-docker poe build-image
|
|
342
|
+
poe run-container --privileged
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
The image starts as root through Tini and the DinD supervisor. The supervisor prepares nested cgroups, starts a dedicated Docker daemon, and waits for `docker info` to succeed before launching the existing `/pkg/entrypoint.sh` as `py`. Application arguments and exit status are preserved. Signals reach the application, and shutdown stops the application before stopping Docker. Startup failure or loss of the daemon terminates the container with a nonzero status. `DIND_STARTUP_TIMEOUT` controls the readiness deadline in seconds (default `60`, accepted range `1`–`9999`). Each process group gets up to five seconds to stop before being killed; allow more than ten seconds for the outer container's stop timeout.
|
|
346
|
+
|
|
347
|
+
Docker listens only on `unix:///var/run/docker.sock`. The image sets `DOCKER_HOST` accordingly, and startup clears Docker context and TLS environment overrides so the application uses its own daemon. Do not mount the host Docker socket. The `py` user belongs to the Docker group and can control the nested daemon; this is a privileged container, not a sandbox for untrusted workloads.
|
|
348
|
+
|
|
349
|
+
The image declares volumes for `/var/lib/docker` and `/var/lib/containerd`. Docker creates anonymous volumes automatically. Use dedicated named volumes when state should survive container replacement, and never share them between concurrently running daemons. For example, when launching the built image directly, replace `your-image:tag` with its tag.
|
|
350
|
+
|
|
351
|
+
```sh
|
|
352
|
+
docker run --rm --privileged --stop-timeout 20 \
|
|
353
|
+
--mount source=my-app-docker,target=/var/lib/docker \
|
|
354
|
+
--mount source=my-app-containerd,target=/var/lib/containerd \
|
|
355
|
+
your-image:tag
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
For Compose, set `privileged: true`, `stop_grace_period: 20s`, and the equivalent volume mounts on the application service. Keep the image's entrypoint and startup user. `container-shell` and an explicit `--entrypoint` override bypass DinD startup; to inspect a running DinD container, use `docker exec -it --user py <container> sh`.
|
|
359
|
+
|
|
360
|
+
By default, the build installs the current stable packages available in Docker's repository. An optional bundle value pins the exact Docker Engine and CLI APT version. Include literal quotes around the version inside `CONTAINER_EXTENSIONS` so its epoch colon is not parsed as an extension separator. For example, `CONTAINER_EXTENSIONS='docker-in-docker="5:29.8.1-1~debian.12~bookworm"'` selects that version if available. This pins only Engine and CLI; containerd and CLI plugins still use the repository's current versions.
|
|
361
|
+
|
|
362
|
+
Maintainers can run the opt-in integration tests with `CPT_DIND_INTEGRATION=1 poe test tests/test_docker_in_docker.py`. These tests require a running Docker daemon, privileged Linux containers, and network access for image and package downloads. They build the actual generated application Dockerfile and remove their test images, containers, and anonymous volumes afterward.
|
|
363
|
+
|
|
309
364
|
## Supplying external dependencies
|
|
310
365
|
|
|
311
366
|
Dependency images support artifacts that should be built separately from the application wheel, such as compiled tools or browser binaries. The dependency image must place its exported content under `/tmp/deps`; the generated application Dockerfile copies that directory into its `runtime` stage.
|
|
@@ -344,7 +399,7 @@ See [Container settings](../configuration.md#container-settings) for the complet
|
|
|
344
399
|
|
|
345
400
|
| Task | Description |
|
|
346
401
|
| - | - |
|
|
347
|
-
| [`build-image`](reference/build-image.md) | Build the container image
|
|
402
|
+
| [`build-image`](reference/build-image.md) | Build the container image using a project-owned or bundled Dockerfile. |
|
|
348
403
|
| [`build-deps-image`](reference/build-deps-image.md) | Build only the container dependency collector image for this project. |
|
|
349
404
|
| [`run-container`](reference/run-container.md) | Run the Docker image as a container for this project. |
|
|
350
405
|
| [`push-image`](reference/push-image.md) | Push the Docker image for this project to the container registry. |
|
{common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/docs/tasks/reference/build-image.md
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# `poe build-image`
|
|
2
2
|
|
|
3
|
-
Build the container image
|
|
3
|
+
Build the container image using a project-owned or bundled Dockerfile.
|
|
4
4
|
|
|
5
5
|
**Category:** [`container-images`](../container-images.md)
|
|
6
6
|
|
|
@@ -9,7 +9,7 @@ Build the container image for this project using the Dockerfile template.
|
|
|
9
9
|
## Usage
|
|
10
10
|
|
|
11
11
|
```shell
|
|
12
|
-
poe build-image [DOCKER_BUILD_ARGS...] [--debug] [--no-cache] [--plain] [--single-arch] [--dockerfile-hook-path DOCKERFILE_HOOK_PATH] [--container-env CONTAINER_ENV...] [--container-envfile CONTAINER_ENVFILE...]
|
|
12
|
+
poe build-image [DOCKER_BUILD_ARGS...] [--debug] [--no-cache] [--plain] [--single-arch] [--dockerfile-path DOCKERFILE_PATH] [--dockerfile-hook-path DOCKERFILE_HOOK_PATH] [--container-env CONTAINER_ENV...] [--container-envfile CONTAINER_ENVFILE...]
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
## Arguments
|
|
@@ -21,6 +21,7 @@ poe build-image [DOCKER_BUILD_ARGS...] [--debug] [--no-cache] [--plain] [--singl
|
|
|
21
21
|
| `--no-cache` | `boolean` | Do not use cache when building the image. | `false` |
|
|
22
22
|
| `--plain` | `boolean` | Do not pretty-print output. | `false` |
|
|
23
23
|
| `--single-arch` | `boolean` | Build images for a single architecture. | `false` |
|
|
24
|
-
| `--dockerfile-
|
|
24
|
+
| `--dockerfile-path` | `string` | Optional project-owned Dockerfile. Overrides CONTAINER_DOCKERFILE_PATH if provided. | — |
|
|
25
|
+
| `--dockerfile-hook-path` | `string` | Optional executable script path that can mutate the selected Dockerfile before build. Overrides CONTAINER_DOCKERFILE_HOOK_PATH if provided. | — |
|
|
25
26
|
| `--container-env` | `string, repeatable` | Builder and runtime environment declarations as repeated KEY=VALUE values. | — |
|
|
26
27
|
| `--container-envfile` | `string, repeatable` | Optional repeated list of files containing builder and runtime environment declarations. | — |
|
|
@@ -9,7 +9,7 @@ Build the project and its containers.
|
|
|
9
9
|
## Usage
|
|
10
10
|
|
|
11
11
|
```shell
|
|
12
|
-
poe build [--debug] [--no-cache] [--plain] [--single-arch] [--container-env CONTAINER_ENV...] [--container-envfile CONTAINER_ENVFILE...]
|
|
12
|
+
poe build [--debug] [--no-cache] [--plain] [--single-arch] [--dockerfile-path DOCKERFILE_PATH] [--container-env CONTAINER_ENV...] [--container-envfile CONTAINER_ENVFILE...]
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
## Arguments
|
|
@@ -20,5 +20,6 @@ poe build [--debug] [--no-cache] [--plain] [--single-arch] [--container-env CONT
|
|
|
20
20
|
| `--no-cache` | `boolean` | Do not use cache when building the image. | `false` |
|
|
21
21
|
| `--plain` | `boolean` | Do not pretty-print output. | `false` |
|
|
22
22
|
| `--single-arch` | `boolean` | Build images for a single architecture. | `false` |
|
|
23
|
+
| `--dockerfile-path` | `string` | Optional project-owned Dockerfile used for the image build. Overrides CONTAINER_DOCKERFILE_PATH if provided. | — |
|
|
23
24
|
| `--container-env` | `string, repeatable` | Inline container environment variables as repeated KEY=VALUE values. | — |
|
|
24
25
|
| `--container-envfile` | `string, repeatable` | Repeated list of container environment files. | — |
|
|
@@ -9,7 +9,7 @@ Run a full release flow for package and containers.
|
|
|
9
9
|
## Usage
|
|
10
10
|
|
|
11
11
|
```shell
|
|
12
|
-
poe release [--component COMPONENT] [--stage STAGE] [--dry-run] [--debug] [--no-cache] [--plain] [--single-arch] [--container-env CONTAINER_ENV...] [--container-envfile CONTAINER_ENVFILE...] [--assets ASSETS...] [--repository REPOSITORY] [--repository-url REPOSITORY_URL] [--pre-script PRE_SCRIPT] [--post-script POST_SCRIPT]
|
|
12
|
+
poe release [--component COMPONENT] [--stage STAGE] [--dry-run] [--debug] [--no-cache] [--plain] [--single-arch] [--dockerfile-path DOCKERFILE_PATH] [--container-env CONTAINER_ENV...] [--container-envfile CONTAINER_ENVFILE...] [--assets ASSETS...] [--repository REPOSITORY] [--repository-url REPOSITORY_URL] [--pre-script PRE_SCRIPT] [--post-script POST_SCRIPT]
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
## Arguments
|
|
@@ -23,6 +23,7 @@ poe release [--component COMPONENT] [--stage STAGE] [--dry-run] [--debug] [--no-
|
|
|
23
23
|
| `--no-cache` | `boolean` | Do not use cache when building container images. | `false` |
|
|
24
24
|
| `--plain` | `boolean` | Do not pretty-print container build output. | `false` |
|
|
25
25
|
| `--single-arch` | `boolean` | Build container image for a single architecture. | `false` |
|
|
26
|
+
| `--dockerfile-path` | `string` | Optional project-owned Dockerfile used for the image build. Overrides CONTAINER_DOCKERFILE_PATH if provided. | — |
|
|
26
27
|
| `--container-env` | `string, repeatable` | Inline container environment variables as repeated KEY=VALUE values. | — |
|
|
27
28
|
| `--container-envfile` | `string, repeatable` | Repeated list of container environment files. | — |
|
|
28
29
|
| `--assets` | `string, repeatable` | Optional repeated list of release asset patterns or paths. | — |
|
|
@@ -111,46 +111,6 @@ def _escape_table_text(value: str) -> str:
|
|
|
111
111
|
return value.replace("|", "\\|")
|
|
112
112
|
|
|
113
113
|
|
|
114
|
-
def _render_task_full(task_name: str) -> list[str]:
|
|
115
|
-
task_config = _get_task_config(task_name)
|
|
116
|
-
arguments = task_config.get("args", [])
|
|
117
|
-
lines = [
|
|
118
|
-
f"## `{task_name}`",
|
|
119
|
-
"",
|
|
120
|
-
task_config.get("help", "No description is available."),
|
|
121
|
-
"",
|
|
122
|
-
f"**Tags:** {', '.join(f'`{tag}`' for tag in get_task_tags(task_name) or [])}",
|
|
123
|
-
"",
|
|
124
|
-
"```shell",
|
|
125
|
-
" ".join(
|
|
126
|
-
[f"poe {task_name}", *[_format_usage_argument(arg) for arg in arguments]]
|
|
127
|
-
),
|
|
128
|
-
"```",
|
|
129
|
-
]
|
|
130
|
-
if not arguments:
|
|
131
|
-
return lines
|
|
132
|
-
|
|
133
|
-
docstring_help = _get_docstring_argument_help(task_config)
|
|
134
|
-
lines.extend(
|
|
135
|
-
[
|
|
136
|
-
"",
|
|
137
|
-
"### Arguments",
|
|
138
|
-
"",
|
|
139
|
-
"| Argument | Type | Description | Default |",
|
|
140
|
-
"| - | - | - | - |",
|
|
141
|
-
]
|
|
142
|
-
)
|
|
143
|
-
lines.extend(
|
|
144
|
-
"| "
|
|
145
|
-
f"{_format_argument_name(argument)} | "
|
|
146
|
-
f"{_format_argument_type(argument)} | "
|
|
147
|
-
f"{_escape_table_text(argument.get('help') or docstring_help.get(argument['name'], 'Additional value passed to the task.'))} | "
|
|
148
|
-
f"{_format_default(argument)} |"
|
|
149
|
-
for argument in arguments
|
|
150
|
-
)
|
|
151
|
-
return lines
|
|
152
|
-
|
|
153
|
-
|
|
154
114
|
def build_task_reference(category: str) -> str:
|
|
155
115
|
"""Build the generated Markdown reference for a task category (link table).
|
|
156
116
|
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Docker-in-Docker currently supports Debian Bookworm on amd64 and arm64.
|
|
2
|
+
USER root
|
|
3
|
+
|
|
4
|
+
# Optional exact APT version, including the epoch and distribution suffix.
|
|
5
|
+
ARG DIND_DOCKER_VERSION
|
|
6
|
+
|
|
7
|
+
COPY --from=cpt-extension-docker-in-docker --chmod=0755 install.sh \
|
|
8
|
+
/usr/local/share/cpt-dind-install.sh
|
|
9
|
+
RUN /usr/local/share/cpt-dind-install.sh \
|
|
10
|
+
&& rm /usr/local/share/cpt-dind-install.sh
|
|
11
|
+
|
|
12
|
+
COPY --from=cpt-extension-docker-in-docker --chmod=0755 supervisor.sh \
|
|
13
|
+
/usr/local/bin/cpt-dind-supervisor
|
|
14
|
+
|
|
15
|
+
RUN mv /pkg/entrypoint.sh /pkg/application-entrypoint.sh \
|
|
16
|
+
&& printf '%s\n' '#!/bin/sh' \
|
|
17
|
+
'exec /usr/bin/tini -- /usr/local/bin/cpt-dind-supervisor "$@"' \
|
|
18
|
+
>/pkg/entrypoint.sh \
|
|
19
|
+
&& chmod 0755 /pkg/entrypoint.sh
|
|
20
|
+
|
|
21
|
+
ENV DOCKER_HOST=unix:///var/run/docker.sock
|
|
22
|
+
VOLUME ["/var/lib/docker", "/var/lib/containerd"]
|
|
23
|
+
|
|
24
|
+
# The generic final and debug stages inherit this startup-user selection.
|
|
25
|
+
# The wrapper drops to py only for the application, after Docker is ready.
|
|
26
|
+
ARG RUNTIME_USER=root
|
|
27
|
+
USER ${RUNTIME_USER}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
set -eu
|
|
3
|
+
|
|
4
|
+
# shellcheck source=/dev/null
|
|
5
|
+
. /etc/os-release
|
|
6
|
+
if [ "$ID" != debian ] || [ "${VERSION_CODENAME:-}" != bookworm ]; then
|
|
7
|
+
echo >&2 'docker-in-docker requires Debian Bookworm; use slim-bookworm.'
|
|
8
|
+
exit 1
|
|
9
|
+
fi
|
|
10
|
+
case "$(dpkg --print-architecture)" in
|
|
11
|
+
amd64 | arm64) ;;
|
|
12
|
+
*)
|
|
13
|
+
echo >&2 'docker-in-docker supports amd64 and arm64 only.'
|
|
14
|
+
exit 1
|
|
15
|
+
;;
|
|
16
|
+
esac
|
|
17
|
+
|
|
18
|
+
apt-get update
|
|
19
|
+
apt-get install -y --no-install-recommends \
|
|
20
|
+
bash ca-certificates curl iptables tini util-linux
|
|
21
|
+
install -m 0755 -d /etc/apt/keyrings
|
|
22
|
+
curl -fsSL https://download.docker.com/linux/debian/gpg \
|
|
23
|
+
-o /etc/apt/keyrings/docker.asc
|
|
24
|
+
chmod 0644 /etc/apt/keyrings/docker.asc
|
|
25
|
+
cat >/etc/apt/sources.list.d/docker.sources <<SOURCES
|
|
26
|
+
Types: deb
|
|
27
|
+
URIs: https://download.docker.com/linux/debian
|
|
28
|
+
Suites: bookworm
|
|
29
|
+
Components: stable
|
|
30
|
+
Architectures: $(dpkg --print-architecture)
|
|
31
|
+
Signed-By: /etc/apt/keyrings/docker.asc
|
|
32
|
+
SOURCES
|
|
33
|
+
apt-get update
|
|
34
|
+
apt-get install -y --no-install-recommends \
|
|
35
|
+
"docker-ce${DIND_DOCKER_VERSION:+=$DIND_DOCKER_VERSION}" \
|
|
36
|
+
"docker-ce-cli${DIND_DOCKER_VERSION:+=$DIND_DOCKER_VERSION}" \
|
|
37
|
+
containerd.io docker-buildx-plugin docker-compose-plugin
|
|
38
|
+
usermod -aG docker py
|
|
39
|
+
rm -rf /var/lib/apt/lists/*
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
_prepare_host() {
|
|
5
|
+
if [[ $(id -u) != 0 ]]; then
|
|
6
|
+
echo >&2 'docker-in-docker must start as root with --privileged.'
|
|
7
|
+
return 1
|
|
8
|
+
fi
|
|
9
|
+
if [[ ! -w /sys/fs/cgroup ]]; then
|
|
10
|
+
echo >&2 'docker-in-docker needs writable cgroups; use --privileged.'
|
|
11
|
+
return 1
|
|
12
|
+
fi
|
|
13
|
+
if [[ -d /sys/kernel/security ]] &&
|
|
14
|
+
! mountpoint -q /sys/kernel/security; then
|
|
15
|
+
mount -t securityfs none /sys/kernel/security
|
|
16
|
+
fi
|
|
17
|
+
_prepare_cgroups
|
|
18
|
+
if ! iptables -nL >/dev/null 2>&1 &&
|
|
19
|
+
iptables-legacy -nL >/dev/null 2>&1; then
|
|
20
|
+
update-alternatives --set iptables /usr/sbin/iptables-legacy
|
|
21
|
+
update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy
|
|
22
|
+
fi
|
|
23
|
+
# Only remove our daemon's PID file, never unrelated processes' files.
|
|
24
|
+
rm -f /var/run/docker.pid
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
_prepare_cgroups() {
|
|
28
|
+
[[ -f /sys/fs/cgroup/cgroup.controllers ]] || return 0
|
|
29
|
+
mkdir -p /sys/fs/cgroup/cpt-init
|
|
30
|
+
local attempt pid controllers
|
|
31
|
+
for ((attempt = 0; attempt < 5; attempt++)); do
|
|
32
|
+
while read -r pid; do
|
|
33
|
+
# Processes can disappear or become immovable while we move them.
|
|
34
|
+
printf '%s\n' "$pid" | tee \
|
|
35
|
+
/sys/fs/cgroup/cpt-init/cgroup.procs >/dev/null 2>&1 || true
|
|
36
|
+
done </sys/fs/cgroup/cgroup.procs
|
|
37
|
+
controllers=$(sed 's/[^ ]\+/+&/g' \
|
|
38
|
+
/sys/fs/cgroup/cgroup.controllers)
|
|
39
|
+
if printf '%s\n' "$controllers" | tee \
|
|
40
|
+
/sys/fs/cgroup/cgroup.subtree_control >/dev/null 2>&1; then
|
|
41
|
+
return 0
|
|
42
|
+
fi
|
|
43
|
+
sleep 0.1
|
|
44
|
+
done
|
|
45
|
+
echo >&2 'docker-in-docker could not enable nested cgroups.'
|
|
46
|
+
return 1
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
_stop_group() {
|
|
50
|
+
local pid=$1
|
|
51
|
+
[[ -n "$pid" ]] || return 0
|
|
52
|
+
kill -TERM -- "-$pid" 2>/dev/null || true
|
|
53
|
+
local attempt
|
|
54
|
+
for ((attempt = 0; attempt < 50; attempt++)); do
|
|
55
|
+
kill -0 -- "-$pid" 2>/dev/null || break
|
|
56
|
+
sleep 0.1
|
|
57
|
+
done
|
|
58
|
+
kill -KILL -- "-$pid" 2>/dev/null || true
|
|
59
|
+
wait "$pid" 2>/dev/null || true
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
_shutdown() {
|
|
63
|
+
trap '' TERM INT
|
|
64
|
+
_stop_group "$app_pid"
|
|
65
|
+
_stop_group "$daemon_pid"
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
_wait_for_docker() {
|
|
69
|
+
local deadline=$((SECONDS + DIND_STARTUP_TIMEOUT))
|
|
70
|
+
while ((SECONDS < deadline)); do
|
|
71
|
+
if ! kill -0 "$daemon_pid" 2>/dev/null; then
|
|
72
|
+
echo >&2 'docker-in-docker daemon exited during startup.'
|
|
73
|
+
return 1
|
|
74
|
+
fi
|
|
75
|
+
if timeout 1 docker --host "$DOCKER_HOST" info >/dev/null 2>&1; then
|
|
76
|
+
return 0
|
|
77
|
+
fi
|
|
78
|
+
sleep 0.2
|
|
79
|
+
done
|
|
80
|
+
echo >&2 'docker-in-docker timed out waiting for the daemon.'
|
|
81
|
+
return 1
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
_main() {
|
|
85
|
+
if [[ ! ${DIND_STARTUP_TIMEOUT:-60} =~ ^[1-9][0-9]{0,3}$ ]]; then
|
|
86
|
+
echo >&2 'DIND_STARTUP_TIMEOUT must be an integer from 1 to 9999.'
|
|
87
|
+
return 1
|
|
88
|
+
fi
|
|
89
|
+
export DIND_STARTUP_TIMEOUT=${DIND_STARTUP_TIMEOUT:-60}
|
|
90
|
+
export DOCKER_HOST=unix:///var/run/docker.sock
|
|
91
|
+
export container=docker
|
|
92
|
+
unset DOCKER_CONTEXT DOCKER_TLS_VERIFY DOCKER_CERT_PATH
|
|
93
|
+
_prepare_host
|
|
94
|
+
daemon_pid=''
|
|
95
|
+
app_pid=''
|
|
96
|
+
trap _shutdown EXIT
|
|
97
|
+
trap 'exit 143' TERM
|
|
98
|
+
trap 'exit 130' INT
|
|
99
|
+
# Keep daemon logs on stderr and expose only the local Unix socket.
|
|
100
|
+
setsid dockerd --host "$DOCKER_HOST" --group docker >&2 &
|
|
101
|
+
daemon_pid=$!
|
|
102
|
+
_wait_for_docker
|
|
103
|
+
setsid setpriv --reuid py --regid py --init-groups \
|
|
104
|
+
env HOME="$(getent passwd py | cut -d: -f6)" USER=py LOGNAME=py \
|
|
105
|
+
/pkg/application-entrypoint.sh "$@" &
|
|
106
|
+
app_pid=$!
|
|
107
|
+
local finished status=0
|
|
108
|
+
wait -n -p finished "$daemon_pid" "$app_pid" || status=$?
|
|
109
|
+
if [[ "$finished" == "$daemon_pid" ]]; then
|
|
110
|
+
echo >&2 'docker-in-docker daemon exited while the app was running.'
|
|
111
|
+
return 1
|
|
112
|
+
fi
|
|
113
|
+
return "$status"
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
_main "$@"
|
|
@@ -40,7 +40,7 @@ COPY . /tmp/build/
|
|
|
40
40
|
# Export debug requirements when the project defines a debug dependency group
|
|
41
41
|
RUN --mount=type=cache,target=/root/.cache/uv,id=uv-cache{{ CACHE_ID_SUFFIX }}{% for mount in UV_INDEX_SECRET_MOUNTS %} \
|
|
42
42
|
--mount={{ mount }}{% endfor %} \
|
|
43
|
-
uv export --group debug --no-hashes --format requirements-txt --output-file requirements-debug.txt
|
|
43
|
+
uv export --frozen --only-group debug --no-hashes --format requirements-txt --output-file requirements-debug.txt
|
|
44
44
|
{% endif %}
|
|
45
45
|
|
|
46
46
|
# Build the wheel, caching the uv cache directory to speed up subsequent builds.
|
|
@@ -133,10 +133,11 @@ LABEL git.commit=${GIT_COMMIT}
|
|
|
133
133
|
# This entrypoint is deliberately not configurable via environment variables in order to
|
|
134
134
|
# ensure that the container always uses the entrypoint selected at build time. If the
|
|
135
135
|
# current package does not provide a console script, the entrypoint will default to `python`
|
|
136
|
-
RUN echo "#!/bin/sh\n\
|
|
136
|
+
RUN echo "#!/bin/sh\n\nexec {{ ENTRYPOINT_COMMAND|default('python') }} \"\$@\"" >/pkg/entrypoint.sh \
|
|
137
137
|
&& chmod +x /pkg/entrypoint.sh
|
|
138
138
|
|
|
139
|
-
|
|
139
|
+
ARG RUNTIME_USER=py
|
|
140
|
+
USER ${RUNTIME_USER}
|
|
140
141
|
|
|
141
142
|
{% if EXTENSION_CONTENT %}
|
|
142
143
|
{{ EXTENSION_CONTENT }}
|
|
@@ -154,10 +155,10 @@ COPY --from=builder /tmp/build /tmp/build
|
|
|
154
155
|
|
|
155
156
|
RUN --mount=type=cache,target=/root/.cache/pip,id=pip-cache{{ CACHE_ID_SUFFIX }} pip install --root-user-action=ignore -r /tmp/build/requirements-debug.txt
|
|
156
157
|
|
|
157
|
-
USER
|
|
158
|
+
USER ${RUNTIME_USER}
|
|
158
159
|
{% endif %}
|
|
159
160
|
|
|
160
161
|
# Final (default) image: explicitly use runtime as the final target so debug is not used unless requested
|
|
161
162
|
FROM runtime AS final
|
|
162
163
|
|
|
163
|
-
USER
|
|
164
|
+
USER ${RUNTIME_USER}
|
|
@@ -3,6 +3,7 @@ import os
|
|
|
3
3
|
import re
|
|
4
4
|
import secrets
|
|
5
5
|
import shlex
|
|
6
|
+
from collections.abc import Iterator
|
|
6
7
|
from pathlib import Path
|
|
7
8
|
|
|
8
9
|
from . import utils
|
|
@@ -53,51 +54,47 @@ def collect_uv_index_credentials() -> list[dict[str, str | None]]:
|
|
|
53
54
|
]
|
|
54
55
|
|
|
55
56
|
|
|
57
|
+
def _iter_uv_index_secrets(
|
|
58
|
+
credentials: list[dict[str, str | None]],
|
|
59
|
+
) -> Iterator[tuple[str, str]]:
|
|
60
|
+
for credential in credentials:
|
|
61
|
+
index_name = credential["index_name"].lower()
|
|
62
|
+
for credential_type in ("username", "password"):
|
|
63
|
+
environment_name = credential[f"{credential_type}_env"]
|
|
64
|
+
if environment_name:
|
|
65
|
+
yield f"uv_index_{index_name}_{credential_type}", environment_name
|
|
66
|
+
|
|
67
|
+
|
|
56
68
|
def uv_index_secret_mounts(credentials: list[dict[str, str | None]]) -> list[str]:
|
|
57
|
-
"""Return Dockerfile
|
|
69
|
+
"""Return Dockerfile `--mount` strings for UV index credentials.
|
|
58
70
|
|
|
59
71
|
Args:
|
|
60
72
|
credentials: Output of `collect_uv_index_credentials`.
|
|
61
73
|
|
|
62
74
|
Returns:
|
|
63
|
-
A list of
|
|
75
|
+
A list of `type=secret,...` strings for Dockerfile `RUN --mount=`
|
|
64
76
|
directives.
|
|
65
77
|
"""
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
mounts.append(
|
|
71
|
-
f"type=secret,id=uv_index_{name}_username,env={cred['username_env']}"
|
|
72
|
-
)
|
|
73
|
-
if cred["password_env"]:
|
|
74
|
-
mounts.append(
|
|
75
|
-
f"type=secret,id=uv_index_{name}_password,env={cred['password_env']}"
|
|
76
|
-
)
|
|
77
|
-
return mounts
|
|
78
|
+
return [
|
|
79
|
+
f"type=secret,id={secret_id},env={environment_name}"
|
|
80
|
+
for secret_id, environment_name in _iter_uv_index_secrets(credentials)
|
|
81
|
+
]
|
|
78
82
|
|
|
79
83
|
|
|
80
84
|
def uv_index_secret_build_args(credentials: list[dict[str, str | None]]) -> list[str]:
|
|
81
|
-
"""Return
|
|
85
|
+
"""Return `docker build --secret` arg pairs for UV index credentials.
|
|
82
86
|
|
|
83
87
|
Args:
|
|
84
88
|
credentials: Output of `collect_uv_index_credentials`.
|
|
85
89
|
|
|
86
90
|
Returns:
|
|
87
|
-
A flat list of
|
|
91
|
+
A flat list of `--secret` flag-value pairs for the docker build command.
|
|
88
92
|
"""
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
["--secret", f"id=uv_index_{name}_username,env={cred['username_env']}"]
|
|
95
|
-
)
|
|
96
|
-
if cred["password_env"]:
|
|
97
|
-
args.extend(
|
|
98
|
-
["--secret", f"id=uv_index_{name}_password,env={cred['password_env']}"]
|
|
99
|
-
)
|
|
100
|
-
return args
|
|
93
|
+
return [
|
|
94
|
+
item
|
|
95
|
+
for secret_id, environment_name in _iter_uv_index_secrets(credentials)
|
|
96
|
+
for item in ("--secret", f"id={secret_id},env={environment_name}")
|
|
97
|
+
]
|
|
101
98
|
|
|
102
99
|
|
|
103
100
|
def env_truthy(env_var: str) -> bool:
|
|
@@ -230,6 +227,40 @@ def resolve_extension_content(descriptor: dict[str, str | None]) -> str:
|
|
|
230
227
|
utils.fatal(f"Unknown extension descriptor source: {descriptor['source']}")
|
|
231
228
|
|
|
232
229
|
|
|
230
|
+
def resolve_extension_build_context(
|
|
231
|
+
descriptor: dict[str, str | None],
|
|
232
|
+
) -> tuple[str, Path] | None:
|
|
233
|
+
"""Return the named build context for a bundled extension's asset directory.
|
|
234
|
+
|
|
235
|
+
Args:
|
|
236
|
+
descriptor: Extension descriptor dictionary containing `source` and
|
|
237
|
+
`bundle_name` values.
|
|
238
|
+
|
|
239
|
+
Returns:
|
|
240
|
+
A Docker build-context name and its directory, or `None` when the
|
|
241
|
+
extension has no packaged assets.
|
|
242
|
+
"""
|
|
243
|
+
if descriptor["source"] != "bundle":
|
|
244
|
+
return None
|
|
245
|
+
bundle_name = descriptor["bundle_name"]
|
|
246
|
+
out = utils.load_data_file(
|
|
247
|
+
f"{bundle_name}/Dockerfile",
|
|
248
|
+
type_identifier="dockerfile_extensions",
|
|
249
|
+
fatal_on_missing=False,
|
|
250
|
+
)
|
|
251
|
+
if out is None:
|
|
252
|
+
utils.fatal(f"Extension bundle not found: {bundle_name}")
|
|
253
|
+
bundle_directory = out[0].parent
|
|
254
|
+
if not bundle_directory.is_dir() or not any(
|
|
255
|
+
path.name != "Dockerfile" for path in bundle_directory.iterdir()
|
|
256
|
+
):
|
|
257
|
+
return None
|
|
258
|
+
return (
|
|
259
|
+
f"cpt-extension-{re.sub(r'[^a-z0-9]+', '-', bundle_name.lower()).strip('-')}",
|
|
260
|
+
bundle_directory,
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
|
|
233
264
|
def get_cache_id_suffix(no_cache: bool) -> str:
|
|
234
265
|
"""Return a cache-break suffix for Docker cache mount IDs.
|
|
235
266
|
Args:
|
|
@@ -330,6 +361,28 @@ def resolve_container_docker_build_args(
|
|
|
330
361
|
utils.fatal(f"Invalid CONTAINER_DOCKER_BUILD_ARGS: {error}")
|
|
331
362
|
|
|
332
363
|
|
|
364
|
+
def _resolve_optional_file_path(
|
|
365
|
+
cli_path: str | None,
|
|
366
|
+
environment_path: str | None,
|
|
367
|
+
description: str,
|
|
368
|
+
) -> Path | None:
|
|
369
|
+
resolved_path = next(
|
|
370
|
+
(
|
|
371
|
+
Path(value.strip())
|
|
372
|
+
for value in (cli_path, environment_path)
|
|
373
|
+
if value and value.strip()
|
|
374
|
+
),
|
|
375
|
+
None,
|
|
376
|
+
)
|
|
377
|
+
if resolved_path is None:
|
|
378
|
+
return None
|
|
379
|
+
if not resolved_path.exists():
|
|
380
|
+
utils.fatal(f"{description} not found: {resolved_path}")
|
|
381
|
+
if not resolved_path.is_file():
|
|
382
|
+
utils.fatal(f"{description} is not a file: {resolved_path}")
|
|
383
|
+
return resolved_path
|
|
384
|
+
|
|
385
|
+
|
|
333
386
|
def resolve_container_dockerfile_hook_path(
|
|
334
387
|
cli_hook_path: str | None, env_hook_path: str | None
|
|
335
388
|
) -> Path | None:
|
|
@@ -342,17 +395,13 @@ def resolve_container_dockerfile_hook_path(
|
|
|
342
395
|
Returns:
|
|
343
396
|
The validated hook path, or `None` when unset.
|
|
344
397
|
"""
|
|
345
|
-
|
|
346
|
-
cli_hook_path
|
|
398
|
+
hook_path = _resolve_optional_file_path(
|
|
399
|
+
cli_hook_path,
|
|
400
|
+
env_hook_path,
|
|
401
|
+
"Dockerfile hook script",
|
|
347
402
|
)
|
|
348
|
-
if
|
|
403
|
+
if hook_path is None:
|
|
349
404
|
return None
|
|
350
|
-
|
|
351
|
-
hook_path = Path(raw_value.strip())
|
|
352
|
-
if not hook_path.exists():
|
|
353
|
-
utils.fatal(f"Dockerfile hook script not found: {hook_path}")
|
|
354
|
-
if not hook_path.is_file():
|
|
355
|
-
utils.fatal(f"Dockerfile hook path is not a file: {hook_path}")
|
|
356
405
|
if not os.access(hook_path, os.X_OK):
|
|
357
406
|
utils.fatal(f"Dockerfile hook script must be executable: {hook_path}")
|
|
358
407
|
|
|
@@ -594,6 +643,28 @@ def get_container_deps_move_script() -> str | None:
|
|
|
594
643
|
return inline_script if inline_script else None
|
|
595
644
|
|
|
596
645
|
|
|
646
|
+
def resolve_container_dockerfile_path(
|
|
647
|
+
dockerfile_path: str | None,
|
|
648
|
+
environment_dockerfile_path: str | None,
|
|
649
|
+
) -> Path | None:
|
|
650
|
+
"""Resolve and validate a project-owned application Dockerfile.
|
|
651
|
+
|
|
652
|
+
Args:
|
|
653
|
+
dockerfile_path: Dockerfile path supplied directly to a task.
|
|
654
|
+
environment_dockerfile_path: Dockerfile path supplied through the
|
|
655
|
+
environment.
|
|
656
|
+
|
|
657
|
+
Returns:
|
|
658
|
+
The configured Dockerfile path, or `None` when the bundled template
|
|
659
|
+
should be used.
|
|
660
|
+
"""
|
|
661
|
+
return _resolve_optional_file_path(
|
|
662
|
+
dockerfile_path,
|
|
663
|
+
environment_dockerfile_path,
|
|
664
|
+
"Container Dockerfile",
|
|
665
|
+
)
|
|
666
|
+
|
|
667
|
+
|
|
597
668
|
def get_prune_keep() -> int:
|
|
598
669
|
"""Return the integer value of CONTAINER_PRUNE_KEEP.
|
|
599
670
|
|
|
@@ -70,6 +70,28 @@ class _ContainerBuild(NamedTuple):
|
|
|
70
70
|
commit_tag: str
|
|
71
71
|
|
|
72
72
|
|
|
73
|
+
def _prune_container_images(version_tag: str, commit_tag: str) -> None:
|
|
74
|
+
from .docker import prune_images_keep
|
|
75
|
+
from .env import get_prune_keep
|
|
76
|
+
from .utils import get_full_image_name, get_package_name
|
|
77
|
+
|
|
78
|
+
keep = get_prune_keep()
|
|
79
|
+
if keep < 0:
|
|
80
|
+
return
|
|
81
|
+
|
|
82
|
+
LOGGER.debug(
|
|
83
|
+
"Pruning old images; keeping %d and protecting tags: %s",
|
|
84
|
+
keep,
|
|
85
|
+
[version_tag, commit_tag],
|
|
86
|
+
)
|
|
87
|
+
prune_images_keep(
|
|
88
|
+
get_full_image_name(),
|
|
89
|
+
get_package_name(),
|
|
90
|
+
keep,
|
|
91
|
+
protect_tags=[version_tag, commit_tag],
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
|
|
73
95
|
def _make_var_positional_task_args_optional(
|
|
74
96
|
func: callable, resolved_task_name: str
|
|
75
97
|
) -> None:
|
|
@@ -367,11 +389,19 @@ def clean(dist_only: bool = False) -> None:
|
|
|
367
389
|
return
|
|
368
390
|
else:
|
|
369
391
|
to_clean = [
|
|
370
|
-
*[
|
|
392
|
+
*[
|
|
393
|
+
Path(p)
|
|
394
|
+
for p in [
|
|
395
|
+
".pytest_cache",
|
|
396
|
+
"dist",
|
|
397
|
+
".mypy_cache",
|
|
398
|
+
".coverage",
|
|
399
|
+
"coverage.xml",
|
|
400
|
+
".ruff_cache",
|
|
401
|
+
]
|
|
402
|
+
],
|
|
371
403
|
*Path(".").rglob("__pycache__"),
|
|
372
404
|
*Path(".").rglob("*.pyc"),
|
|
373
|
-
Path(".coverage"),
|
|
374
|
-
Path("coverage.xml"),
|
|
375
405
|
]
|
|
376
406
|
|
|
377
407
|
for item in to_clean:
|
|
@@ -465,11 +495,12 @@ def build_image(
|
|
|
465
495
|
no_cache: bool = False,
|
|
466
496
|
plain: bool = False,
|
|
467
497
|
single_arch: bool = False,
|
|
498
|
+
dockerfile_path: str | None = None,
|
|
468
499
|
dockerfile_hook_path: str | None = None,
|
|
469
500
|
container_env: list[str] | None = None,
|
|
470
501
|
container_envfile: list[str] | None = None,
|
|
471
502
|
) -> _ContainerBuild:
|
|
472
|
-
"""Build the container image
|
|
503
|
+
"""Build the container image using a project-owned or bundled Dockerfile.
|
|
473
504
|
|
|
474
505
|
Args:
|
|
475
506
|
*docker_build_args: Additional arguments passed directly to `docker build`.
|
|
@@ -479,8 +510,10 @@ def build_image(
|
|
|
479
510
|
no_cache: Do not use cache when building the image.
|
|
480
511
|
plain: Do not pretty-print output.
|
|
481
512
|
single_arch: Build images for a single architecture.
|
|
513
|
+
dockerfile_path: Optional project-owned Dockerfile. Overrides
|
|
514
|
+
CONTAINER_DOCKERFILE_PATH if provided.
|
|
482
515
|
dockerfile_hook_path: Optional executable script path that can mutate
|
|
483
|
-
the
|
|
516
|
+
the selected Dockerfile before build. Overrides
|
|
484
517
|
CONTAINER_DOCKERFILE_HOOK_PATH if provided.
|
|
485
518
|
container_env: Builder and runtime environment declarations as repeated
|
|
486
519
|
KEY=VALUE values.
|
|
@@ -494,14 +527,10 @@ def build_image(
|
|
|
494
527
|
The generated Dockerfile text and image tags.
|
|
495
528
|
"""
|
|
496
529
|
from .docker import build_image as _build_image
|
|
497
|
-
from .docker import (
|
|
498
|
-
prune_images_keep,
|
|
499
|
-
)
|
|
500
530
|
from .env import (
|
|
501
531
|
collect_uv_index_credentials,
|
|
502
532
|
get_cache_id_suffix,
|
|
503
533
|
get_container_deps_move_script,
|
|
504
|
-
get_prune_keep,
|
|
505
534
|
get_python_variant,
|
|
506
535
|
inject_auto_build_args_from_env,
|
|
507
536
|
load_container_env_tokens,
|
|
@@ -511,6 +540,8 @@ def build_image(
|
|
|
511
540
|
render_container_deps_move_script,
|
|
512
541
|
resolve_container_docker_build_args,
|
|
513
542
|
resolve_container_dockerfile_hook_path,
|
|
543
|
+
resolve_container_dockerfile_path,
|
|
544
|
+
resolve_extension_build_context,
|
|
514
545
|
resolve_extension_content,
|
|
515
546
|
uv_index_secret_build_args,
|
|
516
547
|
uv_index_secret_mounts,
|
|
@@ -521,14 +552,17 @@ def build_image(
|
|
|
521
552
|
)
|
|
522
553
|
from .utils import (
|
|
523
554
|
fatal,
|
|
524
|
-
get_full_image_name,
|
|
525
|
-
get_package_name,
|
|
526
555
|
load_data_file,
|
|
527
556
|
render_template_text,
|
|
528
557
|
)
|
|
529
558
|
|
|
559
|
+
resolved_dockerfile_path = resolve_container_dockerfile_path(
|
|
560
|
+
dockerfile_path,
|
|
561
|
+
os.getenv("CONTAINER_DOCKERFILE_PATH"),
|
|
562
|
+
)
|
|
563
|
+
|
|
530
564
|
# Determine extensions up-front so we can log a single, accurate message
|
|
531
|
-
extensions = parse_container_extensions()
|
|
565
|
+
extensions = [] if resolved_dockerfile_path else parse_container_extensions()
|
|
532
566
|
extension_ids = [desc.get("id") for desc in extensions if desc.get("id")]
|
|
533
567
|
if extension_ids:
|
|
534
568
|
LOGGER.info("Building image (with extensions: %s)", ", ".join(extension_ids))
|
|
@@ -538,6 +572,11 @@ def build_image(
|
|
|
538
572
|
# Resolve all extension fragments up-front so we fail fast on missing
|
|
539
573
|
# bundles or files and avoid calling resolution logic multiple times.
|
|
540
574
|
resolved_fragments = [resolve_extension_content(desc) for desc in extensions]
|
|
575
|
+
extension_build_contexts = [
|
|
576
|
+
context
|
|
577
|
+
for desc in extensions
|
|
578
|
+
if (context := resolve_extension_build_context(desc)) is not None
|
|
579
|
+
]
|
|
541
580
|
|
|
542
581
|
resolved_docker_build_args = resolve_container_docker_build_args(
|
|
543
582
|
docker_build_args,
|
|
@@ -556,6 +595,29 @@ def build_image(
|
|
|
556
595
|
dockerfile_hook_path,
|
|
557
596
|
os.getenv("CONTAINER_DOCKERFILE_HOOK_PATH"),
|
|
558
597
|
)
|
|
598
|
+
top_level_build_args = inject_auto_build_args_from_env(
|
|
599
|
+
{"PYTHON_VARIANT": get_python_variant()}
|
|
600
|
+
)
|
|
601
|
+
|
|
602
|
+
if resolved_dockerfile_path:
|
|
603
|
+
version_tag, commit_tag = _build_image(
|
|
604
|
+
dockerfile_path=resolved_dockerfile_path,
|
|
605
|
+
context_path=Path("."),
|
|
606
|
+
debug=debug,
|
|
607
|
+
no_cache=no_cache,
|
|
608
|
+
plain=plain,
|
|
609
|
+
single_arch=single_arch,
|
|
610
|
+
omit_target=not debug,
|
|
611
|
+
extra_build_args=top_level_build_args or None,
|
|
612
|
+
docker_build_args=resolved_docker_build_args,
|
|
613
|
+
dockerfile_hook_path=resolved_dockerfile_hook_path,
|
|
614
|
+
)
|
|
615
|
+
_prune_container_images(version_tag, commit_tag)
|
|
616
|
+
return _ContainerBuild(
|
|
617
|
+
dockerfile_text=resolved_dockerfile_path.read_text(encoding="utf-8"),
|
|
618
|
+
version_tag=version_tag,
|
|
619
|
+
commit_tag=commit_tag,
|
|
620
|
+
)
|
|
559
621
|
|
|
560
622
|
has_debug_deps = has_debug_dependency_group()
|
|
561
623
|
if debug and not has_debug_deps:
|
|
@@ -579,9 +641,6 @@ def build_image(
|
|
|
579
641
|
"Injecting builder and runtime env vars: %s",
|
|
580
642
|
", ".join(container_env_vars),
|
|
581
643
|
)
|
|
582
|
-
top_level_build_args = inject_auto_build_args_from_env(
|
|
583
|
-
{"PYTHON_VARIANT": get_python_variant()}
|
|
584
|
-
)
|
|
585
644
|
external_deps_image = _get_container_build_setting("CONTAINER_DEPS_IMAGE")
|
|
586
645
|
if external_deps_image:
|
|
587
646
|
top_level_build_args["CONTAINER_DEPS_IMAGE"] = external_deps_image
|
|
@@ -687,20 +746,18 @@ def build_image(
|
|
|
687
746
|
plain=plain,
|
|
688
747
|
single_arch=single_arch,
|
|
689
748
|
extra_build_args=merged_build_args or None,
|
|
690
|
-
docker_build_args=
|
|
749
|
+
docker_build_args=[
|
|
750
|
+
*resolved_docker_build_args,
|
|
751
|
+
*(
|
|
752
|
+
item
|
|
753
|
+
for name, path in extension_build_contexts
|
|
754
|
+
for item in ("--build-context", f"{name}={path}")
|
|
755
|
+
),
|
|
756
|
+
],
|
|
691
757
|
dockerfile_hook_path=resolved_dockerfile_hook_path,
|
|
692
758
|
)
|
|
693
759
|
|
|
694
|
-
|
|
695
|
-
if keep >= 0:
|
|
696
|
-
# Protect the tags created by this build
|
|
697
|
-
protect = [t for t in (version_tag, commit_tag) if t is not None]
|
|
698
|
-
LOGGER.debug(
|
|
699
|
-
"Pruning old images; keeping %d and protecting tags: %s", keep, protect
|
|
700
|
-
)
|
|
701
|
-
prune_images_keep(
|
|
702
|
-
get_full_image_name(), get_package_name(), keep, protect_tags=protect
|
|
703
|
-
)
|
|
760
|
+
_prune_container_images(version_tag, commit_tag)
|
|
704
761
|
|
|
705
762
|
return _ContainerBuild(
|
|
706
763
|
dockerfile_text=dockerfile_text,
|
|
@@ -1320,6 +1377,7 @@ def _run_release_flow(
|
|
|
1320
1377
|
no_cache: bool = False,
|
|
1321
1378
|
plain: bool = False,
|
|
1322
1379
|
single_arch: bool = False,
|
|
1380
|
+
dockerfile_path: str | None = None,
|
|
1323
1381
|
container_env: list[str] | None = None,
|
|
1324
1382
|
container_envfile: list[str] | None = None,
|
|
1325
1383
|
assets: list[str] | None = None,
|
|
@@ -1426,6 +1484,7 @@ def _run_release_flow(
|
|
|
1426
1484
|
no_cache=no_cache,
|
|
1427
1485
|
plain=plain,
|
|
1428
1486
|
single_arch=single_arch,
|
|
1487
|
+
dockerfile_path=dockerfile_path,
|
|
1429
1488
|
container_env=container_env,
|
|
1430
1489
|
container_envfile=container_envfile,
|
|
1431
1490
|
)
|
|
@@ -1444,6 +1503,7 @@ def release(
|
|
|
1444
1503
|
no_cache: bool = False,
|
|
1445
1504
|
plain: bool = False,
|
|
1446
1505
|
single_arch: bool = False,
|
|
1506
|
+
dockerfile_path: str | None = None,
|
|
1447
1507
|
container_env: list[str] | None = None,
|
|
1448
1508
|
container_envfile: list[str] | None = None,
|
|
1449
1509
|
assets: list[str] | None = None,
|
|
@@ -1462,6 +1522,8 @@ def release(
|
|
|
1462
1522
|
no_cache: Do not use cache when building container images.
|
|
1463
1523
|
plain: Do not pretty-print container build output.
|
|
1464
1524
|
single_arch: Build container image for a single architecture.
|
|
1525
|
+
dockerfile_path: Optional project-owned Dockerfile used for the image
|
|
1526
|
+
build. Overrides CONTAINER_DOCKERFILE_PATH if provided.
|
|
1465
1527
|
container_env: Inline container environment variables as repeated
|
|
1466
1528
|
KEY=VALUE values.
|
|
1467
1529
|
container_envfile: Repeated list of container environment files.
|
|
@@ -1480,6 +1542,7 @@ def release(
|
|
|
1480
1542
|
no_cache=no_cache,
|
|
1481
1543
|
plain=plain,
|
|
1482
1544
|
single_arch=single_arch,
|
|
1545
|
+
dockerfile_path=dockerfile_path,
|
|
1483
1546
|
container_env=container_env,
|
|
1484
1547
|
container_envfile=container_envfile,
|
|
1485
1548
|
assets=assets,
|
|
@@ -1532,6 +1595,7 @@ def build(
|
|
|
1532
1595
|
no_cache: bool = False,
|
|
1533
1596
|
plain: bool = False,
|
|
1534
1597
|
single_arch: bool = False,
|
|
1598
|
+
dockerfile_path: str | None = None,
|
|
1535
1599
|
container_env: list[str] | None = None,
|
|
1536
1600
|
container_envfile: list[str] | None = None,
|
|
1537
1601
|
) -> None:
|
|
@@ -1544,6 +1608,8 @@ def build(
|
|
|
1544
1608
|
no_cache: Pass `--no-cache` to the Docker build command.
|
|
1545
1609
|
plain: Pass `--progress plain` to the Docker build command.
|
|
1546
1610
|
single_arch: Build the container for the current host architecture only.
|
|
1611
|
+
dockerfile_path: Optional project-owned Dockerfile used for the image
|
|
1612
|
+
build. Overrides CONTAINER_DOCKERFILE_PATH if provided.
|
|
1547
1613
|
container_env: Inline container environment variables as repeated
|
|
1548
1614
|
`KEY=VALUE` values.
|
|
1549
1615
|
container_envfile: Repeated list of container environment files.
|
|
@@ -1558,6 +1624,7 @@ def build(
|
|
|
1558
1624
|
no_cache=no_cache,
|
|
1559
1625
|
plain=plain,
|
|
1560
1626
|
single_arch=single_arch,
|
|
1627
|
+
dockerfile_path=dockerfile_path,
|
|
1561
1628
|
container_env=container_env,
|
|
1562
1629
|
container_envfile=container_envfile,
|
|
1563
1630
|
)
|
|
@@ -1572,6 +1639,7 @@ def build_with_containers(
|
|
|
1572
1639
|
no_cache: bool = False,
|
|
1573
1640
|
plain: bool = False,
|
|
1574
1641
|
single_arch: bool = False,
|
|
1642
|
+
dockerfile_path: str | None = None,
|
|
1575
1643
|
container_env: list[str] | None = None,
|
|
1576
1644
|
container_envfile: list[str] | None = None,
|
|
1577
1645
|
) -> None:
|
|
@@ -1582,6 +1650,8 @@ def build_with_containers(
|
|
|
1582
1650
|
no_cache: Do not use cache when building the image.
|
|
1583
1651
|
plain: Do not pretty-print output.
|
|
1584
1652
|
single_arch: Build images for a single architecture.
|
|
1653
|
+
dockerfile_path: Optional project-owned Dockerfile used for the image
|
|
1654
|
+
build. Overrides CONTAINER_DOCKERFILE_PATH if provided.
|
|
1585
1655
|
container_env: Inline container environment variables as repeated KEY=VALUE
|
|
1586
1656
|
values.
|
|
1587
1657
|
container_envfile: Repeated list of container environment files.
|
|
@@ -1593,6 +1663,7 @@ def build_with_containers(
|
|
|
1593
1663
|
no_cache=no_cache,
|
|
1594
1664
|
plain=plain,
|
|
1595
1665
|
single_arch=single_arch,
|
|
1666
|
+
dockerfile_path=dockerfile_path,
|
|
1596
1667
|
container_env=container_env,
|
|
1597
1668
|
container_envfile=container_envfile,
|
|
1598
1669
|
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/docs/tasks/packaging-and-releases.md
RENAMED
|
File without changes
|
{common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/docs/tasks/reference/build-deps-image.md
RENAMED
|
File without changes
|
{common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/docs/tasks/reference/build-package.md
RENAMED
|
File without changes
|
{common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/docs/tasks/reference/bump-version.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/docs/tasks/reference/container-shell.md
RENAMED
|
File without changes
|
|
File without changes
|
{common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/docs/tasks/reference/docs-build.md
RENAMED
|
File without changes
|
{common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/docs/tasks/reference/docs-serve.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/docs/tasks/reference/publish-package.md
RENAMED
|
File without changes
|
{common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/docs/tasks/reference/push-image.md
RENAMED
|
File without changes
|
|
File without changes
|
{common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/docs/tasks/reference/run-container.md
RENAMED
|
File without changes
|
{common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/docs/tasks/reference/run-db-migrations.md
RENAMED
|
File without changes
|
{common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/docs/tasks/reference/stack-down.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/scripts/add_common_python_tasks.py
RENAMED
|
File without changes
|
|
File without changes
|
{common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/scripts/update_docs_tasks_reference.py
RENAMED
|
File without changes
|
|
File without changes
|
{common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/src/common_python_tasks/__init__.py
RENAMED
|
File without changes
|
{common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/src/common_python_tasks/__main__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/src/common_python_tasks/docker_compose.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{common_python_tasks-0.11.0 → common_python_tasks-0.12.0}/src/common_python_tasks/project.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|