Skip to content
Snippets Groups Projects
Commit a3b3027f authored by Tim Jaacks's avatar Tim Jaacks
Browse files

Refactor 'check_pipeline_status' and add 'trigger_pipeline'

Rename 'check_pipeline_status' to 'mirror_pipeline_result' in order to
better reflect what the function does.

Move determination of the pipeline out of this function to a new
function 'get_pipelines' so that this can be tested separately and we
can do different things depending on whether a pipeline exists or not.

Add function 'trigger_pipeline' to trigger a pipeline on a branch.

BCS 746-000635
parent 5847145f
No related branches found
No related tags found
No related merge requests found
Pipeline #8750 failed with stages
in 31 seconds
#!/usr/bin/env python3
import common
import argparse
import sys
from gitlab import Gitlab
from gitlab.v4.objects import Project
def get_pipelines(project: Project, commit, ref: str):
"""
Get all pipelines for a given commit and ref.
The ref can be negated with a preceding '^', e.g. '^master' finds pipelines on any
ref different from 'master'.
"""
# Find pipelines for commit
pipelines = project.pipelines.list(sha=commit, retry_transient_errors=True)
# Remove pipelines not matching the ref condition
if ref:
for p in pipelines[:]:
if (
ref.startswith("^")
and p.ref == ref[1:]
or not ref.startswith("^")
and p.ref != ref
):
pipelines.remove(p)
if not pipelines:
raise LookupError(
"No pipeline for commit '%s'%s found"
% (commit, " on ref '%s'" % ref if ref else "")
)
return pipelines
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(
"--commit",
help="""sha of the project commit to check""",
dest="commit",
required=True,
)
parser.add_argument(
"--ref",
help="""ref the pipeline ran on (can be negated with preceding '^')""",
dest="ref",
default="",
required=False,
)
args, _ = parser.parse_known_args()
gitlab = Gitlab(args.gitlab_url, private_token=args.token)
project = common.get_project(gitlab, args.project)
try:
pipelines = get_pipelines(project, args.commit, args.ref)
except LookupError as e:
sys.exit(e)
for p in pipelines:
print(p.id)
sys.exit(0)
if __name__ == "__main__":
main()
...@@ -9,31 +9,14 @@ from gitlab import Gitlab, GitlabGetError ...@@ -9,31 +9,14 @@ from gitlab import Gitlab, GitlabGetError
from gitlab.v4.objects import Project from gitlab.v4.objects import Project
def check_pipeline_status(project: Project, commit, ref: str): def mirror_pipeline_result(project: Project, pipeline_id, job=None):
""" """
Get latest pipeline status for a given commit and ref. Get latest pipeline status for a given commit and ref.
The ref can be negated with a preceding '^', e.g. '^master' finds a pipeline on any The ref can be negated with a preceding '^', e.g. '^master' finds a pipeline on any
ref different from 'master'. ref different from 'master'.
""" """
# Find pipeline for commit pipeline = project.pipelines.get(pipeline_id, retry_transient_errors=True)
pipelines = project.pipelines.list(sha=commit, retry_transient_errors=True)
# Remove pipelines not matching the ref condition
if ref:
for p in pipelines[:]:
if (
ref.startswith("^")
and p.ref == ref[1:]
or not ref.startswith("^")
and p.ref != ref
):
pipelines.remove(p)
if not pipelines:
print("ERROR: no pipeline for commit '%s' with ref '%s' found" % (commit, ref))
sys.exit(1)
pipeline = pipelines[0]
# Wait for pipeline termination # Wait for pipeline termination
print("Waiting for pipeline %s" % pipeline.web_url) print("Waiting for pipeline %s" % pipeline.web_url)
...@@ -45,6 +28,13 @@ def check_pipeline_status(project: Project, commit, ref: str): ...@@ -45,6 +28,13 @@ def check_pipeline_status(project: Project, commit, ref: str):
print("") print("")
print("Result: %s" % pipeline.status, flush=True) print("Result: %s" % pipeline.status, flush=True)
# If we are running in a job environment and the upstream status is canceled,
# explicitly cancel this job as well
if job and pipeline.status == "canceled":
time.sleep(5)
job.cancel()
# Else just reflect job status in return value
return pipeline.status return pipeline.status
...@@ -69,43 +59,31 @@ def main(): ...@@ -69,43 +59,31 @@ def main():
required=True, required=True,
) )
parser.add_argument( parser.add_argument(
"--commit", "--pipeline",
help="""sha of the project commit to check""", help="""id of the pipeline to mirror the result of""",
dest="commit", dest="pipeline",
required=True, required=True,
) )
parser.add_argument(
"--ref",
help="""ref the pipeline ran on (can be negated with preceding '^')""",
dest="ref",
default="",
required=False,
)
args, _ = parser.parse_known_args() args, _ = parser.parse_known_args()
gitlab = Gitlab(args.gitlab_url, private_token=args.token) gitlab = Gitlab(args.gitlab_url, private_token=args.token)
project = common.get_project(gitlab, args.project) project = common.get_project(gitlab, args.project)
status = check_pipeline_status(project, args.commit, args.ref) # Check if we are running in a GitLab job context
# If we are running in a job environment and the upstream status is canceled,
# explicitly cancel this job as well
job_project_path = os.environ.get("CI_PROJECT_PATH") job_project_path = os.environ.get("CI_PROJECT_PATH")
job_id = os.environ.get("CI_JOB_ID") job_id = os.environ.get("CI_JOB_ID")
if job_project_path and job_id and status == "canceled": if job_project_path and job_id:
try: try:
job_project = common.get_project(gitlab, job_project_path) job_project = common.get_project(gitlab, job_project_path)
job = job_project.jobs.get(id=job_id, retry_transient_errors=True) job = job_project.jobs.get(id=job_id, retry_transient_errors=True)
# Wait some time until Gitlab has flushed the job log, otherwise it will be
# truncated before all lines are visible
time.sleep(5)
job.cancel()
except GitlabGetError: except GitlabGetError:
print("WARNING: job %s not found in project %s" % (args.job, args.project)) print("WARNING: job %s not found in project %s" % (args.job, args.project))
job = None
# Else just reflect job status in return value status = mirror_pipeline_result(project, args.pipeline, job)
elif status != "success":
if status != "success":
sys.exit(1) sys.exit(1)
sys.exit(0) sys.exit(0)
......
#!/usr/bin/env python3
import common
import argparse
import os
import sys
import time
from gitlab import Gitlab, GitlabCreateError
from gitlab.v4.objects import Project
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(
"--ref",
help="""branch or tag ref to trigger the pipeline for""",
dest="ref",
required=True,
)
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.create({"ref": args.ref})
except GitlabCreateError as e:
sys.exit("ERROR: %s" % e)
print("Created new pipeline:")
print(pipeline.web_url)
sys.exit(0)
if __name__ == "__main__":
main()
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment