From c7e6fff1d8a2ccb8febd7dc59d73974e885fbac2 Mon Sep 17 00:00:00 2001 From: mprahl Date: Tue, 31 Oct 2017 13:50:51 -0400 Subject: [PATCH] Handle module builds without components --- .../scheduler/handlers/modules.py | 10 ++++++ .../scheduler/handlers/repos.py | 8 +++-- module_build_service/scheduler/producer.py | 11 +++--- tests/staged_data/python3-no-components.yaml | 34 +++++++++++++++++++ tests/test_build/test_build.py | 27 +++++++++++++++ 5 files changed, 84 insertions(+), 6 deletions(-) create mode 100644 tests/staged_data/python3-no-components.yaml diff --git a/module_build_service/scheduler/handlers/modules.py b/module_build_service/scheduler/handlers/modules.py index 21979097..37b6d8aa 100644 --- a/module_build_service/scheduler/handlers/modules.py +++ b/module_build_service/scheduler/handlers/modules.py @@ -267,6 +267,16 @@ def wait(config, session, msg): log.debug("Adding dependencies %s into buildroot for module %s" % (dependencies, module_info)) builder.buildroot_add_repos(dependencies) + if not build.component_builds: + log.info("There are no components in module %r, skipping build" % build) + build.transition(config, state="build") + session.add(build) + session.commit() + # Return a KojiRepoChange message so that the build can be transitioned to done + # in the repos handler + return [module_build_service.messaging.KojiRepoChange( + 'handlers.modules.wait: fake msg', builder.module_build_tag['name'])] + # If all components in module build will be reused, we don't have to build # module-build-macros, because there won't be any build done. if attempt_to_reuse_all_components(builder, session, build): diff --git a/module_build_service/scheduler/handlers/repos.py b/module_build_service/scheduler/handlers/repos.py index 56c8668b..b4692938 100644 --- a/module_build_service/scheduler/handlers/repos.py +++ b/module_build_service/scheduler/handlers/repos.py @@ -54,7 +54,11 @@ def done(config, session, msg): log.info("Ignoring repo regen for already failed %r" % module_build) return - current_batch = module_build.current_batch() + # If there are no components in this module build, then current_batch will be empty + if not module_build.component_builds: + current_batch = [] + else: + current_batch = module_build.current_batch() # If any in the current batch are still running.. just wait. running = [c.state == koji.BUILD_STATES['BUILDING'] for c in current_batch] @@ -74,7 +78,7 @@ def done(config, session, msg): # logic over in the component handler which should fail the module build # first before we ever get here. This is here as a race condition safety # valve. - if not good: + if module_build.component_builds and not good: module_build.transition(config, models.BUILD_STATES['failed'], "Some components failed to build.") session.commit() diff --git a/module_build_service/scheduler/producer.py b/module_build_service/scheduler/producer.py index 9bc193db..4b961712 100644 --- a/module_build_service/scheduler/producer.py +++ b/module_build_service/scheduler/producer.py @@ -194,10 +194,13 @@ class MBSProducer(PollingProducer): 'the concurrent build threshold being met') return - # Check to see if module builds that are in build state but don't have - # any component builds being built can be worked on - for module_build in session.query(models.ModuleBuild) \ - .filter_by(state=models.BUILD_STATES['build']).all(): + # Check for module builds that are in the build state but don't have any active component + # builds. Exclude module builds in batch 0. This is likely a build of a module without + # components. + module_builds = session.query(models.ModuleBuild).filter( + models.ModuleBuild.state == models.BUILD_STATES['build'], + models.ModuleBuild.batch > 0).all() + for module_build in module_builds: # If there are no components in the build state on the module build, # then no possible event will start off new component builds. # But do not try to start new builds when we are waiting for the diff --git a/tests/staged_data/python3-no-components.yaml b/tests/staged_data/python3-no-components.yaml new file mode 100644 index 00000000..5395a068 --- /dev/null +++ b/tests/staged_data/python3-no-components.yaml @@ -0,0 +1,34 @@ +# This module is left empty because python3 is contained in the +# Platform module of Fedora 27 Modular Server edition. + +# Other modules can depend on this empty one so that, when the +# implementation of python3 is moved out of the Platform module, +# other modules should not be affected. + +document: modulemd +version: 1 +data: + summary: Python programming language, version 3 + description: >- + Python is an interpreted, interactive, object-oriented programming + language often compared to Tcl, Perl, Scheme or Java. Python includes + modules, classes, exceptions, very high level dynamic data types + and dynamic typing. Python supports interfaces to many system calls and + libraries, as well as to various windowing systems (X11, Motif, Tk, + Mac and MFC). + + Programmers can write new built-in modules for Python in C or C++. + Python can be used as an extension language for applications that + need a programmable interface. + license: + module: + - MIT + dependencies: + buildrequires: + bootstrap: master + requires: + platform: master + references: + community: https://www.python.org/ + documentation: https://docs.python.org/3/ + tracker: https://src.fedoraproject.org/modules/python3 diff --git a/tests/test_build/test_build.py b/tests/test_build/test_build.py index d285e498..9acb62da 100644 --- a/tests/test_build/test_build.py +++ b/tests/test_build/test_build.py @@ -316,6 +316,33 @@ class TestBuild(unittest.TestCase): self.assertEqual(tag_groups, []) self.assertEqual(buildroot_groups, []) + @timed(30) + @patch('module_build_service.auth.get_user', return_value=user) + @patch('module_build_service.scm.SCM') + def test_submit_build_no_components(self, mocked_scm, mocked_get_user, conf_system, dbg): + """ + Tests the build of a module with no components + """ + FakeSCM(mocked_scm, 'python3', 'python3-no-components.yaml', + '620ec77321b2ea7b0d67d82992dda3e1d67055b4') + + rv = self.client.post('/module-build-service/1/module-builds/', data=json.dumps( + {'branch': 'master', 'scmurl': 'git://pkgs.stg.fedoraproject.org/modules/' + 'testmodule.git?#68932c90de214d9d13feefbd35246a81b6cb8d49'})) + + data = json.loads(rv.data) + module_build_id = data['id'] + + msgs = [] + stop = module_build_service.scheduler.make_simple_stop_condition(db.session) + module_build_service.scheduler.main(msgs, stop) + + module_build = models.ModuleBuild.query.filter_by(id=module_build_id).one() + # Make sure no component builds were registered + self.assertEqual(len(module_build.component_builds), 0) + # Make sure the build is done + self.assertEqual(module_build.state, models.BUILD_STATES['ready']) + @timed(30) @patch('module_build_service.auth.get_user', return_value=user) @patch('module_build_service.scm.SCM')