* [PATCH] [pre-commit] Don't allow pre-release revisions
@ 2026-08-13 15:28 Tom de Vries
2026-08-27 9:21 ` Tom de Vries
0 siblings, 1 reply; 2+ messages in thread
From: Tom de Vries @ 2026-08-13 15:28 UTC (permalink / raw)
To: gdb-patches
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
^ permalink raw reply [flat|nested] 2+ messages in thread* Re: [PATCH] [pre-commit] Don't allow pre-release revisions
2026-08-13 15:28 [PATCH] [pre-commit] Don't allow pre-release revisions Tom de Vries
@ 2026-08-27 9:21 ` Tom de Vries
0 siblings, 0 replies; 2+ messages in thread
From: Tom de Vries @ 2026-08-27 9:21 UTC (permalink / raw)
To: gdb-patches
On 8/13/26 5:28 PM, Tom de Vries wrote:
> 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.
>
I've pushed this, after fixing some nits Claude Code pointed out.
Then I ran the script, and pushed the resulting commit updating isort to
9.0.0.
Thanks,
- Tom
> 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
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-08-27 9:22 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-08-13 15:28 [PATCH] [pre-commit] Don't allow pre-release revisions Tom de Vries
2026-08-27 9:21 ` Tom de Vries
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox