common-python-tasks 0.7.0__tar.gz → 0.9.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.7.0 → common_python_tasks-0.9.0}/.gitignore +2 -0
- {common_python_tasks-0.7.0 → common_python_tasks-0.9.0}/PKG-INFO +63 -29
- {common_python_tasks-0.7.0 → common_python_tasks-0.9.0}/README.md +61 -27
- {common_python_tasks-0.7.0 → common_python_tasks-0.9.0}/pyproject.toml +7 -3
- {common_python_tasks-0.7.0 → common_python_tasks-0.9.0}/scripts/add_common_python_tasks.py +8 -41
- common_python_tasks-0.9.0/scripts/readme_tasks_table.py +78 -0
- common_python_tasks-0.9.0/scripts/release_script.py +102 -0
- common_python_tasks-0.9.0/scripts/update_readme_tasks_table.py +37 -0
- common_python_tasks-0.9.0/scripts/utils.py +76 -0
- {common_python_tasks-0.7.0 → common_python_tasks-0.9.0}/src/common_python_tasks/__init__.py +9 -0
- {common_python_tasks-0.7.0 → common_python_tasks-0.9.0}/src/common_python_tasks/__main__.py +19 -3
- common_python_tasks-0.9.0/src/common_python_tasks/data/dockerfile_extensions/.gitkeep +0 -0
- {common_python_tasks-0.7.0 → common_python_tasks-0.9.0}/src/common_python_tasks/data/fastapi/compose-base.yml.j2 +1 -2
- {common_python_tasks-0.7.0 → common_python_tasks-0.9.0}/src/common_python_tasks/data/fastapi/compose-db.yml.j2 +1 -2
- {common_python_tasks-0.7.0 → common_python_tasks-0.9.0}/src/common_python_tasks/data/fastapi/compose-debug.yml.j2 +1 -1
- {common_python_tasks-0.7.0 → common_python_tasks-0.9.0}/src/common_python_tasks/data/generic/.dockerignore +1 -1
- {common_python_tasks-0.7.0 → common_python_tasks-0.9.0}/src/common_python_tasks/data/generic/Dockerfile.j2 +6 -39
- common_python_tasks-0.9.0/src/common_python_tasks/data/generic/ruff.toml +2 -0
- {common_python_tasks-0.7.0 → common_python_tasks-0.9.0}/src/common_python_tasks/docker.py +274 -154
- {common_python_tasks-0.7.0 → common_python_tasks-0.9.0}/src/common_python_tasks/docker_compose.py +16 -11
- {common_python_tasks-0.7.0 → common_python_tasks-0.9.0}/src/common_python_tasks/env.py +82 -36
- {common_python_tasks-0.7.0 → common_python_tasks-0.9.0}/src/common_python_tasks/git.py +30 -16
- {common_python_tasks-0.7.0 → common_python_tasks-0.9.0}/src/common_python_tasks/github.py +37 -3
- {common_python_tasks-0.7.0 → common_python_tasks-0.9.0}/src/common_python_tasks/project.py +126 -297
- {common_python_tasks-0.7.0 → common_python_tasks-0.9.0}/src/common_python_tasks/tasks.py +145 -171
- {common_python_tasks-0.7.0 → common_python_tasks-0.9.0}/src/common_python_tasks/utils.py +29 -4
- common_python_tasks-0.7.0/scripts/release_script.py +0 -214
- common_python_tasks-0.7.0/src/common_python_tasks/data/generic/ruff.toml +0 -6
- {common_python_tasks-0.7.0 → common_python_tasks-0.9.0}/.poetry/plugins/poetry_dynamic_versioning-1.10.0.dist-info/licenses/LICENSE +0 -0
- {common_python_tasks-0.7.0 → common_python_tasks-0.9.0}/.poetry/plugins/poetry_plugin_export-1.10.0.dist-info/licenses/LICENSE +0 -0
- {common_python_tasks-0.7.0 → common_python_tasks-0.9.0}/LICENSE +0 -0
- /common_python_tasks-0.7.0/src/common_python_tasks/data/dockerfile_extensions/.gitkeep → /common_python_tasks-0.9.0/scripts/__init__.py +0 -0
- {common_python_tasks-0.7.0 → common_python_tasks-0.9.0}/src/common_python_tasks/data/fastapi/alembic.ini.j2 +0 -0
- {common_python_tasks-0.7.0 → common_python_tasks-0.9.0}/src/common_python_tasks/data/fastapi/compose-db-debug.yml.j2 +0 -0
- {common_python_tasks-0.7.0 → common_python_tasks-0.9.0}/src/common_python_tasks/data/generic/.coveragerc +0 -0
- {common_python_tasks-0.7.0 → common_python_tasks-0.9.0}/src/common_python_tasks/data/generic/Dockerfile.deps.j2 +0 -0
- {common_python_tasks-0.7.0 → common_python_tasks-0.9.0}/src/common_python_tasks/data/generic/cliff.toml +0 -0
- {common_python_tasks-0.7.0 → common_python_tasks-0.9.0}/src/common_python_tasks/data/generic/pytest.ini +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: common-python-tasks
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.9.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
|
|
@@ -43,9 +43,7 @@ It supplies sensible defaults for formatting, linting, testing, packaging, relea
|
|
|
43
43
|
Add `common-python-tasks` as a development dependency from your project root.
|
|
44
44
|
|
|
45
45
|
```shell
|
|
46
|
-
uv add --dev common-python-tasks==0.
|
|
47
|
-
# or, for Poetry projects
|
|
48
|
-
poetry add --group dev common-python-tasks==0.7.0
|
|
46
|
+
uv add --dev common-python-tasks==0.9.0
|
|
49
47
|
```
|
|
50
48
|
|
|
51
49
|
Configure Poe the Poet to expose the default `common` task set.
|
|
@@ -70,7 +68,7 @@ The helper script performs the same development-dependency installation and Poe
|
|
|
70
68
|
```shell
|
|
71
69
|
curl --fail --silent --show-error --location \
|
|
72
70
|
--output /tmp/add_common_python_tasks.py \
|
|
73
|
-
https://raw.githubusercontent.com/ci-sourcerer/common-python-tasks/v0.
|
|
71
|
+
https://raw.githubusercontent.com/ci-sourcerer/common-python-tasks/v0.9.0/scripts/add_common_python_tasks.py
|
|
74
72
|
```
|
|
75
73
|
|
|
76
74
|
Review the downloaded script before executing it.
|
|
@@ -82,10 +80,10 @@ less /tmp/add_common_python_tasks.py
|
|
|
82
80
|
Run the reviewed script with the same pinned package version.
|
|
83
81
|
|
|
84
82
|
```shell
|
|
85
|
-
COMMON_PYTHON_TASKS_VERSION=0.
|
|
83
|
+
COMMON_PYTHON_TASKS_VERSION=0.9.0 python3 /tmp/add_common_python_tasks.py
|
|
86
84
|
```
|
|
87
85
|
|
|
88
|
-
To install another release, replace both occurrences of `0.
|
|
86
|
+
To install another release, replace both occurrences of `0.9.0` with that release's version.
|
|
89
87
|
|
|
90
88
|
## Available tasks
|
|
91
89
|
|
|
@@ -108,7 +106,7 @@ The generated tables below list public tasks only. Tags identify which tasks are
|
|
|
108
106
|
| --- | --- | --- |
|
|
109
107
|
| `publish-package` | Publish the package to the PyPI server. | common, packaging |
|
|
110
108
|
| `publish-github-release` | Publish or update a GitHub Release for the current repository. | common, packaging, release |
|
|
111
|
-
| `update-dependencies` | Update project dependencies with
|
|
109
|
+
| `update-dependencies` | Update project dependencies with uv. | common, packaging |
|
|
112
110
|
| `build-package` | Build the package (wheel and sdist). | build, common, packaging |
|
|
113
111
|
| `bump-version` | Bump the project version. | common, packaging |
|
|
114
112
|
| `changelog` | Print the changelog for the current version based on git history and git-cliff. | common, packaging, release |
|
|
@@ -143,7 +141,7 @@ The generated tables below list public tasks only. Tags identify which tasks are
|
|
|
143
141
|
|
|
144
142
|
Every project needs a `pyproject.toml` file at its root and Poe the Poet available in its development environment.
|
|
145
143
|
|
|
146
|
-
Tasks that install, build, publish, or update dependencies
|
|
144
|
+
Tasks that install, build, publish, or update dependencies require uv. Package and release tasks need a resolvable project version from `project.version` or Git tags. Dynamic versioning is supported but is not a baseline requirement.
|
|
147
145
|
|
|
148
146
|
### Task selection
|
|
149
147
|
|
|
@@ -163,18 +161,27 @@ include_script = "common_python_tasks:tasks(include_tags=['common', 'containers'
|
|
|
163
161
|
|
|
164
162
|
The `containers` tag also includes container-based development-stack tasks. Use the tags in the task tables to tailor a smaller task set.
|
|
165
163
|
|
|
166
|
-
### Package
|
|
164
|
+
### Package management
|
|
167
165
|
|
|
168
|
-
Packaging-related tasks, including `build-package`, `publish-package`, release version resolution, and container build metadata,
|
|
166
|
+
Packaging-related tasks, including `build-package`, `publish-package`, dependency updates, release version resolution, and container build metadata, use uv exclusively. The `uv` executable must be available on `PATH`.
|
|
169
167
|
|
|
170
|
-
|
|
168
|
+
### Publish target selection
|
|
171
169
|
|
|
172
|
-
|
|
173
|
-
2. `COMMON_PYTHON_TASKS_BUILD_TOOL`
|
|
174
|
-
3. `PACKAGE_MANAGER`
|
|
175
|
-
4. Auto-discovery (`auto`) based on installed tools and project metadata
|
|
170
|
+
The `publish-package` task resolves publish targets with this precedence.
|
|
176
171
|
|
|
177
|
-
|
|
172
|
+
1. Explicit task arguments (`repository` or `repository_url`)
|
|
173
|
+
2. Environment-variable fallback
|
|
174
|
+
3. uv project configuration fallback from `[[tool.uv.index]]`
|
|
175
|
+
4. The `uv publish` default
|
|
176
|
+
|
|
177
|
+
uv prefers named publish indexes.
|
|
178
|
+
|
|
179
|
+
- `COMMON_PYTHON_TASKS_PUBLISH_REPOSITORY`
|
|
180
|
+
- `UV_PUBLISH_INDEX`
|
|
181
|
+
- `COMMON_PYTHON_TASKS_PUBLISH_URL`
|
|
182
|
+
- `UV_PUBLISH_URL`
|
|
183
|
+
|
|
184
|
+
When using uv project configuration fallback, `[[tool.uv.index]]` must include both `name` and `publish-url` for publish selection. If multiple publishable indexes exist, set exactly one `default = true` or pass an explicit repository.
|
|
178
185
|
|
|
179
186
|
### Configuration precedence
|
|
180
187
|
|
|
@@ -196,7 +203,7 @@ After installing the package, a minimal project configuration looks like this.
|
|
|
196
203
|
```toml
|
|
197
204
|
[project]
|
|
198
205
|
name = "simple-cli-tool"
|
|
199
|
-
version = "0.
|
|
206
|
+
version = "0.9.0"
|
|
200
207
|
|
|
201
208
|
[tool.poe]
|
|
202
209
|
include_script = "common_python_tasks:tasks()"
|
|
@@ -232,21 +239,25 @@ addopts = "-ra"
|
|
|
232
239
|
#### Project and package settings
|
|
233
240
|
|
|
234
241
|
- `PACKAGE_NAME`: Overrides the package name inferred from `pyproject.toml`
|
|
235
|
-
- `
|
|
236
|
-
- `
|
|
237
|
-
- `
|
|
242
|
+
- `COMMON_PYTHON_TASKS_PUBLISH_REPOSITORY`: Preferred publish repository/index name for `publish-package`
|
|
243
|
+
- `COMMON_PYTHON_TASKS_PUBLISH_URL`: Preferred uv publish upload URL for `publish-package` when no repository/index is selected
|
|
244
|
+
- `UV_PUBLISH_INDEX`: uv publish-index fallback for `publish-package`
|
|
245
|
+
- `UV_PUBLISH_URL`: uv publish upload-url fallback for `publish-package`
|
|
238
246
|
|
|
239
247
|
#### Container image settings
|
|
240
248
|
|
|
241
249
|
- `CONTAINER_REGISTRY_USERNAME`: Container-registry username for image tagging; the default is the current local user
|
|
242
250
|
- `CONTAINER_REGISTRY_URL`: Registry URL with a default of `docker.io/{username}`
|
|
243
|
-
- `
|
|
251
|
+
- `CONTAINER_DOCKER_BUILD_ARGS`: Additional arguments passed directly to `docker build`, parsed using shell quoting rules. Free arguments provided to the task after `--` take precedence.
|
|
252
|
+
- `CONTAINER_DOCKERFILE_HOOK_PATH`: Optional host path to an executable hook script that receives the generated Dockerfile path and can modify the file before `docker build` runs.
|
|
253
|
+
- `CONTAINER_APT_PACKAGES`: Space-delimited system packages installed in the generated image
|
|
254
|
+
- `CONTAINER_CUSTOM_ENTRYPOINT`: Custom container entrypoint script. The value must match a key in `[project].scripts`.
|
|
255
|
+
- `CONTAINER_DEPS_IMAGE`: Existing dependency image used when neither `CONTAINER_DEPS_CONTENT` nor `CONTAINER_DEPS_FILE` is configured
|
|
244
256
|
- `CONTAINER_EXTENSION_FILES`: Colon-delimited local extension Dockerfile paths. Escape literal colons as `\:` or quote the complete path.
|
|
245
257
|
- `CONTAINER_EXTENSIONS`: Colon-delimited extension-bundle names or parameterized values. Escape literal colons as `\:` or quote the complete value.
|
|
246
258
|
- `CONTAINER_ENV`: Colon-delimited `KEY=VALUE` declarations injected into the rendered Dockerfile's builder stage. Escape literal colons as `\:` or quote the complete value.
|
|
247
259
|
- `.containerenv`: A project-root file that can supply the same declarations. It is loaded before the `container_envfile` task argument, `CONTAINER_ENV`, and the `container_env` task argument.
|
|
248
260
|
- `CONTAINER_PRUNE_KEEP`: Image-pruning policy after builds. `-1` keeps all images, `0` keeps only the latest, and `N` keeps the latest plus `N` prior images.
|
|
249
|
-
- `CUSTOM_ENTRYPOINT`: Custom container entrypoint script. The value must match a key in `[project].scripts`.
|
|
250
261
|
- `CONTAINER_DEPS_CONTENT`: Inline Dockerfile instructions for a dependency image that installs artifacts into `/tmp/deps`
|
|
251
262
|
- `CONTAINER_DEPS_FILE`: One or more dependency-image Dockerfiles. It accepts colon-delimited paths with literal colons escaped as `\:` and is used only when `CONTAINER_DEPS_CONTENT` is unset.
|
|
252
263
|
- `CONTAINER_DEPS_MAPPINGS`: Space-delimited `name:/target/path` entries for copying items from `/tmp/deps`. It is used only when no dependency move script is set.
|
|
@@ -293,6 +304,28 @@ addopts = "-ra"
|
|
|
293
304
|
|
|
294
305
|
Docker Compose development-stack tasks are available when the `containers` tag is selected. The current stack supports FastAPI applications and an optional PostgreSQL database.
|
|
295
306
|
|
|
307
|
+
### Native Docker build arguments
|
|
308
|
+
|
|
309
|
+
Arguments after the task's `--` separator are passed directly to `docker build`. Docker performs option validation, so any supported build option and its value can be used without a package-specific allowlist.
|
|
310
|
+
|
|
311
|
+
```shell
|
|
312
|
+
poe build-image --single-arch -- \
|
|
313
|
+
--secret id=pip_conf,env=PIP_CONF \
|
|
314
|
+
--ssh default \
|
|
315
|
+
--add-host example:127.0.0.1
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
Set `CONTAINER_DOCKER_BUILD_ARGS` to provide the same arguments through the environment. The value uses shell quoting rules, and task arguments provided after `--` take precedence.
|
|
319
|
+
|
|
320
|
+
Settings that affect generated Dockerfile content or dependency-image orchestration can be persisted directly in the project configuration.
|
|
321
|
+
|
|
322
|
+
```toml
|
|
323
|
+
[tool.poe.env]
|
|
324
|
+
CONTAINER_APT_PACKAGES = "curl jq"
|
|
325
|
+
CONTAINER_CUSTOM_ENTRYPOINT = "serve"
|
|
326
|
+
CONTAINER_DEPS_IMAGE = "example/dependencies:latest"
|
|
327
|
+
```
|
|
328
|
+
|
|
296
329
|
### Stack configuration
|
|
297
330
|
|
|
298
331
|
Set `COMPOSE_TYPE` to select the application stack. `fastapi` is currently supported and includes optional database support and Alembic migrations.
|
|
@@ -361,7 +394,7 @@ GITHUB_RELEASE_ASSETS="dist/*.whl:dist/*.tar.gz" poe publish-github-release
|
|
|
361
394
|
|
|
362
395
|
### Container build fails with "unable to find package"
|
|
363
396
|
|
|
364
|
-
Check that `pyproject.toml` has a correct package name and the package-discovery settings required by its build backend. For
|
|
397
|
+
Check that `pyproject.toml` has a correct package name and the package-discovery settings required by its build backend. For a `src` layout built with Hatch, configure `[tool.hatch.build.targets.wheel] packages = ["src/your_package"]`.
|
|
365
398
|
|
|
366
399
|
### Stack fails to start or services cannot connect
|
|
367
400
|
|
|
@@ -386,12 +419,13 @@ Ensure the project-root `.env` file is writable and inspect its permissions with
|
|
|
386
419
|
|
|
387
420
|
See the [standard Dockerfile template](src/common_python_tasks/data/generic/Dockerfile.j2) for the implementation.
|
|
388
421
|
|
|
389
|
-
- Multi-stage build: The build stage installs
|
|
390
|
-
- Cache mounts: Pip and
|
|
391
|
-
- Explicit build
|
|
422
|
+
- Multi-stage build: The build stage installs uv and builds a wheel. The runtime stage installs only the wheel to keep the final image slim and reproducible.
|
|
423
|
+
- Cache mounts: Pip and uv cache mounts speed up iterative builds without bloating the final image.
|
|
424
|
+
- Explicit build metadata: `PYTHON_VERSION`, `UV_VERSION`, `PACKAGE_VERSION`, `PACKAGE_NAME`, `AUTHORS`, and `GIT_COMMIT` make image metadata predictable and auditable.
|
|
425
|
+
- Project-level build settings: `CONTAINER_APT_PACKAGES`, `CONTAINER_CUSTOM_ENTRYPOINT`, and `CONTAINER_DEPS_IMAGE` configure generated image behavior without being encoded as generic Docker arguments.
|
|
392
426
|
- Optional debug stage: The image exports and installs the `debug` dependency group only when present and does not include it in the default final image.
|
|
393
427
|
- Stable package path: Symlinks give entrypoints and consumers consistent `/pkg` and `/_$PACKAGE_NAME` paths regardless of wheel layout.
|
|
394
|
-
- Safe entrypoint selection: The default entrypoint resolves the console script matching the package name and falls back to `python`. `
|
|
428
|
+
- Safe entrypoint selection: The default entrypoint resolves the console script matching the package name and falls back to `python`. `CONTAINER_CUSTOM_ENTRYPOINT` is validated against `[project].scripts`.
|
|
395
429
|
- Minimal final image: The standard slim Python base, cache cleanup, and explicit `runtime` final target keep the default image small.
|
|
396
430
|
|
|
397
431
|
## Project notes
|
|
@@ -11,9 +11,7 @@ It supplies sensible defaults for formatting, linting, testing, packaging, relea
|
|
|
11
11
|
Add `common-python-tasks` as a development dependency from your project root.
|
|
12
12
|
|
|
13
13
|
```shell
|
|
14
|
-
uv add --dev common-python-tasks==0.
|
|
15
|
-
# or, for Poetry projects
|
|
16
|
-
poetry add --group dev common-python-tasks==0.7.0
|
|
14
|
+
uv add --dev common-python-tasks==0.9.0
|
|
17
15
|
```
|
|
18
16
|
|
|
19
17
|
Configure Poe the Poet to expose the default `common` task set.
|
|
@@ -38,7 +36,7 @@ The helper script performs the same development-dependency installation and Poe
|
|
|
38
36
|
```shell
|
|
39
37
|
curl --fail --silent --show-error --location \
|
|
40
38
|
--output /tmp/add_common_python_tasks.py \
|
|
41
|
-
https://raw.githubusercontent.com/ci-sourcerer/common-python-tasks/v0.
|
|
39
|
+
https://raw.githubusercontent.com/ci-sourcerer/common-python-tasks/v0.9.0/scripts/add_common_python_tasks.py
|
|
42
40
|
```
|
|
43
41
|
|
|
44
42
|
Review the downloaded script before executing it.
|
|
@@ -50,10 +48,10 @@ less /tmp/add_common_python_tasks.py
|
|
|
50
48
|
Run the reviewed script with the same pinned package version.
|
|
51
49
|
|
|
52
50
|
```shell
|
|
53
|
-
COMMON_PYTHON_TASKS_VERSION=0.
|
|
51
|
+
COMMON_PYTHON_TASKS_VERSION=0.9.0 python3 /tmp/add_common_python_tasks.py
|
|
54
52
|
```
|
|
55
53
|
|
|
56
|
-
To install another release, replace both occurrences of `0.
|
|
54
|
+
To install another release, replace both occurrences of `0.9.0` with that release's version.
|
|
57
55
|
|
|
58
56
|
## Available tasks
|
|
59
57
|
|
|
@@ -76,7 +74,7 @@ The generated tables below list public tasks only. Tags identify which tasks are
|
|
|
76
74
|
| --- | --- | --- |
|
|
77
75
|
| `publish-package` | Publish the package to the PyPI server. | common, packaging |
|
|
78
76
|
| `publish-github-release` | Publish or update a GitHub Release for the current repository. | common, packaging, release |
|
|
79
|
-
| `update-dependencies` | Update project dependencies with
|
|
77
|
+
| `update-dependencies` | Update project dependencies with uv. | common, packaging |
|
|
80
78
|
| `build-package` | Build the package (wheel and sdist). | build, common, packaging |
|
|
81
79
|
| `bump-version` | Bump the project version. | common, packaging |
|
|
82
80
|
| `changelog` | Print the changelog for the current version based on git history and git-cliff. | common, packaging, release |
|
|
@@ -111,7 +109,7 @@ The generated tables below list public tasks only. Tags identify which tasks are
|
|
|
111
109
|
|
|
112
110
|
Every project needs a `pyproject.toml` file at its root and Poe the Poet available in its development environment.
|
|
113
111
|
|
|
114
|
-
Tasks that install, build, publish, or update dependencies
|
|
112
|
+
Tasks that install, build, publish, or update dependencies require uv. Package and release tasks need a resolvable project version from `project.version` or Git tags. Dynamic versioning is supported but is not a baseline requirement.
|
|
115
113
|
|
|
116
114
|
### Task selection
|
|
117
115
|
|
|
@@ -131,18 +129,27 @@ include_script = "common_python_tasks:tasks(include_tags=['common', 'containers'
|
|
|
131
129
|
|
|
132
130
|
The `containers` tag also includes container-based development-stack tasks. Use the tags in the task tables to tailor a smaller task set.
|
|
133
131
|
|
|
134
|
-
### Package
|
|
132
|
+
### Package management
|
|
135
133
|
|
|
136
|
-
Packaging-related tasks, including `build-package`, `publish-package`, release version resolution, and container build metadata,
|
|
134
|
+
Packaging-related tasks, including `build-package`, `publish-package`, dependency updates, release version resolution, and container build metadata, use uv exclusively. The `uv` executable must be available on `PATH`.
|
|
137
135
|
|
|
138
|
-
|
|
136
|
+
### Publish target selection
|
|
139
137
|
|
|
140
|
-
|
|
141
|
-
2. `COMMON_PYTHON_TASKS_BUILD_TOOL`
|
|
142
|
-
3. `PACKAGE_MANAGER`
|
|
143
|
-
4. Auto-discovery (`auto`) based on installed tools and project metadata
|
|
138
|
+
The `publish-package` task resolves publish targets with this precedence.
|
|
144
139
|
|
|
145
|
-
|
|
140
|
+
1. Explicit task arguments (`repository` or `repository_url`)
|
|
141
|
+
2. Environment-variable fallback
|
|
142
|
+
3. uv project configuration fallback from `[[tool.uv.index]]`
|
|
143
|
+
4. The `uv publish` default
|
|
144
|
+
|
|
145
|
+
uv prefers named publish indexes.
|
|
146
|
+
|
|
147
|
+
- `COMMON_PYTHON_TASKS_PUBLISH_REPOSITORY`
|
|
148
|
+
- `UV_PUBLISH_INDEX`
|
|
149
|
+
- `COMMON_PYTHON_TASKS_PUBLISH_URL`
|
|
150
|
+
- `UV_PUBLISH_URL`
|
|
151
|
+
|
|
152
|
+
When using uv project configuration fallback, `[[tool.uv.index]]` must include both `name` and `publish-url` for publish selection. If multiple publishable indexes exist, set exactly one `default = true` or pass an explicit repository.
|
|
146
153
|
|
|
147
154
|
### Configuration precedence
|
|
148
155
|
|
|
@@ -164,7 +171,7 @@ After installing the package, a minimal project configuration looks like this.
|
|
|
164
171
|
```toml
|
|
165
172
|
[project]
|
|
166
173
|
name = "simple-cli-tool"
|
|
167
|
-
version = "0.
|
|
174
|
+
version = "0.9.0"
|
|
168
175
|
|
|
169
176
|
[tool.poe]
|
|
170
177
|
include_script = "common_python_tasks:tasks()"
|
|
@@ -200,21 +207,25 @@ addopts = "-ra"
|
|
|
200
207
|
#### Project and package settings
|
|
201
208
|
|
|
202
209
|
- `PACKAGE_NAME`: Overrides the package name inferred from `pyproject.toml`
|
|
203
|
-
- `
|
|
204
|
-
- `
|
|
205
|
-
- `
|
|
210
|
+
- `COMMON_PYTHON_TASKS_PUBLISH_REPOSITORY`: Preferred publish repository/index name for `publish-package`
|
|
211
|
+
- `COMMON_PYTHON_TASKS_PUBLISH_URL`: Preferred uv publish upload URL for `publish-package` when no repository/index is selected
|
|
212
|
+
- `UV_PUBLISH_INDEX`: uv publish-index fallback for `publish-package`
|
|
213
|
+
- `UV_PUBLISH_URL`: uv publish upload-url fallback for `publish-package`
|
|
206
214
|
|
|
207
215
|
#### Container image settings
|
|
208
216
|
|
|
209
217
|
- `CONTAINER_REGISTRY_USERNAME`: Container-registry username for image tagging; the default is the current local user
|
|
210
218
|
- `CONTAINER_REGISTRY_URL`: Registry URL with a default of `docker.io/{username}`
|
|
211
|
-
- `
|
|
219
|
+
- `CONTAINER_DOCKER_BUILD_ARGS`: Additional arguments passed directly to `docker build`, parsed using shell quoting rules. Free arguments provided to the task after `--` take precedence.
|
|
220
|
+
- `CONTAINER_DOCKERFILE_HOOK_PATH`: Optional host path to an executable hook script that receives the generated Dockerfile path and can modify the file before `docker build` runs.
|
|
221
|
+
- `CONTAINER_APT_PACKAGES`: Space-delimited system packages installed in the generated image
|
|
222
|
+
- `CONTAINER_CUSTOM_ENTRYPOINT`: Custom container entrypoint script. The value must match a key in `[project].scripts`.
|
|
223
|
+
- `CONTAINER_DEPS_IMAGE`: Existing dependency image used when neither `CONTAINER_DEPS_CONTENT` nor `CONTAINER_DEPS_FILE` is configured
|
|
212
224
|
- `CONTAINER_EXTENSION_FILES`: Colon-delimited local extension Dockerfile paths. Escape literal colons as `\:` or quote the complete path.
|
|
213
225
|
- `CONTAINER_EXTENSIONS`: Colon-delimited extension-bundle names or parameterized values. Escape literal colons as `\:` or quote the complete value.
|
|
214
226
|
- `CONTAINER_ENV`: Colon-delimited `KEY=VALUE` declarations injected into the rendered Dockerfile's builder stage. Escape literal colons as `\:` or quote the complete value.
|
|
215
227
|
- `.containerenv`: A project-root file that can supply the same declarations. It is loaded before the `container_envfile` task argument, `CONTAINER_ENV`, and the `container_env` task argument.
|
|
216
228
|
- `CONTAINER_PRUNE_KEEP`: Image-pruning policy after builds. `-1` keeps all images, `0` keeps only the latest, and `N` keeps the latest plus `N` prior images.
|
|
217
|
-
- `CUSTOM_ENTRYPOINT`: Custom container entrypoint script. The value must match a key in `[project].scripts`.
|
|
218
229
|
- `CONTAINER_DEPS_CONTENT`: Inline Dockerfile instructions for a dependency image that installs artifacts into `/tmp/deps`
|
|
219
230
|
- `CONTAINER_DEPS_FILE`: One or more dependency-image Dockerfiles. It accepts colon-delimited paths with literal colons escaped as `\:` and is used only when `CONTAINER_DEPS_CONTENT` is unset.
|
|
220
231
|
- `CONTAINER_DEPS_MAPPINGS`: Space-delimited `name:/target/path` entries for copying items from `/tmp/deps`. It is used only when no dependency move script is set.
|
|
@@ -261,6 +272,28 @@ addopts = "-ra"
|
|
|
261
272
|
|
|
262
273
|
Docker Compose development-stack tasks are available when the `containers` tag is selected. The current stack supports FastAPI applications and an optional PostgreSQL database.
|
|
263
274
|
|
|
275
|
+
### Native Docker build arguments
|
|
276
|
+
|
|
277
|
+
Arguments after the task's `--` separator are passed directly to `docker build`. Docker performs option validation, so any supported build option and its value can be used without a package-specific allowlist.
|
|
278
|
+
|
|
279
|
+
```shell
|
|
280
|
+
poe build-image --single-arch -- \
|
|
281
|
+
--secret id=pip_conf,env=PIP_CONF \
|
|
282
|
+
--ssh default \
|
|
283
|
+
--add-host example:127.0.0.1
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
Set `CONTAINER_DOCKER_BUILD_ARGS` to provide the same arguments through the environment. The value uses shell quoting rules, and task arguments provided after `--` take precedence.
|
|
287
|
+
|
|
288
|
+
Settings that affect generated Dockerfile content or dependency-image orchestration can be persisted directly in the project configuration.
|
|
289
|
+
|
|
290
|
+
```toml
|
|
291
|
+
[tool.poe.env]
|
|
292
|
+
CONTAINER_APT_PACKAGES = "curl jq"
|
|
293
|
+
CONTAINER_CUSTOM_ENTRYPOINT = "serve"
|
|
294
|
+
CONTAINER_DEPS_IMAGE = "example/dependencies:latest"
|
|
295
|
+
```
|
|
296
|
+
|
|
264
297
|
### Stack configuration
|
|
265
298
|
|
|
266
299
|
Set `COMPOSE_TYPE` to select the application stack. `fastapi` is currently supported and includes optional database support and Alembic migrations.
|
|
@@ -329,7 +362,7 @@ GITHUB_RELEASE_ASSETS="dist/*.whl:dist/*.tar.gz" poe publish-github-release
|
|
|
329
362
|
|
|
330
363
|
### Container build fails with "unable to find package"
|
|
331
364
|
|
|
332
|
-
Check that `pyproject.toml` has a correct package name and the package-discovery settings required by its build backend. For
|
|
365
|
+
Check that `pyproject.toml` has a correct package name and the package-discovery settings required by its build backend. For a `src` layout built with Hatch, configure `[tool.hatch.build.targets.wheel] packages = ["src/your_package"]`.
|
|
333
366
|
|
|
334
367
|
### Stack fails to start or services cannot connect
|
|
335
368
|
|
|
@@ -354,12 +387,13 @@ Ensure the project-root `.env` file is writable and inspect its permissions with
|
|
|
354
387
|
|
|
355
388
|
See the [standard Dockerfile template](src/common_python_tasks/data/generic/Dockerfile.j2) for the implementation.
|
|
356
389
|
|
|
357
|
-
- Multi-stage build: The build stage installs
|
|
358
|
-
- Cache mounts: Pip and
|
|
359
|
-
- Explicit build
|
|
390
|
+
- Multi-stage build: The build stage installs uv and builds a wheel. The runtime stage installs only the wheel to keep the final image slim and reproducible.
|
|
391
|
+
- Cache mounts: Pip and uv cache mounts speed up iterative builds without bloating the final image.
|
|
392
|
+
- Explicit build metadata: `PYTHON_VERSION`, `UV_VERSION`, `PACKAGE_VERSION`, `PACKAGE_NAME`, `AUTHORS`, and `GIT_COMMIT` make image metadata predictable and auditable.
|
|
393
|
+
- Project-level build settings: `CONTAINER_APT_PACKAGES`, `CONTAINER_CUSTOM_ENTRYPOINT`, and `CONTAINER_DEPS_IMAGE` configure generated image behavior without being encoded as generic Docker arguments.
|
|
360
394
|
- Optional debug stage: The image exports and installs the `debug` dependency group only when present and does not include it in the default final image.
|
|
361
395
|
- Stable package path: Symlinks give entrypoints and consumers consistent `/pkg` and `/_$PACKAGE_NAME` paths regardless of wheel layout.
|
|
362
|
-
- Safe entrypoint selection: The default entrypoint resolves the console script matching the package name and falls back to `python`. `
|
|
396
|
+
- Safe entrypoint selection: The default entrypoint resolves the console script matching the package name and falls back to `python`. `CONTAINER_CUSTOM_ENTRYPOINT` is validated against `[project].scripts`.
|
|
363
397
|
- Minimal final image: The standard slim Python base, cache cleanup, and explicit `runtime` final target keep the default image small.
|
|
364
398
|
|
|
365
399
|
## Project notes
|
|
@@ -37,12 +37,16 @@ Source = "http://github.com/ci-sourcerer/common-python-tasks.git"
|
|
|
37
37
|
Issues = "http://github.com/ci-sourcerer/common-python-tasks/issues"
|
|
38
38
|
|
|
39
39
|
[tool.poe]
|
|
40
|
-
include_script = "common_python_tasks:tasks(exclude_tags=['containers'])"
|
|
40
|
+
include_script = "common_python_tasks:tasks(exclude_tags=['containers', 'fastapi'])"
|
|
41
41
|
|
|
42
42
|
[tool.poe.env]
|
|
43
43
|
PYTHONPATH = "src"
|
|
44
44
|
RELEASE_UPDATE_CHANGELOG = "1"
|
|
45
|
-
RELEASE_PRE_SCRIPT = "RELEASE_SCRIPT_PHASE=pre python scripts
|
|
45
|
+
RELEASE_PRE_SCRIPT = "RELEASE_SCRIPT_PHASE=pre python -m scripts.release_script"
|
|
46
|
+
CONTAINER_APT_PACKAGES = "jq"
|
|
47
|
+
|
|
48
|
+
[tool.poe.tasks]
|
|
49
|
+
update-readme-tasks-table = { cmd = "python -m scripts.update_readme_tasks_table" }
|
|
46
50
|
|
|
47
51
|
[tool.hatch.version]
|
|
48
52
|
source = "uv-dynamic-versioning"
|
|
@@ -69,7 +73,7 @@ package = true
|
|
|
69
73
|
|
|
70
74
|
[tool.ruff]
|
|
71
75
|
line-length = 88
|
|
72
|
-
extend-exclude = [".dist", "
|
|
76
|
+
extend-exclude = [".dist", "build"]
|
|
73
77
|
|
|
74
78
|
[tool.ruff.lint]
|
|
75
79
|
select = ["E4", "E7", "E9", "F", "I", "W"]
|
|
@@ -10,11 +10,6 @@ import tomllib
|
|
|
10
10
|
from pathlib import Path
|
|
11
11
|
|
|
12
12
|
PACKAGE_NAME = "common-python-tasks"
|
|
13
|
-
PACKAGE_MANAGER_ENV_VARS = (
|
|
14
|
-
"COMMON_PYTHON_TASKS_PACKAGE_MANAGER",
|
|
15
|
-
"COMMON_PYTHON_TASKS_BUILD_TOOL",
|
|
16
|
-
"PACKAGE_MANAGER",
|
|
17
|
-
)
|
|
18
13
|
PYPROJECT_PATH = Path("pyproject.toml")
|
|
19
14
|
TOOL_POE_PATTERN = re.compile(r"^\s*\[tool\.poe\]\s*(?:#.*)?$")
|
|
20
15
|
TABLE_PATTERN = re.compile(r"^\s*\[")
|
|
@@ -26,47 +21,18 @@ def _require_command(command: str) -> None:
|
|
|
26
21
|
sys.exit(f"Required command not found: {command}")
|
|
27
22
|
|
|
28
23
|
|
|
29
|
-
def _get_requested_package_manager() -> str:
|
|
30
|
-
for env_var in PACKAGE_MANAGER_ENV_VARS:
|
|
31
|
-
if os.getenv(env_var, "").strip():
|
|
32
|
-
return os.environ[env_var].strip().lower()
|
|
33
|
-
return "auto"
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
def _select_package_manager() -> str:
|
|
37
|
-
requested_manager = _get_requested_package_manager()
|
|
38
|
-
if requested_manager in {"poetry", "uv"}:
|
|
39
|
-
_require_command(requested_manager)
|
|
40
|
-
return requested_manager
|
|
41
|
-
if requested_manager != "auto":
|
|
42
|
-
sys.exit(f"Unsupported package manager: {requested_manager}")
|
|
43
|
-
|
|
44
|
-
for lock_file, package_manager in (
|
|
45
|
-
(Path("uv.lock"), "uv"),
|
|
46
|
-
(Path("poetry.lock"), "poetry"),
|
|
47
|
-
):
|
|
48
|
-
if lock_file.is_file() and shutil.which(package_manager) is not None:
|
|
49
|
-
return package_manager
|
|
50
|
-
|
|
51
|
-
for package_manager in ("uv", "poetry"):
|
|
52
|
-
if shutil.which(package_manager) is not None:
|
|
53
|
-
return package_manager
|
|
54
|
-
|
|
55
|
-
sys.exit("Neither uv nor Poetry is installed.")
|
|
56
|
-
|
|
57
|
-
|
|
58
24
|
def _get_package_requirement() -> str:
|
|
59
25
|
if os.getenv("COMMON_PYTHON_TASKS_VERSION", "").strip():
|
|
60
26
|
return f"{PACKAGE_NAME}=={os.environ['COMMON_PYTHON_TASKS_VERSION'].strip()}"
|
|
61
27
|
return PACKAGE_NAME
|
|
62
28
|
|
|
63
29
|
|
|
64
|
-
def _install_package(
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
30
|
+
def _install_package() -> None:
|
|
31
|
+
subprocess.run(
|
|
32
|
+
["uv", "add", "--dev", _get_package_requirement()],
|
|
33
|
+
check=True,
|
|
34
|
+
shell=False,
|
|
35
|
+
)
|
|
70
36
|
|
|
71
37
|
|
|
72
38
|
def _get_include_script() -> str:
|
|
@@ -132,7 +98,8 @@ def _print_available_tasks() -> None:
|
|
|
132
98
|
|
|
133
99
|
def main() -> None:
|
|
134
100
|
"""Install common tasks and configure Poe in the current project."""
|
|
135
|
-
|
|
101
|
+
_require_command("uv")
|
|
102
|
+
_install_package()
|
|
136
103
|
_configure_poe()
|
|
137
104
|
print("\n\033[1;32mCommon Python tasks added to project.\033[0m")
|
|
138
105
|
print("\n\033[1mAvailable tasks:\033[0m")
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import re
|
|
2
|
+
|
|
3
|
+
from common_python_tasks.__main__ import (
|
|
4
|
+
_get_task_docstring,
|
|
5
|
+
get_available_tasks,
|
|
6
|
+
get_task_tags,
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
TASKS_TABLE_PATTERN = r"(?ms)<!-- tasks-table -->.*?<!-- end-tasks-table -->"
|
|
10
|
+
TASK_CATEGORY_ORDER = (
|
|
11
|
+
"Daily development",
|
|
12
|
+
"Packaging and releases",
|
|
13
|
+
"Container images",
|
|
14
|
+
"Development stacks",
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _get_task_category(task_name: str) -> str:
|
|
19
|
+
tags = get_task_tags(task_name) or []
|
|
20
|
+
if "web" in tags or "database" in tags:
|
|
21
|
+
return "Development stacks"
|
|
22
|
+
if task_name == "release":
|
|
23
|
+
return "Packaging and releases"
|
|
24
|
+
if "containers" in tags:
|
|
25
|
+
return "Container images"
|
|
26
|
+
if "packaging" in tags or "release" in tags:
|
|
27
|
+
return "Packaging and releases"
|
|
28
|
+
return "Daily development"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _get_task_description(task_name: str) -> str:
|
|
32
|
+
return " ".join(
|
|
33
|
+
line.strip()
|
|
34
|
+
for line in (_get_task_docstring(task_name) or "").splitlines()
|
|
35
|
+
if line.strip()
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def build_tasks_table() -> str:
|
|
40
|
+
"""Build the markdown task table for README insertion."""
|
|
41
|
+
tasks_by_category = {category: [] for category in TASK_CATEGORY_ORDER}
|
|
42
|
+
for task_name in get_available_tasks(internal=False):
|
|
43
|
+
tasks_by_category[_get_task_category(task_name)].append(task_name)
|
|
44
|
+
|
|
45
|
+
lines = ["<!-- tasks-table -->"]
|
|
46
|
+
for category in TASK_CATEGORY_ORDER:
|
|
47
|
+
if not tasks_by_category[category]:
|
|
48
|
+
continue
|
|
49
|
+
|
|
50
|
+
lines.extend(
|
|
51
|
+
[
|
|
52
|
+
"",
|
|
53
|
+
f"### {category}",
|
|
54
|
+
"",
|
|
55
|
+
"| Task | Description | Tags |",
|
|
56
|
+
"| --- | --- | --- |",
|
|
57
|
+
]
|
|
58
|
+
)
|
|
59
|
+
lines.extend(
|
|
60
|
+
f"| `{task_name}` | {_get_task_description(task_name)} | "
|
|
61
|
+
f"{', '.join(get_task_tags(task_name) or [])} |"
|
|
62
|
+
for task_name in tasks_by_category[category]
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
lines.extend(["", "<!-- end-tasks-table -->"])
|
|
66
|
+
return "\n".join(lines)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def replace_tasks_table(readme_text: str) -> str:
|
|
70
|
+
"""Replace the task table in the README text with the generated task table.
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
readme_text: The text of the README.md file to update.
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
The updated README.md text with the task table replaced.
|
|
77
|
+
"""
|
|
78
|
+
return re.sub(TASKS_TABLE_PATTERN, build_tasks_table(), readme_text)
|