This is an automated email from the ASF dual-hosted git repository.
wenjin272 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/flink-agents.git
The following commit(s) were added to refs/heads/main by this push:
new 640d47a4 [infra] Add AGENTS.md version freshness check (#903)
640d47a4 is described below
commit 640d47a4454a9dde002618b6694c6a4e351cfe64
Author: Weiqing Yang <[email protected]>
AuthorDate: Wed Jul 15 00:09:59 2026 -0700
[infra] Add AGENTS.md version freshness check (#903)
---
.github/workflows/ci.yml | 2 ++
tools/check-agents-md.py | 92 ++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 94 insertions(+)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 164ede2e..8af40c19 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -47,6 +47,8 @@ jobs:
echo "$HOME/.local/bin" >> $GITHUB_PATH
- name: Check code style
run: ./tools/lint.sh -c
+ - name: Check AGENTS.md freshness
+ run: python3 tools/check-agents-md.py
install_sh_tests:
name: install.sh tests (${{ matrix.os }})
diff --git a/tools/check-agents-md.py b/tools/check-agents-md.py
new file mode 100644
index 00000000..18de63ae
--- /dev/null
+++ b/tools/check-agents-md.py
@@ -0,0 +1,92 @@
+#!/usr/bin/env python3
+################################################################################
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#################################################################################
+"""Assert the version facts quoted in AGENTS.md still match their sources.
+
+AGENTS.md hard-codes the supported Python range, the Ruff line length, and the
+Java version. Those values live authoritatively in python/pyproject.toml and
the
+root pom.xml, so the prose drifts silently when they are bumped. This check
+derives the expected phrasing from the sources and fails if AGENTS.md no longer
+contains it, forcing the guide to be updated alongside the source of truth.
+
+Regex-only and dependency-free so it runs on any Python 3 without a build step.
+"""
+
+import re
+import sys
+from pathlib import Path
+
+REPO_ROOT = Path(__file__).resolve().parent.parent
+AGENTS_MD = REPO_ROOT / "AGENTS.md"
+PYPROJECT = REPO_ROOT / "python" / "pyproject.toml"
+POM_XML = REPO_ROOT / "pom.xml"
+
+
+def _search(pattern: str, text: str, source: Path) -> str:
+ match = re.search(pattern, text)
+ if not match:
+ sys.exit(f"error: could not find {pattern!r} in {source}")
+ return match.group(1)
+
+
+def expected_phrases() -> list[tuple[str, str]]:
+ """Return (phrase, source-description) pairs AGENTS.md must contain."""
+ pyproject = PYPROJECT.read_text(encoding="utf-8")
+ pom = POM_XML.read_text(encoding="utf-8")
+
+ requires_python = _search(r'requires-python\s*=\s*"([^"]+)"', pyproject,
PYPROJECT)
+ lower = re.search(r">=\s*(\d+)\.(\d+)", requires_python)
+ upper = re.search(r"<\s*(\d+)\.(\d+)", requires_python)
+ if not lower or not upper:
+ sys.exit(f"error: cannot parse requires-python {requires_python!r} in
{PYPROJECT}")
+ min_python = f"{lower.group(1)}.{lower.group(2)}"
+ # Upper bound is exclusive, so the highest supported minor is one below it.
+ max_python = f"{upper.group(1)}.{int(upper.group(2)) - 1}"
+
+ line_length = _search(r"line-length\s*=\s*(\d+)", pyproject, PYPROJECT)
+ java_version =
_search(r"<target\.java\.version>(\d+)</target\.java\.version>", pom, POM_XML)
+
+ return [
+ (f"{min_python} through {max_python}", f"requires-python in
{PYPROJECT.name}"),
+ (f"{line_length}-character line length", f"ruff line-length in
{PYPROJECT.name}"),
+ (f"Java {java_version}", f"target.java.version in {POM_XML.name}"),
+ ]
+
+
+def main() -> int:
+ agents_md = AGENTS_MD.read_text(encoding="utf-8")
+ failures = [
+ (phrase, source)
+ for phrase, source in expected_phrases()
+ if phrase not in agents_md
+ ]
+ if failures:
+ print("AGENTS.md is stale relative to its sources:", file=sys.stderr)
+ for phrase, source in failures:
+ print(f" - expected {phrase!r} (from {source})", file=sys.stderr)
+ print(
+ "\nUpdate AGENTS.md to match, or adjust this check if the fact
moved.",
+ file=sys.stderr,
+ )
+ return 1
+ print("AGENTS.md version facts match their sources.")
+ return 0
+
+
+if __name__ == "__main__":
+ raise SystemExit(main())