Merge "Allow merge failures to have unique reporters."
This commit is contained in:
commit
6e81141f58
|
@ -238,6 +238,12 @@ explanation of each of the parameters::
|
||||||
reported back to Gerrit when at least one voting build fails.
|
reported back to Gerrit when at least one voting build fails.
|
||||||
Defaults to "Build failed."
|
Defaults to "Build failed."
|
||||||
|
|
||||||
|
**merge-failure-message**
|
||||||
|
An optional field that supplies the introductory text in message
|
||||||
|
reported back to Gerrit when a change fails to merge with the
|
||||||
|
current state of the repository.
|
||||||
|
Defaults to "Merge failed."
|
||||||
|
|
||||||
**footer-message**
|
**footer-message**
|
||||||
An optional field to supply additional information after test results.
|
An optional field to supply additional information after test results.
|
||||||
Useful for adding information about the CI system such as debugging
|
Useful for adding information about the CI system such as debugging
|
||||||
|
@ -413,6 +419,12 @@ explanation of each of the parameters::
|
||||||
Uses the same syntax as **success**, but describes what Zuul should
|
Uses the same syntax as **success**, but describes what Zuul should
|
||||||
do if at least one job fails.
|
do if at least one job fails.
|
||||||
|
|
||||||
|
**merge-failure**
|
||||||
|
Uses the same syntax as **success**, but describes what Zuul should
|
||||||
|
do if it is unable to merge in the patchset. If no merge-failure
|
||||||
|
reporters are listed then the ``failure`` reporters will be used to
|
||||||
|
notify of unsuccessful merges.
|
||||||
|
|
||||||
**start**
|
**start**
|
||||||
Uses the same syntax as **success**, but describes what Zuul should
|
Uses the same syntax as **success**, but describes what Zuul should
|
||||||
do when a change is added to the pipeline manager. This can be used,
|
do when a change is added to the pipeline manager. This can be used,
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
pipelines:
|
||||||
|
- name: check
|
||||||
|
manager: IndependentPipelineManager
|
||||||
|
trigger:
|
||||||
|
gerrit:
|
||||||
|
- event: patchset-created
|
||||||
|
success:
|
||||||
|
gerrit:
|
||||||
|
verified: 1
|
||||||
|
failure:
|
||||||
|
gerrit:
|
||||||
|
verified: -1
|
||||||
|
|
||||||
|
- name: post
|
||||||
|
manager: IndependentPipelineManager
|
||||||
|
trigger:
|
||||||
|
gerrit:
|
||||||
|
- event: ref-updated
|
||||||
|
ref: ^(?!refs/).*$
|
||||||
|
|
||||||
|
- name: gate
|
||||||
|
manager: DependentPipelineManager
|
||||||
|
failure-message: Build failed. For information on how to proceed, see http://wiki.example.org/Test_Failures
|
||||||
|
merge-failure-message: "The merge failed! For more information..."
|
||||||
|
trigger:
|
||||||
|
gerrit:
|
||||||
|
- event: comment-added
|
||||||
|
approval:
|
||||||
|
- approved: 1
|
||||||
|
success:
|
||||||
|
gerrit:
|
||||||
|
verified: 2
|
||||||
|
submit: true
|
||||||
|
failure:
|
||||||
|
gerrit:
|
||||||
|
verified: -2
|
||||||
|
merge-failure:
|
||||||
|
gerrit:
|
||||||
|
verified: -1
|
||||||
|
smtp:
|
||||||
|
to: you@example.com
|
||||||
|
start:
|
||||||
|
gerrit:
|
||||||
|
verified: 0
|
||||||
|
precedence: high
|
||||||
|
|
||||||
|
projects:
|
||||||
|
- name: org/project
|
||||||
|
check:
|
||||||
|
- project-merge:
|
||||||
|
- project-test1
|
||||||
|
- project-test2
|
||||||
|
gate:
|
||||||
|
- project-merge:
|
||||||
|
- project-test1
|
||||||
|
- project-test2
|
|
@ -0,0 +1,39 @@
|
||||||
|
pipelines:
|
||||||
|
- name: check
|
||||||
|
manager: IndependentPipelineManager
|
||||||
|
trigger:
|
||||||
|
gerrit:
|
||||||
|
- event: patchset-created
|
||||||
|
success:
|
||||||
|
gerrit:
|
||||||
|
verified: 1
|
||||||
|
failure:
|
||||||
|
gerrit:
|
||||||
|
verified: -1
|
||||||
|
merge-failure-message:
|
||||||
|
|
||||||
|
- name: gate
|
||||||
|
manager: DependentPipelineManager
|
||||||
|
failure-message: Build failed. For information on how to proceed, see http://wiki.example.org/Test_Failures
|
||||||
|
trigger:
|
||||||
|
gerrit:
|
||||||
|
- event: comment-added
|
||||||
|
approval:
|
||||||
|
- approved: 1
|
||||||
|
success:
|
||||||
|
gerrit:
|
||||||
|
verified: 2
|
||||||
|
submit: true
|
||||||
|
failure:
|
||||||
|
gerrit:
|
||||||
|
verified: -2
|
||||||
|
merge-failure:
|
||||||
|
start:
|
||||||
|
gerrit:
|
||||||
|
verified: 0
|
||||||
|
precedence: high
|
||||||
|
|
||||||
|
projects:
|
||||||
|
- name: org/project
|
||||||
|
check:
|
||||||
|
- project-check
|
|
@ -0,0 +1,53 @@
|
||||||
|
pipelines:
|
||||||
|
- name: check
|
||||||
|
manager: IndependentPipelineManager
|
||||||
|
merge-failure-message: "Could not merge the change. Please rebase..."
|
||||||
|
trigger:
|
||||||
|
gerrit:
|
||||||
|
- event: patchset-created
|
||||||
|
success:
|
||||||
|
gerrit:
|
||||||
|
verified: 1
|
||||||
|
failure:
|
||||||
|
gerrit:
|
||||||
|
verified: -1
|
||||||
|
|
||||||
|
- name: post
|
||||||
|
manager: IndependentPipelineManager
|
||||||
|
trigger:
|
||||||
|
gerrit:
|
||||||
|
- event: ref-updated
|
||||||
|
ref: ^(?!refs/).*$
|
||||||
|
merge-failure:
|
||||||
|
gerrit:
|
||||||
|
verified: -1
|
||||||
|
|
||||||
|
- name: gate
|
||||||
|
manager: DependentPipelineManager
|
||||||
|
failure-message: Build failed. For information on how to proceed, see http://wiki.example.org/Test_Failures
|
||||||
|
trigger:
|
||||||
|
gerrit:
|
||||||
|
- event: comment-added
|
||||||
|
approval:
|
||||||
|
- approved: 1
|
||||||
|
success:
|
||||||
|
gerrit:
|
||||||
|
verified: 2
|
||||||
|
submit: true
|
||||||
|
failure:
|
||||||
|
gerrit:
|
||||||
|
verified: -2
|
||||||
|
merge-failure:
|
||||||
|
gerrit:
|
||||||
|
verified: -1
|
||||||
|
smtp:
|
||||||
|
to: you@example.com
|
||||||
|
start:
|
||||||
|
gerrit:
|
||||||
|
verified: 0
|
||||||
|
precedence: high
|
||||||
|
|
||||||
|
projects:
|
||||||
|
- name: org/project
|
||||||
|
check:
|
||||||
|
- project-check
|
|
@ -3731,3 +3731,82 @@ For CI problems and help debugging, contact ci@example.org"""
|
||||||
|
|
||||||
self.assertEqual(failure_body, self.smtp_messages[0]['body'])
|
self.assertEqual(failure_body, self.smtp_messages[0]['body'])
|
||||||
self.assertEqual(success_body, self.smtp_messages[1]['body'])
|
self.assertEqual(success_body, self.smtp_messages[1]['body'])
|
||||||
|
|
||||||
|
def test_merge_failure_reporters(self):
|
||||||
|
"""Check that the config is set up correctly"""
|
||||||
|
|
||||||
|
self.config.set('zuul', 'layout_config',
|
||||||
|
'tests/fixtures/layout-merge-failure.yaml')
|
||||||
|
self.sched.reconfigure(self.config)
|
||||||
|
self.registerJobs()
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
"Merge Failed.\n\nThis change was unable to be automatically "
|
||||||
|
"merged with the current state of the repository. Please rebase "
|
||||||
|
"your change and upload a new patchset.",
|
||||||
|
self.sched.layout.pipelines['check'].merge_failure_message)
|
||||||
|
self.assertEqual(
|
||||||
|
"The merge failed! For more information...",
|
||||||
|
self.sched.layout.pipelines['gate'].merge_failure_message)
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
len(self.sched.layout.pipelines['check'].merge_failure_actions), 1)
|
||||||
|
self.assertEqual(
|
||||||
|
len(self.sched.layout.pipelines['gate'].merge_failure_actions), 2)
|
||||||
|
|
||||||
|
self.assertTrue(isinstance(
|
||||||
|
self.sched.layout.pipelines['check'].merge_failure_actions[0].
|
||||||
|
reporter, zuul.reporter.gerrit.Reporter))
|
||||||
|
|
||||||
|
self.assertTrue(
|
||||||
|
(
|
||||||
|
isinstance(self.sched.layout.pipelines['gate'].
|
||||||
|
merge_failure_actions[0].reporter,
|
||||||
|
zuul.reporter.smtp.Reporter) and
|
||||||
|
isinstance(self.sched.layout.pipelines['gate'].
|
||||||
|
merge_failure_actions[1].reporter,
|
||||||
|
zuul.reporter.gerrit.Reporter)
|
||||||
|
) or (
|
||||||
|
isinstance(self.sched.layout.pipelines['gate'].
|
||||||
|
merge_failure_actions[0].reporter,
|
||||||
|
zuul.reporter.gerrit.Reporter) and
|
||||||
|
isinstance(self.sched.layout.pipelines['gate'].
|
||||||
|
merge_failure_actions[1].reporter,
|
||||||
|
zuul.reporter.smtp.Reporter)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_merge_failure_reports(self):
|
||||||
|
"""Check that when a change fails to merge the correct message is sent
|
||||||
|
to the correct reporter"""
|
||||||
|
self.config.set('zuul', 'layout_config',
|
||||||
|
'tests/fixtures/layout-merge-failure.yaml')
|
||||||
|
self.sched.reconfigure(self.config)
|
||||||
|
self.registerJobs()
|
||||||
|
|
||||||
|
# Check a test failure isn't reported to SMTP
|
||||||
|
A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
|
||||||
|
A.addApproval('CRVW', 2)
|
||||||
|
self.worker.addFailTest('project-test1', A)
|
||||||
|
self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
|
||||||
|
self.waitUntilSettled()
|
||||||
|
|
||||||
|
self.assertEqual(3, len(self.history)) # 3 jobs
|
||||||
|
self.assertEqual(0, len(self.smtp_messages))
|
||||||
|
|
||||||
|
# Check a merge failure is reported to SMTP
|
||||||
|
# B should be merged, but C will conflict with B
|
||||||
|
B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
|
||||||
|
B.addPatchset(['conflict'])
|
||||||
|
C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
|
||||||
|
C.addPatchset(['conflict'])
|
||||||
|
B.addApproval('CRVW', 2)
|
||||||
|
C.addApproval('CRVW', 2)
|
||||||
|
self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
|
||||||
|
self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
|
||||||
|
self.waitUntilSettled()
|
||||||
|
|
||||||
|
self.assertEqual(6, len(self.history)) # A and B jobs
|
||||||
|
self.assertEqual(1, len(self.smtp_messages))
|
||||||
|
self.assertEqual('The merge failed! For more information...',
|
||||||
|
self.smtp_messages[0]['body'])
|
||||||
|
|
|
@ -79,11 +79,13 @@ class LayoutSchema(object):
|
||||||
'description': str,
|
'description': str,
|
||||||
'success-message': str,
|
'success-message': str,
|
||||||
'failure-message': str,
|
'failure-message': str,
|
||||||
|
'merge-failure-message': str,
|
||||||
'footer-message': str,
|
'footer-message': str,
|
||||||
'dequeue-on-new-patchset': bool,
|
'dequeue-on-new-patchset': bool,
|
||||||
'trigger': trigger,
|
'trigger': trigger,
|
||||||
'success': report_actions,
|
'success': report_actions,
|
||||||
'failure': report_actions,
|
'failure': report_actions,
|
||||||
|
'merge-failure': report_actions,
|
||||||
'start': report_actions,
|
'start': report_actions,
|
||||||
'window': window,
|
'window': window,
|
||||||
'window-floor': window_floor,
|
'window-floor': window_floor,
|
||||||
|
|
|
@ -63,6 +63,7 @@ class Pipeline(object):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.description = None
|
self.description = None
|
||||||
self.failure_message = None
|
self.failure_message = None
|
||||||
|
self.merge_failure_message = None
|
||||||
self.success_message = None
|
self.success_message = None
|
||||||
self.footer_message = None
|
self.footer_message = None
|
||||||
self.dequeue_on_new_patchset = True
|
self.dequeue_on_new_patchset = True
|
||||||
|
@ -171,6 +172,11 @@ class Pipeline(object):
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def didMergerSucceed(self, item):
|
||||||
|
if item.current_build_set.unable_to_merge:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
def didAnyJobFail(self, item):
|
def didAnyJobFail(self, item):
|
||||||
for job in self.getJobs(item.change):
|
for job in self.getJobs(item.change):
|
||||||
if not job.voting:
|
if not job.voting:
|
||||||
|
@ -206,9 +212,8 @@ class Pipeline(object):
|
||||||
fakebuild.result = 'SKIPPED'
|
fakebuild.result = 'SKIPPED'
|
||||||
item.addBuild(fakebuild)
|
item.addBuild(fakebuild)
|
||||||
|
|
||||||
def setUnableToMerge(self, item, msg):
|
def setUnableToMerge(self, item):
|
||||||
item.current_build_set.unable_to_merge = True
|
item.current_build_set.unable_to_merge = True
|
||||||
item.current_build_set.unable_to_merge_message = msg
|
|
||||||
root = self.getJobTree(item.change.project)
|
root = self.getJobTree(item.change.project)
|
||||||
for job in root.getJobs():
|
for job in root.getJobs():
|
||||||
fakebuild = Build(job, None)
|
fakebuild = Build(job, None)
|
||||||
|
@ -677,7 +682,6 @@ class BuildSet(object):
|
||||||
self.commit = None
|
self.commit = None
|
||||||
self.zuul_url = None
|
self.zuul_url = None
|
||||||
self.unable_to_merge = False
|
self.unable_to_merge = False
|
||||||
self.unable_to_merge_message = None
|
|
||||||
self.failing_reasons = []
|
self.failing_reasons = []
|
||||||
self.merge_state = self.NEW
|
self.merge_state = self.NEW
|
||||||
|
|
||||||
|
|
|
@ -226,6 +226,11 @@ class Scheduler(threading.Thread):
|
||||||
pipeline.precedence = precedence
|
pipeline.precedence = precedence
|
||||||
pipeline.failure_message = conf_pipeline.get('failure-message',
|
pipeline.failure_message = conf_pipeline.get('failure-message',
|
||||||
"Build failed.")
|
"Build failed.")
|
||||||
|
pipeline.merge_failure_message = conf_pipeline.get(
|
||||||
|
'merge-failure-message', "Merge Failed.\n\nThis change was "
|
||||||
|
"unable to be automatically merged with the current state of "
|
||||||
|
"the repository. Please rebase your change and upload a new "
|
||||||
|
"patchset.")
|
||||||
pipeline.success_message = conf_pipeline.get('success-message',
|
pipeline.success_message = conf_pipeline.get('success-message',
|
||||||
"Build succeeded.")
|
"Build succeeded.")
|
||||||
pipeline.footer_message = conf_pipeline.get('footer-message', "")
|
pipeline.footer_message = conf_pipeline.get('footer-message', "")
|
||||||
|
@ -233,7 +238,7 @@ class Scheduler(threading.Thread):
|
||||||
'dequeue-on-new-patchset', True)
|
'dequeue-on-new-patchset', True)
|
||||||
|
|
||||||
action_reporters = {}
|
action_reporters = {}
|
||||||
for action in ['start', 'success', 'failure']:
|
for action in ['start', 'success', 'failure', 'merge-failure']:
|
||||||
action_reporters[action] = []
|
action_reporters[action] = []
|
||||||
if conf_pipeline.get(action):
|
if conf_pipeline.get(action):
|
||||||
for reporter_name, params \
|
for reporter_name, params \
|
||||||
|
@ -247,6 +252,11 @@ class Scheduler(threading.Thread):
|
||||||
pipeline.start_actions = action_reporters['start']
|
pipeline.start_actions = action_reporters['start']
|
||||||
pipeline.success_actions = action_reporters['success']
|
pipeline.success_actions = action_reporters['success']
|
||||||
pipeline.failure_actions = action_reporters['failure']
|
pipeline.failure_actions = action_reporters['failure']
|
||||||
|
if len(action_reporters['merge-failure']) > 0:
|
||||||
|
pipeline.merge_failure_actions = \
|
||||||
|
action_reporters['merge-failure']
|
||||||
|
else:
|
||||||
|
pipeline.merge_failure_actions = action_reporters['failure']
|
||||||
|
|
||||||
pipeline.window = conf_pipeline.get('window', 20)
|
pipeline.window = conf_pipeline.get('window', 20)
|
||||||
pipeline.window_floor = conf_pipeline.get('window-floor', 3)
|
pipeline.window_floor = conf_pipeline.get('window-floor', 3)
|
||||||
|
@ -936,6 +946,8 @@ class BasePipelineManager(object):
|
||||||
self.log.info(" %s" % self.pipeline.success_actions)
|
self.log.info(" %s" % self.pipeline.success_actions)
|
||||||
self.log.info(" On failure:")
|
self.log.info(" On failure:")
|
||||||
self.log.info(" %s" % self.pipeline.failure_actions)
|
self.log.info(" %s" % self.pipeline.failure_actions)
|
||||||
|
self.log.info(" On merge-failure:")
|
||||||
|
self.log.info(" %s" % self.pipeline.merge_failure_actions)
|
||||||
|
|
||||||
def getSubmitAllowNeeds(self):
|
def getSubmitAllowNeeds(self):
|
||||||
# Get a list of code review labels that are allowed to be
|
# Get a list of code review labels that are allowed to be
|
||||||
|
@ -1334,10 +1346,7 @@ class BasePipelineManager(object):
|
||||||
build_set.commit = item.change.newrev
|
build_set.commit = item.change.newrev
|
||||||
if not build_set.commit:
|
if not build_set.commit:
|
||||||
self.log.info("Unable to merge change %s" % item.change)
|
self.log.info("Unable to merge change %s" % item.change)
|
||||||
msg = ("This change was unable to be automatically merged "
|
self.pipeline.setUnableToMerge(item)
|
||||||
"with the current state of the repository. Please "
|
|
||||||
"rebase your change and upload a new patchset.")
|
|
||||||
self.pipeline.setUnableToMerge(item, msg)
|
|
||||||
|
|
||||||
def reportItem(self, item):
|
def reportItem(self, item):
|
||||||
if item.reported:
|
if item.reported:
|
||||||
|
@ -1370,10 +1379,12 @@ class BasePipelineManager(object):
|
||||||
self.log.debug("Reporting change %s" % item.change)
|
self.log.debug("Reporting change %s" % item.change)
|
||||||
ret = True # Means error as returned by trigger.report
|
ret = True # Means error as returned by trigger.report
|
||||||
if self.pipeline.didAllJobsSucceed(item):
|
if self.pipeline.didAllJobsSucceed(item):
|
||||||
self.log.debug("success %s %s" % (self.pipeline.success_actions,
|
self.log.debug("success %s" % (self.pipeline.success_actions))
|
||||||
self.pipeline.failure_actions))
|
|
||||||
actions = self.pipeline.success_actions
|
actions = self.pipeline.success_actions
|
||||||
item.setReportedResult('SUCCESS')
|
item.setReportedResult('SUCCESS')
|
||||||
|
elif not self.pipeline.didMergerSucceed(item):
|
||||||
|
actions = self.pipeline.merge_failure_actions
|
||||||
|
item.setReportedResult('MERGER_FAILURE')
|
||||||
else:
|
else:
|
||||||
actions = self.pipeline.failure_actions
|
actions = self.pipeline.failure_actions
|
||||||
item.setReportedResult('FAILURE')
|
item.setReportedResult('FAILURE')
|
||||||
|
@ -1395,66 +1406,72 @@ class BasePipelineManager(object):
|
||||||
|
|
||||||
def formatReport(self, item):
|
def formatReport(self, item):
|
||||||
ret = ''
|
ret = ''
|
||||||
|
|
||||||
|
if not self.pipeline.didMergerSucceed(item):
|
||||||
|
ret += self.pipeline.merge_failure_message
|
||||||
|
if item.dequeued_needing_change:
|
||||||
|
ret += ('\n\nThis change depends on a change that failed to '
|
||||||
|
'merge.')
|
||||||
|
if self.pipeline.footer_message:
|
||||||
|
ret += '\n\n' + self.pipeline.footer_message
|
||||||
|
return ret
|
||||||
|
|
||||||
if self.pipeline.didAllJobsSucceed(item):
|
if self.pipeline.didAllJobsSucceed(item):
|
||||||
ret += self.pipeline.success_message + '\n\n'
|
ret += self.pipeline.success_message + '\n\n'
|
||||||
else:
|
else:
|
||||||
ret += self.pipeline.failure_message + '\n\n'
|
ret += self.pipeline.failure_message + '\n\n'
|
||||||
|
|
||||||
if item.dequeued_needing_change:
|
if self.sched.config.has_option('zuul', 'url_pattern'):
|
||||||
ret += "This change depends on a change that failed to merge."
|
url_pattern = self.sched.config.get('zuul', 'url_pattern')
|
||||||
elif item.current_build_set.unable_to_merge_message:
|
|
||||||
ret += item.current_build_set.unable_to_merge_message
|
|
||||||
else:
|
else:
|
||||||
if self.sched.config.has_option('zuul', 'url_pattern'):
|
url_pattern = None
|
||||||
url_pattern = self.sched.config.get('zuul', 'url_pattern')
|
|
||||||
|
for job in self.pipeline.getJobs(item.change):
|
||||||
|
build = item.current_build_set.getBuild(job.name)
|
||||||
|
result = build.result
|
||||||
|
pattern = url_pattern
|
||||||
|
if result == 'SUCCESS':
|
||||||
|
if job.success_message:
|
||||||
|
result = job.success_message
|
||||||
|
if job.success_pattern:
|
||||||
|
pattern = job.success_pattern
|
||||||
|
elif result == 'FAILURE':
|
||||||
|
if job.failure_message:
|
||||||
|
result = job.failure_message
|
||||||
|
if job.failure_pattern:
|
||||||
|
pattern = job.failure_pattern
|
||||||
|
if pattern:
|
||||||
|
url = pattern.format(change=item.change,
|
||||||
|
pipeline=self.pipeline,
|
||||||
|
job=job,
|
||||||
|
build=build)
|
||||||
else:
|
else:
|
||||||
url_pattern = None
|
url = build.url or job.name
|
||||||
for job in self.pipeline.getJobs(item.change):
|
if not job.voting:
|
||||||
build = item.current_build_set.getBuild(job.name)
|
voting = ' (non-voting)'
|
||||||
result = build.result
|
else:
|
||||||
pattern = url_pattern
|
voting = ''
|
||||||
if result == 'SUCCESS':
|
if self.report_times and build.end_time and build.start_time:
|
||||||
if job.success_message:
|
dt = int(build.end_time - build.start_time)
|
||||||
result = job.success_message
|
m, s = divmod(dt, 60)
|
||||||
if job.success_pattern:
|
h, m = divmod(m, 60)
|
||||||
pattern = job.success_pattern
|
if h:
|
||||||
elif result == 'FAILURE':
|
elapsed = ' in %dh %02dm %02ds' % (h, m, s)
|
||||||
if job.failure_message:
|
elif m:
|
||||||
result = job.failure_message
|
elapsed = ' in %dm %02ds' % (m, s)
|
||||||
if job.failure_pattern:
|
|
||||||
pattern = job.failure_pattern
|
|
||||||
if pattern:
|
|
||||||
url = pattern.format(change=item.change,
|
|
||||||
pipeline=self.pipeline,
|
|
||||||
job=job,
|
|
||||||
build=build)
|
|
||||||
else:
|
else:
|
||||||
url = build.url or job.name
|
elapsed = ' in %ds' % (s)
|
||||||
if not job.voting:
|
else:
|
||||||
voting = ' (non-voting)'
|
elapsed = ''
|
||||||
else:
|
name = ''
|
||||||
voting = ''
|
if self.sched.config.has_option('zuul', 'job_name_in_report'):
|
||||||
if self.report_times and build.end_time and build.start_time:
|
if self.sched.config.getboolean('zuul',
|
||||||
dt = int(build.end_time - build.start_time)
|
'job_name_in_report'):
|
||||||
m, s = divmod(dt, 60)
|
name = job.name + ' '
|
||||||
h, m = divmod(m, 60)
|
ret += '- %s%s : %s%s%s\n' % (name, url, result, elapsed,
|
||||||
if h:
|
voting)
|
||||||
elapsed = ' in %dh %02dm %02ds' % (h, m, s)
|
if self.pipeline.footer_message:
|
||||||
elif m:
|
ret += '\n' + self.pipeline.footer_message
|
||||||
elapsed = ' in %dm %02ds' % (m, s)
|
|
||||||
else:
|
|
||||||
elapsed = ' in %ds' % (s)
|
|
||||||
else:
|
|
||||||
elapsed = ''
|
|
||||||
name = ''
|
|
||||||
if self.sched.config.has_option('zuul', 'job_name_in_report'):
|
|
||||||
if self.sched.config.getboolean('zuul',
|
|
||||||
'job_name_in_report'):
|
|
||||||
name = job.name + ' '
|
|
||||||
ret += '- %s%s : %s%s%s\n' % (name, url, result, elapsed,
|
|
||||||
voting)
|
|
||||||
ret += '\n'
|
|
||||||
ret += self.pipeline.footer_message
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def formatDescription(self, build):
|
def formatDescription(self, build):
|
||||||
|
|
Loading…
Reference in New Issue