common-python-tasks 0.0.3__tar.gz → 0.1.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.0.3 → common_python_tasks-0.1.0}/PKG-INFO +56 -43
- {common_python_tasks-0.0.3 → common_python_tasks-0.1.0}/README.md +53 -40
- {common_python_tasks-0.0.3 → common_python_tasks-0.1.0}/pyproject.toml +10 -4
- common_python_tasks-0.1.0/src/common_python_tasks/__init__.py +27 -0
- common_python_tasks-0.1.0/src/common_python_tasks/__main__.py +108 -0
- {common_python_tasks-0.0.3 → common_python_tasks-0.1.0}/src/common_python_tasks/data/generic/.pytest_cache/v/cache/nodeids +84 -1
- {common_python_tasks-0.0.3 → common_python_tasks-0.1.0}/src/common_python_tasks/git.py +61 -22
- {common_python_tasks-0.0.3 → common_python_tasks-0.1.0}/src/common_python_tasks/github.py +25 -0
- {common_python_tasks-0.0.3 → common_python_tasks-0.1.0}/src/common_python_tasks/project.py +3 -3
- {common_python_tasks-0.0.3 → common_python_tasks-0.1.0}/src/common_python_tasks/tasks.py +275 -127
- {common_python_tasks-0.0.3 → common_python_tasks-0.1.0}/src/common_python_tasks/utils.py +43 -9
- common_python_tasks-0.0.3/src/common_python_tasks/__init__.py +0 -16
- common_python_tasks-0.0.3/src/common_python_tasks/__main__.py +0 -35
- {common_python_tasks-0.0.3 → common_python_tasks-0.1.0}/LICENSE +0 -0
- {common_python_tasks-0.0.3 → common_python_tasks-0.1.0}/src/common_python_tasks/compose.py +0 -0
- {common_python_tasks-0.0.3 → common_python_tasks-0.1.0}/src/common_python_tasks/data/dockerfile_extensions/.gitkeep +0 -0
- {common_python_tasks-0.0.3 → common_python_tasks-0.1.0}/src/common_python_tasks/data/fastapi/alembic.ini.j2 +0 -0
- {common_python_tasks-0.0.3 → common_python_tasks-0.1.0}/src/common_python_tasks/data/fastapi/compose-base.yml.j2 +0 -0
- {common_python_tasks-0.0.3 → common_python_tasks-0.1.0}/src/common_python_tasks/data/fastapi/compose-db-debug.yml.j2 +0 -0
- {common_python_tasks-0.0.3 → common_python_tasks-0.1.0}/src/common_python_tasks/data/fastapi/compose-db.yml.j2 +0 -0
- {common_python_tasks-0.0.3 → common_python_tasks-0.1.0}/src/common_python_tasks/data/fastapi/compose-debug.yml.j2 +0 -0
- {common_python_tasks-0.0.3 → common_python_tasks-0.1.0}/src/common_python_tasks/data/generic/.coveragerc +0 -0
- {common_python_tasks-0.0.3 → common_python_tasks-0.1.0}/src/common_python_tasks/data/generic/.dockerignore +0 -0
- {common_python_tasks-0.0.3 → common_python_tasks-0.1.0}/src/common_python_tasks/data/generic/.flake8 +0 -0
- {common_python_tasks-0.0.3 → common_python_tasks-0.1.0}/src/common_python_tasks/data/generic/.isort.cfg +0 -0
- {common_python_tasks-0.0.3 → common_python_tasks-0.1.0}/src/common_python_tasks/data/generic/.pytest_cache/.gitignore +0 -0
- {common_python_tasks-0.0.3 → common_python_tasks-0.1.0}/src/common_python_tasks/data/generic/.pytest_cache/CACHEDIR.TAG +0 -0
- {common_python_tasks-0.0.3 → common_python_tasks-0.1.0}/src/common_python_tasks/data/generic/.pytest_cache/README.md +0 -0
- {common_python_tasks-0.0.3 → common_python_tasks-0.1.0}/src/common_python_tasks/data/generic/.pytest_cache/v/cache/lastfailed +0 -0
- {common_python_tasks-0.0.3 → common_python_tasks-0.1.0}/src/common_python_tasks/data/generic/Dockerfile.deps.j2 +0 -0
- {common_python_tasks-0.0.3 → common_python_tasks-0.1.0}/src/common_python_tasks/data/generic/Dockerfile.j2 +0 -0
- {common_python_tasks-0.0.3 → common_python_tasks-0.1.0}/src/common_python_tasks/data/generic/pytest.ini +0 -0
- {common_python_tasks-0.0.3 → common_python_tasks-0.1.0}/src/common_python_tasks/docker.py +0 -0
- {common_python_tasks-0.0.3 → common_python_tasks-0.1.0}/src/common_python_tasks/env.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: common-python-tasks
|
|
3
|
-
Version: 0.0
|
|
3
|
+
Version: 0.1.0
|
|
4
4
|
Summary: Opinionated Poe the Poet tasks for Python package development.
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
License-File: LICENSE
|
|
@@ -16,11 +16,11 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
16
16
|
Classifier: Programming Language :: Python :: 3.14
|
|
17
17
|
Classifier: Topic :: Software Development :: Build Tools
|
|
18
18
|
Requires-Dist: autoflake (>=2.3.1,<3.0.0)
|
|
19
|
-
Requires-Dist: black (>=
|
|
19
|
+
Requires-Dist: black (>=26.3.1,<27.0.0)
|
|
20
20
|
Requires-Dist: dunamai (>=1.25.0,<2.0.0)
|
|
21
21
|
Requires-Dist: flake8 (>=7.3.0,<8.0.0)
|
|
22
22
|
Requires-Dist: git-cliff (>=2.12.0,<3.0.0)
|
|
23
|
-
Requires-Dist: isort (>=
|
|
23
|
+
Requires-Dist: isort (>=8.0.1,<9.0.0)
|
|
24
24
|
Requires-Dist: jinja2 (>=3.1.6,<4.0.0)
|
|
25
25
|
Requires-Dist: poethepoet-tasks (>=0.3.0,<0.4.0)
|
|
26
26
|
Requires-Dist: pytest (>=9.0.1,<10.0.0)
|
|
@@ -35,6 +35,8 @@ Description-Content-Type: text/markdown
|
|
|
35
35
|
|
|
36
36
|
This package is a collection of (very) opinionated [Poe the Poet](https://poethepoet.natn.io/guides/packaged_tasks.html) Python tasks for common Python development workflows.
|
|
37
37
|
|
|
38
|
+
Instead of writing your own tasks for formatting, linting, testing, packaging, and more, you can use these pre-built tasks that work out of the box with reasonable defaults and support configuration overrides when needed. In the past, I found myself copying and pasting the same task definitions across projects, and this package is my attempt to DRY up that workflow and provide a single source of truth for common Python development tasks. I hope you can use them too.
|
|
39
|
+
|
|
38
40
|
## Quick start
|
|
39
41
|
|
|
40
42
|
### Automated setup
|
|
@@ -42,31 +44,40 @@ This package is a collection of (very) opinionated [Poe the Poet](https://poethe
|
|
|
42
44
|
You can add `common-python-tasks` to a new project by using the handy automated installation script.
|
|
43
45
|
|
|
44
46
|
```shell
|
|
45
|
-
curl -sSL https://api.github.com/repos/ci-sourcerer/common-python-tasks/contents/scripts/add-common-python-tasks.sh | jq -r '.content' | base64 -d |
|
|
47
|
+
curl -sSL https://api.github.com/repos/ci-sourcerer/common-python-tasks/contents/scripts/add-common-python-tasks.sh | jq -r '.content' | base64 -d | sh
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
To install a specific release, set the environment variable `COMMON_PYTHON_TASKS_VERSION`.
|
|
51
|
+
|
|
52
|
+
```shell
|
|
53
|
+
COMMON_PYTHON_TASKS_VERSION=0.1.0 \
|
|
54
|
+
sh -c "$(curl -sSL https://api.github.com/repos/ci-sourcerer/common-python-tasks/contents/scripts/add-common-python-tasks.sh | jq -r '.content' | base64 -d)"
|
|
46
55
|
```
|
|
47
56
|
|
|
48
57
|
This will complete the following steps.
|
|
49
58
|
|
|
50
59
|
1. Add the latest version of `common-python-tasks` to your `pyproject.toml` dependencies
|
|
51
|
-
2. Configure Poe the Poet to
|
|
60
|
+
2. Configure Poe the Poet to expose the default common task set
|
|
52
61
|
3. Install the package using Poetry
|
|
53
62
|
|
|
54
63
|
**Always review scripts before running them!** Even though I believe I write good software, it's best practice to verify any script you download from the Internet.
|
|
55
64
|
|
|
56
65
|
### Manual setup
|
|
57
66
|
|
|
58
|
-
|
|
67
|
+
There's no real reason to run the automated script; I just like automating everything. You can achieve the same result by following these steps.
|
|
68
|
+
|
|
69
|
+
1. Add `common-python-tasks` to your `pyproject.toml` and configure Poe the Poet
|
|
59
70
|
|
|
60
71
|
```toml
|
|
61
72
|
[project]
|
|
62
73
|
name = "my-awesome-project"
|
|
63
|
-
version = "0.0
|
|
74
|
+
version = "0.1.0"
|
|
64
75
|
dependencies = [
|
|
65
|
-
"common-python-tasks==0.0
|
|
76
|
+
"common-python-tasks==0.1.0", # Always pin to a specific version
|
|
66
77
|
]
|
|
67
78
|
|
|
68
79
|
[tool.poe]
|
|
69
|
-
include_script = "common_python_tasks:tasks(
|
|
80
|
+
include_script = "common_python_tasks:tasks()" # Uses the default `common` task set
|
|
70
81
|
```
|
|
71
82
|
|
|
72
83
|
2. Install the package
|
|
@@ -90,26 +101,26 @@ Internal tasks are used by other tasks and are not meant to be run directly.
|
|
|
90
101
|
<!-- tasks-table -->
|
|
91
102
|
| Task | Description | Tags |
|
|
92
103
|
| - | - | - |
|
|
93
|
-
| `
|
|
94
|
-
| `
|
|
95
|
-
| `
|
|
96
|
-
| `
|
|
97
|
-
| `
|
|
98
|
-
| `
|
|
99
|
-
| `
|
|
100
|
-
| `
|
|
101
|
-
| `
|
|
102
|
-
| `
|
|
103
|
-
| `
|
|
104
|
-
| `
|
|
105
|
-
| `
|
|
106
|
-
| `
|
|
107
|
-
| `
|
|
108
|
-
| `
|
|
109
|
-
| `
|
|
110
|
-
| `
|
|
111
|
-
| `
|
|
112
|
-
| `
|
|
104
|
+
| `test` | Run the test suite with coverage (if `pytest-cov` is installed). | common, test |
|
|
105
|
+
| `clean` | Clean up temporary files and directories. | clean, common |
|
|
106
|
+
| `format` | Format Python code with autoflake, black, and isort. | common, format |
|
|
107
|
+
| `lint` | Lint Python code with autoflake, black, isort, and flake8. | common, lint |
|
|
108
|
+
| `build-image` | Build the container image for this project using the Dockerfile template. | build, containers |
|
|
109
|
+
| `run-container` | Run the Docker image as a container for this project. By default (when `tag` is `None`) this will run the most-recently-built tag for the project's image. | containers |
|
|
110
|
+
| `push-image` | Push the Docker image for this project to the container registry. | containers, packaging, release |
|
|
111
|
+
| `publish-package` | Publish the package to the PyPI server. | common, packaging |
|
|
112
|
+
| `publish-github-release` | Publish or update a GitHub Release for the current repository. | common, packaging, release |
|
|
113
|
+
| `build-package` | Build the package (wheel and sdist). | build, common, packaging |
|
|
114
|
+
| `bump-version` | Bump the project version. | common, packaging |
|
|
115
|
+
| `changelog` | Print the changelog for the current version based on git history and git-cliff. | common, packaging, release |
|
|
116
|
+
| `release` | Run a full release flow for package and containers. | common, containers, packaging, release |
|
|
117
|
+
| `build` | Build the project and its containers. | common, containers, packaging |
|
|
118
|
+
| `stack-up` | Bring up the development stack for the application. | containers, fastapi, web |
|
|
119
|
+
| `stack-down` | Bring down the development stack for the application. | containers, fastapi, web |
|
|
120
|
+
| `reset-db` | Reset the database by deleting the database volume. | containers, database, fastapi, web |
|
|
121
|
+
| `run-db-migrations` | Run database migrations. | containers, database, fastapi, web |
|
|
122
|
+
| `db-shell` | Open a psql shell to the database container. | containers, database, fastapi, web |
|
|
123
|
+
| `container-shell` | Run the debug image with an interactive shell. | containers, debug |
|
|
113
124
|
<!-- end-tasks-table -->
|
|
114
125
|
|
|
115
126
|
## Docker Compose Development Stacks
|
|
@@ -237,9 +248,10 @@ The following environment variables configure package and container behavior.
|
|
|
237
248
|
- `GITHUB_RELEASE_TAG` optional tag name to publish for the GitHub Release.
|
|
238
249
|
- `GITHUB_RELEASE_NAME` optional release title to use for the GitHub Release.
|
|
239
250
|
- `GITHUB_RELEASE_BODY` optional release body text to use for the GitHub Release.
|
|
251
|
+
- `RELEASE_UPDATE_CHANGELOG` truthy value to update `CHANGELOG.md` with `git-cliff --tag "$RELEASE_TAG" --prepend CHANGELOG.md` before the release tag is created. This is enabled by default; set it to a falsy value to disable changelog commits during release.
|
|
240
252
|
- `RELEASE_PRE_SCRIPT` optional shell command to run before the release steps.
|
|
241
253
|
- `RELEASE_POST_SCRIPT` optional shell command to run after the release completes.
|
|
242
|
-
- Hook commands receive the following env vars: `RELEASE_TAG`, `RELEASE_VERSION`, `RELEASE_STAGE`, `RELEASE_COMPONENT`, and `RELEASE_DRY_RUN`.
|
|
254
|
+
- Hook commands receive the following env vars: `RELEASE_SCRIPT_PHASE`, `RELEASE_TAG`, `RELEASE_VERSION`, `RELEASE_STAGE`, `RELEASE_COMPONENT`, and `RELEASE_DRY_RUN`.
|
|
243
255
|
|
|
244
256
|
#### Docker Compose settings
|
|
245
257
|
|
|
@@ -268,32 +280,32 @@ The following environment variable enables debugging output.
|
|
|
268
280
|
|
|
269
281
|
### Usage examples
|
|
270
282
|
|
|
271
|
-
You can include or exclude
|
|
283
|
+
By default, `tasks()` exposes the common task set. You can still include or exclude tags in your `pyproject.toml` when needed.
|
|
272
284
|
|
|
273
285
|
#### Minimal setup
|
|
274
286
|
|
|
275
287
|
```toml
|
|
276
288
|
[project]
|
|
277
289
|
name = "simple-cli-tool"
|
|
278
|
-
version = "0.0
|
|
279
|
-
dependencies = ["common-python-tasks==0.0
|
|
290
|
+
version = "0.1.0"
|
|
291
|
+
dependencies = ["common-python-tasks==0.1.0"]
|
|
280
292
|
|
|
281
293
|
[tool.poe]
|
|
282
|
-
include_script = "common_python_tasks:tasks(
|
|
294
|
+
include_script = "common_python_tasks:tasks()"
|
|
283
295
|
```
|
|
284
296
|
|
|
285
|
-
Available tasks: `format`, `lint`.
|
|
297
|
+
Available tasks: common defaults such as `format`, `lint`, `test`, and `build`.
|
|
286
298
|
|
|
287
299
|
#### Container-based project
|
|
288
300
|
|
|
289
301
|
```toml
|
|
290
302
|
[project]
|
|
291
303
|
name = "containerized-app"
|
|
292
|
-
version = "0.0
|
|
293
|
-
dependencies = ["common-python-tasks==0.0
|
|
304
|
+
version = "0.1.0"
|
|
305
|
+
dependencies = ["common-python-tasks==0.1.0"]
|
|
294
306
|
|
|
295
307
|
[tool.poe]
|
|
296
|
-
include_script = "common_python_tasks:tasks(include_tags=['
|
|
308
|
+
include_script = "common_python_tasks:tasks(include_tags=['common', 'containers'])"
|
|
297
309
|
|
|
298
310
|
[tool.poe.env]
|
|
299
311
|
DOCKERHUB_USERNAME = "myusername"
|
|
@@ -307,11 +319,11 @@ Available tasks: All tasks including `build-image` and `push-image`.
|
|
|
307
319
|
```toml
|
|
308
320
|
[project]
|
|
309
321
|
name = "custom-test-setup"
|
|
310
|
-
dependencies = ["common-python-tasks==0.0
|
|
322
|
+
dependencies = ["common-python-tasks==0.1.0"]
|
|
311
323
|
dynamic = ["version"]
|
|
312
324
|
|
|
313
325
|
[tool.poe]
|
|
314
|
-
include_script = "common_python_tasks:tasks(
|
|
326
|
+
include_script = "common_python_tasks:tasks()"
|
|
315
327
|
|
|
316
328
|
[tool.pytest.ini_options]
|
|
317
329
|
testpaths = ["tests", "integration"]
|
|
@@ -324,7 +336,7 @@ The `test` task will automatically use your `[tool.pytest.ini_options]` configur
|
|
|
324
336
|
|
|
325
337
|
### Tasks not showing up with `poe --help`
|
|
326
338
|
|
|
327
|
-
Check your `[tool.poe]` configuration in `pyproject.toml`. Make sure you're using `include_script
|
|
339
|
+
Check your `[tool.poe]` configuration in `pyproject.toml`. Make sure you're using `include_script`.
|
|
328
340
|
|
|
329
341
|
```toml
|
|
330
342
|
# Correct
|
|
@@ -408,8 +420,9 @@ The standard Python Dockerfile incorporates several intentional design choices.
|
|
|
408
420
|
|
|
409
421
|
## Notes
|
|
410
422
|
|
|
411
|
-
- This project dogfoods itself - it uses `common-python-tasks` for its own development
|
|
412
|
-
- `
|
|
423
|
+
- This project dogfoods itself - it uses `common-python-tasks` for its own development. **That said, you must set the environment variable `PYTHONPATH=src` when running tasks locally to ensure you are using the local version of the package instead of the installed version**
|
|
424
|
+
- `RELEASE_UPDATE_CHANGELOG` is enabled by default for releases and prepends a tagged section into `CHANGELOG.md` before the release tag is created. Set it to a falsy value if you prefer to manage changelog commits yourself.
|
|
425
|
+
- `RELEASE_PRE_SCRIPT` and `RELEASE_POST_SCRIPT` hooks may not be necessary for most users, as this package promotes the use of `poetry-dynamic-versioning` and `git-cliff` to automate versioning and changelog generation based on git history. One advanced use case for the `RELEASE_PRE_SCRIPT` hook is to edit another file before release, such as a README that references the current stable version number. This allows you to keep the README up to date with the latest version without hardcoding it.
|
|
413
426
|
- Contributions welcome! Open an issue/discussion to discuss changes before submitting a PR. I do not claim to have all the answers, and you can help determine the future of low-code solutions for Python. I am very interested in your feedback as I don't want to work in a vacuum
|
|
414
427
|
- Alpha status: Expect breaking changes between minor versions until 1.0.0
|
|
415
428
|
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
This package is a collection of (very) opinionated [Poe the Poet](https://poethepoet.natn.io/guides/packaged_tasks.html) Python tasks for common Python development workflows.
|
|
4
4
|
|
|
5
|
+
Instead of writing your own tasks for formatting, linting, testing, packaging, and more, you can use these pre-built tasks that work out of the box with reasonable defaults and support configuration overrides when needed. In the past, I found myself copying and pasting the same task definitions across projects, and this package is my attempt to DRY up that workflow and provide a single source of truth for common Python development tasks. I hope you can use them too.
|
|
6
|
+
|
|
5
7
|
## Quick start
|
|
6
8
|
|
|
7
9
|
### Automated setup
|
|
@@ -9,31 +11,40 @@ This package is a collection of (very) opinionated [Poe the Poet](https://poethe
|
|
|
9
11
|
You can add `common-python-tasks` to a new project by using the handy automated installation script.
|
|
10
12
|
|
|
11
13
|
```shell
|
|
12
|
-
curl -sSL https://api.github.com/repos/ci-sourcerer/common-python-tasks/contents/scripts/add-common-python-tasks.sh | jq -r '.content' | base64 -d |
|
|
14
|
+
curl -sSL https://api.github.com/repos/ci-sourcerer/common-python-tasks/contents/scripts/add-common-python-tasks.sh | jq -r '.content' | base64 -d | sh
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
To install a specific release, set the environment variable `COMMON_PYTHON_TASKS_VERSION`.
|
|
18
|
+
|
|
19
|
+
```shell
|
|
20
|
+
COMMON_PYTHON_TASKS_VERSION=0.1.0 \
|
|
21
|
+
sh -c "$(curl -sSL https://api.github.com/repos/ci-sourcerer/common-python-tasks/contents/scripts/add-common-python-tasks.sh | jq -r '.content' | base64 -d)"
|
|
13
22
|
```
|
|
14
23
|
|
|
15
24
|
This will complete the following steps.
|
|
16
25
|
|
|
17
26
|
1. Add the latest version of `common-python-tasks` to your `pyproject.toml` dependencies
|
|
18
|
-
2. Configure Poe the Poet to
|
|
27
|
+
2. Configure Poe the Poet to expose the default common task set
|
|
19
28
|
3. Install the package using Poetry
|
|
20
29
|
|
|
21
30
|
**Always review scripts before running them!** Even though I believe I write good software, it's best practice to verify any script you download from the Internet.
|
|
22
31
|
|
|
23
32
|
### Manual setup
|
|
24
33
|
|
|
25
|
-
|
|
34
|
+
There's no real reason to run the automated script; I just like automating everything. You can achieve the same result by following these steps.
|
|
35
|
+
|
|
36
|
+
1. Add `common-python-tasks` to your `pyproject.toml` and configure Poe the Poet
|
|
26
37
|
|
|
27
38
|
```toml
|
|
28
39
|
[project]
|
|
29
40
|
name = "my-awesome-project"
|
|
30
|
-
version = "0.0
|
|
41
|
+
version = "0.1.0"
|
|
31
42
|
dependencies = [
|
|
32
|
-
"common-python-tasks==0.0
|
|
43
|
+
"common-python-tasks==0.1.0", # Always pin to a specific version
|
|
33
44
|
]
|
|
34
45
|
|
|
35
46
|
[tool.poe]
|
|
36
|
-
include_script = "common_python_tasks:tasks(
|
|
47
|
+
include_script = "common_python_tasks:tasks()" # Uses the default `common` task set
|
|
37
48
|
```
|
|
38
49
|
|
|
39
50
|
2. Install the package
|
|
@@ -57,26 +68,26 @@ Internal tasks are used by other tasks and are not meant to be run directly.
|
|
|
57
68
|
<!-- tasks-table -->
|
|
58
69
|
| Task | Description | Tags |
|
|
59
70
|
| - | - | - |
|
|
60
|
-
| `
|
|
61
|
-
| `
|
|
62
|
-
| `
|
|
63
|
-
| `
|
|
64
|
-
| `
|
|
65
|
-
| `
|
|
66
|
-
| `
|
|
67
|
-
| `
|
|
68
|
-
| `
|
|
69
|
-
| `
|
|
70
|
-
| `
|
|
71
|
-
| `
|
|
72
|
-
| `
|
|
73
|
-
| `
|
|
74
|
-
| `
|
|
75
|
-
| `
|
|
76
|
-
| `
|
|
77
|
-
| `
|
|
78
|
-
| `
|
|
79
|
-
| `
|
|
71
|
+
| `test` | Run the test suite with coverage (if `pytest-cov` is installed). | common, test |
|
|
72
|
+
| `clean` | Clean up temporary files and directories. | clean, common |
|
|
73
|
+
| `format` | Format Python code with autoflake, black, and isort. | common, format |
|
|
74
|
+
| `lint` | Lint Python code with autoflake, black, isort, and flake8. | common, lint |
|
|
75
|
+
| `build-image` | Build the container image for this project using the Dockerfile template. | build, containers |
|
|
76
|
+
| `run-container` | Run the Docker image as a container for this project. By default (when `tag` is `None`) this will run the most-recently-built tag for the project's image. | containers |
|
|
77
|
+
| `push-image` | Push the Docker image for this project to the container registry. | containers, packaging, release |
|
|
78
|
+
| `publish-package` | Publish the package to the PyPI server. | common, packaging |
|
|
79
|
+
| `publish-github-release` | Publish or update a GitHub Release for the current repository. | common, packaging, release |
|
|
80
|
+
| `build-package` | Build the package (wheel and sdist). | build, common, packaging |
|
|
81
|
+
| `bump-version` | Bump the project version. | common, packaging |
|
|
82
|
+
| `changelog` | Print the changelog for the current version based on git history and git-cliff. | common, packaging, release |
|
|
83
|
+
| `release` | Run a full release flow for package and containers. | common, containers, packaging, release |
|
|
84
|
+
| `build` | Build the project and its containers. | common, containers, packaging |
|
|
85
|
+
| `stack-up` | Bring up the development stack for the application. | containers, fastapi, web |
|
|
86
|
+
| `stack-down` | Bring down the development stack for the application. | containers, fastapi, web |
|
|
87
|
+
| `reset-db` | Reset the database by deleting the database volume. | containers, database, fastapi, web |
|
|
88
|
+
| `run-db-migrations` | Run database migrations. | containers, database, fastapi, web |
|
|
89
|
+
| `db-shell` | Open a psql shell to the database container. | containers, database, fastapi, web |
|
|
90
|
+
| `container-shell` | Run the debug image with an interactive shell. | containers, debug |
|
|
80
91
|
<!-- end-tasks-table -->
|
|
81
92
|
|
|
82
93
|
## Docker Compose Development Stacks
|
|
@@ -204,9 +215,10 @@ The following environment variables configure package and container behavior.
|
|
|
204
215
|
- `GITHUB_RELEASE_TAG` optional tag name to publish for the GitHub Release.
|
|
205
216
|
- `GITHUB_RELEASE_NAME` optional release title to use for the GitHub Release.
|
|
206
217
|
- `GITHUB_RELEASE_BODY` optional release body text to use for the GitHub Release.
|
|
218
|
+
- `RELEASE_UPDATE_CHANGELOG` truthy value to update `CHANGELOG.md` with `git-cliff --tag "$RELEASE_TAG" --prepend CHANGELOG.md` before the release tag is created. This is enabled by default; set it to a falsy value to disable changelog commits during release.
|
|
207
219
|
- `RELEASE_PRE_SCRIPT` optional shell command to run before the release steps.
|
|
208
220
|
- `RELEASE_POST_SCRIPT` optional shell command to run after the release completes.
|
|
209
|
-
- Hook commands receive the following env vars: `RELEASE_TAG`, `RELEASE_VERSION`, `RELEASE_STAGE`, `RELEASE_COMPONENT`, and `RELEASE_DRY_RUN`.
|
|
221
|
+
- Hook commands receive the following env vars: `RELEASE_SCRIPT_PHASE`, `RELEASE_TAG`, `RELEASE_VERSION`, `RELEASE_STAGE`, `RELEASE_COMPONENT`, and `RELEASE_DRY_RUN`.
|
|
210
222
|
|
|
211
223
|
#### Docker Compose settings
|
|
212
224
|
|
|
@@ -235,32 +247,32 @@ The following environment variable enables debugging output.
|
|
|
235
247
|
|
|
236
248
|
### Usage examples
|
|
237
249
|
|
|
238
|
-
You can include or exclude
|
|
250
|
+
By default, `tasks()` exposes the common task set. You can still include or exclude tags in your `pyproject.toml` when needed.
|
|
239
251
|
|
|
240
252
|
#### Minimal setup
|
|
241
253
|
|
|
242
254
|
```toml
|
|
243
255
|
[project]
|
|
244
256
|
name = "simple-cli-tool"
|
|
245
|
-
version = "0.0
|
|
246
|
-
dependencies = ["common-python-tasks==0.0
|
|
257
|
+
version = "0.1.0"
|
|
258
|
+
dependencies = ["common-python-tasks==0.1.0"]
|
|
247
259
|
|
|
248
260
|
[tool.poe]
|
|
249
|
-
include_script = "common_python_tasks:tasks(
|
|
261
|
+
include_script = "common_python_tasks:tasks()"
|
|
250
262
|
```
|
|
251
263
|
|
|
252
|
-
Available tasks: `format`, `lint`.
|
|
264
|
+
Available tasks: common defaults such as `format`, `lint`, `test`, and `build`.
|
|
253
265
|
|
|
254
266
|
#### Container-based project
|
|
255
267
|
|
|
256
268
|
```toml
|
|
257
269
|
[project]
|
|
258
270
|
name = "containerized-app"
|
|
259
|
-
version = "0.0
|
|
260
|
-
dependencies = ["common-python-tasks==0.0
|
|
271
|
+
version = "0.1.0"
|
|
272
|
+
dependencies = ["common-python-tasks==0.1.0"]
|
|
261
273
|
|
|
262
274
|
[tool.poe]
|
|
263
|
-
include_script = "common_python_tasks:tasks(include_tags=['
|
|
275
|
+
include_script = "common_python_tasks:tasks(include_tags=['common', 'containers'])"
|
|
264
276
|
|
|
265
277
|
[tool.poe.env]
|
|
266
278
|
DOCKERHUB_USERNAME = "myusername"
|
|
@@ -274,11 +286,11 @@ Available tasks: All tasks including `build-image` and `push-image`.
|
|
|
274
286
|
```toml
|
|
275
287
|
[project]
|
|
276
288
|
name = "custom-test-setup"
|
|
277
|
-
dependencies = ["common-python-tasks==0.0
|
|
289
|
+
dependencies = ["common-python-tasks==0.1.0"]
|
|
278
290
|
dynamic = ["version"]
|
|
279
291
|
|
|
280
292
|
[tool.poe]
|
|
281
|
-
include_script = "common_python_tasks:tasks(
|
|
293
|
+
include_script = "common_python_tasks:tasks()"
|
|
282
294
|
|
|
283
295
|
[tool.pytest.ini_options]
|
|
284
296
|
testpaths = ["tests", "integration"]
|
|
@@ -291,7 +303,7 @@ The `test` task will automatically use your `[tool.pytest.ini_options]` configur
|
|
|
291
303
|
|
|
292
304
|
### Tasks not showing up with `poe --help`
|
|
293
305
|
|
|
294
|
-
Check your `[tool.poe]` configuration in `pyproject.toml`. Make sure you're using `include_script
|
|
306
|
+
Check your `[tool.poe]` configuration in `pyproject.toml`. Make sure you're using `include_script`.
|
|
295
307
|
|
|
296
308
|
```toml
|
|
297
309
|
# Correct
|
|
@@ -375,7 +387,8 @@ The standard Python Dockerfile incorporates several intentional design choices.
|
|
|
375
387
|
|
|
376
388
|
## Notes
|
|
377
389
|
|
|
378
|
-
- This project dogfoods itself - it uses `common-python-tasks` for its own development
|
|
379
|
-
- `
|
|
390
|
+
- This project dogfoods itself - it uses `common-python-tasks` for its own development. **That said, you must set the environment variable `PYTHONPATH=src` when running tasks locally to ensure you are using the local version of the package instead of the installed version**
|
|
391
|
+
- `RELEASE_UPDATE_CHANGELOG` is enabled by default for releases and prepends a tagged section into `CHANGELOG.md` before the release tag is created. Set it to a falsy value if you prefer to manage changelog commits yourself.
|
|
392
|
+
- `RELEASE_PRE_SCRIPT` and `RELEASE_POST_SCRIPT` hooks may not be necessary for most users, as this package promotes the use of `poetry-dynamic-versioning` and `git-cliff` to automate versioning and changelog generation based on git history. One advanced use case for the `RELEASE_PRE_SCRIPT` hook is to edit another file before release, such as a README that references the current stable version number. This allows you to keep the README up to date with the latest version without hardcoding it.
|
|
380
393
|
- Contributions welcome! Open an issue/discussion to discuss changes before submitting a PR. I do not claim to have all the answers, and you can help determine the future of low-code solutions for Python. I am very interested in your feedback as I don't want to work in a vacuum
|
|
381
394
|
- Alpha status: Expect breaking changes between minor versions until 1.0.0
|
|
@@ -18,10 +18,10 @@ classifiers = [
|
|
|
18
18
|
]
|
|
19
19
|
dependencies = [
|
|
20
20
|
"autoflake (>=2.3.1,<3.0.0)",
|
|
21
|
-
"black (>=
|
|
21
|
+
"black (>=26.3.1,<27.0.0)",
|
|
22
22
|
"dunamai (>=1.25.0,<2.0.0)",
|
|
23
23
|
"flake8 (>=7.3.0,<8.0.0)",
|
|
24
|
-
"isort (>=
|
|
24
|
+
"isort (>=8.0.1,<9.0.0)",
|
|
25
25
|
"poethepoet-tasks (>=0.3.0,<0.4.0)",
|
|
26
26
|
"pytest-cov (>=7.0.0,<8.0.0)",
|
|
27
27
|
"pytest (>=9.0.1,<10.0.0)",
|
|
@@ -30,7 +30,7 @@ dependencies = [
|
|
|
30
30
|
"git-cliff (>=2.12.0,<3.0.0)",
|
|
31
31
|
]
|
|
32
32
|
dynamic = []
|
|
33
|
-
version = "0.0
|
|
33
|
+
version = "0.1.0"
|
|
34
34
|
|
|
35
35
|
[project.urls]
|
|
36
36
|
Homepage = "http://github.com/ci-sourcerer/common-python-tasks"
|
|
@@ -38,7 +38,13 @@ 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=['
|
|
41
|
+
include_script = "common_python_tasks:tasks(exclude_tags=['containers'])"
|
|
42
|
+
|
|
43
|
+
[tool.poe.env]
|
|
44
|
+
PYTHONPATH = "src"
|
|
45
|
+
RELEASE_UPDATE_CHANGELOG = "1"
|
|
46
|
+
RELEASE_PRE_SCRIPT = "RELEASE_SCRIPT_PHASE=pre python scripts/release_script.py"
|
|
47
|
+
RELEASE_POST_SCRIPT = "RELEASE_SCRIPT_PHASE=post python scripts/release_script.py"
|
|
42
48
|
|
|
43
49
|
[tool.poetry.requires-plugins]
|
|
44
50
|
poetry-dynamic-versioning = { version = ">=1.0.0,<2.0.0", extras = ["plugin"] }
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from typing import TYPE_CHECKING
|
|
2
|
+
|
|
3
|
+
if TYPE_CHECKING:
|
|
4
|
+
from typing import Sequence
|
|
5
|
+
|
|
6
|
+
from poethepoet_tasks import TaskCollection
|
|
7
|
+
|
|
8
|
+
__all__ = ["TaskCollection"]
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def tasks(
|
|
12
|
+
include_tags: "Sequence[str] | None" = None,
|
|
13
|
+
exclude_tags: "Sequence[str]" = tuple(),
|
|
14
|
+
) -> dict:
|
|
15
|
+
from .tasks import tasks as task_collection
|
|
16
|
+
|
|
17
|
+
if include_tags is None and not exclude_tags:
|
|
18
|
+
include_tags = ("common",)
|
|
19
|
+
elif include_tags is None:
|
|
20
|
+
include_tags = tuple()
|
|
21
|
+
|
|
22
|
+
result = task_collection(include_tags=include_tags, exclude_tags=exclude_tags)
|
|
23
|
+
globals()["tasks"] = _TASKS_ENTRYPOINT
|
|
24
|
+
return result
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
_TASKS_ENTRYPOINT = tasks
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import importlib
|
|
2
|
+
import inspect
|
|
3
|
+
import os
|
|
4
|
+
import re
|
|
5
|
+
import sys
|
|
6
|
+
|
|
7
|
+
from .tasks import tasks
|
|
8
|
+
|
|
9
|
+
__all__ = ["get_available_tasks", "print_available_tasks"]
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def get_available_tasks(internal: bool = False) -> list[str]:
|
|
13
|
+
"""Return available task names for this package.
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
internal: When True, include internal task names starting with '_'.
|
|
17
|
+
|
|
18
|
+
Returns:
|
|
19
|
+
A list of task names.
|
|
20
|
+
"""
|
|
21
|
+
return [
|
|
22
|
+
task_name
|
|
23
|
+
for task_name in tasks()["tasks"]
|
|
24
|
+
if internal or not task_name.startswith("_")
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _extract_docstring_excerpt(doc: str) -> str:
|
|
29
|
+
excerpt = []
|
|
30
|
+
for line in doc.strip().splitlines():
|
|
31
|
+
if re.match(r"^(Args?|Arguments?|Parameters?):\s*$", line):
|
|
32
|
+
break
|
|
33
|
+
excerpt.append(line)
|
|
34
|
+
|
|
35
|
+
while excerpt and excerpt[-1].strip() == "":
|
|
36
|
+
excerpt.pop()
|
|
37
|
+
|
|
38
|
+
return "\n".join(excerpt)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _get_task_docstring(task_name: str) -> str | None:
|
|
42
|
+
|
|
43
|
+
task_config = tasks()["tasks"].get(task_name)
|
|
44
|
+
if not isinstance(task_config, dict):
|
|
45
|
+
return None
|
|
46
|
+
|
|
47
|
+
script = task_config.get("script")
|
|
48
|
+
if not isinstance(script, str) or ":" not in script:
|
|
49
|
+
return None
|
|
50
|
+
|
|
51
|
+
module_name, func_name = script.split(":", 1)
|
|
52
|
+
|
|
53
|
+
try:
|
|
54
|
+
module = importlib.import_module(module_name)
|
|
55
|
+
func = getattr(module, func_name)
|
|
56
|
+
except (ImportError, AttributeError):
|
|
57
|
+
return None
|
|
58
|
+
|
|
59
|
+
doc = inspect.getdoc(func)
|
|
60
|
+
if not doc:
|
|
61
|
+
return None
|
|
62
|
+
|
|
63
|
+
return _extract_docstring_excerpt(doc)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _get_task_tags(task_name: str) -> list[str] | None:
|
|
67
|
+
task_variants = getattr(tasks, "_tasks", {}).get(task_name)
|
|
68
|
+
if not task_variants:
|
|
69
|
+
return None
|
|
70
|
+
|
|
71
|
+
tags = {
|
|
72
|
+
tag
|
|
73
|
+
for variant in task_variants
|
|
74
|
+
for tag in getattr(variant, "tags", ())
|
|
75
|
+
if isinstance(tag, str) and not tag.startswith("task-")
|
|
76
|
+
}
|
|
77
|
+
return sorted(tags) or None
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def print_available_tasks(internal: bool = False, include_docs: bool = False) -> None:
|
|
81
|
+
"""Print available tasks.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
internal: Whether or not to include internal task names starting with '_'.
|
|
85
|
+
include_docs: Whether or not to include task docstrings.
|
|
86
|
+
"""
|
|
87
|
+
print("\nAvailable tasks in this release:\n")
|
|
88
|
+
for task_name in get_available_tasks(internal=internal):
|
|
89
|
+
print(f" - {task_name}")
|
|
90
|
+
if include_docs:
|
|
91
|
+
doc = _get_task_docstring(task_name)
|
|
92
|
+
if doc:
|
|
93
|
+
for line in doc.splitlines():
|
|
94
|
+
print(f" {line}")
|
|
95
|
+
print()
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
if __name__ == "__main__":
|
|
99
|
+
print(
|
|
100
|
+
"common_python_tasks is not intended to be run as a standalone script. Invoke a task via poethepoet.",
|
|
101
|
+
file=sys.stderr if len(sys.argv) > 1 else sys.stdout,
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
if len(sys.argv) == 1:
|
|
105
|
+
debug = os.getenv("COMMON_PYTHON_TASKS_LOG_LEVEL", "info").lower() == "debug"
|
|
106
|
+
print_available_tasks(include_docs=debug)
|
|
107
|
+
else:
|
|
108
|
+
sys.exit(1)
|