From 02683cc1dc898a138634b11d03b7d6e65155148f Mon Sep 17 00:00:00 2001 From: Tim Jaacks <tim.jaacks@garz-fricke.com> Date: Tue, 16 Aug 2022 09:35:46 +0200 Subject: [PATCH] Recurse to child pipelines on retrigger This makes it possible to retrigger jobs that are not part of the given pipeline but in any nested child pipeline of it. --- manifest-pipeline.yml | 1 + scripts/retrigger_mr_pipeline_job.py | 89 ------------------- scripts/retrigger_mr_pipeline_jobs.py | 23 ++++- scripts/retrigger_pipeline_jobs.py | 122 ++++++++++++++++++++++++++ 4 files changed, 144 insertions(+), 91 deletions(-) delete mode 100755 scripts/retrigger_mr_pipeline_job.py create mode 100755 scripts/retrigger_pipeline_jobs.py diff --git a/manifest-pipeline.yml b/manifest-pipeline.yml index 77877579..ae394457 100644 --- a/manifest-pipeline.yml +++ b/manifest-pipeline.yml @@ -79,6 +79,7 @@ retrigger: --state=opened --target-branch=${MASTER_BRANCH} --job=check + --include-children ; done diff --git a/scripts/retrigger_mr_pipeline_job.py b/scripts/retrigger_mr_pipeline_job.py deleted file mode 100755 index b4ac6827..00000000 --- a/scripts/retrigger_mr_pipeline_job.py +++ /dev/null @@ -1,89 +0,0 @@ -#!/usr/bin/env python3 -import common - -import argparse -import sys -from gitlab import Gitlab, GitlabGetError - - -def retrigger_mr_pipeline_job(project, mr, job_name, status_list): - # Get pipeline - if not mr.pipeline: - print("No pipeline in !%s" % mr.iid) - return None - pipeline = project.pipelines.get(mr.pipeline.get("id"), retry_transient_errors=True) - - # Find job - job = None - for pipelinejob in pipeline.jobs.list(): - if pipelinejob.name == job_name: - job = project.jobs.get(pipelinejob.id, retry_transient_errors=True) - if not job: - print("Could not find job '%s' in pipeline of !%s" % (job_name, mr.iid)) - return None - - # Only retrigger if job is in certain status - if job.status not in status_list: - return None - - # Retrigger job - job.retry() - print("Retrigger job '%s' of pipeline #%s:" % (job_name, pipeline.id)) - job = project.jobs.get(job.id, retry_transient_errors=True) - print(job.web_url) - - return job - - -def main(): - parser = argparse.ArgumentParser() - parser.add_argument( - "--gitlab-url", - help="""URL to the GitLab instance""", - dest="gitlab_url", - required=True, - ) - parser.add_argument( - "--token", - help="""GitLab REST API private access token""", - dest="token", - required=True, - ) - parser.add_argument( - "--project", - help="""name of the GitLab project""", - dest="project", - required=True, - ) - parser.add_argument( - "--iid", - help="""iid of the merge request""", - dest="iid", - required=True, - ) - parser.add_argument( - "--job", - help="""name of the job""", - dest="job", - required=True, - ) - - args, _ = parser.parse_known_args() - - gitlab = Gitlab(args.gitlab_url, private_token=args.token) - project = common.get_project(gitlab, args.project) - try: - mr = project.mergerequests.get(args.iid, retry_transient_errors=True) - except GitlabGetError as e: - sys.exit( - "ERROR: could not get merge request %s:!%s: %s" - % (project.name, args.iid, e) - ) - if not mr: - sys.exit("ERROR: could not find merge request %s!%s" % (project.name, args.iid)) - - retrigger_mr_pipeline_job(project, mr, args.job, ["success", "running"]) - - -if __name__ == "__main__": - main() diff --git a/scripts/retrigger_mr_pipeline_jobs.py b/scripts/retrigger_mr_pipeline_jobs.py index 24019bbf..8879b2d1 100755 --- a/scripts/retrigger_mr_pipeline_jobs.py +++ b/scripts/retrigger_mr_pipeline_jobs.py @@ -6,7 +6,7 @@ import sys from gitlab import Gitlab, GitlabJobRetryError from get_merge_requests import get_merge_requests -from retrigger_mr_pipeline_job import retrigger_mr_pipeline_job +from retrigger_pipeline_jobs import retrigger_pipeline_jobs def main(): @@ -75,8 +75,27 @@ def main(): failed = 0 for mr in mrs: + # Get pipeline + if not mr.pipeline: + print("No pipeline in !%s" % mr.iid) + continue + pipeline = project.pipelines.get( + mr.pipeline.get("id"), + retry_transient_errors=True, + ) try: - retrigger_mr_pipeline_job(project, mr, args.job, ["success", "running"]) + jobs = retrigger_pipeline_jobs( + project, + pipeline, + args.job, + ["success", "running"], + include_children=True, + ) + if not jobs: + print( + "Could not find any jobs named '%s' in pipeline of !%s" + % (args.job, mr.iid) + ) except GitlabJobRetryError as e: print( "ERROR: Could not retrigger job '%s' of %s!%s: %s" diff --git a/scripts/retrigger_pipeline_jobs.py b/scripts/retrigger_pipeline_jobs.py new file mode 100755 index 00000000..21b9e263 --- /dev/null +++ b/scripts/retrigger_pipeline_jobs.py @@ -0,0 +1,122 @@ +#!/usr/bin/env python3 +import common + +import argparse +import sys +from gitlab import Gitlab, GitlabGetError +from gitlab.v4.objects import Project, ProjectPipeline +from typing import List + + +def retrigger_pipeline_jobs( + project: Project, + pipeline: ProjectPipeline, + job_name: str, + status_list: List[str], + include_children: bool = False, +): + jobs = [] + + # Recurse to child pipelines + if include_children: + for bridge in pipeline.bridges.list(): + if bridge.downstream_pipeline["project_id"] == project.id: + child_pipeline = project.pipelines.get( + bridge.downstream_pipeline["id"], + retry_transient_errors=True, + ) + jobs += retrigger_pipeline_jobs( + project, + child_pipeline, + job_name, + status_list, + include_children=True, + ) + + # Find job + job = None + for pipelinejob in pipeline.jobs.list(): + if pipelinejob.name == job_name: + job = project.jobs.get(pipelinejob.id, retry_transient_errors=True) + if not job: + return jobs + + # Only retrigger if job is in certain status + if job.status not in status_list: + return jobs + + # Retrigger job + job.retry() + print("Retrigger job '%s' of pipeline #%s:" % (job_name, pipeline.id)) + job = project.jobs.get(job.id, retry_transient_errors=True) + print(job.web_url) + jobs.append(job) + + return jobs + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument( + "--gitlab-url", + help="""URL to the GitLab instance""", + dest="gitlab_url", + required=True, + ) + parser.add_argument( + "--token", + help="""GitLab REST API private access token""", + dest="token", + required=True, + ) + parser.add_argument( + "--project", + help="""name of the GitLab project""", + dest="project", + required=True, + ) + parser.add_argument( + "--pipeline", + help="""pipeline id""", + dest="pipeline", + required=True, + ) + parser.add_argument( + "--job", + help="""name of the job""", + dest="job", + required=True, + ) + + parser.add_argument( + "--include-children", + help="""search for job in child pipelines""", + dest="include_children", + action="store_true", + default=False, + ) + + args, _ = parser.parse_known_args() + + gitlab = Gitlab(args.gitlab_url, private_token=args.token) + project = common.get_project(gitlab, args.project) + try: + pipeline = project.pipelines.get(args.pipeline, retry_transient_errors=True) + except GitlabGetError as e: + sys.exit("ERROR: could not get pipeline %s: %s" % (args.pipeline, e)) + if not pipeline: + sys.exit("ERROR: could not find pipeline %s" % args.pipeline) + + jobs = retrigger_pipeline_jobs( + project, + pipeline, + args.job, + ["success", "running"], + args.include_children, + ) + + print("Retriggered %d jobs for pipeline #%s" % (len(jobs), args.pipeline)) + + +if __name__ == "__main__": + main() -- GitLab