diff --git a/doc/source/user/config.rst b/doc/source/user/config.rst index bc8c8726f5..fcb35a3cba 100644 --- a/doc/source/user/config.rst +++ b/doc/source/user/config.rst @@ -259,6 +259,11 @@ success, the pipeline reports back to Gerrit with ``Verified`` vote of fails to merge with the current state of the repository. Defaults to "Merge failed." + .. attr:: no-jobs-message + + The introductory text in reports when an item is dequeued + without running any jobs. Empty by default. + .. attr:: footer-message Supplies additional information after test results. Useful for @@ -382,6 +387,13 @@ success, the pipeline reports back to Gerrit with ``Verified`` vote of running for an item in the pipeline. This can be used, for example, to reset a previously reported result. + .. attr:: no-jobs + + These reporters describe what Zuul should do when an item is + dequeued from a pipeline without running any jobs. This may be + used to indicate to a system or user that the pipeline is not + relevant for a change. + .. attr:: disabled These reporters describe what Zuul should do when a pipeline is diff --git a/releasenotes/notes/add-no-jobs-reporter-action-a868ff8baf42c44c.yaml b/releasenotes/notes/add-no-jobs-reporter-action-a868ff8baf42c44c.yaml new file mode 100644 index 0000000000..582830e6b3 --- /dev/null +++ b/releasenotes/notes/add-no-jobs-reporter-action-a868ff8baf42c44c.yaml @@ -0,0 +1,6 @@ +--- +features: + - | + Added the :attr:`pipeline.no-jobs` reporter action so that + reporters may be run when an item is dequeued into a pipeline + without having run any jobs. diff --git a/zuul/configloader.py b/zuul/configloader.py index bb78dc1820..43e1f3db9a 100644 --- a/zuul/configloader.py +++ b/zuul/configloader.py @@ -1124,6 +1124,7 @@ class PipelineParser(object): 'success': 'success_actions', 'failure': 'failure_actions', 'merge-failure': 'merge_failure_actions', + 'no-jobs': 'no_jobs_actions', 'disabled': 'disabled_actions', } @@ -1171,6 +1172,7 @@ class PipelineParser(object): 'failure-message': str, 'start-message': str, 'merge-failure-message': str, + 'no-jobs-message': str, 'footer-message': str, 'dequeue-on-new-patchset': bool, 'ignore-dependencies': bool, @@ -1190,7 +1192,7 @@ class PipelineParser(object): pipeline['reject'] = self.getDriverSchema('reject') pipeline['trigger'] = vs.Required(self.getDriverSchema('trigger')) for action in ['enqueue', 'start', 'success', 'failure', - 'merge-failure', 'disabled']: + 'merge-failure', 'no-jobs', 'disabled']: pipeline[action] = self.getDriverSchema('reporter') return vs.Schema(pipeline) @@ -1218,6 +1220,7 @@ class PipelineParser(object): pipeline.start_message = conf.get('start-message', "Starting {pipeline.name} jobs.") pipeline.enqueue_message = conf.get('enqueue-message', "") + pipeline.no_jobs_message = conf.get('no-jobs-message', "") pipeline.dequeue_on_new_patchset = conf.get( 'dequeue-on-new-patchset', True) pipeline.ignore_dependencies = conf.get( diff --git a/zuul/manager/__init__.py b/zuul/manager/__init__.py index 227089b960..67071476ae 100644 --- a/zuul/manager/__init__.py +++ b/zuul/manager/__init__.py @@ -1113,7 +1113,8 @@ class PipelineManager(object): log.debug("Project %s not in pipeline %s for change %s", item.change.project, self.pipeline, item.change) project_in_pipeline = False - actions = [] + actions = self.pipeline.no_jobs_actions + item.setReportedResult('NO_JOBS') elif item.getConfigErrors(): log.debug("Invalid config for change %s", item.change) # TODOv3(jeblair): consider a new reporter action for this @@ -1128,7 +1129,8 @@ class PipelineManager(object): elif not item.getJobs(): # We don't send empty reports with +1 log.debug("No jobs for change %s", item.change) - actions = [] + actions = self.pipeline.no_jobs_actions + item.setReportedResult('NO_JOBS') elif item.didAllJobsSucceed(): log.debug("success %s", self.pipeline.success_actions) actions = self.pipeline.success_actions diff --git a/zuul/model.py b/zuul/model.py index a06a7dde60..3821624e40 100644 --- a/zuul/model.py +++ b/zuul/model.py @@ -273,6 +273,7 @@ class Pipeline(object): self.success_actions = [] self.failure_actions = [] self.merge_failure_actions = [] + self.no_jobs_actions = [] self.disabled_actions = [] self.disable_at = None self._consecutive_failures = 0 @@ -292,6 +293,7 @@ class Pipeline(object): self.success_actions + self.failure_actions + self.merge_failure_actions + + self.no_jobs_actions + self.disabled_actions ) diff --git a/zuul/reporter/__init__.py b/zuul/reporter/__init__.py index 272680113f..a0698ff210 100644 --- a/zuul/reporter/__init__.py +++ b/zuul/reporter/__init__.py @@ -104,6 +104,7 @@ class BaseReporter(object, metaclass=abc.ABCMeta): 'success': self._formatItemReportSuccess, 'failure': self._formatItemReportFailure, 'merge-failure': self._formatItemReportMergeFailure, + 'no-jobs': self._formatItemReportNoJobs, 'disabled': self._formatItemReportDisabled } return format_methods[self._action] @@ -170,6 +171,17 @@ class BaseReporter(object, metaclass=abc.ABCMeta): def _formatItemReportMergeFailure(self, item, with_jobs=True): return item.pipeline.merge_failure_message + def _formatItemReportNoJobs(self, item, with_jobs=True): + status_url = get_default(self.connection.sched.config, + 'web', 'status_url', '') + if status_url: + status_url = item.formatUrlPattern(status_url) + + return item.pipeline.no_jobs_message.format( + pipeline=item.pipeline.getSafeAttributes(), + change=item.change.getSafeAttributes(), + status_url=status_url) + def _formatItemReportDisabled(self, item, with_jobs=True): if item.current_build_set.result == 'SUCCESS': return self._formatItemReportSuccess(item)