common-python-tasks 0.12.1__tar.gz → 0.13.1__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.
Files changed (81) hide show
  1. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/PKG-INFO +7 -8
  2. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/README.md +6 -7
  3. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/docs/configuration.md +1 -14
  4. common_python_tasks-0.13.1/docs/documentation-workflows.md +183 -0
  5. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/docs/getting-started.md +1 -1
  6. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/docs/index.md +0 -1
  7. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/docs/tasks/container-images.md +12 -3
  8. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/docs/tasks/index.md +0 -1
  9. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/docs/tasks/packaging-and-releases.md +3 -1
  10. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/docs/tasks/reference/build-deps-image.md +2 -2
  11. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/docs/tasks/reference/build-image.md +2 -2
  12. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/pyproject.toml +1 -3
  13. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/scripts/docs_tasks_reference.py +0 -3
  14. common_python_tasks-0.13.1/src/common_python_tasks/_task_registry.py +163 -0
  15. common_python_tasks-0.13.1/src/common_python_tasks/container_tasks.py +609 -0
  16. common_python_tasks-0.13.1/src/common_python_tasks/dependency_tasks.py +180 -0
  17. common_python_tasks-0.13.1/src/common_python_tasks/development_tasks.py +211 -0
  18. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/src/common_python_tasks/docker.py +12 -12
  19. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/src/common_python_tasks/env.py +19 -16
  20. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/src/common_python_tasks/git.py +47 -30
  21. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/src/common_python_tasks/github.py +4 -2
  22. common_python_tasks-0.13.1/src/common_python_tasks/packaging_tasks.py +161 -0
  23. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/src/common_python_tasks/project.py +0 -2
  24. common_python_tasks-0.13.1/src/common_python_tasks/release_tasks.py +433 -0
  25. common_python_tasks-0.13.1/src/common_python_tasks/tasks.py +93 -0
  26. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/src/common_python_tasks/utils.py +27 -15
  27. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/zensical.toml +8 -1
  28. common_python_tasks-0.12.1/docs/documentation-workflows.md +0 -104
  29. common_python_tasks-0.12.1/docs/tasks/development-stacks.md +0 -25
  30. common_python_tasks-0.12.1/docs/tasks/reference/db-shell.md +0 -13
  31. common_python_tasks-0.12.1/docs/tasks/reference/reset-db.md +0 -13
  32. common_python_tasks-0.12.1/docs/tasks/reference/run-db-migrations.md +0 -13
  33. common_python_tasks-0.12.1/docs/tasks/reference/stack-down.md +0 -13
  34. common_python_tasks-0.12.1/docs/tasks/reference/stack-up.md +0 -24
  35. common_python_tasks-0.12.1/src/common_python_tasks/data/fastapi/alembic.ini.j2 +0 -51
  36. common_python_tasks-0.12.1/src/common_python_tasks/data/fastapi/compose-base.yml.j2 +0 -40
  37. common_python_tasks-0.12.1/src/common_python_tasks/data/fastapi/compose-db-debug.yml.j2 +0 -45
  38. common_python_tasks-0.12.1/src/common_python_tasks/data/fastapi/compose-db.yml.j2 +0 -80
  39. common_python_tasks-0.12.1/src/common_python_tasks/data/fastapi/compose-debug.yml.j2 +0 -30
  40. common_python_tasks-0.12.1/src/common_python_tasks/docker_compose.py +0 -643
  41. common_python_tasks-0.12.1/src/common_python_tasks/tasks.py +0 -1982
  42. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/.gitignore +0 -0
  43. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/.poetry/plugins/poetry_dynamic_versioning-1.10.0.dist-info/licenses/LICENSE +0 -0
  44. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/.poetry/plugins/poetry_plugin_export-1.10.0.dist-info/licenses/LICENSE +0 -0
  45. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/LICENSE +0 -0
  46. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/docs/tasks/daily-development.md +0 -0
  47. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/docs/tasks/documentation.md +0 -0
  48. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/docs/tasks/reference/build-package.md +0 -0
  49. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/docs/tasks/reference/build.md +0 -0
  50. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/docs/tasks/reference/bump-version.md +0 -0
  51. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/docs/tasks/reference/changelog.md +0 -0
  52. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/docs/tasks/reference/clean.md +0 -0
  53. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/docs/tasks/reference/container-shell.md +0 -0
  54. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/docs/tasks/reference/docs-build.md +0 -0
  55. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/docs/tasks/reference/docs-serve.md +0 -0
  56. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/docs/tasks/reference/format.md +0 -0
  57. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/docs/tasks/reference/lint.md +0 -0
  58. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/docs/tasks/reference/publish-github-release.md +0 -0
  59. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/docs/tasks/reference/publish-package.md +0 -0
  60. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/docs/tasks/reference/push-image.md +0 -0
  61. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/docs/tasks/reference/release.md +0 -0
  62. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/docs/tasks/reference/run-container.md +0 -0
  63. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/docs/tasks/reference/test.md +0 -0
  64. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/docs/tasks/reference/update-dependencies.md +0 -0
  65. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/scripts/__init__.py +0 -0
  66. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/scripts/add_common_python_tasks.py +0 -0
  67. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/scripts/release_script.py +0 -0
  68. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/scripts/update_docs_tasks_reference.py +0 -0
  69. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/scripts/utils.py +0 -0
  70. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/src/common_python_tasks/__init__.py +0 -0
  71. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/src/common_python_tasks/__main__.py +0 -0
  72. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/src/common_python_tasks/data/dockerfile_extensions/docker-in-docker/Dockerfile +0 -0
  73. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/src/common_python_tasks/data/dockerfile_extensions/docker-in-docker/install.sh +0 -0
  74. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/src/common_python_tasks/data/dockerfile_extensions/docker-in-docker/supervisor.sh +0 -0
  75. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/src/common_python_tasks/data/generic/.coveragerc +0 -0
  76. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/src/common_python_tasks/data/generic/.dockerignore +0 -0
  77. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/src/common_python_tasks/data/generic/Dockerfile.deps.j2 +0 -0
  78. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/src/common_python_tasks/data/generic/Dockerfile.j2 +0 -0
  79. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/src/common_python_tasks/data/generic/cliff.toml +0 -0
  80. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/src/common_python_tasks/data/generic/pytest.ini +0 -0
  81. {common_python_tasks-0.12.1 → common_python_tasks-0.13.1}/src/common_python_tasks/data/generic/ruff.toml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: common-python-tasks
3
- Version: 0.12.1
3
+ Version: 0.13.1
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
@@ -35,14 +35,14 @@ Description-Content-Type: text/markdown
35
35
 
36
36
  `common-python-tasks` provides reusable, opinionated [Poe the Poet](https://poethepoet.natn.io/guides/packaged_tasks.html) tasks for Python development, packaging, releases, containers, and documentation.
37
37
 
38
- Read the [complete documentation](https://ci-sourcerer.github.io/common-python-tasks/) for the task reference, configuration options, and deployment guidance.
38
+ Read the [complete documentation](https://common-python-tasks.ci-sourcerer.com/) for the task reference, configuration options, and deployment guidance.
39
39
 
40
40
  ## Quick start
41
41
 
42
42
  Add the package as a development dependency.
43
43
 
44
44
  ```shell
45
- uv add --dev common-python-tasks==0.12.1
45
+ uv add --dev common-python-tasks==0.13.1
46
46
  ```
47
47
 
48
48
  Expose the default task set in `pyproject.toml`.
@@ -74,7 +74,6 @@ include_script = "common_python_tasks:tasks(include_tags=['common', 'docs', 'con
74
74
  | `common` | Formatting, linting, testing, packaging, and releases |
75
75
  | `docs` | Build and serve Zensical documentation |
76
76
  | `containers` | Build, run, inspect, and publish container images |
77
- | `fastapi` | Run the FastAPI and PostgreSQL development stack |
78
77
 
79
78
  Documentation projects can build locally or start a development server.
80
79
 
@@ -83,12 +82,12 @@ poe docs-build
83
82
  poe docs-serve
84
83
  ```
85
84
 
86
- The [documentation workflow guide](https://ci-sourcerer.github.io/common-python-tasks/documentation-workflows/) covers GitHub Actions artifacts, optional Cloudflare Pages previews, and GitHub Pages deployment.
85
+ The [documentation workflow guide](https://common-python-tasks.ci-sourcerer.com/documentation-workflows/) covers GitHub Actions artifacts, optional Cloudflare Pages previews, and GitHub Pages deployment.
87
86
 
88
87
  ## Learn more
89
88
 
90
- - [Getting started](https://ci-sourcerer.github.io/common-python-tasks/getting-started/)
91
- - [Task reference](https://ci-sourcerer.github.io/common-python-tasks/tasks/)
92
- - [Configuration reference](https://ci-sourcerer.github.io/common-python-tasks/configuration/)
89
+ - [Getting started](https://common-python-tasks.ci-sourcerer.com/getting-started/)
90
+ - [Task reference](https://common-python-tasks.ci-sourcerer.com/tasks/)
91
+ - [Configuration reference](https://common-python-tasks.ci-sourcerer.com/configuration/)
93
92
 
94
93
  The project is in alpha, so minor releases may contain breaking changes. It is distributed under the [MIT license](LICENSE).
@@ -2,14 +2,14 @@
2
2
 
3
3
  `common-python-tasks` provides reusable, opinionated [Poe the Poet](https://poethepoet.natn.io/guides/packaged_tasks.html) tasks for Python development, packaging, releases, containers, and documentation.
4
4
 
5
- Read the [complete documentation](https://ci-sourcerer.github.io/common-python-tasks/) for the task reference, configuration options, and deployment guidance.
5
+ Read the [complete documentation](https://common-python-tasks.ci-sourcerer.com/) for the task reference, configuration options, and deployment guidance.
6
6
 
7
7
  ## Quick start
8
8
 
9
9
  Add the package as a development dependency.
10
10
 
11
11
  ```shell
12
- uv add --dev common-python-tasks==0.12.1
12
+ uv add --dev common-python-tasks==0.13.1
13
13
  ```
14
14
 
15
15
  Expose the default task set in `pyproject.toml`.
@@ -41,7 +41,6 @@ include_script = "common_python_tasks:tasks(include_tags=['common', 'docs', 'con
41
41
  | `common` | Formatting, linting, testing, packaging, and releases |
42
42
  | `docs` | Build and serve Zensical documentation |
43
43
  | `containers` | Build, run, inspect, and publish container images |
44
- | `fastapi` | Run the FastAPI and PostgreSQL development stack |
45
44
 
46
45
  Documentation projects can build locally or start a development server.
47
46
 
@@ -50,12 +49,12 @@ poe docs-build
50
49
  poe docs-serve
51
50
  ```
52
51
 
53
- The [documentation workflow guide](https://ci-sourcerer.github.io/common-python-tasks/documentation-workflows/) covers GitHub Actions artifacts, optional Cloudflare Pages previews, and GitHub Pages deployment.
52
+ The [documentation workflow guide](https://common-python-tasks.ci-sourcerer.com/documentation-workflows/) covers GitHub Actions artifacts, optional Cloudflare Pages previews, and GitHub Pages deployment.
54
53
 
55
54
  ## Learn more
56
55
 
57
- - [Getting started](https://ci-sourcerer.github.io/common-python-tasks/getting-started/)
58
- - [Task reference](https://ci-sourcerer.github.io/common-python-tasks/tasks/)
59
- - [Configuration reference](https://ci-sourcerer.github.io/common-python-tasks/configuration/)
56
+ - [Getting started](https://common-python-tasks.ci-sourcerer.com/getting-started/)
57
+ - [Task reference](https://common-python-tasks.ci-sourcerer.com/tasks/)
58
+ - [Configuration reference](https://common-python-tasks.ci-sourcerer.com/configuration/)
60
59
 
61
60
  The project is in alpha, so minor releases may contain breaking changes. It is distributed under the [MIT license](LICENSE).
@@ -43,7 +43,7 @@ Container variables are read by the host-side tasks unless their description exp
43
43
  | `WORKDIR_PATH` | Home and working directory for the non-root `py` user; defaults to `/workspace` |
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
- | `CONTAINER_DOCKER_BUILD_ARGS` | Shell-tokenized arguments passed directly to `docker build`; task arguments after `--` take precedence |
46
+ | `CONTAINER_DOCKER_BUILD_OPTIONS` | Shell-tokenized options passed directly to `docker build`; task options 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
48
  | `CONTAINER_DOCKERFILE_HOOK_PATH` | Executable host script that modifies the selected Dockerfile before the build |
49
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 |
@@ -70,19 +70,6 @@ Container variables are read by the host-side tasks unless their description exp
70
70
  | `CONTAINER_DEPS_MOVE_SCRIPT` | Inline script that distributes copied dependency artifacts and takes precedence over mappings |
71
71
  | `CONTAINER_DEPS_MOVE_SCRIPT_PATH` | Host path to a dependency move script; takes precedence over the inline script and mappings |
72
72
 
73
- ## Development-stack settings
74
-
75
- Set `COMPOSE_TYPE=fastapi` to use the bundled FastAPI stack. Add PostgreSQL with `COMPOSE_ADDONS=db`.
76
-
77
- ```toml
78
- [tool.poe.env]
79
- COMPOSE_TYPE = "fastapi"
80
- COMPOSE_ADDONS = "db"
81
- API_PORT = "8080"
82
- DB_PORT = "5432"
83
- ```
84
-
85
- `COMPOSE_FILE` replaces automatic compose-file selection. `COMPOSE_OVERLAY_FILES` appends project-specific overlays to the automatically selected files.
86
73
 
87
74
  ## Diagnostics
88
75
 
@@ -0,0 +1,183 @@
1
+ # Documentation workflows
2
+
3
+ Projects can use the packaged documentation tasks locally and the repository's reusable GitHub workflow in CI. The workflow builds the caller's repository, not `common-python-tasks`.
4
+
5
+ ## Configure a project
6
+
7
+ Add a `zensical.toml` file and select the `docs` task group.
8
+
9
+ ```toml
10
+ [tool.poe]
11
+ include_script = "common_python_tasks:tasks(include_tags=['common', 'docs'])"
12
+ ```
13
+
14
+ Build or serve the site locally.
15
+
16
+ ```shell
17
+ poe docs-build
18
+ poe docs-serve
19
+ ```
20
+
21
+ ## Build pull-request artifacts
22
+
23
+ Keep event triggers and path filters in the consuming repository, then call the reusable workflow from a job.
24
+
25
+ ```yaml
26
+ name: docs-preview
27
+
28
+ on:
29
+ pull_request:
30
+ paths:
31
+ - 'docs/**'
32
+ - 'zensical.toml'
33
+ - 'pyproject.toml'
34
+ - 'uv.lock'
35
+
36
+ jobs:
37
+ docs:
38
+ uses: ci-sourcerer/common-python-tasks/.github/workflows/docs.yml@v0.11.0
39
+ with:
40
+ python_version: '3.14'
41
+ dependency_group: dev
42
+ permissions:
43
+ contents: read
44
+ ```
45
+
46
+ The workflow uploads the rendered site as a GitHub Actions artifact by default.
47
+
48
+ ## Run a client-owned generated-document check
49
+
50
+ Some projects generate additional documentation from application code. Keep that generator in the consuming project and pass its Poe check task to the workflow.
51
+
52
+ ```yaml
53
+ with:
54
+ python_version: '3.14'
55
+ dependency_group: dev
56
+ generated_docs_check_task: docs-cli-reference-check
57
+ ```
58
+
59
+ Only task names containing letters, digits, underscores, and hyphens are accepted.
60
+
61
+ ## Enable Cloudflare Pages previews
62
+
63
+ Cloudflare publication is optional. The workflow ensures that one Direct Upload Pages project exists for the consuming repository, then deploys previews to it with narrowly scoped credentials.
64
+
65
+ ```yaml
66
+ jobs:
67
+ docs:
68
+ uses: ci-sourcerer/common-python-tasks/.github/workflows/docs.yml@v0.11.0
69
+ with:
70
+ python_version: '3.14'
71
+ dependency_group: dev
72
+ publish_cloudflare: true
73
+ cloudflare_project_name: stacksmith-docs
74
+ cloudflare_preview_domain: preview.example.com
75
+ cloudflare_preview_zone: example.com
76
+ permissions:
77
+ contents: read
78
+ deployments: write
79
+ secrets:
80
+ cloudflare_account_id: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
81
+ cloudflare_api_token: ${{ secrets.CLOUDFLARE_API_TOKEN }}
82
+ ```
83
+
84
+ The project is created on the first trusted pull request, using `main` as its production branch by default. Set `cloudflare_production_branch` if the repository uses a different default branch. Set `cloudflare_preview_domain` to publish previews at `pr-42.preview.example.com`; leave it empty to use `pr-42.stacksmith-docs.pages.dev`. Set `cloudflare_preview_zone` when the preview domain is a subdomain of the DNS zone. The API token needs Pages Write, Zone Read, and Zone DNS Edit permissions when custom preview domains are enabled. Fork pull requests receive the build artifact but are not published because repository secrets are unavailable. A separate `pull_request`-closed workflow can remove the custom hostname, its matching DNS record, and older deployments for that preview branch while preserving the shared Pages project. Cloudflare retains the latest branch deployment.
85
+
86
+ ## Deploy documentation to GitHub Pages
87
+
88
+ Enable GitHub Actions as the repository's Pages source. GitHub Pages deployments are versioned by default and publish the current checkout as `dev` unless the caller selects another version. The caller must grant `contents: write` so the workflow can update the versions branch.
89
+
90
+ ```yaml
91
+ jobs:
92
+ docs:
93
+ uses: ci-sourcerer/common-python-tasks/.github/workflows/docs.yml@v0.11.0
94
+ with:
95
+ python_version: '3.14'
96
+ dependency_group: dev
97
+ deploy_github_pages: true
98
+ permissions:
99
+ contents: write
100
+ pages: write
101
+ id-token: write
102
+ ```
103
+
104
+ This initial deployment creates `dev` and uses it as the site root when the versions branch does not already contain a root redirect. Pin the workflow to the release that matches the installed package. Pin an exact commit SHA when an immutable workflow reference is required.
105
+
106
+ ## Configure versioned documentation
107
+
108
+ Versioned deployment uses the Zensical-compatible `mike` fork. The workflow keeps generated versions on a Git branch and publishes the assembled branch through GitHub Actions, so the repository's Pages source remains GitHub Actions. The fork is a transitional dependency until Zensical provides native versioning support.
109
+
110
+ Enable the version selector in `zensical.toml`.
111
+
112
+ ```toml
113
+ [project.extra.version]
114
+ provider = "mike"
115
+ default = ["latest", "dev"]
116
+
117
+ [project.plugins.mike]
118
+ alias_type = "redirect"
119
+ ```
120
+
121
+ Pass a version identifier, title, aliases, and default version when publishing a release.
122
+
123
+ ```yaml
124
+ jobs:
125
+ docs:
126
+ uses: ci-sourcerer/common-python-tasks/.github/workflows/docs.yml@v0.12.1
127
+ with:
128
+ python_version: '3.14'
129
+ dependency_group: dev
130
+ deploy_github_pages: true
131
+ docs_version: '2.4'
132
+ docs_version_title: '2.4.3'
133
+ docs_aliases: '["latest"]'
134
+ docs_default_version: latest
135
+ permissions:
136
+ contents: write
137
+ pages: write
138
+ id-token: write
139
+ ```
140
+
141
+ `docs_aliases` must be a JSON array. Versions and aliases accept letters, digits, periods, underscores, and hyphens. The default versions branch is `gh-pages`; set `docs_versions_branch` to use another valid Git branch. The reusable workflow serializes updates to each repository and versions branch. Alias redirects are updated atomically with the version metadata, and versions not named by the current deployment remain unchanged.
142
+
143
+ The workflow still performs the strict `poe docs-build` check and uploads the current checkout as the normal Actions artifact. It then builds through `mike`, updates the versions branch, and gives the complete assembled site to GitHub Pages.
144
+
145
+ ## Preview multiple versions locally
146
+
147
+ `poe docs-serve` builds and watches only the current checkout. It is the quickest way to review content, but its version selector has no assembled `versions.json` to load.
148
+
149
+ Install the same pinned Zensical-compatible `mike` fork used by the workflow, assemble two versions on a disposable local Git branch, and serve that branch.
150
+
151
+ ```shell
152
+ uv pip install 'mike @ git+https://github.com/squidfunk/mike.git@2d4ad799442f4592db8ad53b179bfb33db8c69ac'
153
+ uv run --no-sync mike deploy --branch local-docs --alias-type redirect --update-aliases --title Development dev
154
+ uv run --no-sync mike deploy --branch local-docs --alias-type redirect --update-aliases --title 0.12.1 0.12 latest
155
+ uv run --no-sync mike set-default --branch local-docs latest
156
+ uv run --no-sync mike serve --branch local-docs
157
+ ```
158
+
159
+ Open `http://localhost:8000/`. The root redirects to `latest`, and the selector switches between `0.12` and `dev`. These commands create only local commits on `local-docs`; they do not push anything. Stop the server before removing the disposable branch with `git branch -D local-docs`.
160
+
161
+ ## Publish development and release versions
162
+
163
+ Use one serialized production workflow for default-branch and tag deployment. Publish the default branch as `dev`, and publish stable tags to a major/minor documentation series. For example, `v2.4.3` updates version `2.4`, uses `2.4.3` as its display title, moves the `latest` alias, and makes `latest` the site root. Later default-branch deployments update `dev` without moving the root away from `latest`.
164
+
165
+ The repository's own deployment workflow demonstrates this policy. Pull requests continue to use the unversioned artifact and Cloudflare preview flow, so a pull request previews the next `dev` site without modifying the versions branch.
166
+
167
+ ## Backfill an existing release
168
+
169
+ A repository can expose manual workflow inputs that pass an older tag through `checkout_ref` while deploying it under an explicit documentation version. For this repository, run `docs-deploy` manually with values such as the following.
170
+
171
+ | Input | Value |
172
+ | - | - |
173
+ | `source_ref` | A tag that already enables the `mike` version selector, or empty to build the selected workflow ref |
174
+ | `docs_version` | `0.12` |
175
+ | `docs_version_title` | `0.12.1` |
176
+ | `update_latest` | `true` |
177
+ | `default_version` | `latest` |
178
+
179
+ Backfill supported series from oldest to newest so the selector order and `latest` alias finish in the desired state. Historical refs created before versioning was configured cannot produce a working selector without a compatible configuration change; build those docs from a suitable maintenance branch or the current branch instead. A normal default-branch deployment uses `dev` as the initial site root only when the versions branch has no root redirect, which keeps the documentation reachable before the first release or backfill.
180
+
181
+ ## Maintain published versions
182
+
183
+ The versions branch contains `versions.json`, the generated version directories, aliases, and the root redirect. Inspect a local checkout with the same pinned Zensical-compatible fork before deleting or retitling published versions. Since the fork is installed directly from GitHub, changes to its pinned commit require a versioned workflow update and a representative multi-version build test.
@@ -36,7 +36,7 @@ Use `exclude_tags` when a project wants nearly every group.
36
36
 
37
37
  ```toml
38
38
  [tool.poe]
39
- include_script = "common_python_tasks:tasks(exclude_tags=['fastapi'])"
39
+ include_script = "common_python_tasks:tasks(exclude_tags=['containers'])"
40
40
  ```
41
41
 
42
42
  Calling `tasks()` with no arguments selects only `common`. Passing an explicit empty `include_tags` sequence selects every task unless an exclusion removes it.
@@ -18,7 +18,6 @@ Tasks are organized by tags, so each project can select only the workflows it ne
18
18
  | `common` | Formatting, linting, testing, packaging, and releases |
19
19
  | `docs` | Build and locally serve Zensical documentation |
20
20
  | `containers` | Build, run, inspect, and publish container images |
21
- | `fastapi` | Run a local FastAPI and PostgreSQL development stack |
22
21
 
23
22
  The default task collection exposes the `common` group. Optional groups are enabled through the package's `include_script` expression.
24
23
 
@@ -295,7 +295,7 @@ poe build --dockerfile-path docker/Dockerfile.ci
295
295
  poe release --dockerfile-path docker/Dockerfile.release
296
296
  ```
297
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`.
298
+ The project root remains the Docker build context. Standard image naming, version and commit tags, metadata build arguments, `CONTAINER_DOCKER_BUILD_OPTIONS`, 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
299
 
300
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
301
 
@@ -393,7 +393,16 @@ Arguments following Poe's `--` separator are passed directly to `docker build` w
393
393
  poe build-image --single-arch -- --secret id=pip_conf,env=PIP_CONF
394
394
  ```
395
395
 
396
- Set `CONTAINER_DOCKER_BUILD_ARGS` to persist the same options using shell quoting rules. Arguments supplied after `--` replace this setting for that invocation. Managed arguments are emitted before these native Docker arguments, so an explicit option such as `--build-arg WORKDIR_PATH=/app` can override its managed value.
396
+ Set `CONTAINER_DOCKER_BUILD_OPTIONS` to persist the same options using shell quoting rules. Options supplied after `--` replace this setting for that invocation. Managed build arguments are emitted before these native Docker options, so an explicit option such as `--build-arg WORKDIR_PATH=/app` can override its managed value.
397
+
398
+ For project-specific defaults, declare the options in Poe's environment. A name-only `--build-arg` reads its value from the current environment, while `env=` explicitly selects the host variable used for a BuildKit secret.
399
+
400
+ ```toml
401
+ [tool.poe.env]
402
+ CONTAINER_DOCKER_BUILD_OPTIONS = "--secret id=MY_TOKEN,env=MY_TOKEN --build-arg MY_SETTING"
403
+ ```
404
+
405
+ The Dockerfile must consume `MY_TOKEN` with a secret mount. Do not pass sensitive values through `--build-arg`, because build arguments are not designed to protect secrets.
397
406
 
398
407
  See [Container settings](../configuration.md#container-settings) for the complete settings reference.
399
408
 
@@ -405,7 +414,7 @@ See [Container settings](../configuration.md#container-settings) for the complet
405
414
  | [`build-deps-image`](reference/build-deps-image.md) | Build only the container dependency collector image for this project. |
406
415
  | [`run-container`](reference/run-container.md) | Run the Docker image as a container for this project. |
407
416
  | [`push-image`](reference/push-image.md) | Push the Docker image for this project to the container registry. |
408
- | [`build`](reference/build.md) | Build the project and its containers. |
409
417
  | [`container-shell`](reference/container-shell.md) | Run the debug image with an interactive shell. |
418
+ | [`build`](reference/build.md) | Build the project and its containers. |
410
419
 
411
420
  <!-- end-generated-task-reference -->
@@ -10,7 +10,6 @@ The task reference is divided by workflow. Each category page includes a table l
10
10
  | [Documentation](documentation.md) | Build and locally serve a Zensical site |
11
11
  | [Packaging and releases](packaging-and-releases.md) | Build, version, publish, and release packages |
12
12
  | [Container images](container-images.md) | Build, run, inspect, and publish images |
13
- | [Development stacks](development-stacks.md) | Operate the FastAPI and PostgreSQL Compose stack |
14
13
 
15
14
  Individual task reference pages are also available in the sidebar under the "reference" section.
16
15
 
@@ -10,12 +10,14 @@ Publish targets and release hooks are described in [Configuration](../configurat
10
10
 
11
11
  | Task | Description |
12
12
  | - | - |
13
+ | [`update-dependencies`](reference/update-dependencies.md) | Update project dependencies with uv. |
13
14
  | [`publish-package`](reference/publish-package.md) | Publish the package to the PyPI server. |
14
15
  | [`publish-github-release`](reference/publish-github-release.md) | Publish or update a GitHub Release for the current repository. |
15
- | [`update-dependencies`](reference/update-dependencies.md) | Update project dependencies with uv. |
16
16
  | [`build-package`](reference/build-package.md) | Build the package (wheel and sdist). |
17
17
  | [`bump-version`](reference/bump-version.md) | Bump the project version. |
18
18
  | [`changelog`](reference/changelog.md) | Print the changelog for the current version based on git history and git-cliff. |
19
19
  | [`release`](reference/release.md) | Run a full release flow for package and containers. |
20
20
 
21
21
  <!-- end-generated-task-reference -->
22
+
23
+ Automatic releases default to a patch bump when no version bump is inferred, including when there are no new commits. Empty generated release notes use “No conventional commit messages found.” No synthetic commits are created for version inference.
@@ -9,14 +9,14 @@ Build only the container dependency collector image for this project.
9
9
  ## Usage
10
10
 
11
11
  ```shell
12
- poe build-deps-image [DOCKER_BUILD_ARGS...] [--no-cache] [--plain] [--single-arch]
12
+ poe build-deps-image [DOCKER_BUILD_OPTIONS...] [--no-cache] [--plain] [--single-arch]
13
13
  ```
14
14
 
15
15
  ## Arguments
16
16
 
17
17
  | Argument | Type | Description | Default |
18
18
  | - | - | - | - |
19
- | `docker_build_args...` | `string, repeatable` | Additional arguments passed directly to `docker build`. Provide them after the task's `--` separator. Overrides `CONTAINER_DOCKER_BUILD_ARGS` when provided. | — |
19
+ | `docker_build_options...` | `string, repeatable` | Additional options passed directly to `docker build`. Provide them after the task's `--` separator. Overrides `CONTAINER_DOCKER_BUILD_OPTIONS` when provided. | — |
20
20
  | `--no-cache` | `boolean` | Do not use cache when building the deps image. | `false` |
21
21
  | `--plain` | `boolean` | Do not pretty-print output. | `false` |
22
22
  | `--single-arch` | `boolean` | Build images for a single architecture. | `false` |
@@ -9,14 +9,14 @@ Build the container image using a project-owned or bundled Dockerfile.
9
9
  ## Usage
10
10
 
11
11
  ```shell
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...]
12
+ poe build-image [DOCKER_BUILD_OPTIONS...] [--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
16
16
 
17
17
  | Argument | Type | Description | Default |
18
18
  | - | - | - | - |
19
- | `docker_build_args...` | `string, repeatable` | Additional arguments passed directly to `docker build`. Provide them after the task's `--` separator. Overrides `CONTAINER_DOCKER_BUILD_ARGS` when provided. | — |
19
+ | `docker_build_options...` | `string, repeatable` | Additional options passed directly to `docker build`. Provide them after the task's `--` separator. Overrides `CONTAINER_DOCKER_BUILD_OPTIONS` when provided. | — |
20
20
  | `--debug` | `boolean` | Build the debug image. | `false` |
21
21
  | `--no-cache` | `boolean` | Do not use cache when building the image. | `false` |
22
22
  | `--plain` | `boolean` | Do not pretty-print output. | `false` |
@@ -38,13 +38,11 @@ Source = "http://github.com/ci-sourcerer/common-python-tasks.git"
38
38
  Issues = "http://github.com/ci-sourcerer/common-python-tasks/issues"
39
39
 
40
40
  [tool.poe]
41
- include_script = "common_python_tasks:tasks(exclude_tags=['containers', 'fastapi'])"
41
+ include_script = "common_python_tasks:tasks(exclude_tags=['containers'])"
42
42
 
43
43
  [tool.poe.tasks]
44
44
  update-docs-references = { cmd = "python -m scripts.update_docs_tasks_reference" }
45
45
  check-docs-references = { cmd = "python -m scripts.update_docs_tasks_reference --check" }
46
- update-docs-tasks-reference = { cmd = "python -m scripts.update_docs_tasks_reference" }
47
- check-docs-tasks-reference = { cmd = "python -m scripts.update_docs_tasks_reference --check" }
48
46
 
49
47
  [tool.poe.env]
50
48
  PYTHONPATH = "src"
@@ -17,7 +17,6 @@ TASK_CATEGORY_FILES = {
17
17
  "documentation": Path("docs/tasks/documentation.md"),
18
18
  "packaging-and-releases": Path("docs/tasks/packaging-and-releases.md"),
19
19
  "container-images": Path("docs/tasks/container-images.md"),
20
- "development-stacks": Path("docs/tasks/development-stacks.md"),
21
20
  }
22
21
  DOCKERFILE_REFERENCE_FILE = Path("docs/tasks/container-images.md")
23
22
  DOCKERFILE_TEMPLATE_FILES = (
@@ -36,8 +35,6 @@ def _get_task_category(task_name: str) -> str:
36
35
  tags = get_task_tags(task_name) or []
37
36
  if "docs" in tags:
38
37
  return "documentation"
39
- if "web" in tags or "database" in tags:
40
- return "development-stacks"
41
38
  if task_name == "release":
42
39
  return "packaging-and-releases"
43
40
  if "containers" in tags:
@@ -0,0 +1,163 @@
1
+ import contextvars
2
+ import inspect
3
+ import logging
4
+ import os
5
+ import shlex
6
+ from collections.abc import Callable
7
+ from functools import partial, wraps
8
+ from pathlib import Path
9
+ from typing import ClassVar
10
+
11
+ from poethepoet_tasks import TaskCollection
12
+
13
+
14
+ class _ColoredFormatter(logging.Formatter):
15
+ COLORS: ClassVar = {
16
+ "WARNING": "\033[93m",
17
+ "ERROR": "\033[91m",
18
+ "CRITICAL": "\033[91m",
19
+ "RESET": "\033[0m",
20
+ }
21
+
22
+ def format(self, record: logging.LogRecord) -> str:
23
+ log_color = self.COLORS.get(record.levelname, "")
24
+ record.levelname = f"\033[1m{log_color}{record.levelname}{self.COLORS['RESET'] if log_color else ''}\033[0m"
25
+ return super().format(record)
26
+
27
+
28
+ LOGGER = logging.getLogger("common_python_tasks")
29
+ handler = logging.StreamHandler()
30
+ handler.setFormatter(_ColoredFormatter("[%(asctime)s] %(levelname)s: %(message)s"))
31
+ LOGGER.addHandler(handler)
32
+ LOGGER.setLevel(
33
+ {
34
+ "DEBUG": logging.DEBUG,
35
+ "INFO": logging.INFO,
36
+ "WARNING": logging.WARNING,
37
+ "ERROR": logging.ERROR,
38
+ "CRITICAL": logging.CRITICAL,
39
+ }[os.getenv("COMMON_PYTHON_TASKS_LOG_LEVEL", "INFO").upper()]
40
+ )
41
+
42
+
43
+ tasks = TaskCollection(
44
+ envfile=[
45
+ f
46
+ for f in [
47
+ ".env.defaults",
48
+ "project.properties",
49
+ ".env",
50
+ ]
51
+ if Path(f).exists()
52
+ ]
53
+ )
54
+
55
+ _task_call_depth: contextvars.ContextVar[int] = contextvars.ContextVar(
56
+ "common_python_tasks_task_call_depth", default=0
57
+ )
58
+
59
+ _original_script = tasks.script
60
+
61
+
62
+ def _make_var_positional_task_args_optional(
63
+ func: callable, resolved_task_name: str
64
+ ) -> None:
65
+ var_positional_arg_names = {
66
+ param.name
67
+ for param in inspect.signature(func).parameters.values()
68
+ if param.kind == inspect.Parameter.VAR_POSITIONAL
69
+ }
70
+ if not var_positional_arg_names:
71
+ return
72
+
73
+ for task_config in tasks._tasks.get(resolved_task_name, []):
74
+ for arg_config in task_config.options.get("args", []):
75
+ if arg_config.get("name") in var_positional_arg_names:
76
+ arg_config["required"] = False
77
+
78
+
79
+ def _wrap_task_function(func: callable, task_name: str | None) -> callable:
80
+ resolved_task_name = task_name or func.__name__.replace("_", "-").lower()
81
+ var_positional_arg_names = [
82
+ param.name
83
+ for param in inspect.signature(func).parameters.values()
84
+ if param.kind == inspect.Parameter.VAR_POSITIONAL
85
+ ]
86
+
87
+ @wraps(func)
88
+ def wrapped(*args, **kwargs):
89
+ for arg_name in var_positional_arg_names:
90
+ if arg_name not in kwargs:
91
+ continue
92
+ values = kwargs.pop(arg_name)
93
+ if values is None:
94
+ continue
95
+ if isinstance(values, list | tuple):
96
+ args = (*args, *values)
97
+ else:
98
+ args = (*args, values)
99
+
100
+ if var_positional_arg_names and (
101
+ poe_extra_args := os.environ.pop("POE_EXTRA_ARGS", None)
102
+ ):
103
+ args = (*args, *shlex.split(poe_extra_args))
104
+
105
+ current_depth = _task_call_depth.get()
106
+ if current_depth > 0:
107
+ LOGGER.log(
108
+ (
109
+ logging.INFO
110
+ if not resolved_task_name.startswith("_")
111
+ else logging.DEBUG
112
+ ),
113
+ "Running task %s",
114
+ resolved_task_name,
115
+ )
116
+ token = _task_call_depth.set(current_depth + 1)
117
+ try:
118
+ return func(*args, **kwargs)
119
+ finally:
120
+ _task_call_depth.reset(token)
121
+
122
+ return wrapped
123
+
124
+
125
+ def _script(
126
+ func: Callable | None = None,
127
+ task_name: str | None = None,
128
+ help: str | None = None,
129
+ task_args: bool = True,
130
+ options: dict | None = None,
131
+ tags: tuple[str, ...] | None = None,
132
+ ):
133
+
134
+ if tags is None:
135
+ tags = ()
136
+
137
+ if func is None:
138
+ return partial(
139
+ _script,
140
+ task_name=task_name,
141
+ help=help,
142
+ task_args=task_args,
143
+ options=options,
144
+ tags=tags,
145
+ )
146
+
147
+ resolved_task_name = task_name or func.__name__.replace("_", "-").lower()
148
+ wrapped = _wrap_task_function(func, resolved_task_name)
149
+ decorated = _original_script(
150
+ wrapped,
151
+ task_name=resolved_task_name,
152
+ help=help,
153
+ task_args=task_args,
154
+ options=options,
155
+ tags=tags,
156
+ )
157
+ _make_var_positional_task_args_optional(wrapped, resolved_task_name)
158
+ return decorated
159
+
160
+
161
+ tasks.script = _script
162
+
163
+ NO_PROMPT_ENV_VAR = "COMMON_PYTHON_TASKS_NO_PROMPT"