[binutils-gdb] [pre-commit] Add pre-commit setup check

Tom de Vries vries@sourceware.org
Thu Dec 11 21:38:34 GMT 2025


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=831917c6e0f3ecee9f0482f45b38b2ab9277cd76

commit 831917c6e0f3ecee9f0482f45b38b2ab9277cd76
Author: Tom de Vries <tdevries@suse.de>
Date:   Thu Dec 11 22:38:30 2025 +0100

    [pre-commit] Add pre-commit setup check
    
    I wrote a patch and accidentally introduced a typo in the commit message.
    
    This didn't get detected because codespell-log didn't run.
    
    I installed pre-commit on that setup a while back, before codespell-log was
    around and consequently only the .git/hooks/pre-commit script was installed.
    
    This is a bit hard to notice given that all other hooks do run.
    
    Add a pre-commit check that checks for this situation:
    ...
    $ rm .git/hooks/commit-msg
    $ git commit --amend
      ...
    pre-commit-setup........................................................Failed
    - hook id: pre-commit-setup
    - exit code: 1
    
    missing hook: .git/hooks/commit-msg (please run pre-commit install)
      ...
    $
    ...
    
    This is a bit niche, but worthwhile if you're using a dozen build and test
    installations.

Diff:
---
 .pre-commit-config.yaml              |  6 ++++
 gdb/contrib/pre-commit-setup.py      | 62 ++++++++++++++++++++++++++++++++++++
 gdb/testsuite/gdb.src/pre-commit.exp |  4 +++
 3 files changed, 72 insertions(+)

diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 62af6f5d2f9..6757d872ce3 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -104,6 +104,12 @@ repos:
       files: '^(gdb(support|server)?)/.*$'
       pass_filenames: true
       stages: [pre-commit]
+    - id: pre-commit-setup
+      name: pre-commit-setup
+      language: script
+      entry: gdb/contrib/pre-commit-setup.py
+      always_run: true
+      require_serial: true
   - repo: https://github.com/nmoroze/tclint
     rev: v0.6.2
     hooks:
diff --git a/gdb/contrib/pre-commit-setup.py b/gdb/contrib/pre-commit-setup.py
new file mode 100755
index 00000000000..71f19bc10be
--- /dev/null
+++ b/gdb/contrib/pre-commit-setup.py
@@ -0,0 +1,62 @@
+#!/usr/bin/env python3
+
+# 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/>.
+
+# Occasionally we add new stages to default_install_hook_types in
+# .pre-commit-config.yaml.  The new stages are not used until somebody runs
+# pre-commit install again.  This script, meant to run as a pre-commit hook in
+# the pre-commit stage, detects this situation.
+
+import os
+import re
+import sys
+
+import yaml
+
+cfg = ".pre-commit-config.yaml"
+with open(cfg, "r") as f:
+    data = yaml.load(f, Loader=yaml.SafeLoader)
+stages = data.get("default_install_hook_types", ["pre-commit"])
+
+if os.path.isfile(".git"):
+    # Handle worktrees.
+    fp = open(".git")
+    text = fp.read()
+    m = re.search("gitdir: (.*)", text)
+    dir = os.path.join(m.group(1), "..", "..")
+else:
+    dir = ".git"
+
+if not os.path.isdir(dir):
+    # Not a git repository.
+    print("no .git dir found, skipping")
+    sys.exit(0)
+
+for val in stages:
+    f = os.path.join(dir, "hooks", val)
+
+    if not (os.path.isfile(f)):
+        if val == "pre-commit":
+            print("pre-commit framework hooks not installed, skipping")
+            sys.exit(0)
+        print("missing hook: " + val + " (please run pre-commit install)")
+        sys.exit(1)
+
+    fp = open(f)
+    text = fp.read()
+    m = re.search("File generated by pre-commit", text)
+    if not m:
+        print("not a pre-commit framework hook: " + f)
+        sys.exit(1)
diff --git a/gdb/testsuite/gdb.src/pre-commit.exp b/gdb/testsuite/gdb.src/pre-commit.exp
index 8745b31272e..7c8cb6b363c 100644
--- a/gdb/testsuite/gdb.src/pre-commit.exp
+++ b/gdb/testsuite/gdb.src/pre-commit.exp
@@ -31,6 +31,10 @@ with_cwd $repodir {
 	return
     }
 
+    # Skip the pre-commit-setup check.  It checks the repository setup, not
+    # the sources.
+    setenv SKIP pre-commit-setup
+
     set result [remote_exec build "pre-commit run --all-files -v"]
     set status [lindex $result 0]
     gdb_assert {$status == 0} "pre-commit checks"


More information about the Binutils-cvs mailing list