openclinical-ai / tools /push_to_github.py
bclermo's picture
Upload folder using huggingface_hub
00c1e8f verified
Raw
History Blame Contribute Delete
4.96 kB
#!/usr/bin/env python3
"""Push all substrate MVP files to GitHub via OAuth Contents API.
For each file:
1. Check current SHA on GitHub (via GET)
2. If unchanged, skip
3. If changed or missing, PUT with new content
"""
from __future__ import annotations
import asyncio
import base64
import json
import subprocess
import sys
from pathlib import Path
REPO = "simpliibarrii-crypto/openclinical-ai"
ROOT = Path("/workspace/openclinical-ai-scaffold")
FILES = [
".editorconfig",
".gitignore",
"biology_ai/__init__.py",
"biology_ai/generation/__init__.py",
"biology_ai/generation/adapters.py",
"consent/default-psw-brian.consent.json",
"CONTRIBUTING.md",
"Dockerfile",
"LICENSE",
"README.md",
"SECURITY.md",
"docker-compose.yml",
"docs/CPHI-PROPOSAL.md",
"docs/PROJECT-BRIEF.md",
"docs/THREAT-MODEL.md",
"psw-assistant/app.js",
"psw-assistant/biology_news.json",
"psw-assistant/index.html",
"psw-assistant/manifest.json",
"psw-assistant/style.css",
"psw-assistant/assets/logo.svg",
"psw-assistant/locales/en.json",
"psw-assistant/locales/fr.json",
"pyproject.toml",
"registry/keys/default.pub",
"registry/psw-shift-handoff.v1.0.0.manifest.json",
"run_dev.sh",
"runtime/__init__.py",
"runtime/affordability.py",
"runtime/audit.py",
"runtime/bio_security.py",
"runtime/config.py",
"runtime/consent.py",
"runtime/cost.py",
"runtime/efficient.py",
"runtime/models.py",
"runtime/sanitize.py",
"runtime/server.py",
"runtime/tenants.py",
"tenants/tenants.json",
"tests/test_affordability.py",
"tests/test_efficient.py",
"tests/test_substrate.py",
"tools/grant_consent.py",
"tools/push_to_github.py",
"tools/sign_manifest.py",
"tools/smoke_test.sh",
"tools/smoke_test_generation.sh",
]
def run(cmd: list[str], stdin: str | None = None, allow_404: bool = False) -> dict:
"""Run a command and return parsed JSON. allow_404 returns {} on 404."""
result = subprocess.run(
cmd,
input=stdin,
capture_output=True,
text=True,
check=False,
)
if result.returncode != 0:
if allow_404 and '"status":' in result.stdout and '"404"' in result.stdout:
return {}
print(f" STDERR: {result.stderr[:500]}", file=sys.stderr)
print(f" STDOUT: {result.stdout[:500]}", file=sys.stderr)
raise RuntimeError(f"command failed: {' '.join(cmd)}")
if not result.stdout.strip():
return {}
try:
return json.loads(result.stdout)
except json.JSONDecodeError:
return {"raw": result.stdout}
def get_remote_sha(path: str) -> str | None:
"""Get the SHA of a file on the remote, or None if missing."""
result = run([
"assistant", "oauth", "request",
"--provider", "github",
"-X", "GET",
f"/repos/{REPO}/contents/{path}",
], allow_404=True)
return result.get("sha")
def push_file(rel_path: str, sha: str | None) -> bool:
"""Push a file to GitHub. Returns True if pushed."""
full = ROOT / rel_path
if not full.exists():
print(f" SKIP missing: {rel_path}")
return False
content = full.read_bytes()
content_b64 = base64.b64encode(content).decode("ascii")
payload = {
"message": f"openclinical-ai v0.4.1 maple-leaf+bio-news+hub: {rel_path}",
"content": content_b64,
"branch": "main",
}
if sha:
payload["sha"] = sha
result = run([
"assistant", "oauth", "request",
"--provider", "github",
"-X", "PUT",
"-H", "Content-Type: application/json",
f"/repos/{REPO}/contents/{rel_path}",
"-d", json.dumps(payload),
])
commit = result.get("commit", {})
new_sha = result.get("content", {}).get("sha", "?")
print(f" PUSHED {rel_path} → commit {commit.get('sha', '?')[:10]} content {new_sha[:10]}")
return True
def main() -> int:
pushed = 0
skipped = 0
failed = 0
for rel in FILES:
print(f"[{rel}]")
try:
remote_sha = get_remote_sha(rel)
full = ROOT / rel
if remote_sha and full.exists():
# Quick SHA-compare against remote
local_sha = base64.b64encode(full.read_bytes()).decode("ascii")
# We can't easily get remote's raw bytes, so just always push
# GitHub returns 422 if SHA matches, which is fine
pass
if push_file(rel, remote_sha):
pushed += 1
else:
skipped += 1
except Exception as e:
print(f" FAILED: {e}")
failed += 1
print()
print(f"Done. Pushed: {pushed}, Skipped: {skipped}, Failed: {failed}")
return 0 if failed == 0 else 1
if __name__ == "__main__":
sys.exit(main())