From 263d260494052419507fa9fdf1715a424937b0c4 Mon Sep 17 00:00:00 2001 From: Eric Engestrom Date: Sat, 30 Aug 2025 17:26:15 +0200 Subject: [PATCH] ci_run_n_monitor: add --job-tags filter This allows limiting to eg. `--target '(zink-)?radv-.*' --job-tags 'farm:(mupuf|keywords)'` to only run radv jobs on DUTs in these two farms. Part-of: --- bin/ci/ci_run_n_monitor.py | 23 +++++++++++++++++++++++ bin/ci/gitlab_gql.py | 20 ++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/bin/ci/ci_run_n_monitor.py b/bin/ci/ci_run_n_monitor.py index 1a31e752079..05c358a24f2 100755 --- a/bin/ci/ci_run_n_monitor.py +++ b/bin/ci/ci_run_n_monitor.py @@ -168,6 +168,7 @@ def monitor_pipeline( if job_filter( job_name=job.name, job_stage=job.stage, + job_tags=job.tag_list, ) and job.status in COMPLETED_STATUSES: execution_times[job.name][job.id] = (job_duration(job), job.status, job.web_url) @@ -192,6 +193,7 @@ def monitor_pipeline( if job_filter( job_name=job.name, job_stage=job.stage, + job_tags=job.tag_list, ): run_target_job( job, @@ -464,6 +466,18 @@ def parse_args() -> argparse.Namespace: default=["performance", ".*-postmerge", ".*-nightly"], nargs=argparse.ONE_OR_MORE, ) + parser.add_argument( + "--job-tags", + metavar="job-tags", + help="Job tags to require when searching for target jobs. If multiple " + "values are passed, eg. `--job-tags 'foo.*' 'bar'`, the job will " + "need to have a tag matching `foo.*` *and* a tag matching `bar` " + "to qualify. Passing `--job-tags '.*'` makes sure the job has " + "a tag defined, while not passing `--job-tags` also allows " + "untagged jobs.", + default=[], + nargs=argparse.ONE_OR_MORE, + ) parser.add_argument( "--token", metavar="token", @@ -718,9 +732,13 @@ def main() -> None: exclude_stage_regex = re.compile(exclude_stage) + print("🞋 target jobs with tags: " + Fore.BLUE + str(args.job_tags) + Style.RESET_ALL) # U+1F78B Round target + job_tags_regexes = [re.compile(job_tag) for job_tag in args.job_tags] + def job_filter( job_name: str, job_stage: str, + job_tags: set[str], ) -> bool: """ Apply user-specified filters to a job, and return whether the @@ -732,6 +750,11 @@ def main() -> None: return False if exclude_stage_regex.fullmatch(job_stage): return False + if not all( + any(job_tags_regex.fullmatch(tag) for tag in job_tags) + for job_tags_regex in job_tags_regexes + ): + return False return True deps = find_dependencies( diff --git a/bin/ci/gitlab_gql.py b/bin/ci/gitlab_gql.py index 6729d63950c..a1928bf87bb 100755 --- a/bin/ci/gitlab_gql.py +++ b/bin/ci/gitlab_gql.py @@ -338,6 +338,7 @@ def filter_dag(dag: Dag, job_filter: callable) -> Dag: if job_filter( job_name=job, job_stage=data["stage"], + job_tags=data["tags"], ) }) @@ -532,6 +533,18 @@ def parse_args() -> Namespace: default="^$", help="Regex pattern for the stage name to be excluded", ) + parser.add_argument( + "--job-tags", + metavar="job-tags", + help="Job tags to require when searching for target jobs. If multiple " + "values are passed, eg. `--job-tags 'foo.*' 'bar'`, the job will " + "need to have a tag matching `foo.*` *and* a tag matching `bar` " + "to qualify. Passing `--job-tags '.*'` makes sure the job has " + "a tag defined, while not passing `--job-tags` also allows " + "untagged jobs.", + default=[], + nargs='+', + ) mutex_group_print = parser.add_mutually_exclusive_group() mutex_group_print.add_argument( "--print-dag", @@ -576,10 +589,12 @@ def main(): job_name_regex = re.compile(args.regex) include_stage_regex = re.compile(args.include_stage) exclude_stage_regex = re.compile(args.exclude_stage) + job_tags_regexes = [re.compile(job_tag) for job_tag in args.job_tags] def job_filter( job_name: str, job_stage: str, + job_tags: set[str], ) -> bool: """ Apply user-specified filters to a job, and return whether the @@ -591,6 +606,11 @@ def main(): return False if exclude_stage_regex.fullmatch(job_stage): return False + if not all( + any(job_tags_regex.fullmatch(tag) for tag in job_tags) + for job_tags_regex in job_tags_regexes + ): + return False return True dag = filter_dag(dag, job_filter)