Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions .github/scripts/dispatch.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ def _build_inputs(
head_sha: str,
target_branch: str,
upload: bool,
comment_pr_number: str,
) -> dict:
inputs = {
"kernel_name": kernel_name,
Expand All @@ -169,6 +170,11 @@ def _build_inputs(
inputs["target_branch"] = target_branch
if not upload:
inputs["upload"] = "false"
# PR to report Hub upload pull-request links back to. Distinct from
# pr_number (which selects the branch to check out): release/merge uploads
# build from the default branch but still comment on the originating PR.
if comment_pr_number:
inputs["comment_pr_number"] = comment_pr_number
return inputs


Expand Down Expand Up @@ -232,6 +238,7 @@ def _plan_build_actions(
head_sha: str,
target_branch: str,
upload: bool,
comment_pr_number: str,
) -> None:
backends = read_backends(kernel_name) or []
workflows = select_workflows(kernel_name, notes=plan.notes)
Expand Down Expand Up @@ -272,6 +279,7 @@ def _plan_build_actions(
head_sha=head_sha,
target_branch=target_branch,
upload=upload,
comment_pr_number=comment_pr_number,
),
},
description=f"for kernel `{kernel_name}` on ref `{ref}`",
Expand All @@ -292,6 +300,7 @@ def plan_dispatch(
head_sha: str = "",
target_branch: str = "",
upload: bool = True,
comment_pr_number: str = "",
run_security: bool = False,
security_only: bool = False,
) -> DispatchPlan:
Expand All @@ -311,6 +320,7 @@ def plan_dispatch(
head_sha=head_sha,
target_branch=target_branch,
upload=upload,
comment_pr_number=comment_pr_number,
)

if want_security:
Expand Down Expand Up @@ -458,6 +468,7 @@ def dispatch(
head_sha: str = "",
target_branch: str = "",
upload: bool = True,
comment_pr_number: str = "",
run_security: bool = False,
security_only: bool = False,
) -> DispatchResult:
Expand All @@ -479,6 +490,7 @@ def dispatch(
head_sha=head_sha,
target_branch=target_branch,
upload=upload,
comment_pr_number=comment_pr_number,
run_security=run_security,
security_only=security_only,
)
Expand Down Expand Up @@ -583,6 +595,11 @@ def main() -> int:
action="store_true",
help="Build only, do not upload",
)
parser.add_argument(
"--comment-pr-number",
default="",
help="PR to report Hub upload pull-request links back to (for --create-pr uploads)",
)
parser.add_argument(
"--dry-run",
action="store_true",
Expand Down Expand Up @@ -631,6 +648,7 @@ def main() -> int:
head_sha=args.head_sha,
target_branch=args.target_branch,
upload=not args.no_upload,
comment_pr_number=args.comment_pr_number,
run_security=args.security,
security_only=args.security_only,
dispatch_key_prefix=args.dispatch_key_prefix,
Expand Down
4 changes: 4 additions & 0 deletions .github/scripts/pr_comment_kernel_bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -875,6 +875,10 @@ def main(*, dry_run: bool = False):
head_sha=pr_head_sha or "",
target_branch=target_branch,
upload=dispatch_upload,
# For uploads, report Hub create-pr links back to this PR. Only
# external-org kernels (repo-id outside kernels-community) actually
# open PRs and comment; direct uploads ignore this.
comment_pr_number=str(issue_number) if dispatch_upload else "",
# The audit is per-PR, so request it only once (on the first kernel).
run_security=run_security and index == 0,
dry_run=dry_run,
Expand Down
188 changes: 188 additions & 0 deletions .github/scripts/test_upload_and_report.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
import os
import sys
from pathlib import Path
from unittest import mock

sys.path.insert(0, os.path.dirname(__file__))

import upload_and_report as uar # noqa: E402


def test_external_kernel_uses_repo_id_and_create_pr():
# Repo-id outside kernels-community -> upload to that repo-id via PR,
# ignoring the repo_prefix (external kernels publish to their own repo).
assert uar.resolve_upload_target("MiniMaxAI/msa", "msa", "kernels-community") == (
"MiniMaxAI/msa",
True,
)
assert uar.resolve_upload_target("MiniMaxAI/msa", "msa", "kernels-staging") == (
"MiniMaxAI/msa",
True,
)
assert uar.resolve_upload_target(
"sgl-project/sgl-flash-attn3", "sgl-flash-attn3", "kernels-community"
) == ("sgl-project/sgl-flash-attn3", True)


def test_community_kernel_uses_prefix_no_create_pr():
assert uar.resolve_upload_target(
"kernels-community/relu", "relu", "kernels-community"
) == ("kernels-community/relu", False)
# repo_prefix override (build-and-stage) still routes directly, no PR.
assert uar.resolve_upload_target(
"kernels-community/relu", "relu", "kernels-staging"
) == ("kernels-staging/relu", False)


def test_missing_repo_id_falls_back_to_prefix():
assert uar.resolve_upload_target(None, "foo", "kernels-community") == (
"kernels-community/foo",
False,
)


def test_parse_pr_urls():
out = (
"progress...\n"
"Pull request created: https://hf.co/kernels/MiniMaxAI/msa/discussions/3\n"
"Pull request created: https://hf.co/kernels/MiniMaxAI/msa/discussions/4\n"
)
assert uar.parse_pr_urls(out) == [
"https://hf.co/kernels/MiniMaxAI/msa/discussions/3",
"https://hf.co/kernels/MiniMaxAI/msa/discussions/4",
]
assert uar.parse_pr_urls("No changes to upload.\n") == []


def test_success_comment_lists_links():
msg = uar.format_success_comment(
"msa", "MiniMaxAI/msa", "Build / cuda / x86_64-linux", ["url1", "url2"]
)
assert "pull request opened" in msg
assert "MiniMaxAI/msa" in msg
assert "- url1" in msg and "- url2" in msg


def test_success_comment_no_changes():
msg = uar.format_success_comment("msa", "MiniMaxAI/msa", "Build", [])
assert "no changes to upload" in msg


def test_failure_comment_includes_run_url_and_code():
msg = uar.format_failure_comment(
"msa", "MiniMaxAI/msa", "Build", "http://run/1", 2
)
assert "failed" in msg
assert "http://run/1" in msg
assert "exit code 2" in msg


def _fake_kernel(tmp_path: Path, repo_id: str) -> Path:
kdir = tmp_path / "kern"
kdir.mkdir()
(kdir / "build.toml").write_text(
f'[general.hub]\nrepo-id = "{repo_id}"\n'
)
return kdir


def test_read_repo_id(tmp_path):
kdir = _fake_kernel(tmp_path, "MiniMaxAI/msa")
assert uar.read_repo_id(kdir) == "MiniMaxAI/msa"
assert uar.read_repo_id(tmp_path / "missing") is None


def _run_main(argv, posts):
def fake_post(url, token, data):
posts.append((url, data))

with mock.patch.object(uar, "github_api_post", fake_post), mock.patch.dict(
os.environ,
{"GITHUB_TOKEN": "tok", "GITHUB_REPOSITORY": "huggingface/kernels-community"},
):
old = sys.argv
sys.argv = ["upload_and_report.py"] + argv
try:
return uar.main()
finally:
sys.argv = old


def _builder_script(tmp_path: Path, name: str, body: str) -> str:
script = tmp_path / name
script.write_text("#!/bin/bash\n" + body)
script.chmod(0o755)
return str(script)


def test_main_external_success_comments(tmp_path):
kdir = _fake_kernel(tmp_path, "MiniMaxAI/msa")
builder = _builder_script(
tmp_path,
"ok.sh",
"echo 'Pull request created: https://hf.co/kernels/MiniMaxAI/msa/discussions/9'\n",
)
posts = []
rc = _run_main(
[
"--kernel", str(kdir),
"--repo-prefix", "kernels-community",
"--comment-pr-number", "42",
"--label", "Build / cuda",
"--run-url", "http://run",
"--builder", f"{builder} up",
],
posts,
)
assert rc == 0
assert len(posts) == 1
url, data = posts[0]
assert url.endswith("/issues/42/comments")
assert "discussions/9" in data["body"]


def test_main_external_failure_comments_and_propagates(tmp_path):
kdir = _fake_kernel(tmp_path, "MiniMaxAI/msa")
builder = _builder_script(tmp_path, "fail.sh", "echo boom >&2\nexit 3\n")
posts = []
rc = _run_main(
[
"--kernel", str(kdir),
"--comment-pr-number", "42",
"--run-url", "http://run/9",
"--builder", f"{builder} up",
],
posts,
)
assert rc == 3
assert len(posts) == 1
assert "failed" in posts[0][1]["body"]


def test_main_community_does_not_comment(tmp_path):
kdir = _fake_kernel(tmp_path, "kernels-community/relu")
builder = _builder_script(tmp_path, "ok.sh", "echo hi\n")
posts = []
rc = _run_main(
[
"--kernel", str(kdir),
"--repo-prefix", "kernels-community",
"--comment-pr-number", "42",
"--builder", f"{builder} up",
],
posts,
)
assert rc == 0
assert posts == []


def test_main_external_without_comment_pr_number_does_not_comment(tmp_path):
kdir = _fake_kernel(tmp_path, "MiniMaxAI/msa")
builder = _builder_script(tmp_path, "ok.sh", "echo hi\n")
posts = []
rc = _run_main(
["--kernel", str(kdir), "--builder", f"{builder} up"],
posts,
)
assert rc == 0
assert posts == []
Loading