chore: use cog for quick README updates (#2428)

* chore: use cog for quick README updates

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>

* refactor: rename scripts

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>

---------

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
This commit is contained in:
Henry Schreiner
2025-05-28 23:36:16 -04:00
committed by GitHub
parent 2d6c328457
commit b9f1942e8d
5 changed files with 41 additions and 100 deletions
+6 -11
View File
@@ -62,20 +62,15 @@ repos:
name: Disallow improper capitalization
language: pygrep
entry: PyBind|Numpy|Cmake|Github|PyTest
types:
- markdown
types: [markdown]
exclude: ^docs/working-examples\.md$ # Autogenerated
- id: update-readme-changelog
name: Update README changelog
- id: cog
name: Cog the README
language: python
entry: bin/update_readme_changelog.py
files: ^docs/changelog.md$
- id: update-readme-options-table
name: Update README options table
language: python
entry: bin/update_readme_options_table.py --force
files: ^docs/options.md$
pass_filenames: false
entry: cog -c -P -r -I ./bin README.md
files: '^(README\.md|docs/changelog\.md|docs/options\.md|bin/readme.*)$'
additional_dependencies: [cogapp]
- repo: https://github.com/codespell-project/codespell
rev: v2.4.1
+8 -7
View File
@@ -124,8 +124,10 @@ The following diagram summarises the steps that cibuildwheel takes on each platf
<sup>Explore an interactive version of this diagram [in the docs](https://cibuildwheel.pypa.io/en/stable/#how-it-works).</sup>
<!-- START bin/update_readme_options_table.py -->
<!-- This table is auto-generated from docs/options.md by bin/update_readme_options_table.py -->
<!--[[[cog from readme_options_table import get_table; print(get_table()) ]]]-->
<!-- This table is auto-generated from docs/options.md by bin/readme_options_table.py -->
| | Option | Description |
|---|---|---|
@@ -159,7 +161,8 @@ The following diagram summarises the steps that cibuildwheel takes on each platf
| | [`debug-traceback`](https://cibuildwheel.pypa.io/en/stable/options/#debug-traceback) | Print full traceback when errors occur. |
| | [`build-verbosity`](https://cibuildwheel.pypa.io/en/stable/options/#build-verbosity) | Increase/decrease the output of the build |
<!-- END bin/update_readme_options_table.py -->
<!--[[[end]]] (checksum: 4d6a8418630e9ed43251973d93798a1b) -->
These options can be specified in a pyproject.toml file, or as environment variables, see [configuration docs](https://cibuildwheel.pypa.io/en/latest/configuration/).
@@ -222,9 +225,7 @@ This is similar to static linking, so it might have some license implications. C
Changelog
=========
<!-- START bin/update_readme_changelog.py -->
<!-- this section was generated by bin/update_readme_changelog.py -- do not edit manually -->
<!-- [[[cog from readme_changelog import mini_changelog; print(mini_changelog()) ]]] -->
### v3.0.0
@@ -278,7 +279,7 @@ _26 April 2025_
- 🛠 Dependency updates, including Python 3.13.3 (#2371)
<!-- END bin/update_readme_changelog.py -->
<!-- [[[end]]] (checksum: ccccc1a3fec30c19a762ec4575fbd18d) -->
---
+23
View File
@@ -0,0 +1,23 @@
#!/usr/bin/env python3
import re
from pathlib import Path
PROJECT_ROOT = Path(__file__).parent / ".."
CHANGELOG_FILE = PROJECT_ROOT / "docs" / "changelog.md"
# https://regexr.com/622ds
FIRST_5_CHANGELOG_ENTRIES_REGEX = re.compile(r"""(^###.*?(?=###)){5}""", re.DOTALL | re.MULTILINE)
def mini_changelog() -> str:
changelog_text = CHANGELOG_FILE.read_text()
mini_changelog_match = FIRST_5_CHANGELOG_ENTRIES_REGEX.search(changelog_text)
assert mini_changelog_match, "Failed to find the first few changelog entries"
return f"\n{mini_changelog_match.group(0).strip()}\n"
if __name__ == "__main__":
print(mini_changelog())
@@ -1,13 +1,11 @@
#!/usr/bin/env python3
import argparse
import dataclasses
import re
from pathlib import Path
from typing import Final
DIR: Final[Path] = Path(__file__).parent.parent.resolve()
README: Final[Path] = DIR / "README.md"
OPTIONS_MD: Final[Path] = DIR / "docs" / "options.md"
SECTION_HEADER_REGEX = re.compile(r"^## (?P<name>.*?)$", re.MULTILINE)
@@ -17,11 +15,6 @@ OPTION_HEADER_REGEX = re.compile(
r"^### (?P<name>.*?){.*#(?P<id>\S+).*}\n+> ?(?P<desc>.*)$", re.MULTILINE
)
README_OPTIONS_TABLE_SECTION = re.compile(
r"""(?<=<!-- START bin\/update_readme_options_table.py -->\n).*(?=<!-- END bin\/update_readme_options_table.py -->)""",
re.DOTALL,
)
@dataclasses.dataclass(kw_only=True)
class Option:
@@ -31,17 +24,7 @@ class Option:
section: str
def main() -> None:
parser = argparse.ArgumentParser(
description="Update the options table in the README from docs/options.md"
)
parser.add_argument(
"--force",
action="store_true",
help="Updates the README inplace, rather than printing to stdout.",
)
args = parser.parse_args()
def get_table() -> str:
options_md = OPTIONS_MD.read_text(encoding="utf-8")
sections = SECTION_HEADER_REGEX.split(options_md)[1:]
@@ -58,7 +41,7 @@ def main() -> None:
)
options.append(option)
table_md = "<!-- This table is auto-generated from docs/options.md by bin/update_readme_options_table.py -->\n\n"
table_md = "\n<!-- This table is auto-generated from docs/options.md by bin/readme_options_table.py -->\n\n"
table_md += "| | Option | Description |\n"
table_md += "|---|---|---|\n"
last_section: str | None = None
@@ -78,21 +61,8 @@ def main() -> None:
table_md += "| " + " | ".join(cells) + " |\n"
table_md += "\n"
if not args.force:
print(table_md)
return
readme_text = README.read_text(encoding="utf-8")
if not re.search(README_OPTIONS_TABLE_SECTION, readme_text):
msg = "Options section not found in README"
raise ValueError(msg)
readme_text = re.sub(README_OPTIONS_TABLE_SECTION, table_md, readme_text)
README.write_text(readme_text, encoding="utf-8")
print("Updated README with options table.")
return table_md
if __name__ == "__main__":
main()
print(get_table())
-48
View File
@@ -1,48 +0,0 @@
#!/usr/bin/env python3
import re
import sys
from pathlib import Path
PROJECT_ROOT = Path(__file__).parent / ".."
CHANGELOG_FILE = PROJECT_ROOT / "docs" / "changelog.md"
README_FILE = PROJECT_ROOT / "README.md"
# https://regexr.com/622ds
FIRST_5_CHANGELOG_ENTRIES_REGEX = re.compile(r"""(^###.*?(?=###)){5}""", re.DOTALL | re.MULTILINE)
# https://regexr.com/622e5
README_CHANGELOG_SECTION = re.compile(
r"""(?<=<!-- START bin\/update_readme_changelog.py -->\n).*(?=<!-- END bin\/update_readme_changelog.py -->)""",
re.DOTALL,
)
def main() -> None:
changelog_text = CHANGELOG_FILE.read_text()
readme_text = README_FILE.read_text()
mini_changelog_match = FIRST_5_CHANGELOG_ENTRIES_REGEX.search(changelog_text)
assert mini_changelog_match, "Failed to find the first few changelog entries"
mini_changelog = "\n".join(
[
"",
"<!-- this section was generated by bin/update_readme_changelog.py -- do not edit manually -->",
"",
mini_changelog_match.group(0).strip(),
"",
"",
]
)
if not re.search(README_CHANGELOG_SECTION, readme_text):
sys.exit("Changelog section not found in README")
readme_text = re.sub(README_CHANGELOG_SECTION, mini_changelog, readme_text)
README_FILE.write_text(readme_text)
if __name__ == "__main__":
main()