Commit 3ccbbfdf authored by Dennis Gläser's avatar Dennis Gläser
Browse files

[ci] make pipeline search more robust

the CI enters the repo in a detached HEAD state, and thus, the query if
a pipeline was run on the same branch failed. We now check the last
parent 39cd1bff
......@@ -11,37 +11,24 @@ except Exception:
sys.exit('Could not import common module')
def performApiQuery(command, err='API query unsuccessful'):
return runCommand(command, suppressTraceBack=True, errorMessage=err)
class APIRequester:
def __init__(self, projectURL, token):
self.projectURL = projectURL.rstrip('/')
self.token = token
def __call__(self, urlSuffix, msg='API request failed'):
reqURL = self.projectURL + '/' + urlSuffix.lstrip('/')
reqCmd = 'curl --header "token={}" "{}"'.format(self.token, reqURL)
data = runCommand(reqCmd, suppressTraceBack=True, errorMessage=msg)
return json.loads(data)
def getPipeLinesApiURL(apiURL):
return apiURL.rstrip('/') + '/pipelines/'
def getPipeLinesApiSuffix(): return 'pipelines/'
def getPipeLineApiSuffix(id): return 'pipelines/' + str(id) + '/'
def getPipelines(apiURL, token, filter=''):
queryURL = getPipeLinesApiURL(apiURL) + filter
queryCmd = 'curl --header "token={}" "{}"'.format(token, queryURL)
pl = performApiQuery(queryCmd, 'Could not retrieve pipelines')
return json.loads(pl)
def getPipelineInfo(apiURL, token, pipeLineId, infoString):
queryURL = getPipeLinesApiURL(apiURL) + str(pipeLineId) + '/' + infoString
queryCmd = 'curl --header "token={}" "{}"'.format(token, queryURL)
pl = performApiQuery(queryCmd, 'Could not retrieve pipeline info')
return json.loads(pl)
def getPipeLineJobs(apiURL, token, pipeLineId):
return getPipelineInfo(apiURL, token, pipeLineId, 'jobs')
def findPipeline(pipeLines, predicate):
for pipeLine in pipeLines:
if predicate(pipeLine):
return pipeLine
return None
def getCommitsApiSuffix(): return 'repository/commits/'
def getCommitApiSuffix(sha): return 'repository/commits/' + sha + '/'
parser = ArgumentParser(
......@@ -52,7 +39,7 @@ parser.add_argument('-p', '--print-format',
required=True, choices=['pipeline-id', 'commit-sha'],
help='Switch between reporting the pipeline-id/commit-sha')
parser.add_argument('-l', '--look-for',
required=True, choices=['latest', 'HEAD'],
required=True, choices=['latest', 'latest-merge', 'HEAD'],
help='Define how to search for pipelines')
parser.add_argument('-t', '--access-token',
......@@ -61,54 +48,63 @@ parser.add_argument('-u', '--project-api-url',
help='The token to post read requests to the GitLab API')
parser.add_argument('-f', '--filter',
required=False, default='?status=success',
help='Pipeline query filter (default: "?status=success"')
parser.add_argument('-s', '--pipeline-status',
required=False, default='success',
help='Status of pipeline candidates (default: success')
parser.add_argument('-e', '--exclude-jobs',
required=False, nargs='*',
help='Exclude pipelines that contain the given jobs')
args = vars(parser.parse_args())
apiURL = args['project_api_url']
token = args['access_token']
pipeLines = getPipelines(apiURL, token, args['filter'])
currentBranch = runCommand('git branch --show-current').strip('\n')
currentCommitInfo = runCommand('git show HEAD').split('\n')
headIsMergeCommit = 'Merge:' in currentCommitInfo[1]
requester = APIRequester(args['project_api_url'], args['access_token'])
headSHA = runCommand('git rev-list HEAD --max-count=1').strip('\n')
if headIsMergeCommit:
preSHA = runCommand('git rev-list HEAD --max-count=2').split('\n')[1]
mrSHA = currentCommitInfo[1].split()[2]
def isMergeCommit(commitSHA):
commitInfo = runCommand(f'git show --no-patch {commitSHA}').split('\n')
return commitInfo[1].startswith('Merge:')
def checkBranch(pipeLine):
return pipeLine['ref'] == currentBranch
def getLastPipeline(commitSHA):
return requester(getCommitApiSuffix(commitSHA))['last_pipeline']
def checkCommit(pipeLine):
sha = pipeLine['sha']
if headIsMergeCommit:
return sha == headSHA or sha == preSHA or mrSHA in sha
return sha == headSHA
def hasMatchingStatus(pipeline):
return pipeline['status'] == args['pipeline_status']
def skip(pipeLine):
jobs = getPipeLineJobs(apiURL, token, pipeLine['id'])
jobNames = [j['name'] for j in jobs]
return any(j in jobNames for j in args['exclude_jobs'])
def hasExcludeJob(pipeLine):
id = pipeLine['id']
suffix = getPipeLineApiSuffix(id)
jobs = requester(suffix.rstrip('/') + '/jobs/')
return any(j in jobs for j in args['exclude_jobs'])
def findPipeline(commits):
for commit in commits:
pipeLine = getLastPipeline(commit)
if pipeLine is not None:
if hasMatchingStatus(pipeLine) and not hasExcludeJob(pipeLine):
return pipeLine
return None
if args['look_for'] == 'HEAD':
pipeLine = findPipeline(
pipeLines, lambda p: checkCommit(p) and not skip(p)
commits = [runCommand('git rev-list HEAD --max-count=1').strip('\n')]
if isMergeCommit(commits[0]):
preSHA = runCommand('git rev-list HEAD --max-count=2').split('\n')[1]
pipeLine = findPipeline(commits)
elif args['look_for'] == 'latest':
pipeLine = findPipeline(
pipeLines, lambda p: checkBranch(p) and not skip(p)
commits = runCommand('git rev-list HEAD').split('\n')
pipeLine = findPipeline(commits)
elif args['look_for'] == 'latest-merge':
commits = runCommand('git rev-list HEAD').split('\n')
commits = [c for c in commits if isMergeCommit(c)]
pipeLine = findPipeline(commits)
if pipeLine is not None:
if args['print_format'] == 'pipeline-id':
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment