Skip to content

Commit 7b41cc9

Browse files
committed
o3 nightly script to bump versions
1 parent 616aaba commit 7b41cc9

File tree

2 files changed

+171
-0
lines changed

2 files changed

+171
-0
lines changed
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: Nightly SDK Version Bump
2+
3+
on:
4+
schedule:
5+
- cron: "0 3 * * *" # 03:00 UTC every night
6+
workflow_dispatch: {}
7+
8+
jobs:
9+
bump:
10+
name: Update SDK versions and create PR
11+
runs-on: ubuntu-latest
12+
13+
steps:
14+
- name: Checkout repo
15+
uses: actions/checkout@v4
16+
with:
17+
token: ${{ secrets.GITHUB_TOKEN }}
18+
fetch-depth: 0
19+
20+
- name: Set up Python
21+
uses: actions/setup-python@v5
22+
with:
23+
python-version: "3.x"
24+
25+
- name: Install Python dependencies for script
26+
run: pip install requests
27+
28+
- name: Run update_versions.py
29+
run: python scripts/update_versions.py
30+
31+
- name: Create Pull Request
32+
uses: peter-evans/create-pull-request@v5
33+
with:
34+
token: ${{ secrets.GITHUB_TOKEN }}
35+
commit-message: "chore: bump kernel sdk versions to latest"
36+
title: "chore: nightly SDK version bump"
37+
body: |
38+
This PR updates Python `kernel` and TypeScript `@onkernel/sdk` version constraints to the latest published releases.
39+
branch: "github-actions/nightly-sdk-bump"
40+
signoff: false
41+
delete-branch: true

scripts/update_versions.py

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
#!/usr/bin/env python3
2+
"""update_versions.py
3+
4+
Fetch the latest released versions of:
5+
* PyPI package `kernel`
6+
* npm package `@onkernel/sdk`
7+
8+
and update every version constraint inside:
9+
* templates/python/*/pyproject.toml -> "kernel>=<latest>"
10+
* templates/typescript/*/package.json -> "@onkernel/sdk": ">=<latest>"
11+
12+
If a file is modified, it is overwritten in-place. The script exits with code 0
13+
whether or not modifications were required. However, it prints a summary that is
14+
useful inside CI to decide if a commit is necessary.
15+
"""
16+
from __future__ import annotations
17+
18+
import json
19+
import os
20+
import re
21+
import subprocess
22+
import sys
23+
from pathlib import Path
24+
from typing import List
25+
26+
try:
27+
import requests # type: ignore
28+
except ImportError:
29+
subprocess.check_call([sys.executable, "-m", "pip", "install", "requests"])
30+
import requests # type: ignore
31+
32+
REPO_ROOT = Path(__file__).resolve().parent.parent
33+
PY_TEMPLATES_GLOB = REPO_ROOT / "templates" / "python" / "*" / "pyproject.toml"
34+
TS_TEMPLATES_GLOB = REPO_ROOT / "templates" / "typescript" / "*" / "package.json"
35+
36+
37+
# ---------------------------------------------------------------------------
38+
# Helpers to fetch latest versions
39+
# ---------------------------------------------------------------------------
40+
41+
def _get_latest_pypi_version(package: str) -> str:
42+
url = f"https://pypi.org/pypi/{package}/json"
43+
resp = requests.get(url, timeout=10)
44+
resp.raise_for_status()
45+
data = resp.json()
46+
return data["info"]["version"]
47+
48+
49+
def _get_latest_npm_version(package: str) -> str:
50+
# NPM package names are url-encoded
51+
import urllib.parse as _up
52+
53+
encoded = _up.quote(package, safe="")
54+
url = f"https://registry.npmjs.org/{encoded}"
55+
resp = requests.get(url, timeout=10)
56+
resp.raise_for_status()
57+
data = resp.json()
58+
return data["dist-tags"]["latest"]
59+
60+
61+
# ---------------------------------------------------------------------------
62+
# Updaters
63+
# ---------------------------------------------------------------------------
64+
65+
_KERN_DEP_REGEX = re.compile(r"(\"kernel)([^\"]*)(\")")
66+
67+
68+
def _update_pyproject(file_path: Path, new_version: str) -> bool:
69+
"""Return True if file changed."""
70+
text = file_path.read_text()
71+
72+
# Replace any appearance like "kernel>=0.8.0", "kernel==0.5.0", "kernel~=0.7"
73+
new_constraint = f'"kernel>={new_version}"'
74+
new_text = re.sub(r'"kernel[<>=~!0-9.]*"', new_constraint, text)
75+
76+
if new_text != text:
77+
file_path.write_text(new_text)
78+
return True
79+
return False
80+
81+
82+
def _update_package_json(file_path: Path, new_version: str) -> bool:
83+
data = json.loads(file_path.read_text())
84+
changed = False
85+
86+
for section in ("dependencies", "peerDependencies" , "devDependencies"):
87+
deps = data.get(section)
88+
if deps and "@onkernel/sdk" in deps:
89+
if deps["@onkernel/sdk"] != f">={new_version}":
90+
deps["@onkernel/sdk"] = f">={new_version}"
91+
changed = True
92+
93+
if changed:
94+
file_path.write_text(json.dumps(data, indent=2, ensure_ascii=False) + "\n")
95+
return changed
96+
97+
98+
# ---------------------------------------------------------------------------
99+
# Main execution
100+
# ---------------------------------------------------------------------------
101+
102+
def main() -> None:
103+
latest_kernel = _get_latest_pypi_version("kernel")
104+
latest_sdk = _get_latest_npm_version("@onkernel/sdk")
105+
106+
print(f"Latest kernel version on PyPI: {latest_kernel}")
107+
print(f"Latest @onkernel/sdk version on npm: {latest_sdk}")
108+
109+
modified_files: List[Path] = []
110+
111+
# Python templates
112+
for file_path in REPO_ROOT.glob("templates/python/*/pyproject.toml"):
113+
if _update_pyproject(file_path, latest_kernel):
114+
modified_files.append(file_path.relative_to(REPO_ROOT))
115+
116+
# Typescript templates
117+
for file_path in REPO_ROOT.glob("templates/typescript/*/package.json"):
118+
if _update_package_json(file_path, latest_sdk):
119+
modified_files.append(file_path.relative_to(REPO_ROOT))
120+
121+
if modified_files:
122+
print("Updated the following files:")
123+
for p in modified_files:
124+
print(f" - {p}")
125+
else:
126+
print("All template files already up-to-date. No changes made.")
127+
128+
129+
if __name__ == "__main__":
130+
main()

0 commit comments

Comments
 (0)