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
2 changes: 1 addition & 1 deletion .envrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
use flake
use nix
49 changes: 5 additions & 44 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,51 +13,12 @@ concurrency:
permissions:
contents: read

env:
# CI runs the same recipes as a developer does; the GitHub-flavoured output
# comes from the environment rather than from a CI-only spelling of the
# command, so there is nothing here that cannot be reproduced locally.
RUFF_OUTPUT_FORMAT: github

jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
# Pinned exactly: setup-uv stopped publishing moving major tags after
# v7, and v7 has not moved since March.
- uses: astral-sh/setup-uv@v10.0.1
with:
enable-cache: true
# There is no uv.lock to key the cache on, and committing one would
# pin CI to known-good dependency versions -- exactly the upstream
# breakage the unbounded requirements rely on the suite to catch.
cache-dependency-glob: pyproject.toml
- run: uv tool install rust-just
- run: just lint

test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.11", "3.12", "3.13", "3.14"]
env:
UV_PYTHON: ${{ matrix.python-version }}
steps:
- uses: actions/checkout@v7
- uses: astral-sh/setup-uv@v10.0.1
with:
enable-cache: true
cache-dependency-glob: pyproject.toml
- run: uv tool install rust-just
- run: just test

build:
# One job, one command: `just ci` runs the same checks in the same order
# locally, so a red build can always be reproduced with `nix-shell --run 'just ci'`.
ci:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: astral-sh/setup-uv@v10.0.1
- run: uv tool install rust-just
- run: just dist
- run: uvx twine check --strict dist/*
- uses: cachix/install-nix-action@v31
- run: nix-shell --run 'just ci'
33 changes: 14 additions & 19 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,15 @@ jobs:
name: Build distributions
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v10.0.1
with:
enable-cache: true
cache-dependency-glob: pyproject.toml
- run: uv tool install rust-just
- run: just release-build "$GITHUB_REF_NAME"
- run: uvx twine check --strict dist/*
- uses: actions/checkout@v7
- uses: cachix/install-nix-action@v31
- run: |
# The single quotes are deliberate: the variable is expanded by the
# shell nix-shell starts, which inherits the environment.
# shellcheck disable=SC2016
nix-shell --run 'just release-build "$GITHUB_REF_NAME"'

- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v7
with:
name: dist
path: dist/
Expand All @@ -35,17 +34,13 @@ jobs:
matrix:
python-version: ["3.11", "3.14"]
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
- uses: actions/checkout@v7
- uses: actions/download-artifact@v8
with:
name: dist
path: dist/
- uses: astral-sh/setup-uv@v10.0.1
with:
enable-cache: true
cache-dependency-glob: pyproject.toml
- run: uv tool install rust-just
- run: just test-wheel ${{ matrix.python-version }}
- uses: cachix/install-nix-action@v31
- run: nix-shell --run 'just test-wheel ${{ matrix.python-version }}'

publish:
name: Publish to PyPI
Expand All @@ -57,7 +52,7 @@ jobs:
permissions:
id-token: write # trusted publishing; no API token needed
steps:
- uses: actions/download-artifact@v4
- uses: actions/download-artifact@v8
with:
name: dist
path: dist/
Expand All @@ -70,7 +65,7 @@ jobs:
permissions:
contents: write
steps:
- uses: actions/download-artifact@v4
- uses: actions/download-artifact@v8
with:
name: dist
path: dist/
Expand Down
48 changes: 48 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Every hook is `language: system`: the tools come from the environment rather
# than from pre-commit's own isolated installs. On NixOS that is the only thing
# that works for ruff (the published wheel is a prebuilt dynamically linked
# binary), and it keeps every hook on the same version as `just lint`.
# `nix-shell` provides all of them; see CONTRIBUTING.rst.
default_install_hook_types: [pre-commit]

repos:
- repo: local
hooks:
- id: ruff-check
name: ruff check
entry: ruff check --force-exclude --fix
language: system
types_or: [python, pyi]
require_serial: true

- id: ruff-format
name: ruff format
entry: ruff format --force-exclude
language: system
types_or: [python, pyi]
require_serial: true

- id: pyright
name: pyright
entry: pyright
language: system
types_or: [python, pyi]
# pyright checks the whole `include` set from pyproject.toml: a change
# in one file breaks type checking in another.
pass_filenames: false

- id: alejandra
name: alejandra
entry: alejandra --quiet
language: system
types: [nix]
# Generated by `npins`; formatting it here would only be undone by the
# next `npins update`.
exclude: ^npins/

- id: actionlint
name: actionlint
entry: actionlint
language: system
files: ^\.github/workflows/.*\.ya?ml$
types: [yaml]
54 changes: 43 additions & 11 deletions CONTRIBUTING.rst
Original file line number Diff line number Diff line change
Expand Up @@ -70,37 +70,62 @@ Ready to contribute? Here's how to set up `domain_utils` for local development.
$ cd domain_utils/
$ just install-dev

On NixOS there is a flake providing uv, ruff and the supported
interpreters; ``nix develop`` (or ``direnv allow``) drops you into it.
The flake pins uv to the interpreters from nixpkgs, because uv's own
prebuilt CPython downloads assume an FHS layout and will not run.
If you use nix, on any operating system, there is a ``shell.nix`` providing
just_, uv, ruff and the supported interpreters; ``nix-shell`` (or
``direnv allow``) drops you into it. It is what CI uses, so the tooling
matches exactly. nixpkgs is pinned with npins_; ``npins update``
refreshes it.

4. Create a branch for local development::
The shell pins uv to the interpreters from nixpkgs and points ``RUFF`` and
``PYRIGHT`` at the nixpkgs binaries. That is required on NixOS, where uv's
prebuilt CPython downloads and the published ruff and pyright wheels assume
an FHS layout and will not run; elsewhere it simply keeps your versions the
same as CI's.

4. Install the pre-commit_ hooks::

$ just hooks

They run ruff and pyright over the Python, alejandra_ over the Nix and
actionlint_ (which delegates the workflows' ``run:`` blocks to shellcheck_)
over the GitHub Actions workflows. Every hook is ``language: system``, so it uses
the tool from your environment rather than installing its own; the
``nix-shell`` above provides all of them.

5. Create a branch for local development::

$ git checkout -b name-of-your-bugfix-or-feature

Now you can make your changes locally.

5. When you're done making changes, check that your changes pass the linter and
6. When you're done making changes, check that your changes pass the linter and
the tests::

$ just ci

That is the single command CI runs, so a red build reproduces locally. The
individual steps are available too; ``just`` on its own lists them all::

$ just lint
$ just typecheck
$ just test

``just test`` fails if coverage drops below 100%. ``just format`` applies
the fixes the linter can make on its own.
the fixes the linter can make on its own. ``just typecheck`` runs pyright_
in strict mode over both the package and the tests; the package ships a
``py.typed`` marker, so its annotations are part of its public interface.

To test against another interpreter, pass it to uv::
To test against another interpreter::

$ uv run --python 3.11 --group test pytest
$ just test-python 3.11

6. Commit your changes and push your branch to GitHub::
7. Commit your changes and push your branch to GitHub::

$ git add .
$ git commit -m "Your detailed description of your changes."
$ git push origin name-of-your-bugfix-or-feature

7. Submit a pull request through the GitHub website.
8. Submit a pull request through the GitHub website.

Pull Request Guidelines
-----------------------
Expand All @@ -127,6 +152,13 @@ whole-suite gate. ``just coverage`` runs everything under the gate, which is
what CI enforces.

.. _uv: https://docs.astral.sh/uv/
.. _npins: https://github.com/andir/npins
.. _pre-commit: https://pre-commit.com/
.. _alejandra: https://github.com/kamadorueda/alejandra
.. _actionlint: https://github.com/rhysd/actionlint
.. _shellcheck: https://www.shellcheck.net/
.. _pyright: https://microsoft.github.io/pyright/
.. _just: https://just.systems/


Deploying
Expand Down
11 changes: 10 additions & 1 deletion HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,16 @@ History
running more than one process could race and lose data. Upstream moved the
cache out of the package directory in 3.1.0.
* Drop support for Python 3.6 to 3.10; the minimum is now 3.11.
* Replace CircleCI with GitHub Actions (#31).
* Ship type annotations. The package now carries a ``py.typed`` marker, so
type checkers see the annotations, and the whole codebase is checked with
pyright in strict mode. Passing ``extractor=None`` explicitly is now a type
error as well as the ``ValueError`` it always raised; leave the argument
out to get the automatically created extractor.
* Replace CircleCI with GitHub Actions (#31). CI now runs a single
``just ci`` inside the nix shell, so a red build reproduces locally with
the same command and the same tool versions.
* Replace the Makefile with a justfile. Every target was a ``.PHONY``
command alias, which is a command runner's job rather than make's.
* The test suite now fails below 100% statement and branch coverage (#27).
* Fix the docs build, and point urls at openwpm/domain_utils. Install
instructions use the ``domain-utils`` project name (#30).
Expand Down
28 changes: 23 additions & 5 deletions docs/release.rst
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,31 @@ Cutting a release

#. Make sure ``master`` is green, both in
`CI <https://github.com/openwpm/domain_utils/actions/workflows/ci.yml>`_ and
on `Read the Docs <https://readthedocs.org/projects/domain-utils/>`_.
on `Read the Docs <https://readthedocs.org/projects/domain-utils/>`_. CI is
a single ``just ci`` inside the nix shell, so you can run the same thing
locally:

#. Add the release notes to ``HISTORY.rst``.
.. code-block:: bash

nix-shell --run 'just ci'

#. Add the release notes to ``HISTORY.rst``, under the existing
``0.8.0 (unreleased)`` heading.

#. Set the version and date the changelog:

.. code-block:: bash

just bump 0.8.0

#. Bump ``__version__`` in ``domain_utils/__init__.py``. That is the single
source of truth for the version; the packaging metadata reads it and the
release workflow refuses to publish if it disagrees with the tag.
That rewrites ``__version__`` in ``domain_utils/__init__.py`` and turns
``0.8.0 (unreleased)`` into ``0.8.0 (<today>)``. ``__version__`` is the
single source of truth for the version: the packaging metadata reads it,
and the release workflow refuses to publish if it disagrees with the tag
or if the changelog section is still undated. The changelog is part of
the published description, so an undated heading would be the first thing
on the PyPI page. The check is ``just check-version v0.8.0``, which
``just bump`` runs for you.

#. Commit and push both changes:

Expand Down
Loading