diff --git a/doc/source/zuul.rst b/doc/source/zuul.rst index 5086d4d640..c711394b31 100644 --- a/doc/source/zuul.rst +++ b/doc/source/zuul.rst @@ -694,6 +694,11 @@ succeeds. In the above example, project-unittest, project-pep8, and project-pyflakes are only executed if project-merge succeeds. This can help avoid running unnecessary jobs. +The special job named ``noop`` is internal to Zuul and will always +return ``SUCCESS`` immediately. This can be useful if you require +that all changes be processed by a pipeline but a project has no jobs +that can be run on it. + .. seealso:: The OpenStack Zuul configuration for a comprehensive example: https://github.com/openstack-infra/config/blob/master/modules/openstack_project/files/zuul/layout.yaml Project Templates diff --git a/tests/fixtures/layout-no-jobs.yaml b/tests/fixtures/layout-no-jobs.yaml index ee8dc6239a..e860ad55cc 100644 --- a/tests/fixtures/layout-no-jobs.yaml +++ b/tests/fixtures/layout-no-jobs.yaml @@ -38,6 +38,6 @@ projects: - name: org/project merge-mode: cherry-pick check: - - noop + - gate-noop gate: - - noop + - gate-noop diff --git a/tests/test_scheduler.py b/tests/test_scheduler.py index 1d7be4a6d8..2d8d6bb28f 100755 --- a/tests/test_scheduler.py +++ b/tests/test_scheduler.py @@ -795,6 +795,7 @@ class TestScheduler(testtools.TestCase): self.init_repo("org/layered-project") self.init_repo("org/node-project") self.init_repo("org/conflict-project") + self.init_repo("org/noop-project") self.statsd = FakeStatsd() os.environ['STATSD_HOST'] = 'localhost' @@ -2654,6 +2655,19 @@ class TestScheduler(testtools.TestCase): self.assertEqual(len(self.history), 10) self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 1) + def test_noop_job(self): + "Test that the internal noop job works" + A = self.fake_gerrit.addFakeChange('org/noop-project', 'master', 'A') + A.addApproval('CRVW', 2) + self.fake_gerrit.addEvent(A.addApproval('APRV', 1)) + self.waitUntilSettled() + + self.assertEqual(len(self.gearman_server.getQueue()), 0) + self.assertTrue(self.sched._areAllBuildsComplete()) + self.assertEqual(len(self.history), 0) + self.assertEqual(A.data['status'], 'MERGED') + self.assertEqual(A.reported, 2) + def test_zuul_refs(self): "Test that zuul refs exist and have the right changes" self.worker.hold_jobs_in_build = True @@ -2858,6 +2872,11 @@ class TestScheduler(testtools.TestCase): def test_stuck_job_cleanup(self): "Test that pending jobs are cleaned up if removed from layout" + # This job won't be registered at startup because it is not in + # the standard layout, but we need it to already be registerd + # for when we reconfigure, as that is when Zuul will attempt + # to run the new job. + self.worker.registerFunction('build:gate-noop') self.gearman_server.hold_jobs_in_queue = True A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A') A.addApproval('CRVW', 2) @@ -2870,13 +2889,13 @@ class TestScheduler(testtools.TestCase): self.sched.reconfigure(self.config) self.waitUntilSettled() - self.gearman_server.release('noop') + self.gearman_server.release('gate-noop') self.waitUntilSettled() self.assertEqual(len(self.gearman_server.getQueue()), 0) self.assertTrue(self.sched._areAllBuildsComplete()) self.assertEqual(len(self.history), 1) - self.assertEqual(self.history[0].name, 'noop') + self.assertEqual(self.history[0].name, 'gate-noop') self.assertEqual(self.history[0].result, 'SUCCESS') def test_file_jobs(self): diff --git a/zuul/launcher/gearman.py b/zuul/launcher/gearman.py index 3638add3e8..7dd3c7c1c3 100644 --- a/zuul/launcher/gearman.py +++ b/zuul/launcher/gearman.py @@ -290,6 +290,11 @@ class Gearman(object): build = Build(job, uuid) build.parameters = params + if job.name == 'noop': + build.result = 'SUCCESS' + self.sched.onBuildCompleted(build) + return build + gearman_job = gear.Job(name, json.dumps(params), unique=uuid) build.__gearman_job = gearman_job