-
Notifications
You must be signed in to change notification settings - Fork 1
swap to using uv for project management #213
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
0c1666d
1fbe969
8464140
4d29a10
8ecf4c5
6a631bb
e3289ff
9d0e229
f601a35
2af5290
3d4806d
839b8d2
62ef9b3
a29462c
33ef0f0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,28 +1,38 @@ | ||
| FROM python:3.11-slim as base | ||
| ENV PYTHONPATH /app | ||
| ARG PYTHON_VERSION=3.13 | ||
| ARG UID=1000 | ||
| ARG GID=1000 | ||
|
|
||
| FROM python:${PYTHON_VERSION}-slim as base | ||
|
Check warning on line 5 in .dockerfiles/Dockerfile
|
||
| ENV PYTHONDONTWRITEBYTECODE 1 | ||
|
Check warning on line 6 in .dockerfiles/Dockerfile
|
||
| ENV PYTHONUNBUFFERED 1 | ||
|
Check warning on line 7 in .dockerfiles/Dockerfile
|
||
| ENV DEBUG False | ||
| RUN mkdir -p /app | ||
| WORKDIR /app | ||
|
|
||
| ENV UV_LINK_MODE copy | ||
|
Check warning on line 8 in .dockerfiles/Dockerfile
|
||
| ENV UV_COMPILE_BYTECODE 1 | ||
|
Check warning on line 9 in .dockerfiles/Dockerfile
|
||
| ENV UV_PYTHON_DOWNLOADS never | ||
|
Check warning on line 10 in .dockerfiles/Dockerfile
|
||
| ENV UV_PYTHON python${PYTHON_VERSION} | ||
|
Check warning on line 11 in .dockerfiles/Dockerfile
|
||
| ENV UV_PROJECT_ENVIRONMENT /app | ||
|
Check warning on line 12 in .dockerfiles/Dockerfile
|
||
| ENV PATH /app/bin:$PATH | ||
| COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv | ||
|
|
||
| FROM base as py | ||
| 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 | ||
| FROM base as builder | ||
|
Check warning on line 17 in .dockerfiles/Dockerfile
|
||
| RUN --mount=type=cache,target=/root/.cache \ | ||
| --mount=type=bind,source=uv.lock,target=uv.lock \ | ||
| --mount=type=bind,source=pyproject.toml,target=pyproject.toml \ | ||
| uv sync --locked --no-dev --no-install-project | ||
| COPY . /src | ||
| WORKDIR /src | ||
| RUN --mount=type=cache,target=/root/.cache \ | ||
| uv sync --locked --no-dev --no-editable --extra hc --extra psycopg --extra relay | ||
|
|
||
|
|
||
| FROM base as final | ||
|
Check warning on line 28 in .dockerfiles/Dockerfile
|
||
| COPY --from=py /usr/local /usr/local | ||
| COPY --from=app /app /app | ||
| RUN addgroup --system django \ | ||
| && adduser --system --ingroup django django \ | ||
| ARG UID | ||
| ARG GID | ||
| RUN mkdir -p /app | ||
| COPY --from=builder /app /app | ||
| RUN addgroup -gid "${GID}" --system django \ | ||
| && adduser -uid "${UID}" -gid "${GID}" --home /home/django --system django \ | ||
| && chown -R django:django /app | ||
| USER django | ||
| CMD ["python", "-m", "service"] | ||
| WORKDIR /app | ||
| CMD ["uv", "run", "-m", "email_relay.service"] | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,13 +1,7 @@ | ||
| fly.toml | ||
| .git/ | ||
| *.sqlite3 | ||
| .editorconfig | ||
| .env* | ||
| .gitignore | ||
| .pre-commit-config.yaml | ||
| .python-version | ||
| .yarnrc.yml | ||
| Dockerfile | ||
| Justfile | ||
| requirements.in | ||
| __pycache__ | ||
| * | ||
|
|
||
| !src/ | ||
| !LICENSE | ||
| !README.md | ||
| !pyproject.toml | ||
| !uv.lock |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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" | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's amazing how much this cleans stuff up.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 }} | ||
|
|
@@ -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 | ||
|
|
@@ -71,32 +67,51 @@ 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: Generate code coverage | ||
| run: | | ||
| uv run nox --session "coverage" | ||
|
|
||
| - name: Run 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
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👀 oh, is this the trick?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, |
||
|
|
||
| - name: Run container and check | ||
| run: | | ||
| python -m nox --session "coverage" | ||
| docker run --rm --name test-container django-email-relay-test:latest uv run -m email_relay.service --help | ||
| 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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| set unstable := true | ||
|
|
||
| justfile := justfile_directory() + "/.just/docker.just" | ||
|
|
||
| [private] | ||
| default: | ||
| @just --list --justfile {{ justfile }} | ||
|
|
||
| [private] | ||
| fmt: | ||
| @just --fmt --justfile {{ justfile }} | ||
|
|
||
| [no-cd] | ||
| build: | ||
| docker build --file .dockerfiles/Dockerfile --tag docker-email-relay:local . | ||
|
|
||
| [no-cd] | ||
| run *ARGS: build | ||
| docker run --rm docker-email-relay:local {{ ARGS }} | ||
|
|
||
| [no-cd] | ||
| smoke: | ||
| @just docker run uv run -m email_relay.service --help |
| 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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have been struggling with these options. Maybe you have the correct combo but mine was trying to re-download when I run
uv run ...There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh this is totally lifted from Hynek's article about how he builds his Dockerfiles with uv. https://hynek.me/articles/docker-uv/
Just giving it a try to see if it works before rolling it out anywhere else.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
doesn't seem like it's redownloading -- first pass took 13s, second one didn't even clock
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, it did, it just didn't show up in my prompt. 12.5s build time first pass, 0.5s second pass.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or wait, are you talking about uv run redownloading later in the same build? I've confused myself.