From 99cd56a6846407155bfa759cc7517b2ba87e55df Mon Sep 17 00:00:00 2001 From: Daniel Stone Date: Thu, 22 Aug 2024 12:45:39 +0100 Subject: [PATCH] ci/run_n_monitor: Add --exclude-stage filtering Add an argument to ci_run_n_monitor specifying certain stages to be excluded from consideration, defaulting to the one with post-merge and performance jobs. This allows, e.g., to run all Panfrost pre-merge jobs: ./ci_run_n_monitor.py --target 'panfrost.*' or to run all Freedreno pre-merge jobs: ./ci_run_n_monitor.py --target '.*' --include-stage freedreno Signed-off-by: Daniel Stone Part-of: --- bin/ci/ci_run_n_monitor.py | 36 +++++++++++++++++++++++++++++++++--- bin/ci/gitlab_gql.py | 15 +++++++++++++-- 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/bin/ci/ci_run_n_monitor.py b/bin/ci/ci_run_n_monitor.py index e2bb2ce5747..256368b326b 100755 --- a/bin/ci/ci_run_n_monitor.py +++ b/bin/ci/ci_run_n_monitor.py @@ -115,6 +115,7 @@ def monitor_pipeline( pipeline: gitlab.v4.objects.ProjectPipeline, target_jobs_regex: re.Pattern, include_stage_regex: re.Pattern, + exclude_stage_regex: re.Pattern, dependencies: set[str], force_manual: bool, stress: int, @@ -140,6 +141,7 @@ def monitor_pipeline( for job in pipeline.jobs.list(all=True, include_retried=True): if target_jobs_regex.fullmatch(job.name) and \ include_stage_regex.fullmatch(job.stage) and \ + not exclude_stage_regex.fullmatch(job.stage) and \ job.status in COMPLETED_STATUSES: stress_status_counter[job.name][job.status] += 1 execution_times[job.name][job.id] = (job_duration(job), job.status, job.web_url) @@ -162,7 +164,8 @@ def monitor_pipeline( jobs_waiting.clear() for job in sorted(pipeline.jobs.list(all=True), key=lambda j: j.name): if target_jobs_regex.fullmatch(job.name) and \ - include_stage_regex.fullmatch(job.stage): + include_stage_regex.fullmatch(job.stage) and \ + not exclude_stage_regex.fullmatch(job.stage): target_id = job.id target_status = job.status @@ -378,6 +381,17 @@ def parse_args() -> argparse.Namespace: default=[".*"], nargs=argparse.ONE_OR_MORE, ) + parser.add_argument( + "--exclude-stage", + metavar="exclude-stage", + help="Job stages to exclude when searching for target jobs. " + "For multiple targets, pass multiple values, eg. " + "`--exclude-stage foo bar`. By default, performance and " + "post-merge jobs are excluded; pass --exclude-stage '' to " + "include them for consideration.", + default=["performance", ".*-postmerge"], + nargs=argparse.ONE_OR_MORE, + ) parser.add_argument( "--token", metavar="token", @@ -453,6 +467,7 @@ def find_dependencies( token: str | None, target_jobs_regex: re.Pattern, include_stage_regex: re.Pattern, + exclude_stage_regex: re.Pattern, project_path: str, iid: int ) -> set[str]: @@ -481,7 +496,7 @@ def find_dependencies( gql_instance, {"projectPath": project_path.path_with_namespace, "iid": iid} ) - target_dep_dag = filter_dag(dag, target_jobs_regex, include_stage_regex) + target_dep_dag = filter_dag(dag, target_jobs_regex, include_stage_regex, exclude_stage_regex) if not target_dep_dag: print(Fore.RED + "The job(s) were not found in the pipeline." + Fore.RESET) sys.exit(1) @@ -606,15 +621,30 @@ def main() -> None: include_stage_regex = re.compile(include_stage) + exclude_stage = '|'.join(args.exclude_stage) + exclude_stage = exclude_stage.strip() + + print("🞋 target excluding stages: " + Fore.BLUE + exclude_stage + Style.RESET_ALL) # U+1F78B Round target + + exclude_stage_regex = re.compile(exclude_stage) + deps = find_dependencies( token=token, target_jobs_regex=target_jobs_regex, include_stage_regex=include_stage_regex, + exclude_stage_regex=exclude_stage_regex, iid=pipe.iid, project_path=cur_project ) target_job_id, ret, exec_t = monitor_pipeline( - cur_project, pipe, target_jobs_regex, include_stage_regex, deps, args.force_manual, args.stress + cur_project, + pipe, + target_jobs_regex, + include_stage_regex, + exclude_stage_regex, + deps, + args.force_manual, + args.stress ) if target_job_id: diff --git a/bin/ci/gitlab_gql.py b/bin/ci/gitlab_gql.py index bade38e619e..144e3c31d7b 100755 --- a/bin/ci/gitlab_gql.py +++ b/bin/ci/gitlab_gql.py @@ -325,13 +325,17 @@ def create_job_needs_dag(gl_gql: GitlabGQL, params, disable_cache: bool = True) return final_dag -def filter_dag(dag: Dag, job_name_regex: Pattern, include_stage_regex: Pattern) -> Dag: +def filter_dag( + dag: Dag, job_name_regex: Pattern, include_stage_regex: Pattern, exclude_stage_regex: Pattern +) -> Dag: filtered_jobs: Dag = Dag({}) for (job, data) in dag.items(): if not job_name_regex.fullmatch(job): continue if not include_stage_regex.fullmatch(data["stage"]): continue + if exclude_stage_regex.fullmatch(data["stage"]): + continue filtered_jobs[job] = data return filtered_jobs @@ -488,6 +492,13 @@ def parse_args() -> Namespace: default=".*", help="Regex pattern for the stage name to be considered", ) + parser.add_argument( + "--exclude-stage", + type=str, + required=False, + default="^$", + help="Regex pattern for the stage name to be excluded", + ) mutex_group_print = parser.add_mutually_exclusive_group() mutex_group_print.add_argument( "--print-dag", @@ -529,7 +540,7 @@ def main(): gl_gql, {"projectPath": args.project_path, "iid": iid}, disable_cache=True ) - dag = filter_dag(dag, re.compile(args.regex), re.compile(args.include_stage)) + dag = filter_dag(dag, re.compile(args.regex), re.compile(args.include_stage), re.compile(args.exclude_stage)) print_dag(dag)