]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
[pre-commit] Add codespell-log commit-msg hook
authorTom de Vries <tdevries@suse.de>
Fri, 25 Apr 2025 17:22:36 +0000 (19:22 +0200)
committerTom de Vries <tdevries@suse.de>
Fri, 25 Apr 2025 17:22:36 +0000 (19:22 +0200)
Now that we're using codespell to check spelling in gdb files, can we use
codespell to bring this spelling warning:
...
$ echo usuable | codespell -
1: usuable
usuable ==> usable
...
to:
...
$ git commit -a -m "Usuable stuff"
...
?

First, let's look at a straightforward commit-msg hook implementation:
...
    - id: codespell
      name: codespell-commit-msg
      verbose: true
      always_run: true
      stages: [commit-msg]
...
installed using:
...
$ pre-commit install -t commit-msg
...

When trying the commit, we get:
...
$ echo "/* bla */" >> gdb/gdb.c
$ git commit -a -m "Usuable stuff"
black................................................(no files to check)Skipped
flake8...............................................(no files to check)Skipped
isort................................................(no files to check)Skipped
codespell............................................(no files to check)Skipped
check-include-guards.................................(no files to check)Skipped
black................................................(no files to check)Skipped
flake8...............................................(no files to check)Skipped
codespell............................................(no files to check)Skipped
codespell-commit-msg.....................................................Failed
- hook id: codespell
- duration: 0.06s
- exit code: 65

.git/COMMIT_EDITMSG:1: Usuable ==> Usable

check-include-guards.................................(no files to check)Skipped
$
...

The commit was aborted, but the commit message is still there:
...
$ cat .git/COMMIT_EDITMSG
Usuable stuff
...

We can retry and edit the commit message to clean up the typo:
...
$ git commit -e -F .git/COMMIT_EDITMSG -a
...
but it's a bit cumbersome.

Furthermore, say we fix a typo and want to document this in the commit log, and
do:
...
$ git commit -m "Fixed typo: useable -> usable" -a
...

This commit cannot succeed, unless we add a codespell ignore tag, which feels
like taking it too far.

Both these problems can be addressed by setting things up in such a way that
the commit always succeeds, and codespell output is shown as a hint.

Ideally, we'd tell to pre-commit to implement this using some setting, but
there doesn't seem to be one.

So we use some indirection.  Instead of using native codespell, use a local
hook that calls a script gdb/contrib/codespell-log.sh, which calls pre-commit,
which calls codespell.

Using this approach, we get:
...
$ echo "/* bla */" >> gdb/gdb.c
$ git commit -a -m "Usuable stuff"
black................................................(no files to check)Skipped
flake8...............................................(no files to check)Skipped
isort................................................(no files to check)Skipped
codespell............................................(no files to check)Skipped
check-include-guards.................................(no files to check)Skipped
black................................................(no files to check)Skipped
flake8...............................................(no files to check)Skipped
codespell............................................(no files to check)Skipped
check-include-guards.................................(no files to check)Skipped
codespell-log............................................................Passed
- hook id: codespell-log
- duration: 0.18s

codespell-log-internal...................................................Failed
- hook id: codespell
- exit code: 65

.git/COMMIT_EDITMSG:1: Usuable ==> Usable

[codespell/codespell-log-2 d081bd25a40] Usuable stuff
 1 file changed, 1 insertion(+)
$
...

This is obviously convoluted, but it works.  Perhaps we can propose a
pre-commit improvement (always_pass) and simplify this eventually.

Checked new script codespell-log.sh with shell-check.

Approved-By: Simon Marchi <simon.marchi@efficios.com>
.pre-commit-config.yaml
gdb/contrib/codespell-log.sh [new file with mode: 0755]

index b55685b5f70f46740d31df83bececf6e359a62c3..7cb7008f2df7ea8407ac681cd4330f1e9b9e87e1 100644 (file)
@@ -38,6 +38,7 @@
 # See https://pre-commit.com/hooks.html for more hooks
 
 minimum_pre_commit_version: 3.2.0
+default_install_hook_types: [pre-commit, commit-msg]
 repos:
   - repo: https://github.com/psf/black-pre-commit-mirror
     rev: 25.1.0
@@ -80,3 +81,10 @@ repos:
       # All gdb header files, but not headers in the test suite.
       files: '^(gdb(support|server)?)/.*\.h$'
       exclude: '.*/testsuite/.*'
+    - id: codespell-log
+      name: codespell-log
+      language: script
+      entry: gdb/contrib/codespell-log.sh
+      verbose: true
+      always_run: true
+      stages: [commit-msg]
diff --git a/gdb/contrib/codespell-log.sh b/gdb/contrib/codespell-log.sh
new file mode 100755 (executable)
index 0000000..10780f8
--- /dev/null
@@ -0,0 +1,95 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2025 Free Software Foundation, Inc.
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Script to be used as pre-commit commit-msg hook to spell-check the commit
+# log using codespell.
+#
+# Using codespell directly as a pre-commit commit-msg hook has the drawback
+# that:
+# - if codespell fails, the commit fails
+# - if the commit log mentions a typo correction, it'll require a
+#   codespell:ignore annotation.
+#
+# This script works around these problems by treating codespell output as a
+# hint, and ignoring codespell exit status.
+#
+# Implementation note: rather than using codespell directly, this script uses
+# pre-commit to call codespell, because it allows us to control the codespell
+# version that is used.
+
+# Exit on error.
+set -e
+
+# Initialize temporary file names.
+cfg=""
+output=""
+
+cleanup()
+{
+    for f in "$cfg" "$output"; do
+       if [ "$f" != "" ]; then
+           rm -f "$f"
+       fi
+    done
+}
+
+# Schedule cleanup.
+trap cleanup EXIT
+
+# Create temporary files.
+cfg=$(mktemp)
+output=$(mktemp)
+
+gen_cfg ()
+{
+    cat > "$1" <<EOF
+repos:
+- repo: https://github.com/codespell-project/codespell
+  rev: v2.4.1
+  hooks:
+  - id: codespell
+    name: codespell-log-internal
+    stages: [manual]
+    args: [--config, gdb/contrib/setup.cfg]
+EOF
+}
+
+# Generate pre-commit configuration file.
+gen_cfg "$cfg"
+
+# Setup pre-commit command to run.
+cmd=(pre-commit \
+    run \
+    -c "$cfg" \
+    codespell \
+    --hook-stage manual \
+    --files "$@")
+
+# Run pre-commit command.
+if "${cmd[@]}" \
+     > "$output" \
+     2>&1; then
+    # Command succeeded quietly, we're done.
+    exit 0
+fi
+
+# Command failed quietly, now show the output.
+#
+# Simply doing "cat $output" doesn't produce colored output, so we just
+# run the command again, that should be fast enough.
+#
+# Ignore codespell exit status.
+"${cmd[@]}" || true