def dist_git_upload_completed(): """ Mark BuildChroot in a Build as uploaded, which means: - set it to pending state - set BuildChroot.git_hash - if it's the last BuildChroot in a Build: - delete local srpm BuildChroot is identified with task_id which is build id + git branch name - For example: 56-f22 -> build 55, chroots fedora-22-* """ result = {"updated": False} if "task_id" in flask.request.json: app.logger.debug(flask.request.data) task_id = flask.request.json["task_id"] build_chroots = BuildsLogic.get_chroots_from_dist_git_task_id(task_id) build = build_chroots[0].build # Is it OK? if "git_hash" in flask.request.json and "repo_name" in flask.request.json: git_hash = flask.request.json["git_hash"] pkg_name = flask.request.json["pkg_name"] pkg_version = flask.request.json["pkg_version"] # Now I need to assign a package to this build package = PackagesLogic.get(build.copr.id, pkg_name).first() if not package: package = PackagesLogic.add(build.copr.owner, build.copr, pkg_name) db.session.add(package) db.session.flush() build.package_id = package.id build.pkg_version = pkg_version for ch in build_chroots: ch.status = helpers.StatusEnum("pending") ch.git_hash = git_hash # Failed? elif "error" in flask.request.json: error_type = flask.request.json["error"] try: build.fail_type = helpers.FailTypeEnum(error_type) except KeyError: build.fail_type = helpers.FailTypeEnum("unknown_error") for ch in build_chroots: ch.status = helpers.StatusEnum("failed") # is it the last chroot? if not build.has_importing_chroot: BuildsLogic.delete_local_srpm(build) db.session.commit() result.update({"updated": True}) return flask.jsonify(result)
def fail_type_text(self): return helpers.FailTypeEnum(self.fail_type)
class Build(db.Model, helpers.Serializer): """ Representation of one build in one copr """ __table_args__ = (db.Index('build_canceled', "canceled"), ) id = db.Column(db.Integer, primary_key=True) # single url to the source rpm, should not contain " ", "\n", "\t" pkgs = db.Column(db.Text) # built packages built_packages = db.Column(db.Text) # version of the srpm package got by rpm pkg_version = db.Column(db.Text) # was this build canceled by user? canceled = db.Column(db.Boolean, default=False) # list of space separated additional repos repos = db.Column(db.Text) # the three below represent time of important events for this build # as returned by int(time.time()) submitted_on = db.Column(db.Integer, nullable=False) # url of the build results results = db.Column(db.Text) # memory requirements for backend builder memory_reqs = db.Column(db.Integer, default=constants.DEFAULT_BUILD_MEMORY) # maximum allowed time of build, build will fail if exceeded timeout = db.Column(db.Integer, default=constants.DEFAULT_BUILD_TIMEOUT) # enable networking during a build process enable_net = db.Column(db.Boolean, default=False, server_default="0", nullable=False) # Source of the build: type identifier source_type = db.Column(db.Integer, default=helpers.BuildSourceEnum("unset")) # Source of the build: description in json, example: git link, srpm url, etc. source_json = db.Column(db.Text) # Type of failure: type identifier fail_type = db.Column(db.Integer, default=helpers.FailTypeEnum("unset")) # background builds has lesser priority than regular builds. is_background = db.Column(db.Boolean, default=False, server_default="0", nullable=False) # relations user_id = db.Column(db.Integer, db.ForeignKey("user.id")) user = db.relationship("User", backref=db.backref("builds")) copr_id = db.Column(db.Integer, db.ForeignKey("copr.id")) copr = db.relationship("Copr", backref=db.backref("builds")) package_id = db.Column(db.Integer, db.ForeignKey("package.id")) package = db.relationship("Package") chroots = association_proxy("build_chroots", "mock_chroot") @property def user_name(self): return self.user.name @property def group_name(self): return self.copr.group.name @property def copr_name(self): return self.copr.name @property def fail_type_text(self): return helpers.FailTypeEnum(self.fail_type) @property def is_older_results_naming_used(self): # we have changed result directory naming together with transition to dist-git # that's why we use so strange criterion return self.build_chroots[0].git_hash is None @property def repos_list(self): if self.repos is None: return list() else: return self.repos.split() @property def result_dir_name(self): # We can remove this ugly condition after migrating Copr to new machines # It is throw-back from era before dist-git if self.is_older_results_naming_used: return self.src_pkg_name return "{:08d}-{}".format(self.id, self.package.name) @property def source_json_dict(self): if not self.source_json: return {} return json.loads(self.source_json) @property def started_on(self): return self.min_started_on @property def min_started_on(self): mb_list = [ chroot.started_on for chroot in self.build_chroots if chroot.started_on ] if len(mb_list) > 0: return min(mb_list) else: return None @property def ended_on(self): return self.max_ended_on @property def max_ended_on(self): if not self.build_chroots: return None if any(chroot.ended_on is None for chroot in self.build_chroots): return None return max(chroot.ended_on for chroot in self.build_chroots) @property def chroots_started_on(self): return { chroot.name: chroot.started_on for chroot in self.build_chroots } @property def chroots_ended_on(self): return {chroot.name: chroot.ended_on for chroot in self.build_chroots} @property def source_type_text(self): return helpers.BuildSourceEnum(self.source_type) @property def source_metadata(self): if self.source_json is None: return None try: return json.loads(self.source_json) except (TypeError, ValueError): return None @property def chroot_states(self): return map(lambda chroot: chroot.status, self.build_chroots) def get_chroots_by_status(self, statuses=None): """ Get build chroots with states which present in `states` list If states == None, function returns build_chroots """ chroot_states_map = dict(zip(self.build_chroots, self.chroot_states)) if statuses is not None: statuses = set(statuses) else: return self.build_chroots return [ chroot for chroot, status in chroot_states_map.items() if status in statuses ] @property def chroots_dict_by_name(self): return {b.name: b for b in self.build_chroots} @property def has_pending_chroot(self): # FIXME bad name # used when checking if the repo is initialized and results can be set # i think this is the only purpose - check return StatusEnum("pending") in self.chroot_states or \ StatusEnum("starting") in self.chroot_states @property def has_unfinished_chroot(self): return StatusEnum("pending") in self.chroot_states or \ StatusEnum("starting") in self.chroot_states or \ StatusEnum("running") in self.chroot_states @property def has_importing_chroot(self): return StatusEnum("importing") in self.chroot_states @property def status(self): """ Return build status according to build status of its chroots """ if self.canceled: return StatusEnum("canceled") for state in [ "running", "starting", "importing", "pending", "failed", "succeeded", "skipped" ]: if StatusEnum(state) in self.chroot_states: return StatusEnum(state) @property def state(self): """ Return text representation of status of this build """ if self.status is not None: return StatusEnum(self.status) return "unknown" @property def cancelable(self): """ Find out if this build is cancelable. Build is cancelabel only when it's pending (not started) """ return self.status == StatusEnum("pending") or \ self.status == StatusEnum("importing") @property def repeatable(self): """ Find out if this build is repeatable. Build is repeatable only if it's not pending, starting or running """ return self.status not in [ StatusEnum("pending"), StatusEnum("starting"), StatusEnum("running"), ] @property def finished(self): """ Find out if this build is in finished state. Build is finished only if all its build_chroots are in finished state. """ return all([(chroot.state in ["succeeded", "canceled", "skipped", "failed"]) for chroot in self.build_chroots]) @property def persistent(self): """ Find out if this build is persistent. This property is inherited from the project. """ return self.copr.persistent @property def src_pkg_name(self): """ Extract source package name from source name or url todo: obsolete """ try: src_rpm_name = self.pkgs.split("/")[-1] except: return None if src_rpm_name.endswith(".src.rpm"): return src_rpm_name[:-8] else: return src_rpm_name @property def package_name(self): try: return self.package.name except: return None def to_dict(self, options=None, with_chroot_states=False): result = super(Build, self).to_dict(options) result["src_pkg"] = result["pkgs"] del result["pkgs"] del result["copr_id"] result['source_type'] = helpers.BuildSourceEnum(result['source_type']) result["state"] = self.state if with_chroot_states: result["chroots"] = {b.name: b.state for b in self.build_chroots} return result