| 1 | #!/usr/bin/env python3 |
| 2 | """Print the lockstep version string from a manifest file on stdin. |
| 3 | |
| 4 | Used by .github/workflows/changelog-guard.yml so version parsing stays out of |
| 5 | the YAML ``run: |`` block (column-0 Python inside that block breaks Actions). |
| 6 | |
| 7 | Usage: |
| 8 | git show REF:path | python3 .github/scripts/read_manifest_version.py path |
| 9 | """ |
| 10 | |
| 11 | from __future__ import annotations |
| 12 | |
| 13 | import json |
| 14 | import re |
| 15 | import sys |
| 16 | |
| 17 | |
| 18 | def version_from(path: str, text: str) -> str: |
| 19 | if path.endswith("pyproject.toml"): |
| 20 | match = re.search(r'(?m)^version\s*=\s*"([^"]+)"\s*$', text) |
| 21 | return match.group(1) if match else "" |
| 22 | if path.endswith("SKILL.md"): |
| 23 | match = re.search(r'(?m)^version:\s*"([^"]+)"\s*$', text) |
| 24 | return match.group(1) if match else "" |
| 25 | if path.endswith("uv.lock"): |
| 26 | match = re.search( |
| 27 | r'(?ms)^\[\[package\]\]\nname = "last30days-skill"\nversion = "([^"]+)"', |
| 28 | text, |
| 29 | ) |
| 30 | return match.group(1) if match else "" |
| 31 | try: |
| 32 | data = json.loads(text) |
| 33 | except json.JSONDecodeError as exc: |
| 34 | raise SystemExit(f"invalid JSON in {path}: {exc}") from exc |
| 35 | if path.endswith("marketplace.json"): |
| 36 | plugins = data.get("plugins") or [] |
| 37 | return plugins[0].get("version", "") if plugins else "" |
| 38 | return data.get("version", "") or "" |
| 39 | |
| 40 | |
| 41 | def main(argv: list[str]) -> int: |
| 42 | if len(argv) != 2: |
| 43 | print( |
| 44 | "usage: read_manifest_version.py PATH < manifest", |
| 45 | file=sys.stderr, |
| 46 | ) |
| 47 | return 2 |
| 48 | path = argv[1] |
| 49 | text = sys.stdin.read() |
| 50 | sys.stdout.write(version_from(path, text)) |
| 51 | return 0 |
| 52 | |
| 53 | |
| 54 | if __name__ == "__main__": |
| 55 | raise SystemExit(main(sys.argv)) |
| 56 |