Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
30 changes: 16 additions & 14 deletions .dockerfiles/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,28 +1,30 @@
FROM python:3.11-slim as base
ENV PYTHONPATH /app
FROM python:3.13-slim as base
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
ENV DEBUG False
ENV UV_LINK_MODE copy
ENV UV_COMPILE_BYTECODE 1
ENV UV_PYTHON_DOWNLOADS never
ENV UV_PYTHON /usr/local/bin/python
ENV UV_PROJECT_ENVIRONMENT /app
ENV PATH /app/bin:$PATH
COPY --from=ghcr.io/astral-sh/uv:0.6.14 /uv /uvx /bin/
RUN mkdir -p /app
WORKDIR /app


FROM base as py
FROM base as builder
COPY pyproject.toml uv.lock* ./
RUN uv sync --locked --no-dev --no-install-project
COPY src /app/src
COPY LICENSE pyproject.toml README.md /app/
RUN python -m pip install --upgrade pip \
&& python -m pip install '.[hc,psycopg,relay]'


FROM base as app
COPY src/service /app/service
COPY LICENSE README.md ./
RUN uv sync --locked --no-dev --no-editable


FROM base as final
COPY --from=py /usr/local /usr/local
COPY --from=app /app /app
COPY --from=builder /app /app
RUN addgroup --system django \
&& adduser --system --ingroup django django \
# Ensure the app directory is owned by the user
&& chown -R django:django /app
USER django
CMD ["python", "-m", "service"]
CMD ["uv", "run", "-m", "service"]
62 changes: 20 additions & 42 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,69 +2,47 @@ name: release

on:
release:
types: [released]
types: [published]

jobs:
check:
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v4

- name: Check most recent test run on `main`
id: latest-test-result
run: |
echo "result=$(gh run list \
--branch=main \
--workflow=test.yml \
--json headBranch,workflowName,conclusion \
--jq '.[] | select(.headBranch=="main" and .conclusion=="success") | .conclusion' \
| head -n 1)" >> $GITHUB_OUTPUT
Comment on lines -21 to -26

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🍺 pours one out for this code.


- name: OK
if: ${{ (contains(steps.latest-test-result.outputs.result, 'success')) }}
run: exit 0

- name: Fail
if: ${{ !contains(steps.latest-test-result.outputs.result, 'success') }}
run: exit 1
test:
uses: ./.github/workflows/test.yml
secrets: inherit

pypi:
if: ${{ github.event_name == 'release' }}
runs-on: ubuntu-latest
needs: check
needs: test
environment: release
permissions:
contents: read
contents: write
id-token: write
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false

- uses: westerveltco/setup-ci-action@v0
- name: Install uv
uses: astral-sh/setup-uv@v5
with:
python-version: 3.12
extra-python-dependencies: hatch
use-uv: true
enable-cache: true
pyproject-file: pyproject.toml

- name: Build package
run: |
hatch build
uv build

- name: Upload release assets to GitHub
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release upload ${{ github.event.release.tag_name }} ./dist/*

- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
run: |
uv publish

docker:
runs-on: ubuntu-latest
needs: check
environment: release
permissions:
contents: read
contents: write
packages: write
steps:
- uses: actions/checkout@v4
Expand Down
87 changes: 57 additions & 30 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,16 @@ jobs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false

- uses: westerveltco/setup-ci-action@v0
- name: Install uv
uses: astral-sh/setup-uv@v5
with:
python-version: 3.9
extra-python-dependencies: nox
use-uv: true
enable-cache: true
pyproject-file: pyproject.toml

- id: set-matrix
run: |
echo "matrix=$(python -m nox -l --json | jq -c '[.[] | select(.name == "tests") | {"python-version": .python, "django-version": .call_spec.django}] | {include: .}')" >> $GITHUB_OUTPUT
uv run nox --session "gha_matrix"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's amazing how much this cleans stuff up.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, much easier to see what's going on here:

@nox.session
def gha_matrix(session):
    sessions = session.run("nox", "-l", "--json", silent=True)
    matrix = {
        "include": [
            {
                "python-version": session["python"],
                "django-version": session["call_spec"]["django"],
            }
            for session in json.loads(sessions)
            if session["name"] == "tests"
        ]
    }
    with Path(os.environ["GITHUB_OUTPUT"]).open("a") as fh:
        print(f"matrix={matrix}", file=fh)

Arguably you could unroll the comprehension too to help readability.


test:
name: Python ${{ matrix.python-version }}, Django ${{ matrix.django-version }}
Expand All @@ -42,18 +40,16 @@ jobs:
matrix: ${{ fromJSON(needs.generate-matrix.outputs.matrix) }}
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false

- uses: westerveltco/setup-ci-action@v0
- name: Install uv
uses: astral-sh/setup-uv@v5
with:
python-version: ${{ matrix.python-version }}
extra-python-dependencies: nox
use-uv: true
enable-cache: true
pyproject-file: pyproject.toml

- name: Run tests
run: |
python -m nox --session "tests(python='${{ matrix.python-version }}', django='${{ matrix.django-version }}')"
uv run nox --session "tests(python='${{ matrix.python-version }}', django='${{ matrix.django-version }}')"

tests:
runs-on: ubuntu-latest
Expand All @@ -71,32 +67,63 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false

- uses: westerveltco/setup-ci-action@v0
- name: Install uv
uses: astral-sh/setup-uv@v5
with:
python-version: 3.9
extra-python-dependencies: nox
use-uv: true
enable-cache: true
pyproject-file: pyproject.toml

- name: Run mypy
- name: Run type checks
run: |
python -m nox --session "mypy"
uv run nox --session "mypy"

coverage:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false

- uses: westerveltco/setup-ci-action@v0
- name: Install uv
uses: astral-sh/setup-uv@v5
with:
python-version: 3.9
extra-python-dependencies: nox
use-uv: true
enable-cache: true
pyproject-file: pyproject.toml

- name: Run coverage
- name: Generate code coverage
run: |
uv run nox --session "coverage"

docker:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Build Docker image
uses: docker/build-push-action@v6
with:
context: .
file: .dockerfiles/Dockerfile
load: true
tags: django-email-relay-test:latest
push: false
cache-from: type=gha
cache-to: type=gha,mode=max
Comment on lines +112 to +113

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👀 oh, is this the trick?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, mode=max caches everything about PRs indefinitely across GitHub causing the whole service to come to a standstill.


- name: Run container and check status
run: |
docker run -d --name test-container django-email-relay-test:latest
sleep 10
if docker ps -f name=test-container --format '{{.Names}}' | grep -q test-container; then
else
docker logs test-container
exit 1
fi

- name: Clean up container
if: always()
run: |
python -m nox --session "coverage"
docker stop test-container || true
docker rm test-container || true
36 changes: 36 additions & 0 deletions .just/copier.just
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
set unstable := true

justfile := justfile_directory() + "/.just/copier.just"

[private]
default:
@just --list --justfile {{ justfile }}

[private]
fmt:
@just --fmt --justfile {{ justfile }}

# Create a copier answers file
[no-cd]
copy TEMPLATE_PATH DESTINATION_PATH=".":
uv run copier copy --trust {{ TEMPLATE_PATH }} {{ DESTINATION_PATH }}

# Recopy the project from the original template
[no-cd]
recopy ANSWERS_FILE *ARGS:
uv run copier recopy --trust --answers-file {{ ANSWERS_FILE }} {{ ARGS }}

# Loop through all answers files and recopy the project using copier
[no-cd]
@recopy-all *ARGS:
for file in `ls .copier/`; do just copier recopy .copier/$file "{{ ARGS }}"; done

# Update the project using a copier answers file
[no-cd]
update ANSWERS_FILE *ARGS:
uv run copier update --trust --answers-file {{ ANSWERS_FILE }} {{ ARGS }}

# Loop through all answers files and update the project using copier
[no-cd]
@update-all *ARGS:
for file in `ls .copier/`; do just copier update .copier/$file "{{ ARGS }}"; done
31 changes: 31 additions & 0 deletions .just/documentation.just
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
set unstable := true

justfile := justfile_directory() + "/.just/documentation.just"

[private]
default:
@just --list --justfile {{ justfile }}

[private]
fmt:
@just --fmt --justfile {{ justfile }}

# Build documentation using Sphinx
[no-cd]
build LOCATION="docs/_build/html": cog
uv run --group docs sphinx-build docs {{ LOCATION }}

# Serve documentation locally
[no-cd]
serve PORT="8000": cog
#!/usr/bin/env sh
HOST="localhost"
if [ -f "/.dockerenv" ]; then
HOST="0.0.0.0"
fi
uv run --group docs sphinx-autobuild docs docs/_build/html --host "$HOST" --port {{ PORT }}

[no-cd]
[private]
cog:
uv run --with cogapp cog -r CONTRIBUTING.md docs/development/just.md
24 changes: 9 additions & 15 deletions .readthedocs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,18 @@
version: 2

build:
jobs:
pre_build:
- asdf plugin add just && asdf install just latest && asdf global just latest
- just _cog
os: ubuntu-22.04
tools:
python: "3.12"
python: "3.13"
commands:
- asdf plugin add just && asdf install just latest && asdf global just latest
- asdf plugin add uv && asdf install uv latest && asdf global uv latest
- just docs cog
- uv run --group docs sphinx-build docs $READTHEDOCS_OUTPUT/html

sphinx:
configuration: docs/conf.py
configuration: docs/conf.py

formats:
- pdf
- epub

python:
install:
- method: pip
path: .
extra_requirements:
- docs
- pdf
- epub
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ and this project attempts to adhere to [Semantic Versioning](https://semver.org/

- Added support for Python 3.13.

### Changed

- Now using `uv` for project management.

### Removed

- Dropped support for Django 5.0.
Expand Down
Loading