diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..1377554e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.swp diff --git a/check_nightly_success/check-nightly-success/action.yaml b/check_nightly_success/check-nightly-success/action.yaml new file mode 100644 index 00000000..7b7f30d3 --- /dev/null +++ b/check_nightly_success/check-nightly-success/action.yaml @@ -0,0 +1,30 @@ +name: check-nightly-summarize +description: Check if the nightlies have succeeded recently. +inputs: + repo: + description: "The repository to check" + required: true + type: string + repo_owner: + description: "The org that owns the repo (default RAPIDSAI)" + required: false + default: "rapidsai" + type: string + workflow_id: + description: "The workflow whose runs to check" + required: false + default: "test.yaml" + type: string + max_days_without_success: + description: "The number of consecutive days that may go by without a successful CI run" + required: false + default: 7 + type: integer + +runs: + using: composite + steps: + - name: Run the Python script + shell: bash + run: + python shared-actions/check_nightly_success/check-nightly-success/check.py ${{ inputs.repo }} --repo-owner ${{ inputs.repo_owner }} --workflow-id ${{ inputs.workflow_id }} --max-days-without-success ${{ inputs.max_days_without_success }} diff --git a/check_nightly_success/check-nightly-success/check.py b/check_nightly_success/check-nightly-success/check.py new file mode 100644 index 00000000..8d4aeca0 --- /dev/null +++ b/check_nightly_success/check-nightly-success/check.py @@ -0,0 +1,74 @@ +import requests +import itertools +from datetime import datetime +import sys +import argparse +import os + +# Constants +GITHUB_TOKEN = os.environ["RAPIDS_GH_TOKEN"] +GOOD_STATUSES = ("success",) # noqa + + +def main( + repo: str, + repo_owner: str, + workflow_id: str, + max_days_without_success: int, +): + headers = {"Authorization": f"token {GITHUB_TOKEN}"} + url = f"https://api.github.com/repos/{repo_owner}/{repo}/actions/workflows/{workflow_id}/runs" + response = requests.get(url, headers=headers) + response.raise_for_status() + runs = response.json()["workflow_runs"] + tz = datetime.fromisoformat(runs[0]["run_started_at"]).tzinfo + NOW = datetime.now(tz=tz) + + branch_ok = {} + for branch, branch_runs in itertools.groupby(runs, key=lambda r: r["head_branch"]): + if branch.startswith("v"): # Skip tags + continue + + branch_ok[branch] = False + for run in sorted(branch_runs, key=lambda r: r["run_started_at"], reverse=True): + if ( + NOW - datetime.fromisoformat(run["run_started_at"]) + ).days > max_days_without_success: + break + if run["conclusion"] in GOOD_STATUSES: + branch_ok[branch] = True + break + + all_success = all(branch_ok.values()) + if not all_success: + print( + f"Branches with no successful runs of {workflow_id} in the last " + f"{max_days_without_success} days: " + f"{', '.join(k for k, v in branch_ok.items() if not v)}" + ) + return not all(branch_ok.values()) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("repo", type=str, help="Repository name") + parser.add_argument( + "--repo-owner", default="rapidsai", help="Repository organziation/owner" + ) + parser.add_argument("--workflow-id", default="test.yaml", help="Workflow ID") + parser.add_argument( + "--max-days-without-success", + type=int, + default=7, + help="Maximum number of days without a successful run", + ) + args = parser.parse_args() + + sys.exit( + main( + args.repo, + args.repo_owner, + args.workflow_id, + args.max_days_without_success, + ) + ) diff --git a/check_nightly_success/dispatch/action.yml b/check_nightly_success/dispatch/action.yml new file mode 100644 index 00000000..61e52a51 --- /dev/null +++ b/check_nightly_success/dispatch/action.yml @@ -0,0 +1,39 @@ +name: dispatch-check-nightly-summarize +description: Clone shared-actions and dispatch to the check-nightly-success action. +inputs: + repo: + description: "The repository to check" + required: true + type: string + repo_owner: + description: "The org that owns the repo (default RAPIDSAI)" + required: false + default: "rapidsai" + type: string + workflow_id: + description: "The workflow whose runs to check" + required: false + default: "test.yaml" + type: string + max_days_without_success: + description: "The number of consecutive days that may go by without a successful CI run" + required: false + default: 7 + type: integer + +runs: + using: 'composite' + steps: + - name: Clone shared-actions repo + uses: actions/checkout@v4 + with: + repository: ${{ env.SHARED_ACTIONS_REPO || 'rapidsai/shared-actions' }} + ref: ${{ env.SHARED_ACTIONS_REF || 'main' }} + path: ./shared-actions + - name: Run check-nightly-success + uses: ./shared-actions/check_nightly_success/check-nightly-success + with: + repo: ${{ inputs.repo }} + repo_owner: ${{ inputs.repo_owner }} + workflow_id: ${{ inputs.workflow_id }} + max_days_without_success: ${{ inputs.max_days_without_success }}