django-queuebie 0.3.7__tar.gz → 0.3.9__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.
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/.ambient-package-update/metadata.py +51 -51
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/.ambient-package-update/templates/snippets/content.tpl +53 -53
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/.ambient-package-update/templates/snippets/tagline.tpl +1 -1
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/.editorconfig +17 -17
- django_queuebie-0.3.9/.github/workflows/ci.yml +11 -0
- django_queuebie-0.3.7/.github/workflows/ci.yml → django_queuebie-0.3.9/.github/workflows/quality-gate.yml +91 -92
- django_queuebie-0.3.9/.github/workflows/release.yml +115 -0
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/.gitignore +160 -160
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/.pre-commit-config.yaml +59 -59
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/.readthedocs.yaml +31 -31
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/CHANGES.md +37 -31
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/CONTRIBUTING.md +75 -75
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/LICENSE +21 -21
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/LICENSE.md +21 -21
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/MANIFEST.in +4 -4
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/PKG-INFO +28 -37
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/README.md +128 -138
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/SECURITY.md +18 -18
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/docs/Makefile +20 -20
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/docs/conf.py +81 -81
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/docs/features/changelog.rst +2 -2
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/docs/features/getting-started.md +98 -98
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/docs/features/introduction.md +53 -53
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/docs/features/motivation.md +30 -30
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/docs/features/settings.md +41 -41
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/docs/features/setup.md +41 -41
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/docs/index.rst +21 -21
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/docs/make.bat +35 -35
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/manage.py +23 -23
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/pyproject.toml +274 -270
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/queuebie/__init__.py +8 -8
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/queuebie/apps.py +15 -15
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/queuebie/database_blocker.py +25 -25
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/queuebie/exceptions.py +17 -17
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/queuebie/logger.py +10 -10
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/queuebie/management/commands/clear_queuebie_registry.py +13 -13
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/queuebie/messages.py +39 -39
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/queuebie/registry.py +153 -153
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/queuebie/runner.py +63 -63
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/queuebie/settings.py +32 -32
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/queuebie/utils.py +30 -30
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/scripts/unix/install_requirements.sh +3 -3
- django_queuebie-0.3.9/scripts/unix/publish_to_pypi.sh +4 -0
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/scripts/windows/install_requirements.ps1 +2 -2
- django_queuebie-0.3.9/scripts/windows/publish_to_pypi.ps1 +3 -0
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/settings.py +79 -79
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/testapp/handlers/commands/testapp.py +55 -55
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/testapp/handlers/events/testapp.py +20 -20
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/testapp/messages/commands/my_commands.py +33 -33
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/testapp/messages/commands/other_commands.py +8 -8
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/testapp/messages/events/my_events.py +18 -18
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/testapp/urls.py +7 -7
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/tests/helpers/commands.py +8 -8
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/tests/helpers/events.py +8 -8
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/tests/management_commands/test_clear_queuebie_registry.py +27 -27
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/tests/test_apps.py +25 -25
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/tests/test_database_blocker.py +17 -17
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/tests/test_exceptions.py +23 -23
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/tests/test_logger.py +11 -11
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/tests/test_messages.py +16 -16
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/tests/test_registry.py +208 -208
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/tests/test_runner.py +138 -138
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/tests/test_settings.py +45 -45
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/tests/test_utils.py +38 -38
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/uv.lock +1233 -996
- django_queuebie-0.3.7/scripts/unix/publish_to_pypi.sh +0 -4
- django_queuebie-0.3.7/scripts/windows/publish_to_pypi.ps1 +0 -3
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/queuebie/management/__init__.py +0 -0
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/queuebie/management/commands/__init__.py +0 -0
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/testapp/__init__.py +0 -0
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/testapp/handlers/__init__.py +0 -0
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/testapp/handlers/commands/__init__.py +0 -0
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/testapp/handlers/events/__init__.py +0 -0
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/testapp/messages/__init__.py +0 -0
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/testapp/messages/commands/__init__.py +0 -0
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/testapp/messages/events/__init__.py +0 -0
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/tests/__init__.py +0 -0
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/tests/helpers/__init__.py +0 -0
- {django_queuebie-0.3.7 → django_queuebie-0.3.9}/tests/management_commands/__init__.py +0 -0
|
@@ -1,51 +1,51 @@
|
|
|
1
|
-
from ambient_package_update.metadata.author import PackageAuthor
|
|
2
|
-
from ambient_package_update.metadata.constants import (
|
|
3
|
-
DEPLOYMENT_STATUS_BETA,
|
|
4
|
-
DEV_DEPENDENCIES,
|
|
5
|
-
LICENSE_MIT,
|
|
6
|
-
SUPPORTED_DJANGO_VERSIONS,
|
|
7
|
-
)
|
|
8
|
-
from ambient_package_update.metadata.maintainer import PackageMaintainer
|
|
9
|
-
from ambient_package_update.metadata.package import PackageMetadata
|
|
10
|
-
from ambient_package_update.metadata.readme import ReadmeContent
|
|
11
|
-
from ambient_package_update.metadata.ruff_ignored_inspection import RuffIgnoredInspection
|
|
12
|
-
|
|
13
|
-
METADATA = PackageMetadata(
|
|
14
|
-
package_name="django_queuebie",
|
|
15
|
-
module_name="queuebie",
|
|
16
|
-
github_package_group="ambient-innovation",
|
|
17
|
-
authors=[
|
|
18
|
-
PackageAuthor(
|
|
19
|
-
name="Ambient Digital",
|
|
20
|
-
email="hello@ambient.digital",
|
|
21
|
-
),
|
|
22
|
-
],
|
|
23
|
-
maintainer=PackageMaintainer(name="Ambient Digital", url="https://ambient.digital/", email="hello@ambient.digital"),
|
|
24
|
-
licenser="Ambient Innovation: GmbH",
|
|
25
|
-
license=LICENSE_MIT,
|
|
26
|
-
license_year=2025,
|
|
27
|
-
development_status=DEPLOYMENT_STATUS_BETA,
|
|
28
|
-
has_migrations=False,
|
|
29
|
-
main_branch="main",
|
|
30
|
-
claim="A simple and synchronous message queue for commands and events for Django",
|
|
31
|
-
readme_content=ReadmeContent(uses_internationalisation=True),
|
|
32
|
-
dependencies=[
|
|
33
|
-
f"Django>={SUPPORTED_DJANGO_VERSIONS[0]}",
|
|
34
|
-
],
|
|
35
|
-
supported_django_versions=SUPPORTED_DJANGO_VERSIONS,
|
|
36
|
-
supported_python_versions=[
|
|
37
|
-
"3.10",
|
|
38
|
-
"3.11",
|
|
39
|
-
"3.12",
|
|
40
|
-
"3.13",
|
|
41
|
-
],
|
|
42
|
-
optional_dependencies={
|
|
43
|
-
"dev": [
|
|
44
|
-
*DEV_DEPENDENCIES,
|
|
45
|
-
],
|
|
46
|
-
},
|
|
47
|
-
ruff_ignore_list=[
|
|
48
|
-
RuffIgnoredInspection(key="TD002", comment="Missing author in TODO"),
|
|
49
|
-
RuffIgnoredInspection(key="TD003", comment="Missing issue link on the line following this TODO"),
|
|
50
|
-
],
|
|
51
|
-
)
|
|
1
|
+
from ambient_package_update.metadata.author import PackageAuthor
|
|
2
|
+
from ambient_package_update.metadata.constants import (
|
|
3
|
+
DEPLOYMENT_STATUS_BETA,
|
|
4
|
+
DEV_DEPENDENCIES,
|
|
5
|
+
LICENSE_MIT,
|
|
6
|
+
SUPPORTED_DJANGO_VERSIONS,
|
|
7
|
+
)
|
|
8
|
+
from ambient_package_update.metadata.maintainer import PackageMaintainer
|
|
9
|
+
from ambient_package_update.metadata.package import PackageMetadata
|
|
10
|
+
from ambient_package_update.metadata.readme import ReadmeContent
|
|
11
|
+
from ambient_package_update.metadata.ruff_ignored_inspection import RuffIgnoredInspection
|
|
12
|
+
|
|
13
|
+
METADATA = PackageMetadata(
|
|
14
|
+
package_name="django_queuebie",
|
|
15
|
+
module_name="queuebie",
|
|
16
|
+
github_package_group="ambient-innovation",
|
|
17
|
+
authors=[
|
|
18
|
+
PackageAuthor(
|
|
19
|
+
name="Ambient Digital",
|
|
20
|
+
email="hello@ambient.digital",
|
|
21
|
+
),
|
|
22
|
+
],
|
|
23
|
+
maintainer=PackageMaintainer(name="Ambient Digital", url="https://ambient.digital/", email="hello@ambient.digital"),
|
|
24
|
+
licenser="Ambient Innovation: GmbH",
|
|
25
|
+
license=LICENSE_MIT,
|
|
26
|
+
license_year=2025,
|
|
27
|
+
development_status=DEPLOYMENT_STATUS_BETA,
|
|
28
|
+
has_migrations=False,
|
|
29
|
+
main_branch="main",
|
|
30
|
+
claim="A simple and synchronous message queue for commands and events for Django",
|
|
31
|
+
readme_content=ReadmeContent(uses_internationalisation=True),
|
|
32
|
+
dependencies=[
|
|
33
|
+
f"Django>={SUPPORTED_DJANGO_VERSIONS[0]}",
|
|
34
|
+
],
|
|
35
|
+
supported_django_versions=SUPPORTED_DJANGO_VERSIONS,
|
|
36
|
+
supported_python_versions=[
|
|
37
|
+
"3.10",
|
|
38
|
+
"3.11",
|
|
39
|
+
"3.12",
|
|
40
|
+
"3.13",
|
|
41
|
+
],
|
|
42
|
+
optional_dependencies={
|
|
43
|
+
"dev": [
|
|
44
|
+
*DEV_DEPENDENCIES,
|
|
45
|
+
],
|
|
46
|
+
},
|
|
47
|
+
ruff_ignore_list=[
|
|
48
|
+
RuffIgnoredInspection(key="TD002", comment="Missing author in TODO"),
|
|
49
|
+
RuffIgnoredInspection(key="TD003", comment="Missing issue link on the line following this TODO"),
|
|
50
|
+
],
|
|
51
|
+
)
|
|
@@ -1,53 +1,53 @@
|
|
|
1
|
-
## Features
|
|
2
|
-
|
|
3
|
-
* Split up your business logic in commands and events
|
|
4
|
-
* Commands are imperatives telling your system what to do, events reflect that something has happened
|
|
5
|
-
* Register light-weight functions via a decorator to listen to your commands and events
|
|
6
|
-
* Message handlers receive the context of the message (command or event), providing an explicit API
|
|
7
|
-
* No magic, no side effects since the queue works synchronously
|
|
8
|
-
|
|
9
|
-
```python
|
|
10
|
-
import dataclasses
|
|
11
|
-
|
|
12
|
-
from queuebie.runner import handle_message
|
|
13
|
-
from queuebie.messages import Command, Event
|
|
14
|
-
from queuebie import message_registry
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
# Example command
|
|
18
|
-
@dataclasses.dataclass(kw_only=True)
|
|
19
|
-
class BuyProduct(Command):
|
|
20
|
-
product_id: int
|
|
21
|
-
customer_id: int
|
|
22
|
-
price: float
|
|
23
|
-
currency: str
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
# Example event
|
|
27
|
-
@dataclasses.dataclass(kw_only=True)
|
|
28
|
-
class ProductBought(Event):
|
|
29
|
-
product_id: int
|
|
30
|
-
customer_id: int
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
# Example handler
|
|
34
|
-
@message_registry.register_command(BuyProduct)
|
|
35
|
-
def handle_buy_product(context: BuyProduct) -> Event:
|
|
36
|
-
# Here lives your business logic
|
|
37
|
-
|
|
38
|
-
return ProductBought(
|
|
39
|
-
product_id=context.product_id,
|
|
40
|
-
customer_id=context.customer_id,
|
|
41
|
-
)
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
# Start queue and process messages
|
|
45
|
-
handle_message(
|
|
46
|
-
BuyProduct(
|
|
47
|
-
product_id=product.id,
|
|
48
|
-
customer_id=customer.id,
|
|
49
|
-
price=12.99,
|
|
50
|
-
currency="EUR",
|
|
51
|
-
)
|
|
52
|
-
)
|
|
53
|
-
```
|
|
1
|
+
## Features
|
|
2
|
+
|
|
3
|
+
* Split up your business logic in commands and events
|
|
4
|
+
* Commands are imperatives telling your system what to do, events reflect that something has happened
|
|
5
|
+
* Register light-weight functions via a decorator to listen to your commands and events
|
|
6
|
+
* Message handlers receive the context of the message (command or event), providing an explicit API
|
|
7
|
+
* No magic, no side effects since the queue works synchronously
|
|
8
|
+
|
|
9
|
+
```python
|
|
10
|
+
import dataclasses
|
|
11
|
+
|
|
12
|
+
from queuebie.runner import handle_message
|
|
13
|
+
from queuebie.messages import Command, Event
|
|
14
|
+
from queuebie import message_registry
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# Example command
|
|
18
|
+
@dataclasses.dataclass(kw_only=True)
|
|
19
|
+
class BuyProduct(Command):
|
|
20
|
+
product_id: int
|
|
21
|
+
customer_id: int
|
|
22
|
+
price: float
|
|
23
|
+
currency: str
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# Example event
|
|
27
|
+
@dataclasses.dataclass(kw_only=True)
|
|
28
|
+
class ProductBought(Event):
|
|
29
|
+
product_id: int
|
|
30
|
+
customer_id: int
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
# Example handler
|
|
34
|
+
@message_registry.register_command(BuyProduct)
|
|
35
|
+
def handle_buy_product(context: BuyProduct) -> Event:
|
|
36
|
+
# Here lives your business logic
|
|
37
|
+
|
|
38
|
+
return ProductBought(
|
|
39
|
+
product_id=context.product_id,
|
|
40
|
+
customer_id=context.customer_id,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
# Start queue and process messages
|
|
45
|
+
handle_message(
|
|
46
|
+
BuyProduct(
|
|
47
|
+
product_id=product.id,
|
|
48
|
+
customer_id=customer.id,
|
|
49
|
+
price=12.99,
|
|
50
|
+
currency="EUR",
|
|
51
|
+
)
|
|
52
|
+
)
|
|
53
|
+
```
|
|
@@ -1 +1 @@
|
|
|
1
|
-
A simple and synchronous message queue for commands and events for Django.
|
|
1
|
+
A simple and synchronous message queue for commands and events for Django.
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
# http://editorconfig.org
|
|
2
|
-
|
|
3
|
-
root = true
|
|
4
|
-
|
|
5
|
-
[*]
|
|
6
|
-
charset = utf-8
|
|
7
|
-
end_of_line = lf
|
|
8
|
-
insert_final_newline = true
|
|
9
|
-
trim_trailing_whitespace = true
|
|
10
|
-
|
|
11
|
-
[*.{py,rst,ini}]
|
|
12
|
-
indent_style = space
|
|
13
|
-
indent_size = 4
|
|
14
|
-
|
|
15
|
-
[*.yml]
|
|
16
|
-
indent_style = space
|
|
17
|
-
indent_size = 2
|
|
1
|
+
# http://editorconfig.org
|
|
2
|
+
|
|
3
|
+
root = true
|
|
4
|
+
|
|
5
|
+
[*]
|
|
6
|
+
charset = utf-8
|
|
7
|
+
end_of_line = lf
|
|
8
|
+
insert_final_newline = true
|
|
9
|
+
trim_trailing_whitespace = true
|
|
10
|
+
|
|
11
|
+
[*.{py,rst,ini}]
|
|
12
|
+
indent_style = space
|
|
13
|
+
indent_size = 4
|
|
14
|
+
|
|
15
|
+
[*.yml]
|
|
16
|
+
indent_style = space
|
|
17
|
+
indent_size = 2
|
|
@@ -1,92 +1,91 @@
|
|
|
1
|
-
name:
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
- name:
|
|
21
|
-
run:
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
python -m coverage
|
|
88
|
-
python -m coverage
|
|
89
|
-
python -m coverage
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
python -m coverage report --format=markdown >> $GITHUB_STEP_SUMMARY
|
|
1
|
+
name: CI jobs
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_call:
|
|
5
|
+
|
|
6
|
+
jobs:
|
|
7
|
+
linting:
|
|
8
|
+
runs-on: ubuntu-24.04
|
|
9
|
+
steps:
|
|
10
|
+
- uses: actions/checkout@v6
|
|
11
|
+
|
|
12
|
+
- name: Set up Python 3.13
|
|
13
|
+
uses: actions/setup-python@v6
|
|
14
|
+
with:
|
|
15
|
+
python-version: "3.13"
|
|
16
|
+
|
|
17
|
+
- name: Install required packages
|
|
18
|
+
run: pip install pre-commit
|
|
19
|
+
|
|
20
|
+
- name: Run pre-commit hooks
|
|
21
|
+
run: pre-commit run --all-files
|
|
22
|
+
|
|
23
|
+
tests:
|
|
24
|
+
name: Python ${{ matrix.python-version }}, django ${{ matrix.django-version }}
|
|
25
|
+
runs-on: ubuntu-24.04
|
|
26
|
+
strategy:
|
|
27
|
+
matrix:
|
|
28
|
+
python-version: ['3.10', '3.11', '3.12', '3.13', ]
|
|
29
|
+
django-version: ['42', '52', '60', ]
|
|
30
|
+
|
|
31
|
+
exclude:
|
|
32
|
+
- python-version: '3.11'
|
|
33
|
+
django-version: 60
|
|
34
|
+
- python-version: '3.10'
|
|
35
|
+
django-version: 60
|
|
36
|
+
- python-version: '3.9'
|
|
37
|
+
django-version: 52
|
|
38
|
+
- python-version: "3.13"
|
|
39
|
+
django-version: 42
|
|
40
|
+
|
|
41
|
+
steps:
|
|
42
|
+
- uses: actions/checkout@v6
|
|
43
|
+
- name: setup python
|
|
44
|
+
uses: actions/setup-python@v6
|
|
45
|
+
with:
|
|
46
|
+
python-version: ${{ matrix.python-version }}
|
|
47
|
+
- name: Install uv
|
|
48
|
+
uses: astral-sh/setup-uv@v8.0.0
|
|
49
|
+
- name: Install tox
|
|
50
|
+
run: uv pip install --system tox tox-uv
|
|
51
|
+
- name: Run Tests
|
|
52
|
+
env:
|
|
53
|
+
TOXENV: django${{ matrix.django-version }}
|
|
54
|
+
run: tox
|
|
55
|
+
- name: Upload coverage data
|
|
56
|
+
uses: actions/upload-artifact@v7
|
|
57
|
+
with:
|
|
58
|
+
name: coverage-data-${{ matrix.python-version }}-${{ matrix.django-version }}
|
|
59
|
+
path: '${{ github.workspace }}/.coverage'
|
|
60
|
+
include-hidden-files: true
|
|
61
|
+
if-no-files-found: error
|
|
62
|
+
|
|
63
|
+
coverage:
|
|
64
|
+
name: Coverage
|
|
65
|
+
runs-on: ubuntu-24.04
|
|
66
|
+
needs: tests
|
|
67
|
+
steps:
|
|
68
|
+
- uses: actions/checkout@v6
|
|
69
|
+
|
|
70
|
+
- uses: actions/setup-python@v6
|
|
71
|
+
with:
|
|
72
|
+
python-version: '3.13'
|
|
73
|
+
|
|
74
|
+
- name: Install dependencies
|
|
75
|
+
run: python -m pip install --upgrade coverage[toml]
|
|
76
|
+
|
|
77
|
+
- name: Download data
|
|
78
|
+
uses: actions/download-artifact@v8
|
|
79
|
+
with:
|
|
80
|
+
path: ${{ github.workspace }}/coverage-reports
|
|
81
|
+
pattern: coverage-data-*
|
|
82
|
+
merge-multiple: false
|
|
83
|
+
|
|
84
|
+
- name: Combine coverage and fail if it's <100.0%
|
|
85
|
+
run: |
|
|
86
|
+
python -m coverage combine coverage-reports/*/.coverage
|
|
87
|
+
python -m coverage xml
|
|
88
|
+
python -m coverage html --skip-covered --skip-empty
|
|
89
|
+
python -m coverage report --fail-under=100.0
|
|
90
|
+
echo "## Coverage summary" >> $GITHUB_STEP_SUMMARY
|
|
91
|
+
python -m coverage report --format=markdown >> $GITHUB_STEP_SUMMARY
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
# Restrictive default — each job declares only what it needs
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
ci:
|
|
14
|
+
uses: ./.github/workflows/quality-gate.yml
|
|
15
|
+
|
|
16
|
+
build:
|
|
17
|
+
name: Build distribution packages
|
|
18
|
+
runs-on: ubuntu-24.04
|
|
19
|
+
needs: ci
|
|
20
|
+
permissions:
|
|
21
|
+
contents: read
|
|
22
|
+
steps:
|
|
23
|
+
- uses: actions/checkout@v6
|
|
24
|
+
|
|
25
|
+
- name: Set up Python 3.13
|
|
26
|
+
uses: actions/setup-python@v6
|
|
27
|
+
with:
|
|
28
|
+
python-version: "3.13"
|
|
29
|
+
|
|
30
|
+
- name: Install uv
|
|
31
|
+
uses: astral-sh/setup-uv@v8.0.0
|
|
32
|
+
|
|
33
|
+
- name: Build packages
|
|
34
|
+
run: uv build
|
|
35
|
+
|
|
36
|
+
- name: Upload distribution packages
|
|
37
|
+
uses: actions/upload-artifact@v7
|
|
38
|
+
with:
|
|
39
|
+
name: dist
|
|
40
|
+
path: dist/
|
|
41
|
+
if-no-files-found: error
|
|
42
|
+
|
|
43
|
+
sign:
|
|
44
|
+
name: Sign distribution packages
|
|
45
|
+
runs-on: ubuntu-24.04
|
|
46
|
+
needs: build
|
|
47
|
+
permissions:
|
|
48
|
+
id-token: write # required for Sigstore OIDC signing
|
|
49
|
+
contents: read
|
|
50
|
+
steps:
|
|
51
|
+
- name: Download distribution packages
|
|
52
|
+
uses: actions/download-artifact@v8
|
|
53
|
+
with:
|
|
54
|
+
name: dist
|
|
55
|
+
path: dist/
|
|
56
|
+
|
|
57
|
+
- name: Sign packages with Sigstore
|
|
58
|
+
uses: sigstore/gh-action-sigstore-python@v3.3.0
|
|
59
|
+
with:
|
|
60
|
+
inputs: >-
|
|
61
|
+
./dist/*.tar.gz
|
|
62
|
+
./dist/*.whl
|
|
63
|
+
|
|
64
|
+
- name: Upload signed distribution packages
|
|
65
|
+
uses: actions/upload-artifact@v7
|
|
66
|
+
with:
|
|
67
|
+
name: dist-signed
|
|
68
|
+
path: dist/
|
|
69
|
+
if-no-files-found: error
|
|
70
|
+
|
|
71
|
+
github-release:
|
|
72
|
+
name: Create GitHub Release
|
|
73
|
+
runs-on: ubuntu-24.04
|
|
74
|
+
needs: sign
|
|
75
|
+
permissions:
|
|
76
|
+
contents: write # required to create GitHub releases
|
|
77
|
+
steps:
|
|
78
|
+
- name: Download signed distribution packages
|
|
79
|
+
uses: actions/download-artifact@v8
|
|
80
|
+
with:
|
|
81
|
+
name: dist-signed
|
|
82
|
+
path: dist/
|
|
83
|
+
|
|
84
|
+
- name: Create GitHub Release
|
|
85
|
+
env:
|
|
86
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
87
|
+
run: |
|
|
88
|
+
shopt -s failglob
|
|
89
|
+
gh release create "${{ github.ref_name }}" \
|
|
90
|
+
--repo "${{ github.repository }}" \
|
|
91
|
+
--generate-notes \
|
|
92
|
+
dist/*
|
|
93
|
+
|
|
94
|
+
publish-pypi:
|
|
95
|
+
name: Publish to PyPI
|
|
96
|
+
runs-on: ubuntu-24.04
|
|
97
|
+
needs: sign
|
|
98
|
+
environment: pypi
|
|
99
|
+
permissions:
|
|
100
|
+
id-token: write # required for PyPI Trusted Publisher OIDC auth
|
|
101
|
+
contents: read
|
|
102
|
+
steps:
|
|
103
|
+
- name: Download signed distribution packages
|
|
104
|
+
uses: actions/download-artifact@v8
|
|
105
|
+
with:
|
|
106
|
+
name: dist-signed
|
|
107
|
+
path: dist/
|
|
108
|
+
|
|
109
|
+
- name: Remove Sigstore bundles (PyPI only accepts .whl and .tar.gz)
|
|
110
|
+
run: rm dist/*.sigstore.json
|
|
111
|
+
|
|
112
|
+
- name: Publish to PyPI
|
|
113
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
114
|
+
# Sigstore attestations are generated and uploaded to PyPI automatically
|
|
115
|
+
# when using Trusted Publishing — no extra configuration needed.
|