diff --git a/.github/workflows/slash_command_handler.yml b/.github/workflows/slash-command-handler.yml similarity index 88% rename from .github/workflows/slash_command_handler.yml rename to .github/workflows/slash-command-handler.yml index ed76e8921..b1700a36d 100644 --- a/.github/workflows/slash_command_handler.yml +++ b/.github/workflows/slash-command-handler.yml @@ -22,8 +22,6 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 - # We checkout the current context to get the script, - # but the script will fetch permissions from main as requested. - name: Set up Python uses: actions/setup-python@v5 @@ -32,7 +30,7 @@ jobs: - name: Install dependencies run: | - pip install requests PyGithub + pip install PyGithub - name: Handle Slash Command env: diff --git a/docs/developer_guide/contribution_guide.md b/docs/developer_guide/contribution_guide.md index ae6f4a861..437060a98 100644 --- a/docs/developer_guide/contribution_guide.md +++ b/docs/developer_guide/contribution_guide.md @@ -68,19 +68,21 @@ You can follow the pull request merge process described in [MAINTAINER.md](https You will need to work with the Merge Oncall, Codeowner, and other reviewers to get their approvals. Then your PR can be merged. -## How to trigger CI +## How to Trigger CI Tests -To trigger CI, the pull request must have the "run-ci" label. +We have a lot of open PRs but limited CI machines, so only top and trusted contributors have permission to trigger CI tests. -- The "run-ci" label is not added automatically to new pull requests. -- Only collaborators with triage or higher permission can add the "run-ci" label. -- If you have triage/write/maintain/admin access, you can manually add the label by clicking "Labels" on the right side of the pull request. -- If you do not have triage or higher permission, please request a review and ask a collaborator to add the label for you. +Users with permission are listed here: +https://github.com/sgl-project/sglang/blob/main/.github/CI_PERMISSIONS.json -After the "run-ci" label is added, the PR author can trigger CI by: +For CI to run on a pull request, it must have the **run-ci** label. Authorized users can add the label or rerun failed tests by commenting on the PR with one of these commands: -1. Pushing new commits, or -2. Clicking "Re-run" / retrigger on the workflow page. +- `/tag-run-ci-label`: Tag the "run-ci" label. Every future commits will trigger CI. +- `/rerun-failed-ci`: Rerun the failed/flaky tests of the last commit. + +If you have permission, the [Slash Command Handler](https://github.com/sgl-project/sglang/actions/workflows/slash_command_handler.yml) will execute your command and react with a 👍 on your comment. It may take up to several minutes to react. Here is a usage [example](https://github.com/sgl-project/sglang/pull/13498#issuecomment-3547552157). + +If you don’t have permission, please ask maintainers to trigger CI for you. ## Code style guidance - Avoid code duplication. If the same code snippet (more than five lines) appears multiple times, extract it into a shared function. diff --git a/scripts/ci/slash_command_handler.py b/scripts/ci/slash_command_handler.py index 3ce982373..67f2d911d 100644 --- a/scripts/ci/slash_command_handler.py +++ b/scripts/ci/slash_command_handler.py @@ -2,11 +2,10 @@ import json import os import sys -import requests -from github import Github +from github import Auth, Github # Configuration -PERMISSIONS_FILE_URL = "https://raw.githubusercontent.com/sgl-project/sglang/main/.github/CI_PERMISSIONS.json" +PERMISSIONS_FILE_PATH = ".github/CI_PERMISSIONS.json" def get_env_var(name): @@ -19,15 +18,18 @@ def get_env_var(name): def load_permissions(user_login): """ - Downloads the permissions JSON from the main branch and returns + Reads the permissions JSON from the local file system and returns the permissions dict for the specific user. """ try: - print(f"Fetching permissions from {PERMISSIONS_FILE_URL}...") - response = requests.get(PERMISSIONS_FILE_URL) - response.raise_for_status() + print(f"Loading permissions from {PERMISSIONS_FILE_PATH}...") + if not os.path.exists(PERMISSIONS_FILE_PATH): + print(f"Error: Permissions file not found at {PERMISSIONS_FILE_PATH}") + return None + + with open(PERMISSIONS_FILE_PATH, "r") as f: + data = json.load(f) - data = response.json() user_perms = data.get(user_login) if not user_perms: @@ -79,8 +81,13 @@ def handle_rerun_failed_ci(gh_repo, pr, comment, user_perms): # We only care about completed runs that failed if run.status == "completed" and run.conclusion == "failure": print(f"Rerunning workflow: {run.name} (ID: {run.id})") - run.rerun_failed() - rerun_count += 1 + try: + # PyGithub uses rerun_failed_jobs() or rerun() depending on version/intent + # The traceback suggested rerun_failed_jobs + run.rerun_failed_jobs() + rerun_count += 1 + except Exception as e: + print(f"Failed to rerun workflow {run.id}: {e}") if rerun_count > 0: comment.create_reaction("+1") @@ -98,19 +105,21 @@ def main(): comment_body = get_env_var("COMMENT_BODY").strip() user_login = get_env_var("USER_LOGIN") - # 2. Initialize GitHub API - g = Github(token) - repo = g.get_repo(repo_name) - pr = repo.get_pull(pr_number) - comment = repo.get_issue(pr_number).get_comment(comment_id) - - # 3. Load Permissions (Remote Check) + # 2. Load Permissions (Local Check) user_perms = load_permissions(user_login) if not user_perms: print(f"User {user_login} does not have any configured permissions. Exiting.") return + # 3. Initialize GitHub API with Auth + auth = Auth.Token(token) + g = Github(auth=auth) + + repo = g.get_repo(repo_name) + pr = repo.get_pull(pr_number) + comment = repo.get_issue(pr_number).get_comment(comment_id) + # 4. Parse Command and Execute # split lines to handle cases where there might be text after the command first_line = comment_body.split("\n")[0].strip()