Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions .github/scripts/report_nightly_build_failure.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"""
Called by GH Actions when the nightly build fails.

This reports an error to the #nightly-build-failures Slack channel.
"""

import os

import requests


if "SLACK_WEBHOOK_URL" in os.environ:
print("Reporting to #nightly-build-failures slack channel")
response = requests.post(
os.environ["SLACK_WEBHOOK_URL"],
json={
"text": "A Nightly build failed. See https://github.com/torchbox/django-birdbath/actions/runs/"
+ os.environ["GITHUB_RUN_ID"],
},
timeout=30,
)

print("Slack responded with:", response)

else:
print(
"Unable to report to #nightly-build-failures slack channel because SLACK_WEBHOOK_URL is not set"
)
35 changes: 35 additions & 0 deletions .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: Nightly Wagtail Test

on:
schedule:
- cron: '0 1 * * *'
# At 01:00, daily
workflow_dispatch:

jobs:
nightly-wagtail-test:
runs-on: ubuntu-latest
env:
WEBHOOK_EXISTS: ${{ secrets.SLACK_WEBHOOK_URL != '' }}

steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'

- run: git clone https://github.com/wagtail/wagtail.git

- run: python -m pip install flit
- run: flit install --extras dev
- run: python -m pip install ./wagtail

- run: pytest

- name: Report failure
run: |
python -m pip install requests
python ./.github/scripts/report_nightly_build_failure.py
if: ${{ failure() && env.WEBHOOK_EXISTS == 'true' }}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
51 changes: 51 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# See https://packaging.python.org/en/latest/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows/
# for a detailed guide
name: Publish to PyPI

on:
release:
types: [published]

jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read # to fetch code (actions/checkout)
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Set up Python 3.11
uses: actions/setup-python@v5
with:
python-version: '3.11'

- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install flit
python -m flit install --symlink

- name: Build
run: python -m flit build

- uses: actions/upload-artifact@v4
with:
path: ./dist

publish:
needs: build
runs-on: ubuntu-latest
permissions:
contents: none
id-token: write # required for trusted publishing
environment: publish
steps:
- uses: actions/download-artifact@v4

- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: artifact/
print-hash: true
48 changes: 48 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: Django Birdbath CI

on:
push:
branches:
- main
- 'stable/**'

pull_request:

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: read # to fetch code (actions/checkout)

jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Python 3.12
uses: actions/setup-python@v5
with:
python-version: '3.12'
- uses: pre-commit/action@v3.0.1

test:
runs-on: ubuntu-latest
needs: lint
strategy:
matrix:
python: ['3.9', '3.10', '3.11', '3.12', '3.13']

steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python }}
- name: Install
run: |
python -m pip install --upgrade pip tox tox-gh-actions
- name: Test
run: tox
13 changes: 6 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ Your site will probably have some of your own check/processor needs.

Custom checks can be implemented by subclassing `birdbath.checks.BaseCheck` and implementing the `check` method:

```
```python
from birdbath.checks import BaseCheck


Expand All @@ -54,7 +54,7 @@ The `check` method should either return `True` if the checks should continue, or

Custom processors can be implemented by subclassing `birdbath.processors.BaseProcessor` and implementing the `run` method:

```
```python
from birdbath.processors import BaseProcessor


Expand All @@ -65,7 +65,7 @@ class DeleteAllMyUsersProcessor(BaseProcessor):

There are also more specialised base classes in `birdbath.processors` that can help you write cleaner custom processors. For example, the above example could be written using the `BaseModelDeleter` class instead:

```
```python
from birdbath.processors import BaseModelDeleter


Expand All @@ -75,7 +75,7 @@ class DeleteAllMyUsersProcessor(BaseModelDeleter):

If you only need to delete a subset of users, you can override the `get_queryset()` method, like so:

```
```python
from birdbath.processors import BaseModelDeleter


Expand All @@ -88,8 +88,7 @@ class DeleteNonStaffUsersProcessor(BaseModelDeleter):

If you're looking to 'anonymise' rather than delete objects, you will likely find the `BaseModelAnonymiser` class useful. You just need to indicate the fields that should be 'anonymised' or 'cleared', and the class will do the rest. For example:


```
```python
from birdbath.processors import BaseModelAnonymiser


Expand Down Expand Up @@ -122,7 +121,7 @@ The class will generate:

If you have fields with custom validation requirements, or would simply like to generate more realistic replacement values, you can add 'generate' methods to your subclass to achieve this. `BaseModelAnonymiser` will automatically look for method matching the format `"generate_{field_name}"` when anoymising field values. For example, the following processor will generate random values for "account_holder" and "account_number" fields:

```
```python
from birdbath.processors import BaseModelAnonymiser


Expand Down
11 changes: 9 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,17 @@ classifiers = [
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
]
keywords = ["django", "anonymization", "data cleaning"]
dependencies = [
"Faker >=8",
"Faker>=8",
"Django>=4.2",
]
requires-python = ">=3.9"

[project.urls]
Home = "https://git.torchbox.com/internal/django-birdbath"
Home = "https://github.com/torchbox/django-birdbath"

[project.optional-dependencies]
dev = [
Expand Down Expand Up @@ -60,3 +62,8 @@ lint.select = [
"C4", # flake8-comprehensions
"UP", # pyupgrade
]

[tool.pytest.ini_options]
django_find_project = false
pythonpath = "."
DJANGO_SETTINGS_MODULE = "tests.settings"
18 changes: 13 additions & 5 deletions tox.ini
Original file line number Diff line number Diff line change
@@ -1,18 +1,26 @@
[tox]
envlist =
py39-django42-wagtail62
py{310,311,312}-django{50,51}-wagtail62
py312-django42-wagtail{52,60,61,62}
# Django versions with their respectively supported Python versions and the most recent Wagtail LTS
py{39,310,311,312,313}-django42-wagtail62
py{310,311,312,313}-django{50,51}-wagtail62
# Old Wagtail versions with the oldest Django LTS and Python
py39-django42-wagtail52
isolated_build = True

[gh-actions]
python =
3.9: py39
3.10: py310
3.11: py311
3.12: py312
3.13: py313

[testenv]
deps =
django42: Django>=4.2,<5.0
django50: Django>=5.0,<5.1
django51: Django>=5.1,<5.2
wagtail52: wagtail>=5.2,<5.3
wagtail60: wagtail>=6.0,<6.1
wagtail61: wagtail>=6.1,<6.2
wagtail62: wagtail>=6.2,<6.3
pytest
pytest-django
Expand Down