ci: onboard windy-connect + windy-search to private-repo CI
Some checks failed
check / gate (push) Has been cancelled
Some checks failed
check / gate (push) Has been cancelled
windy-connect promoted from pull mirror to writable (release.yml, which publishes to PyPI on tag push, disabled — the sync pushes tags). windy-search was already writable; its scheduled drift-check is disabled because it now runs as cron on Kit 0. Both added to BRIDGE_REPOS. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -14,7 +14,9 @@ from pathlib import Path
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
_spec = importlib.util.spec_from_file_location("pr_status_bridge", ROOT / "scripts" / "pr_status_bridge.py")
|
_spec = importlib.util.spec_from_file_location(
|
||||||
|
"pr_status_bridge", ROOT / "scripts" / "pr_status_bridge.py"
|
||||||
|
)
|
||||||
bridge = importlib.util.module_from_spec(_spec)
|
bridge = importlib.util.module_from_spec(_spec)
|
||||||
_spec.loader.exec_module(bridge)
|
_spec.loader.exec_module(bridge)
|
||||||
|
|
||||||
@@ -22,7 +24,14 @@ SHA = "a" * 40
|
|||||||
|
|
||||||
|
|
||||||
def _run(i, wf, job, status, sha=SHA, n=1):
|
def _run(i, wf, job, status, sha=SHA, n=1):
|
||||||
return {"id": i, "workflow_id": wf, "name": job, "status": status, "head_sha": sha, "run_number": n}
|
return {
|
||||||
|
"id": i,
|
||||||
|
"workflow_id": wf,
|
||||||
|
"name": job,
|
||||||
|
"status": status,
|
||||||
|
"head_sha": sha,
|
||||||
|
"run_number": n,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class Fake:
|
class Fake:
|
||||||
@@ -34,7 +43,7 @@ class Fake:
|
|||||||
def gitea(self, method, path, body=None):
|
def gitea(self, method, path, body=None):
|
||||||
if "/actions/tasks" in path:
|
if "/actions/tasks" in path:
|
||||||
page = int(path.rsplit("page=", 1)[1])
|
page = int(path.rsplit("page=", 1)[1])
|
||||||
return 200, {"workflow_runs": self.runs[(page - 1) * 50: page * 50]}
|
return 200, {"workflow_runs": self.runs[(page - 1) * 50 : page * 50]}
|
||||||
if method == "GET" and path.endswith("/pulls?state=open&limit=50"):
|
if method == "GET" and path.endswith("/pulls?state=open&limit=50"):
|
||||||
return 200, self.wg_prs
|
return 200, self.wg_prs
|
||||||
if method == "POST" and path.endswith("/pulls"):
|
if method == "POST" and path.endswith("/pulls"):
|
||||||
@@ -63,6 +72,7 @@ def fake(monkeypatch):
|
|||||||
monkeypatch.setattr(bridge, "gitea", f.gitea)
|
monkeypatch.setattr(bridge, "gitea", f.gitea)
|
||||||
monkeypatch.setattr(bridge, "github", f.github)
|
monkeypatch.setattr(bridge, "github", f.github)
|
||||||
return f
|
return f
|
||||||
|
|
||||||
return make
|
return make
|
||||||
|
|
||||||
|
|
||||||
@@ -74,8 +84,10 @@ def test_posts_latest_verdict_per_job(fake):
|
|||||||
|
|
||||||
|
|
||||||
def test_unchanged_state_is_not_reposted(fake):
|
def test_unchanged_state_is_not_reposted(fake):
|
||||||
f = fake(runs=[_run(1, "ci.yml", "test", "success")],
|
f = fake(
|
||||||
statuses=[{"context": "windy-git/ci/test", "state": "success"}])
|
runs=[_run(1, "ci.yml", "test", "success")],
|
||||||
|
statuses=[{"context": "windy-git/ci/test", "state": "success"}],
|
||||||
|
)
|
||||||
bridge.post_statuses("r", SHA)
|
bridge.post_statuses("r", SHA)
|
||||||
assert f.posted == []
|
assert f.posted == []
|
||||||
|
|
||||||
@@ -100,9 +112,13 @@ def test_runs_past_the_first_page_are_seen(fake):
|
|||||||
|
|
||||||
|
|
||||||
def _gh_pr(n, repo="sneakyfree/r"):
|
def _gh_pr(n, repo="sneakyfree/r"):
|
||||||
return {"number": n, "title": "t", "html_url": "u",
|
return {
|
||||||
|
"number": n,
|
||||||
|
"title": "t",
|
||||||
|
"html_url": "u",
|
||||||
"head": {"ref": f"b{n}", "sha": SHA, "repo": {"full_name": repo} if repo else None},
|
"head": {"ref": f"b{n}", "sha": SHA, "repo": {"full_name": repo} if repo else None},
|
||||||
"base": {"ref": "main"}}
|
"base": {"ref": "main"},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def test_fork_prs_are_never_mirrored(fake, monkeypatch):
|
def test_fork_prs_are_never_mirrored(fake, monkeypatch):
|
||||||
|
|||||||
@@ -43,7 +43,8 @@ WG_OWNER = os.environ.get("WINDYGIT_OWNER", "windyadmin")
|
|||||||
# Private repos only. Public repos run real GitHub Actions on veron1's GitHub
|
# Private repos only. Public repos run real GitHub Actions on veron1's GitHub
|
||||||
# runner; bridging those too would put two competing verdicts on every commit.
|
# runner; bridging those too would put two competing verdicts on every commit.
|
||||||
REPOS = os.environ.get(
|
REPOS = os.environ.get(
|
||||||
"BRIDGE_REPOS", "windy-chat windy-mail windy-calendar Windy-Clone WindyCloud"
|
"BRIDGE_REPOS",
|
||||||
|
"windy-chat windy-mail windy-calendar Windy-Clone WindyCloud windy-search windy-connect",
|
||||||
).split()
|
).split()
|
||||||
|
|
||||||
# Gitea run status -> GitHub status state. `skipped` is deliberately absent: a
|
# Gitea run status -> GitHub status state. `skipped` is deliberately absent: a
|
||||||
@@ -108,13 +109,17 @@ def sync_prs(repo: str) -> list[str]:
|
|||||||
heads.append(pr["head"]["sha"])
|
heads.append(pr["head"]["sha"])
|
||||||
if tag in ours:
|
if tag in ours:
|
||||||
continue
|
continue
|
||||||
st, _ = gitea("POST", f"/repos/{WG_OWNER}/{repo}/pulls", {
|
st, _ = gitea(
|
||||||
|
"POST",
|
||||||
|
f"/repos/{WG_OWNER}/{repo}/pulls",
|
||||||
|
{
|
||||||
"head": pr["head"]["ref"],
|
"head": pr["head"]["ref"],
|
||||||
"base": pr["base"]["ref"],
|
"base": pr["base"]["ref"],
|
||||||
"title": f"{tag} {pr['title']}"[:250],
|
"title": f"{tag} {pr['title']}"[:250],
|
||||||
"body": f"Mirror of {pr['html_url']} so CI runs here. Do not merge in Windy Git — "
|
"body": f"Mirror of {pr['html_url']} so CI runs here. Do not merge in Windy Git — "
|
||||||
"GitHub is the source of truth; merge there.",
|
"GitHub is the source of truth; merge there.",
|
||||||
})
|
},
|
||||||
|
)
|
||||||
print(f" {repo}: opened mirror PR for GH#{pr['number']} -> {st}")
|
print(f" {repo}: opened mirror PR for GH#{pr['number']} -> {st}")
|
||||||
|
|
||||||
for tag, p in ours.items():
|
for tag, p in ours.items():
|
||||||
@@ -154,12 +159,16 @@ def post_statuses(repo: str, sha: str) -> None:
|
|||||||
state = STATE.get(r["status"])
|
state = STATE.get(r["status"])
|
||||||
if state is None or current.get(ctx) == state:
|
if state is None or current.get(ctx) == state:
|
||||||
continue
|
continue
|
||||||
st, _ = github("POST", f"/repos/{GH_OWNER}/{repo}/statuses/{sha}", {
|
st, _ = github(
|
||||||
|
"POST",
|
||||||
|
f"/repos/{GH_OWNER}/{repo}/statuses/{sha}",
|
||||||
|
{
|
||||||
"state": state,
|
"state": state,
|
||||||
"context": ctx,
|
"context": ctx,
|
||||||
"description": f"Windy Git CI on Veron 1: {r['status']}"[:140],
|
"description": f"Windy Git CI on Veron 1: {r['status']}"[:140],
|
||||||
"target_url": f"{PUBLIC}/{WG_OWNER}/{repo}/actions/runs/{r['run_number']}",
|
"target_url": f"{PUBLIC}/{WG_OWNER}/{repo}/actions/runs/{r['run_number']}",
|
||||||
})
|
},
|
||||||
|
)
|
||||||
print(f" {repo}@{sha[:7]} {ctx} = {state} -> {st}")
|
print(f" {repo}@{sha[:7]} {ctx} = {state} -> {st}")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ FAILED=0
|
|||||||
|
|
||||||
# Repos Windy Git tracks FROM GitHub. Remove a repo from this list at the moment
|
# Repos Windy Git tracks FROM GitHub. Remove a repo from this list at the moment
|
||||||
# it flips to Windy-Git-first, or the sync will fight its authors and win.
|
# it flips to Windy-Git-first, or the sync will fight its authors and win.
|
||||||
REPOS="${SYNC_REPOS:-windy-calendar windy-search windy-registry Windy-Clone WindyCloud windy-cloud-sites windy-mind eternitas windy-agent windy-git windy-chat windy-mail}"
|
REPOS="${SYNC_REPOS:-windy-calendar windy-search windy-registry Windy-Clone WindyCloud windy-cloud-sites windy-mind eternitas windy-agent windy-git windy-chat windy-mail windy-connect}"
|
||||||
|
|
||||||
mkdir -p "$WORK"
|
mkdir -p "$WORK"
|
||||||
log() { printf '[sync %s] %s\n' "$(date -u +%H:%M:%SZ)" "$*"; }
|
log() { printf '[sync %s] %s\n' "$(date -u +%H:%M:%SZ)" "$*"; }
|
||||||
|
|||||||
Reference in New Issue
Block a user