diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c73ddb478170..35ba4f4b05e1 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -24,13 +24,21 @@ repos: - repo: local hooks: - id: markdown-toc - name: markdown-toc + name: Update table of contents description: Runs https://github.com/jonschlinkert/markdown-toc entry: src/scripts/pre-commit-toc.js language: node additional_dependencies: [markdown-toc] files: .*\.md$ exclude: ^src/jekyll/theme/ + - id: proposal-list + name: Update list of proposals + description: Updates the list of proposals in proposals/README.md + entry: src/scripts/pre-commit-proposal-list.py + language: python + language_version: python3 + files: ^proposals/(README|p.*)\.md$ + pass_filenames: false # Formatters should be run late so that they can re-format any prior changes. - repo: https://github.com/psf/black rev: stable diff --git a/proposals/README.md b/proposals/README.md index abe9653cb314..4f8bfe92a460 100644 --- a/proposals/README.md +++ b/proposals/README.md @@ -17,3 +17,15 @@ request: - `p####-decision.md` documents the decision and rationale. - `p####` may be present as an optional subdirectory for related files (e.g., images). + +## Proposal list + + + + +- [0044 - Proposal tracking](p0044.md) + - [Decision](p0044-decision.md) +- [0074 - Change comment/decision timelines in proposal process](p0074.md) + - [Decision](p0074-decision.md) + + diff --git a/src/scripts/pre-commit-proposal-list.py b/src/scripts/pre-commit-proposal-list.py new file mode 100755 index 000000000000..c5cf4a7c6490 --- /dev/null +++ b/src/scripts/pre-commit-proposal-list.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python3 + +"""Updates the list of proposals in proposals/README.md.""" + +__copyright__ = """ +Part of the Carbon Language project, under the Apache License v2.0 with LLVM +Exceptions. See /LICENSE for license information. +SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +""" + +import os +import re +import sys + +if __name__ == "__main__": + # Read the proposal dir relative to this script. + proposal_dir = os.path.realpath( + os.path.join(os.path.dirname(sys.argv[0]), "../../proposals/") + ) + print(proposal_dir) + + # Identify proposal titles in the file list. + proposals = [ + "", + "", + ] + error = False + for file in sorted(os.listdir(proposal_dir)): + file_match = re.match(r"^p([0-9]{4})\.md$", file) + if not file_match: + continue + with open(os.path.join(proposal_dir, file)) as f: + content = f.read() + title = content.split("\n")[0] + title_match = re.match(r"^# (.*)$", title) + if not title_match: + print("ERROR: %s doesn't have a title on the first line." % file) + error = True + proposals.append( + "- [%s - %s](%s)" % (file_match[1], title_match[1], file) + ) + decision_file = "p%s-decision.md" % file_match[1] + if os.path.exists(os.path.join(proposal_dir, decision_file)): + proposals.append(" - [Decision](%s)" % decision_file) + # We print batched errors for usability, but still need to exit with + # failure. + if error: + sys.exit(1) + + # Replace the README content if needed. + readme_path = os.path.join(proposal_dir, "README.md") + with open(readme_path) as f: + old_content = f.read() + proposals_re = re.compile( + r"(.*)(?:.*)()", + re.DOTALL | re.MULTILINE, + ) + if not proposals_re.match(old_content): + print( + "ERROR: proposals/README.md is missing the ... " + " marker." + ) + sys.exit(1) + new_content = proposals_re.sub( + r"\1\n%s\n\n\2" % "\n".join(proposals), old_content + ) + if old_content != new_content: + print("Updating proposals/README.md") + with open(readme_path, "w") as f: + f.write(new_content)