def test_generate_expanded_mmds_static_context(self): """ Tests if generate_expanded_mmds will not change the context of a module if provided with a static one. """ module_deps = [{ "requires": { "gtk": ["1"], "foo": ["1"] }, "buildrequires": { "platform": ["f28"], "gtk": ["1"], "foo": ["1"] }, }] self._generate_default_modules() module_build = make_module_in_db("app:1:0:static", module_deps) mmds = generate_expanded_mmds(db_session, module_build.mmd(), static_context=True) assert type(mmds) is list assert len(mmds) == 1 current_context = mmds[0].get_context() assert current_context == "static"
def test_generate_expanded_mmds_buildrequires(self, module_deps, stream_ambigous, expected_xmd, expected_buildrequires): self._generate_default_modules() module_build = make_module_in_db("app:1:0:c1", module_deps) # Check that generate_expanded_mmds raises an exception if stream is ambigous # and also that it does not raise an exception otherwise. if stream_ambigous: with pytest.raises(StreamAmbigous): generate_expanded_mmds(db_session, module_build.mmd(), raise_if_stream_ambigous=True) else: generate_expanded_mmds(db_session, module_build.mmd(), raise_if_stream_ambigous=True) # Check that if stream is ambigous and we define the stream, it does not raise # an exception. if stream_ambigous: default_streams = {} for ns in list(expected_buildrequires)[0]: name, stream = ns.split(":") default_streams[name] = stream generate_expanded_mmds( db_session, module_build.mmd(), raise_if_stream_ambigous=True, default_streams=default_streams, ) mmds = generate_expanded_mmds(db_session, module_build.mmd()) buildrequires_per_mmd_xmd = set() buildrequires_per_mmd_buildrequires = set() for mmd in mmds: xmd = mmd.get_xmd() br_nsvcs = [] for name, detail in xmd["mbs"]["buildrequires"].items(): br_nsvcs.append(":".join([ name, detail["stream"], detail["version"], detail["context"] ])) buildrequires_per_mmd_xmd.add(frozenset(br_nsvcs)) assert len(mmd.get_dependencies()) == 1 buildrequires = set() dep = mmd.get_dependencies()[0] for req_name in dep.get_buildtime_modules(): for req_stream in dep.get_buildtime_streams(req_name): buildrequires.add(":".join([req_name, req_stream])) buildrequires_per_mmd_buildrequires.add(frozenset(buildrequires)) assert buildrequires_per_mmd_xmd == expected_xmd assert buildrequires_per_mmd_buildrequires == expected_buildrequires
def test_generate_expanded_mmds_requires(self, module_deps, expected): self._generate_default_modules() module_build = make_module_in_db("app:1:0:c1", module_deps) mmds = generate_expanded_mmds(db_session, module_build.mmd()) requires_per_mmd = set() for mmd in mmds: assert len(mmd.get_dependencies()) == 1 mmd_requires = set() dep = mmd.get_dependencies()[0] for req_name in dep.get_runtime_modules(): for req_stream in dep.get_runtime_streams(req_name): mmd_requires.add(":".join([req_name, req_stream])) requires_per_mmd.add(frozenset(mmd_requires)) assert requires_per_mmd == expected
def test_generate_expanded_mmds_context(self): self._generate_default_modules() module_build = make_module_in_db( "app:1:0:c1", [{ "requires": { "gtk": ["1", "2"] }, "buildrequires": { "platform": ["f28"], "gtk": ["1", "2"] }, }], ) mmds = generate_expanded_mmds(db_session, module_build.mmd()) contexts = {mmd.get_context() for mmd in mmds} assert {"e1e005fb", "ce132a1e"} == contexts
def submit_module_build(db_session, username, mmd, params): """ Submits new module build. :param db_session: SQLAlchemy session object. :param str username: Username of the build's owner. :param Modulemd.ModuleStream mmd: Modulemd defining the build. :param dict params: the API parameters passed in by the user :rtype: list with ModuleBuild :return: List with submitted module builds. """ log.debug( "Submitted %s module build for %s:%s:%s", ("scratch" if params.get("scratch", False) else "normal"), mmd.get_module_name(), mmd.get_stream_name(), mmd.get_version(), ) raise_if_stream_ambigous = False default_streams = {} # For local builds, we want the user to choose the exact stream using the default_streams # in case there are multiple streams to choose from and raise an exception otherwise. if "local_build" in params: raise_if_stream_ambigous = True # Get the default_streams if set. if "default_streams" in params: default_streams = params["default_streams"] xmd = mmd.get_xmd() # we check if static contexts are enabled by the `contexts` property defined by the user i # as an build option. static_context = "mbs_options" in xmd and "contexts" in xmd["mbs_options"] input_mmds = generate_mmds_from_static_contexts(mmd) if static_context else [mmd] mmds = [] for mmd in input_mmds: validate_mmd(mmd) _apply_dep_overrides(mmd, params) _modify_buildtime_streams(db_session, mmd, resolve_base_module_virtual_streams) _process_support_streams(db_session, mmd, params) mmds += generate_expanded_mmds(db_session, mmd, raise_if_stream_ambigous, default_streams, static_context=static_context) if not mmds: raise ValidationError( "No dependency combination was satisfied. Please verify the " "buildrequires in your modulemd have previously been built." ) modules = [] # True if all module builds are skipped so MBS will actually not rebuild # anything. To keep the backward compatibility, we need to raise an exception # later in the end of this method. all_modules_skipped = True for mmd in mmds: # Prefix the version of the modulemd based on the base module it buildrequires version = get_prefixed_version(mmd) mmd.set_version(version) nsvc = mmd.get_nsvc() log.debug("Checking whether module build already exists: %s.", nsvc) module = models.ModuleBuild.get_build_from_nsvc(db_session, *nsvc.split(":")) if module and not params.get("scratch", False): if module.state != models.BUILD_STATES["failed"]: log.info( "Skipping rebuild of %s, only rebuild of modules in failed state is allowed.", nsvc, ) modules.append(module) continue rebuild_strategy = params.get("rebuild_strategy") if rebuild_strategy and module.rebuild_strategy != rebuild_strategy: raise ValidationError( 'You cannot change the module\'s "rebuild_strategy" when ' "resuming a module build" ) log.debug("Resuming existing module build %r" % module) # Reset all component builds that didn't complete for component in module.component_builds: if not component.is_waiting_for_build and not component.is_completed: component.state = None component.state_reason = None db_session.add(component) module.username = username prev_state = module.previous_non_failed_state if prev_state == models.BUILD_STATES["init"]: transition_to = models.BUILD_STATES["init"] else: transition_to = models.BUILD_STATES["wait"] module.batch = 0 module.transition(db_session, conf, transition_to, "Resubmitted by %s" % username) db_session.commit() log.info("Resumed existing module build in previous state %s" % module.state) else: # make NSVC unique for every scratch build context_suffix = "" if params.get("scratch", False): log.debug("Checking for existing scratch module builds by NSVC") scrmods = models.ModuleBuild.get_scratch_builds_from_nsvc( db_session, *nsvc.split(":")) scrmod_contexts = [scrmod.context for scrmod in scrmods] log.debug( "Found %d previous scratch module build context(s): %s", len(scrmods), ",".join(scrmod_contexts), ) # append incrementing counter to context context_suffix = "_" + str(len(scrmods) + 1) mmd.set_context(mmd.get_context() + context_suffix) else: # In case the branch is defined, check whether user is allowed to submit # non-scratch build from this branch. Note that the branch is always defined # for official builds from SCM, because it is requested in views.py. branch = params.get("branch") if branch: for regex in conf.scratch_build_only_branches: branch_search = re.search(regex, branch) if branch_search: raise ValidationError( "Only scratch module builds can be built from this branch." ) log.debug("Creating new module build") module = models.ModuleBuild.create( db_session, conf, name=mmd.get_module_name(), stream=mmd.get_stream_name(), version=str(mmd.get_version()), modulemd=mmd_to_str(mmd), scmurl=params.get("scmurl"), username=username, rebuild_strategy=params.get("rebuild_strategy"), reused_module_id=params.get("reuse_components_from"), scratch=params.get("scratch"), srpms=params.get("srpms"), ) module.build_context, module.runtime_context, module.context, \ module.build_context_no_bms = module.contexts_from_mmd(module.modulemd) xmd = mmd.get_xmd() if xmd["mbs"].get("static_context"): module.context = mmd.get_context() module.context += context_suffix db_session.commit() notify_on_module_state_change( # Note the state is "init" here... module.json(db_session, show_tasks=False) ) all_modules_skipped = False modules.append(module) log.info('The user "%s" submitted the build "%s"', username, nsvc) if all_modules_skipped: err_msg = ( "Module (state=%s) already exists. Only a new build, resubmission of " "a failed build or build against new buildrequirements is " "allowed." % module.state ) log.error(err_msg) raise Conflict(err_msg) return modules