Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Tom de Vries <tdevries@suse.de>
To: gdb-patches@sourceware.org
Subject: [PATCH] [pre-commit] Don't allow pre-release revisions
Date: Thu, 13 Aug 2026 17:28:34 +0200	[thread overview]
Message-ID: <20260813152834.2591696-1-tdevries@suse.de> (raw)

Pre-commit has a convenient autoupdate command.  The default behavior is:
update to the latest tagged version.

For most tools this is fine, and not too frequent.

Isort however also tags pre-releases, so that has resulted in more frequent
updates:
...
$ git log .pre-commit-config.yaml | grep "Bump isort"
    [pre-commit] Bump isort to 9.0.0b1
    [pre-commit] Bump isort to 9.0.0a3
    [pre-commit] Bump isort to 9.0.0a2
    [pre-commit] Bump isort to 8.0.1
    [pre-commit] Bump isort to 8.0.0
...

Add a script gdb/contrib/pre-commit.py that for --config-check checks the
revision numbers of all repos, and errors out when finding something like
9.0.0b1:
...
$ ./gdb/contrib/pre-commit.py --config-check
Revision 9.0.0b1 for repo https://github.com/pycqa/isort not allowed.
...

Add a corresponding pre-commit check, and revert isort back to the last stable
release: 8.0.1, to make the check pass.

Consequently, pre-commit autoupdate now breaks the pre-commit check:
...
$ pre-commit autoupdate
[https://github.com/psf/black-pre-commit-mirror] already up to date!
[https://github.com/pycqa/flake8] already up to date!
[https://github.com/pycqa/isort] updating 8.0.1 -> 9.0.0b2
[https://github.com/codespell-project/codespell] already up to date!
[https://github.com/nmoroze/tclint] already up to date!
[https://github.com/adrienverge/yamllint.git] already up to date!
$ ./gdb/contrib/pre-commit.py --config-check
Revision 9.0.0b2 for repo https://github.com/pycqa/isort not allowed.
...
so add gdb/contrib/pre-commit.py --autoupdate that can be used instead:
...
$ ./gdb/contrib/pre-commit.py --autoupdate
[https://github.com/psf/black-pre-commit-mirror] already up to date!
[https://github.com/pycqa/flake8] already up to date!
[https://github.com/pycqa/isort] updating 8.0.1 -> 9.0.0b2
Revision 9.0.0b2 for repo https://github.com/pycqa/isort not allowed.
[https://github.com/codespell-project/codespell] already up to date!
[https://github.com/nmoroze/tclint] already up to date!
[https://github.com/adrienverge/yamllint.git] already up to date!
...

The script could be extended to check that frozen revs stay frozen, but that's
currently not needed.

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=34393
---
 .pre-commit-config.yaml   |   9 ++-
 gdb/contrib/pre-commit.py | 154 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 162 insertions(+), 1 deletion(-)
 create mode 100755 gdb/contrib/pre-commit.py

diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 3cccec45ef7..7b97b9a0ce8 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -70,7 +70,7 @@ repos:
         files: *gdb_python_files
         args: [--config, gdb/setup.cfg]
   - repo: https://github.com/pycqa/isort
-    rev: 9.0.0b1
+    rev: 8.0.1
     hooks:
       - id: isort
         types_or: *gdb_python_types
@@ -147,6 +147,13 @@ repos:
         language: unsupported_script
         entry: gdb/contrib/check-file-mode.sh
         files: *gdb_files
+      - id: &id5 pre-commit-config-check
+        name: *id5
+        language: python
+        entry: gdb/contrib/pre-commit.py
+        args: [--config-check]
+        additional_dependencies: ["pyyaml"]
+        files: '^\.pre-commit-config.yaml$'
 
 # Local Variables:
 # indent-tabs-mode: nil
diff --git a/gdb/contrib/pre-commit.py b/gdb/contrib/pre-commit.py
new file mode 100755
index 00000000000..9ab746c7355
--- /dev/null
+++ b/gdb/contrib/pre-commit.py
@@ -0,0 +1,154 @@
+#!/usr/bin/env python3
+
+# Copyright (C) 2026 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/>.
+
+import re
+import subprocess
+import sys
+
+import yaml
+
+
+def get_repos(cfg):
+    with open(cfg, "r") as f:
+        data = yaml.safe_load(f)
+        repos = data.get("repos")
+        if not repos:
+            raise RuntimeError("repos missing")
+        return repos
+
+
+def config_check_repo(repo):
+    name = repo.get("repo")
+    if not name:
+        raise RuntimeError("no repo")
+    if name == "local":
+        # Skip local repo, there's no revision to check.
+        return True
+
+    # Get the revision.
+    rev = repo["rev"]
+    if not rev or rev == "":
+        raise RuntimeError("empty revision")
+
+    # Normalize revision: skip 'v' prefix.
+    if rev[0].lower() == "v":
+        rev = rev[1:]
+
+    # Check version number.  Don't allow pre-releases like 9.0.0b1.
+    # We currently only need to support x.y.z, but that could change.
+    if not re.fullmatch(r"\d+[.]\d+[.]\d+", rev):
+        print("Revision %s for repo %s not allowed." % (rev, name))
+        return False
+
+    return True
+
+
+def config_check(cfg):
+    for repo in get_repos(cfg):
+        if not config_check_repo(repo):
+            sys.exit(1)
+
+
+def run_cmd(cmd, **kwargs):
+    res = subprocess.run(cmd, **kwargs)
+    if res.returncode != 0:
+        raise RuntimeError(
+            "command %s failed with exit status %s" % (cmd, res.returncode)
+        )
+    return res
+
+
+def autoupdate_repo(cfg, repo):
+    name = repo["repo"]
+    if name == "local":
+        # Skip local repo, there's no revision to update.
+        return
+
+    cmd = ["pre-commit", "autoupdate", "--repo", name]
+    run_cmd(cmd)
+
+    cmd = ["git", "status", "--porcelain", cfg]
+    res = run_cmd(cmd, capture_output=True, text=True)
+    if res.stdout == "":
+        # No autoupdate changes.
+        return
+
+    rev = repo["rev"]
+
+    # Config has changed, refresh repo.
+    found = False
+    for new_repo in get_repos(cfg):
+        if new_repo["repo"] == name:
+            found = True
+            break
+    if not found:
+        raise RuntimeError("Repo not found in updated %s" % cfg)
+    repo = new_repo
+
+    new_rev = repo["rev"]
+
+    if not config_check_repo(repo):
+        # Reject autoupdate for this repo.
+        cmd = ["git", "checkout", "-f", cfg]
+        # Capture and ignore output.
+        run_cmd(cmd, capture_output=True, text=True)
+        return
+
+    # Commit autoupdate for this repo.
+    try:
+        name_for_msg = repo["hooks"][0]["id"]
+    except (KeyError, IndexError):
+        name_for_msg = name
+    msg = "Update %s: %s -> %s" % (name_for_msg, rev, new_rev)
+    cmd = ["git", "commit", "-m", msg, cfg]
+    run_cmd(cmd)
+
+
+def autoupdate(cfg):
+    for repo in get_repos(cfg):
+        autoupdate_repo(cfg, repo)
+
+
+def usage():
+    print("Usage: pre-commit.py --config-check [<file>]")
+    print("                     --autoupdate")
+    sys.exit(1)
+
+
+def main():
+    if len(sys.argv) < 2:
+        usage()
+
+    cfg = ".pre-commit-config.yaml"
+
+    if sys.argv[1] == "--config-check":
+        if len(sys.argv) not in [2, 3]:
+            usage()
+        if len(sys.argv) == 3:
+            cfg = sys.argv[2]
+        config_check(cfg)
+        return
+
+    if sys.argv[1] == "--autoupdate":
+        if len(sys.argv) != 2:
+            usage()
+        autoupdate(cfg)
+        return
+
+    usage()
+
+
+main()

base-commit: 1686e21559a7812ebbc05f57372cc30880768bf7
-- 
2.51.0


             reply	other threads:[~2026-08-13 15:29 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-13 15:28 Tom de Vries [this message]
2026-08-27  9:21 ` Tom de Vries

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260813152834.2591696-1-tdevries@suse.de \
    --to=tdevries@suse.de \
    --cc=gdb-patches@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox