onnxruntime/tools/python/run_CIs_for_branch.py
Scott McKay 01c376a0b9
Update script to run CIs for a branch. (#19797)
### Description
<!-- Describe your changes. -->
- Support multiple include/exclude values. 
- e.g. can now run with `-i MacOS -i iOS` to run CIs for both Apple
platforms.
- Default to current branch if run from directory in repo.
  - make lazier usage possible

### Motivation and Context
<!-- - Why is this change required? What problem does it solve?
- If it fixes an open issue, please link to the issue here. -->
Improve tools.

---------

Co-authored-by: Edward Chen <18449977+edgchen1@users.noreply.github.com>
2024-03-08 17:52:47 +10:00

153 lines
5.1 KiB
Python

#!/usr/bin/env python3
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
import argparse
import json
import os
import subprocess
import sys
import typing
from run_CIs_for_external_pr import get_pipeline_names
from util.platform_helpers import is_windows
class DefaultArgsRawHelpFormatter(argparse.ArgumentDefaultsHelpFormatter, argparse.RawDescriptionHelpFormatter):
pass
def _parse_args():
parser = argparse.ArgumentParser(
os.path.basename(__file__),
formatter_class=DefaultArgsRawHelpFormatter,
description="""Run the CIs used to validate PRs for the specified branch.
If not specified, the branch will be inferred (if possible) by running `git branch --show-current`.
If specified, the `--include` filter is applied first, followed by any `--exclude` filter.
`--include` and `--exclude` can be specified multiple times to accumulate values to include/exclude.
Requires the Azure CLI with DevOps extension to be installed.
Azure CLI: https://learn.microsoft.com/en-us/cli/azure/install-azure-cli
DevOps extension: https://github.com/Azure/azure-devops-cli-extension
Configuration:
Login:`az login`
Configure ORT repo as default:
`az devops configure --defaults organization=https://dev.azure.com/onnxruntime project=onnxruntime`
Example usage:
List all CIs
`python run_CIs_for_branch.py --dry-run my/BranchName`
Run all CIs
`python run_CIs_for_branch.py my/BranchName`
Run only Linux CIs
`python run_CIs_for_branch.py --include linux my/BranchName`
Exclude training CIs
`python run_CIs_for_branch.py --exclude training my/BranchName`
Run non-training Linux CIs
`python run_CIs_for_branch.py --include linux --exclude training my/BranchName`
""",
)
current_branch = None
get_branch_result = subprocess.run(["git", "branch", "--show-current"], capture_output=True, text=True, check=False)
if get_branch_result.returncode == 0:
current_branch = get_branch_result.stdout.strip()
parser.add_argument(
"-i", "--include", action="append", type=str, help="Include CIs that match this string. Case insensitive."
)
parser.add_argument(
"-e", "--exclude", action="append", type=str, help="Exclude CIs that match this string. Case insensitive."
)
parser.add_argument("--dry-run", action="store_true", help="Print selected CIs but do not run them.")
parser.add_argument(
"branch",
type=str,
nargs="?",
default=current_branch,
help="Specify the branch to run. Default is current branch if available.",
)
args = parser.parse_args()
if not args.branch:
raise ValueError("Branch was unable to be inferred and must be specified")
return args
def _run_az_pipelines_command(command: typing.List[str]):
try:
az = "az.cmd" if is_windows() else "az"
az_output = subprocess.run([az, "pipelines", *command], capture_output=True, text=True, check=True)
except subprocess.CalledProcessError as cpe:
print(cpe)
print(cpe.stderr)
sys.exit(-1)
return az_output
def main():
args = _parse_args()
branch = args.branch
# To debug available pipelines:
# az_out = az_pipelines = _run_az_pipelines_command(["list"])
# pipeline_info = json.loads(az_out.stdout)
# print(pipeline_info)
pipelines = get_pipeline_names()
pipelines_to_run = []
if args.include:
values = [i.lower().strip() for i in args.include]
for p in pipelines:
include = False
for value in values:
if value in p.lower():
include = True
break
if include:
print(f"Including {p}")
pipelines_to_run.append(p)
else:
pipelines_to_run = pipelines
if args.exclude:
values = [e.lower().strip() for e in args.exclude]
cur_pipelines = pipelines_to_run
pipelines_to_run = []
for p in cur_pipelines:
exclude = False
for value in values:
if value in p.lower():
exclude = True
break
if exclude:
print(f"Excluding {p}")
else:
pipelines_to_run.append(p)
print(f"Pipelines to run for {args.branch}:")
for p in pipelines_to_run:
print(f"\t{p}")
if args.dry_run:
sys.exit(0)
for pipeline in pipelines_to_run:
az_out = _run_az_pipelines_command(["run", "--branch", branch, "--name", pipeline])
run_output = json.loads(az_out.stdout)
if "id" in run_output:
build_url = f"https://dev.azure.com/onnxruntime/onnxruntime/_build/results?buildId={run_output['id']}"
print(f"{pipeline} build results: {build_url}&view=results")
else:
raise ValueError("Build id was not found in az output:\n" + run_output)
if __name__ == "__main__":
main()