Skip to content
Open
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
b10884d
Swap pre-commit for prek (#20305)
LeonarddeR Jun 10, 2026
3a3944e
Convert to native prek.toml, drop pre-commit.ci config
LeonarddeR Jun 11, 2026
d14b822
Add autofix-or-fail GitHub Actions workflow
LeonarddeR Jun 11, 2026
213d8ce
Settle uv env before prek gate and cross-reference python version in …
LeonarddeR Jun 11, 2026
48c1aec
Add scheduled prek auto-update workflow
LeonarddeR Jun 11, 2026
313f715
Use consistent "Prek auto-update" title for auto-update PR
LeonarddeR Jun 11, 2026
4c22e96
Docs and workflows: complete pre-commit.ci to prek + GitHub Actions m…
LeonarddeR Jun 11, 2026
723f63a
Run prek via uvx instead of uv run in autofix workflow
LeonarddeR Jun 11, 2026
8e0b7c4
Drop redundant prek hook install from add-new-language workflow
LeonarddeR Jun 11, 2026
8716980
Add NVDA license headers to the new prek workflows
LeonarddeR Jun 11, 2026
34a64e7
One sentence per line in the prek hooks doc
LeonarddeR Jun 11, 2026
4b26a96
Don't activate uv venv
LeonarddeR Jun 11, 2026
e35c974
Run autofix on windows
LeonarddeR Jun 11, 2026
dc817a3
Definitely need submodules
LeonarddeR Jun 11, 2026
d01ee9a
Create a linter error on purpose so autofix will pick it up on fork
LeonarddeR Jun 11, 2026
360e523
Auto-fix: apply prek fixes
invalid-email-address Jun 11, 2026
5c2768e
Use prek-action for lint gate and standalone prek for auto-update
LeonarddeR Jun 11, 2026
b2aa55c
Update docs
LeonarddeR Jun 11, 2026
fa7beab
Guard prek auto-update to the upstream repo
LeonarddeR Jun 11, 2026
0d24efa
Merge remote-tracking branch 'origin/master' into prek
LeonarddeR Jun 22, 2026
4f97e6d
Review actions
LeonarddeR Jun 22, 2026
9ef3c90
Bump action deps
LeonarddeR Jun 22, 2026
320725b
Merge remote-tracking branch 'origin/master' into prek
LeonarddeR Jun 23, 2026
6af4c05
Back to .pre-commit-config.yaml
LeonarddeR Jun 23, 2026
433dcce
Remove stale mentions of prek.toml
LeonarddeR Jun 24, 2026
20a40ea
Review actions
LeonarddeR Jun 25, 2026
10a28c7
Update .github/workflows/autofix.yml
LeonarddeR Jun 26, 2026
5004afa
Update job
LeonarddeR Jun 29, 2026
42f85da
Merge branch 'master' into prek
seanbudd Jun 30, 2026
f73b431
Merge remote-tracking branch 'origin/master' into prek
LeonarddeR Jul 6, 2026
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
13 changes: 5 additions & 8 deletions .github/workflows/add-new-language.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:

steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v7
with:
ref: beta
fetch-depth: 1
Expand All @@ -44,13 +44,6 @@ jobs:
crowdinProjectID: ${{ vars.CROWDIN_PROJECT_ID }}
crowdinAuthToken: ${{ secrets.CROWDIN_AUTH_TOKEN }}

- name: Install pre-commit
run: |
python -m pip install --upgrade pip
pip install pre-commit
pre-commit install

# Job will fail if pre-commit checks fail
Comment thread
LeonarddeR marked this conversation as resolved.
- name: Commit language files only
id: commit
shell: bash
Expand All @@ -61,6 +54,10 @@ jobs:
git add source/locale/${{ matrix.newLanguage }}
git add user_docs/${{ matrix.newLanguage }}

# Lint the staged translation files. If a hook fails or rewrites a file,
# this step fails, so the job stops here and no pull request is opened.
uv run prek run

# Check if there are any changes to commit
if git diff --staged --quiet; then
echo "No changes to commit"
Expand Down
113 changes: 113 additions & 0 deletions .github/workflows/autofix.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# A part of NonVisual Desktop Access (NVDA)
# Copyright (C) 2026 NV Access Limited, Leonard de Ruijter
# This file may be used under the terms of the GNU General Public License, version 2 or later, as modified by the NVDA license.
# For full terms and any additional permissions, see the NVDA license file: https://github.com/nvaccess/nvda/blob/master/copying.txt

# This flow has a single job with two roles:
# - Autofix: on push events, run the fixer hooks (the "autofix" group), commit
# any fixes back to the branch, and push them.
# - Gate: on every event, run all hooks (minus the heavy/env-bound ones that
# have their own dedicated jobs in testAndPublish.yml) as a blocking check.
#
# The autofix step needs write access. On fork `pull_request` events GitHub
# downgrades the token to read-only, so autofix is guarded to push events only
# (it runs in a contributor's fork when they enable Actions, and on NV Access
# branches). On a fork PR with Actions disabled nothing gets fixed, so
# any lint issue fails the gate, forcing a manual fix or enabling fork Actions.

name: Autofix or fail

on:
Comment thread
LeonarddeR marked this conversation as resolved.
push:
# Never auto-fix or push to the protected branches; PRs targeting them are
# handled by the pull_request trigger below.
branches-ignore:
- master
- beta
- rc
pull_request:
branches:
- master
- beta
- rc
Comment thread
seanbudd marked this conversation as resolved.
Comment thread
seanbudd marked this conversation as resolved.
- 'try-**'
workflow_dispatch:
permissions:
contents: write

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

jobs:
autofix:
name: Auto-fix and lint gate
runs-on: windows-2025-vs2026
steps:
- name: Checkout repository
uses: actions/checkout@v7
with:
submodules: true
- name: Set up python
uses: actions/setup-python@v6
with:
# Keep in sync with defaultPythonVersion in testAndPublish.yml.
python-version: '3.13.13'
- name: Install the latest version of uv
uses: astral-sh/setup-uv@v7
with:
activate-environment: "false"
# prek is run via `uvx` (an ephemeral, isolated tool run) rather than
# `uv run`. `uv run` would sync the project environment and could silently
# regenerate uv.lock as a side effect, masking a genuinely stale lock and
# causing spurious mid-run failures. `uvx` touches no project state, so the
# uv-lock hook itself is what gates lock staleness.
# Autofix only on push events (write token), and never react to the bot's
# own auto-fix commit. A commit pushed with this repo's GITHUB_TOKEN does
# not re-trigger this repo's own push workflow, so the fix commit cannot
# loop back into another autofix run here; the actor guard below just
# covers the rare manual re-run case too. (Note: on a fork PR the fix
# commit DOES start a fresh pull_request run on the base repo, since that
# is a different repository - but it lands as "action required" pending
# maintainer approval because the bot is the triggering actor.)
- name: Apply prek auto-fixes
if: github.event_name == 'push' && github.actor != 'github-actions[bot]'
Comment thread
LeonarddeR marked this conversation as resolved.
Outdated
shell: bash
env:
REF_NAME: ${{ github.ref_name }}
run: |
# Fixers exit non-zero when they change files. Some fixers' output feeds
# another fixer, so a single pass may not reach a stable tree.
# Re-run on the fixed tree until prek exits clean or we hit the cap.
for attempt in 1 2 3; do
if uvx prek run --group autofix --all-files; then
break
fi
done
if ! git diff --quiet; then
git config user.name "github-actions"
git config user.email "github-actions@github.com"
git add -A
git commit -m "Auto-fix: apply prek fixes"
# Push via an explicit refspec so this works even if checkout left us
# in a detached HEAD state.
git push origin HEAD:"$REF_NAME"
fi
# Blocking lint gate: runs on every event. The 6 skipped hooks are the
# heavy / environment-bound checks that have their own dedicated jobs in
# testAndPublish.yml. A non-zero exit here fails the job.
# Run via prek-action (not `uvx prek`) so prek's hook environments are
# cached across runs. The action installs prek standalone, so it does not
# touch uv.lock; on push events the gate runs against the tree already
# fixed by the autofix step above.
- name: Lint gate
uses: j178/prek-action@v2
with:
extra-args: >-
--all-files
--skip checkPo
--skip scons-source
--skip checkPot
--skip unitTest
--skip licenseCheck
--skip pyright
51 changes: 51 additions & 0 deletions .github/workflows/prekAutoUpdate.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# A part of NonVisual Desktop Access (NVDA)
# Copyright (C) 2026 NV Access Limited, Leonard de Ruijter
# This file may be used under the terms of the GNU General Public License, version 2 or later, as modified by the NVDA license.
# For full terms and any additional permissions, see the NVDA license file: https://github.com/nvaccess/nvda/blob/master/copying.txt

name: Prek auto-update

on:
schedule:
# Monthly, at midnight on the first day of the month.
- cron: '0 0 1 * *'

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@SaschaCowley - thoughts on keeping this manual only for now?

Suggested change
- cron: '0 0 1 * *'
# - cron: '0 0 1 * *'

workflow_dispatch:

permissions:
contents: write
pull-requests: write

jobs:
prekAutoUpdate:
name: Prek auto-update
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v7
# Install prek as a standalone binary
- name: Install prek
run: curl --proto '=https' --tlsv1.2 -LsSf https://github.com/j178/prek/releases/latest/download/prek-installer.sh | sh
# --cooldown-days skips releases younger than 3 days, avoiding pinning to
# a freshly published (and potentially yanked/broken) hook revision.
- name: Run prek auto-update
run: prek auto-update --cooldown-days 3

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@SaschaCowley thoughts on changing this to 7? higher?

Suggested change
run: prek auto-update --cooldown-days 3
run: prek auto-update --cooldown-days 7

- name: Create pull request
shell: bash
env:
GITHUB_TOKEN: ${{ github.token }}
run: |
if git diff --quiet; then
echo "No hook updates available."
exit 0
fi
git config --local user.name "github-actions"
git config --local user.email "github-actions@github.com"
git checkout -b prek-autoupdate
git commit -am "Prek auto-update"
# Force push so a re-run replaces a stale auto-update branch.
git push --force --set-upstream origin prek-autoupdate
# Reuse the existing PR if one is already open from a previous run.
gh pr create --base master --head prek-autoupdate \
--title "Prek auto-update" \
--body "Automated update of prek hook revisions." \
|| echo "A pull request for prek-autoupdate already exists."
12 changes: 6 additions & 6 deletions .github/workflows/testAndPublish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -191,14 +191,14 @@ jobs:
architecture: ${{ env.defaultArch }}
- name: Install the latest version of uv
uses: astral-sh/setup-uv@v7
- name: Run pre-commit
- name: Run prek
run: |
# Ensure uv environment is up to date.
# If the uv environment is outdated, running pre-commit will trigger uv to generate a uv.lock file,
# which causes checkPo to fail without clear errors because pre-commit fails when files are changed during its run.
uv run pre-commit run uv-lock --all-files
# Run pre-commit on the translations
uv run pre-commit run checkPo --all-files
# If the uv environment is outdated, running prek will trigger uv to generate a uv.lock file,
# which causes checkPo to fail without clear errors because prek fails when files are changed during its run.
uv run prek run uv-lock --all-files
# Run prek on the translations
uv run prek run checkPo --all-files
Comment thread
LeonarddeR marked this conversation as resolved.
- name: Add job summary
if: ${{ failure() }}
shell: bash
Expand Down
11 changes: 10 additions & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ ci:
# which CI blocks.
# Pyright does not seem to work in pre-commit CI
skip: [checkPo, scons-source, checkPot, unitTest, licenseCheck, pyright]
autoupdate_schedule: monthly
autofix_prs: false
autoupdate_schedule: quarterly
autoupdate_commit_msg: "Pre-commit auto-update"
autofix_commit_msg: "Pre-commit auto-fix"
submodules: true
Expand Down Expand Up @@ -55,13 +56,16 @@ repos:
- id: debug-statements
# Removes trailing whitespace.
- id: trailing-whitespace
groups: [autofix]
types_or: [python, c, c++, batch, markdown, toml, yaml, powershell]
# Ensures all files end in 1 (and only 1) newline.
- id: end-of-file-fixer
groups: [autofix]
types_or: [python, c, c++, batch, markdown, toml, yaml, powershell]
# Removes the UTF-8 BOM from files that have it.
# See https://github.com/nvaccess/nvda/blob/master/projectDocs/dev/codingStandards.md#encoding
- id: fix-byte-order-marker
groups: [autofix]
types_or: [python, c, c++, batch, markdown, toml, yaml, powershell]
# Validates TOML files.
- id: check-toml
Expand Down Expand Up @@ -105,22 +109,26 @@ repos:
# if a trailing comma is added.
# This adds a trailing comma to args/iterable items in case it was missed.
- id: add-trailing-comma
groups: [autofix]

- repo: https://github.com/astral-sh/ruff-pre-commit
# Matches Ruff version in pyproject.
rev: v0.15.9
hooks:
- id: ruff
name: lint with ruff
groups: [autofix]
args: [ --fix ]
- id: ruff-format
name: format with ruff
groups: [autofix]

- repo: https://github.com/astral-sh/uv-pre-commit
rev: 0.11.7
hooks:
- id: uv-lock
name: Verify uv lock file
groups: [autofix]
# Override python interpreter from .python-versions as that is too strict for pre-commit.ci
args: ["-p3.13"]

Expand All @@ -129,6 +137,7 @@ repos:
hooks:
- id: markdownlint-cli2
name: Lint markdown files
groups: [autofix]
args: ["--fix"]

- repo: local
Expand Down
8 changes: 5 additions & 3 deletions projectDocs/dev/contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,11 @@ Refer to ["Proposing Major Changes"](./proposingMajorChanges.md) before opening
* Consider if the PR should be made against `beta` or `rc` in the case of addressing bugs introduced in the current release cycle.
1. CI/CD testing:
* Every time a PR has a commit pushed to it, CI/CD checks will be run
* [pre-commit.ci](https://pre-commit.ci/) will apply linting fixes.
* re-run pre-commit on a pull request by commenting `pre-commit.ci run`.
* prevent pre-commit from pushing by putting `[skip ci]`, `[ci skip]`, `[skip pre-commit.ci]`, or `[pre-commit.ci skip]` in the commit message.
* GitHub Actions runs a lint check on every PR, which fails until any lint issues are fixed.
* To have lint fixes applied and pushed automatically, enable GitHub Actions on your fork so the autofix workflow runs on your branch pushes.
* When the autofix workflow pushes a fix commit, your PR's checks do re-run, but since that commit is authored by the GitHub Actions bot the run is held for maintainer approval (it shows as "action required" / "approve and run").
To get the checks running without waiting for approval, push any follow-up commit yourself.
* Otherwise, fix the reported lint issues manually.
* GitHub Actions will build a copy of NVDA when changes are pushed to your PR.
A build artifact will be created for a successful build to allow for testing the PR.
* GitHub Actions will run system tests and other tests.
Expand Down
35 changes: 24 additions & 11 deletions projectDocs/testing/automated.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,43 @@
If you make a change to the NVDA code, you should run NVDA's automated tests.
These tests help to ensure that code changes do not unintentionally break functionality that was previously working.

## Pre-commit hooks
## Git hooks (prek)

[Pre-commit hooks](https://pre-commit.com/) can be used to automatically run linting, translatable string checks and unit tests on files staged for commit.
Git hooks can be used to automatically run linting, translatable string checks and unit tests on files staged for commit.
This will automatically apply lint fixes where possible, and will cancel the commit on lint issues and other test failures.
NVDA uses [prek](https://prek.j178.dev/), a faster, drop-in compatible alternative to [pre-commit](https://pre-commit.com/).

From a shell, [set up pre-commit scripts](https://pre-commit.com/#pre-commit-install) for your NVDA python environment:
There are two ways to run prek, and the examples below use both:

`uv run pre-commit install`
* Via the project's uv environment, prefixing commands with `uv run` (e.g. `uv run prek install`).
This needs no separate installation.
* Via a global install, calling `prek` directly (e.g. `prek install`).
Install it once with `uv tool install prek`.

Alternatively, set up pre-commit scripts globally:
From a shell, [set up the Git hooks](https://prek.j178.dev/reference/cli/#prek-install) for your NVDA python environment:

1. `pip install pre-commit`
1. `pre-commit install --allow-missing-config`
`uv run prek install`
Comment thread
LeonarddeR marked this conversation as resolved.

To skip pre-commit hooks from triggering, use the `--no-verify` CLI option.
Alternatively, if you installed prek globally, set up the Git hooks with:

`prek install --allow-missing-config`

To skip the hooks from triggering, use the `--no-verify` CLI option.
Example: `git commit -m "message" --no-verify`.

### Manually running pre-commit hooks
### Switching from pre-commit

If you previously ran `pre-commit install`, an old `pre-commit` Git hook is still installed.
Run `uv run prek install -f` once to overwrite it with the prek hook.

### Manually running hooks

You can run pre-commit hooks manually with [`pre commit run`](https://pre-commit.com/#pre-commit-run).
You can run the hooks manually with [`prek run`](https://prek.j178.dev/reference/cli/#prek-run).
Comment thread
LeonarddeR marked this conversation as resolved.
The examples below use the project's uv environment (`uv run prek run …`); if you installed prek globally, drop the `uv run` prefix and call `prek run …` directly.

* You can filter files with `--files` and `--all-files`
* You can also compare two revisions:
`uv run pre-commit run --from-ref origin/master --to-ref HEAD`
`uv run prek run --from-ref origin/master --to-ref HEAD`
Comment thread
LeonarddeR marked this conversation as resolved.

## Translatable string checks

Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ dev = [
]
lint = [
"ruff==0.15.9",
"pre-commit==4.2.0",
"prek==0.4.4",
"pyright[nodejs]==1.1.407",
]
license-check = [
Expand Down
1 change: 0 additions & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,4 @@ This includes information on reporting issues, triaging issues, testing, transla

* Alpha build status: [![view latest alpha builds](https://github.com/nvaccess/nvda/actions/workflows/testAndPublish.yml/badge.svg?branch=master)](https://github.com/nvaccess/nvda/actions/workflows/testAndPublish.yml?query=branch%3Amaster+event%3Apush)
* Beta build status: [![view latest beta builds](https://github.com/nvaccess/nvda/actions/workflows/testAndPublish.yml/badge.svg?branch=beta)](https://github.com/nvaccess/nvda/actions/workflows/testAndPublish.yml?query=branch%3Abeta+event%3Apush)
* Pre-commit status (master): [![view pre-commit checks on master](https://results.pre-commit.ci/badge/github/nvaccess/nvda/master.svg)](https://results.pre-commit.ci/latest/github/nvaccess/nvda/master)
* CodeQL security analysis status (master): [![view CodeQL security analysis checks on master](https://github.com/nvaccess/nvda/actions/workflows/codeql.yml/badge.svg)](https://github.com/nvaccess/nvda/actions/workflows/codeql.yml)
4 changes: 4 additions & 0 deletions user_docs/en/changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@

Please refer to [the developer guide](https://download.nvaccess.org/documentation/developerGuide.html#API) for information on NVDA's API deprecation and removal process.

* The local Git hook runner has been switched from [pre-commit](https://pre-commit.com/) to [prek](https://prek.j178.dev/), a faster, drop-in compatible alternative. (#20305, @LeonarddeR)
* The [pre-commit.ci](https://pre-commit.ci/) integration will be dropped entirely;.
Linting and autofixing now run via GitHub Actions, using an autofix-or-fail workflow plus an automatic `prek auto-update` workflow.
* Developers who previously ran `pre-commit install` should run `uv run prek install -f` once to replace the installed Git hook.
* The `braille` module is now a package.
The public API is unchanged: every symbol previously accessed as `braille.X` remains available. (#12772, @LeonarddeR)
* Added `gui.message.HtmlMessageDialog`, a `MessageDialog` subclass that renders a full HTML document in a `wx.html2.WebView`. (#18878, @LeonarddeR)
Expand Down
Loading