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
56 changes: 56 additions & 0 deletions .github/workflows/documentation.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# SPDX-FileCopyrightText: 2026 calendaring-sync contributors
# SPDX-License-Identifier: AGPL-3.0-or-later

name: Documentation build, links, spelling, grammar, and style

on:
push:
branches: [main]
pull_request:
workflow_call:

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

permissions:
contents: read

jobs:
docs:
name: Documentation on Python ${{ matrix.python-version }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
# The lowest Python the docs build with, and the one Read the Docs uses.
python-version: ["3.13", "3.14"]
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
# The pages show when each was last changed.
fetch-depth: 0

- name: Install uv
uses: astral-sh/setup-uv@68559e99cc807c1eb7e9238fd43a15bba460eec2 # v10.3.3
with:
version: "0.13.7"
enable-cache: false

- name: Build HTML documentation
run: >-
make html PYTHONVERSION=${{ matrix.python-version }}
UV_GROUPS="--no-default-groups --group docs"

# Vale fails on errors and shows warnings too.
- name: Run Vale
run: >-
make vale VALEOPTS="--minAlertLevel='warning'" PYTHONVERSION=${{ matrix.python-version }}
UV_GROUPS="--no-default-groups --group docs"

- name: Check for broken links
run: >-
make linkcheckbroken PYTHONVERSION=${{ matrix.python-version }}
UV_GROUPS="--no-default-groups --group docs"
21 changes: 7 additions & 14 deletions .github/workflows/integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,23 +39,16 @@ jobs:
persist-credentials: false
fetch-depth: 0

- name: Set up Python
uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
- name: Install uv
uses: astral-sh/setup-uv@68559e99cc807c1eb7e9238fd43a15bba460eec2 # v10.3.3
with:
python-version: "3.15"
pip-version: "26.2.2"

- name: Install dependencies
run: pip install -e ".[dev]"

# Radicale and Xandikos run embedded; the rest from this repo's fixtures.
- name: Start Stalwart, Cyrus and Baïkal
run: bash tests/docker/start.sh stalwart cyrus baikal
version: "0.13.7"
enable-cache: false

# Radicale and Xandikos run embedded; the rest from this repo's fixtures,
# which the target starts.
- name: Run integration tests
run: |
pytest src/calendaring_sync/tests/test_caldav_integration.py \
src/calendaring_sync/tests/test_jmap_integration.py
run: make test-integration PYTHONVERSION=3.15 UV_GROUPS="--no-default-groups --group test"

# Each server's log, to read when a test fails; a server that never
# started has none, and that mustn't hide the others'.
Expand Down
8 changes: 7 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,15 @@ jobs:
permissions:
contents: read

documentation:
name: Build documentation
uses: $/.github/workflows/documentation.yml
permissions:
contents: read

build:
name: Build distribution
needs: [test, integration]
needs: [test, integration, documentation]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
Expand Down
120 changes: 26 additions & 94 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,16 @@ jobs:
persist-credentials: false
fetch-depth: 0

- name: Set up Python
uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
- name: Install uv
uses: astral-sh/setup-uv@68559e99cc807c1eb7e9238fd43a15bba460eec2 # v10.3.3
with:
python-version: "3.15"
pip-version: "26.2.2"

- name: Install towncrier
run: pip install towncrier==26.9.0
version: "0.13.7"
enable-cache: false

- name: Check for a news fragment
run: towncrier check --compare-with origin/${GITHUB_BASE_REF}
run: >-
make changes-check PYTHONVERSION=3.15 UV_GROUPS="--no-default-groups --group checks"
TOWNCRIEROPTS="--compare-with origin/${GITHUB_BASE_REF}"

lint:
name: Lint with Ruff
Expand All @@ -52,74 +51,14 @@ jobs:
with:
persist-credentials: false

- name: Set up Python
uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
with:
python-version: "3.15"
pip-version: "26.2.2"

- name: Install ruff
run: pip install ruff==0.17.2

- name: Lint code
run: ruff check .

- name: Check code format
run: ruff format --check .

vale:
name: Check docs prose with Vale
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- name: Set up Python
uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
- name: Install uv
uses: astral-sh/setup-uv@68559e99cc807c1eb7e9238fd43a15bba460eec2 # v10.3.3
with:
python-version: "3.15"
pip-version: "26.2.2"

- name: Install docutils
run: pip install docutils==0.23

- name: Install Vale
run: |
curl -sL https://github.com/errata-ai/vale/releases/download/v3.25.1/vale_3.25.1_Linux_64-bit.tar.gz | tar -xz -C /usr/local/bin vale

- name: Sync Vale styles
run: vale sync
version: "0.13.7"
enable-cache: false

- name: Lint docs
run: vale --no-exit docs/

docs:
name: Build docs
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
fetch-depth: 0

- name: Set up Python
uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
with:
# Read the Docs builds with 3.14, its newest Python.
python-version: "3.14"
pip-version: "26.2.2"

- name: Install dependencies
run: pip install -e ".[docs]"

- name: Build docs
run: sphinx-build -W -b html docs docs/_build/html

- name: Check links
run: sphinx-build -b linkcheck docs docs/_build/linkcheck
- name: Lint and check the format
run: make lint PYTHONVERSION=3.15 UV_GROUPS="--no-default-groups --group formatting"

mypy:
name: Type check with mypy
Expand All @@ -130,18 +69,15 @@ jobs:
with:
persist-credentials: false

- name: Set up Python
uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
- name: Install uv
uses: astral-sh/setup-uv@68559e99cc807c1eb7e9238fd43a15bba460eec2 # v10.3.3
with:
python-version: "3.15"
pip-version: "26.2.2"

- name: Install dependencies
run: pip install -e ".[dev]"
version: "0.13.7"
enable-cache: false

- name: Type check
# Its settings are in pyproject.toml.
run: python -m mypy src/calendaring_sync docs/examples tests/docker
run: make type-check PYTHONVERSION=3.15 UV_GROUPS="--no-default-groups --group test"

test:
name: Test on Python ${{ matrix.python-version }}
Expand All @@ -161,20 +97,16 @@ jobs:
persist-credentials: false
fetch-depth: 0

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
- name: Install uv
uses: astral-sh/setup-uv@68559e99cc807c1eb7e9238fd43a15bba460eec2 # v10.3.3
with:
python-version: ${{ matrix.python-version }}
pip-version: "26.2.2"

- name: Install dependencies
run: pip install -e ".[dev]"
version: "0.13.7"
enable-cache: false

- name: Run tests
run: |
pytest --cov --cov-branch --cov-report=xml \
--junitxml=junit.xml -o junit_family=legacy \
src/calendaring_sync/tests --ignore-glob="*_integration.py"
- name: Run tests with coverage
run: >-
make test-coverage PYTHONVERSION=${{ matrix.python-version }}
UV_GROUPS="--no-default-groups --group test"

- name: Upload coverage to Codecov
if: ${{ !cancelled() }}
Expand Down
10 changes: 3 additions & 7 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,8 @@ env/
# Generated version file
src/calendaring_sync/_version.py

# uv lock file
uv.lock

# Docs build (including comparison builds under other names, e.g. docs/_build2)
docs/_build*/
# Docs build, outside docs/ as the Makefile writes it
/_build/

# Vale-synced third-party style packages (fetched by `vale sync`)
docs/.vale/styles/Microsoft/
docs/.vale/styles/signs-of-ai-writing/
/docs/styles/Microsoft/
9 changes: 7 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.17.2
rev: v0.17.4
hooks:
- id: ruff-check
args: [--fix]
Expand All @@ -14,10 +14,15 @@ repos:
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
# Jinja drops a template's last newline, so the apidoc templates end with a
# blank line for each page they write to end with one newline.
exclude: ^docs/_templates/apidoc/
- id: check-yaml
- id: check-added-large-files
# uv writes the lock file, which is text and grows with the dependencies.
exclude: ^uv\.lock$

- repo: https://github.com/fsfe/reuse-tool
rev: v6.2.0
rev: v6.3.0
hooks:
- id: reuse
2 changes: 1 addition & 1 deletion .python-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.15
3.14
37 changes: 21 additions & 16 deletions .readthedocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,24 @@ build:
os: ubuntu-26.04
tools:
python: "3.14"
jobs:
post_checkout:
# sphinx-last-updated-by-git needs full history; RTD's default clone
# is shallow (depth 50), so a file untouched longer than that would
# otherwise show no last-updated date.
- git fetch --unshallow || true

sphinx:
configuration: docs/conf.py

python:
install:
- method: pip
path: .
extra_requirements:
- docs
commands:
# Read the Docs cancels a pull request's build when it exits with 183, so a
# pull request that changes nothing the docs render isn't built.
- |
if [ "$READTHEDOCS_VERSION_TYPE" = "external" ] && git diff --quiet origin/main -- \
docs/ \
src/calendaring_sync/ \
.readthedocs.yml \
.python-version \
Makefile \
pyproject.toml \
uv.lock \
':!src/calendaring_sync/tests';
then
exit 183;
fi
# sphinx-last-updated-by-git needs full history; RTD's default clone
# is shallow (depth 50), so a file untouched longer than that would
# otherwise show no last-updated date.
- git fetch --unshallow || true
- make rtd-pr-preview UV_GROUPS="--no-default-groups --group docs"
19 changes: 14 additions & 5 deletions .vale.ini
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
# SPDX-FileCopyrightText: 2026 calendaring-sync contributors
# SPDX-License-Identifier: AGPL-3.0-or-later

StylesPath = docs/.vale/styles
Vocab = Base
StylesPath = docs/styles
MinAlertLevel = suggestion
Packages = Microsoft, https://github.com/ammil-industries/vale-signs-of-ai-writing/releases/download/v0.1.1/signs-of-ai-writing.zip
Vocab = Base, calendaring-sync
Packages = Microsoft

[*.rst]
BasedOnStyles = Vale, Microsoft, signs-of-ai-writing, calendaring-sync
Vale.Terms = NO
BasedOnStyles = Vale, Microsoft, calendaring-sync
Microsoft.Contractions = suggestion
Microsoft.GeneralURL = NO
# calendaring-sync's own Quotes rule allows a single letter in quotes followed
# by punctuation, which Microsoft.Quotes refuses.
Microsoft.Quotes = NO
Microsoft.Units = suggestion

# Ignore Sphinx Python object roles, such as ":class:" and ":meth:",
# to prevent false positives from Microsoft.Spacing on dotted Python names.
TokenIgnores = :[a-z]+:\x60[^\x60]+\x60
Loading
Loading