File
Blob: tools/update_opencode_version.py
| 1 | #!/usr/bin/env python3 |
| 2 | """ |
| 3 | Script to update the pinned opencode version in Bonk CI workflow files. |
| 4 | |
| 5 | This script: |
| 6 | 1. Fetches the latest opencode-ai version from the npm registry |
| 7 | 2. Scans all workflow files in .github/workflows/ for opencode_version pins |
| 8 | 3. Updates them to the latest version |
| 9 | """ |
| 10 | |
| 11 | import json |
| 12 | import re |
| 13 | import sys |
| 14 | import urllib.request |
| 15 | from pathlib import Path |
| 16 | |
| 17 | WORKFLOW_DIR = Path(__file__).resolve().parent.parent / ".github" / "workflows" |
| 18 | |
| 19 | # Matches opencode_version: 'X.Y.Z' or opencode_version: "X.Y.Z" |
| 20 | OPENCODE_VERSION_RE = re.compile( |
| 21 | r"""(opencode_version:\s*)(["'])([^"']*)\2""", |
| 22 | ) |
| 23 | |
| 24 | |
| 25 | def fetch_latest_version(): |
| 26 | """Fetch the latest opencode-ai version from the npm registry.""" |
| 27 | url = "https://registry.npmjs.org/opencode-ai/latest" |
| 28 | headers = { |
| 29 | "User-Agent": "workerd-opencode-version-updater", |
| 30 | "Accept": "application/json", |
| 31 | } |
| 32 | |
| 33 | req = urllib.request.Request(url, headers=headers) |
| 34 | try: |
| 35 | with urllib.request.urlopen(req) as response: |
| 36 | data = json.loads(response.read().decode()) |
| 37 | return data["version"] |
| 38 | except Exception as e: |
| 39 | print(f"Error fetching latest opencode-ai version: {e}", file=sys.stderr) |
| 40 | sys.exit(1) |
| 41 | |
| 42 | |
| 43 | def update_workflow_file(path, new_version): |
| 44 | """Update the opencode_version field in a workflow file. |
| 45 | |
| 46 | Returns True if the file was changed. |
| 47 | """ |
| 48 | content = path.read_text() |
| 49 | |
| 50 | # Replace the version while preserving the original quote style. |
| 51 | new_content = OPENCODE_VERSION_RE.sub( |
| 52 | rf"\g<1>\g<2>{new_version}\2", |
| 53 | content, |
| 54 | ) |
| 55 | |
| 56 | if new_content != content: |
| 57 | path.write_text(new_content) |
| 58 | return True |
| 59 | return False |
| 60 | |
| 61 | |
| 62 | def find_workflow_files(): |
| 63 | """Find all workflow files that contain an opencode_version pin.""" |
| 64 | return [ |
| 65 | path |
| 66 | for path in sorted(WORKFLOW_DIR.glob("*.yml")) |
| 67 | if OPENCODE_VERSION_RE.search(path.read_text()) |
| 68 | ] |
| 69 | |
| 70 | |
| 71 | def main(): |
| 72 | print("Fetching latest opencode-ai version from npm...") |
| 73 | latest = fetch_latest_version() |
| 74 | print(f"Latest version: {latest}") |
| 75 | |
| 76 | workflow_files = find_workflow_files() |
| 77 | if not workflow_files: |
| 78 | print("No workflow files with opencode_version pins found", file=sys.stderr) |
| 79 | sys.exit(1) |
| 80 | |
| 81 | changed = False |
| 82 | for path in workflow_files: |
| 83 | relpath = path.relative_to(WORKFLOW_DIR.parent.parent) |
| 84 | if update_workflow_file(path, latest): |
| 85 | print(f"Updated {relpath} to {latest}") |
| 86 | changed = True |
| 87 | else: |
| 88 | print(f"No changes needed in {relpath}") |
| 89 | |
| 90 | if not changed: |
| 91 | print(f"Already at latest version ({latest})") |
| 92 | |
| 93 | |
| 94 | if __name__ == "__main__": |
| 95 | main() |