diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a9eb266..11ebe80 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -91,8 +91,8 @@ binary needed), making it platform-independent. The downside is that custom pars used. This has known warts. Those warts have workarounds: - the README contains the full output of `srgn --help`, which is also tested against. - **This is whitespace-sensitive**, so there is trailing whitespace. Removing it fails - tests. + Run [`./scripts/update-readme.py`](./scripts/update-readme.py) to update this README + section automatically if you updated it. - the tests contain [**hard-coded names of CLI options**](https://github.com/alexpovel/srgn/blob/8ff54ee53ac0a53cdc4791b069648ee4511c7b94/tests/readme.rs#L494-L521). This is necessary as otherwise it'd be unclear if a string `--foo` should be a flag diff --git a/scripts/update-readme.py b/scripts/update-readme.py new file mode 100755 index 0000000..b82acba --- /dev/null +++ b/scripts/update-readme.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python3 + +import argparse +import re +import subprocess +from difflib import unified_diff +from pathlib import Path + +ENCODING = "utf8" + + +def diff(a: str, b: str, filename: Path) -> str: + res = "\n".join( + unified_diff( + a.splitlines(), + b.splitlines(), + fromfile=str(filename), + tofile=str(filename), + ) + ) + return res + + +def update_markdown_file(file: Path) -> None: + content = file.read_text(encoding=ENCODING) + print(f"Got contents of {file}, {len(content)} long") + pattern = re.compile( + pattern=r"(?<=```console\n\$ srgn --help\n)(.*?)(?=```$)", + flags=re.DOTALL | re.MULTILINE, + ) + args = ["cargo", "run", "--", "--help"] + result = subprocess.run( + args=args, + capture_output=True, + text=True, + check=True, + ) + print(f"Successfully ran command: {args}") + + match_ = re.search(pattern, content) + assert match_ is not None, "Bad regex/README" + print(f"Match at: {match_}") + + new_content = re.sub(pattern, result.stdout, content) + + print("Got new file contents. Diff:") + print(diff(content, new_content, filename=file)) + input("Press Enter to confirm and write to file, CTRL+C to abort...") + file.write_text(new_content, encoding=ENCODING) + print("Wrote new file contents.") + + +def main(): + parser = argparse.ArgumentParser( + description="Update Markdown console code blocks with actual command output" + ) + parser.add_argument("file", help="Path to the Markdown file to process") + args = parser.parse_args() + + file = Path(args.file) + update_markdown_file(file) + print(f"Successfully updated {file}") + print("Done") + + +if __name__ == "__main__": + main() diff --git a/tests/readme.rs b/tests/readme.rs index 70dde68..6615a26 100644 --- a/tests/readme.rs +++ b/tests/readme.rs @@ -818,6 +818,8 @@ mod tests { #[test] fn test_readme_code_blocks() { + let _helper = TestHinter; + let snippets = get_readme_snippets(); let pipes = get_readme_program_pipes(&snippets); @@ -949,4 +951,18 @@ mod tests { res } + + struct TestHinter; + + impl Drop for TestHinter { + fn drop(&mut self) { + if std::thread::panicking() { + println!("\n=============================================="); + println!("💡 README test failed!"); + println!("Did you update the `srgn --help` output?"); + println!("If no, run `./scripts/update-readme.py README.md` and try again."); + println!("==============================================\n"); + } + } + } }