class ChangeRequest(RepositoryBoundMixin, StandardAttributes, db.Model): number = db.Column(db.Integer, nullable=False) # the parent revision is our base commit that this change request applies to parent_revision_sha = db.Column(db.String(40), nullable=False) # for branch-style change requests (e.g. GitHub Pull Requests) we capture # the 'current revision' in addition to the 'parent revision' head_revision_sha = db.Column(db.String(40), nullable=True) message = db.Column(db.String, nullable=False) author_id = db.Column(GUID, db.ForeignKey("author.id"), index=True, nullable=True) provider = db.Column(db.String, nullable=True) external_id = db.Column(db.String(64), nullable=True) url = db.Column(db.String, nullable=True) data = db.Column(JSONEncodedDict, nullable=True) date_updated = db.Column(db.TIMESTAMP(timezone=True), nullable=True, onupdate=timezone.now) head_revision = db.relationship( "Revision", foreign_keys= "[ChangeRequest.repository_id, ChangeRequest.head_revision_sha]", viewonly=True, ) parent_revision = db.relationship( "Revision", foreign_keys= "[ChangeRequest.repository_id, ChangeRequest.parent_revision_sha]", viewonly=True, ) author = db.relationship("Author") __tablename__ = "change_request" __table_args__ = ( db.ForeignKeyConstraint( ("repository_id", "parent_revision_sha"), ("revision.repository_id", "revision.sha"), ), db.ForeignKeyConstraint( ("repository_id", "head_revision_sha"), ("revision.repository_id", "revision.sha"), ), db.Index("idx_cr_parent_revision", "repository_id", "parent_revision_sha"), db.Index("idx_cr_head_revision", "repository_id", "head_revision_sha"), db.UniqueConstraint("repository_id", "number", name="unq_cr_number"), db.UniqueConstraint("repository_id", "provider", "external_id", name="unq_cr_provider"), ) __repr__ = model_repr("repository_id", "parent_revision_sha") @property def subject(self): return self.message.splitlines()[0]
class PendingArtifact(RepositoryBoundMixin, StandardAttributes, db.Model): provider = db.Column(db.String, nullable=False) external_job_id = db.Column(db.String(64), nullable=False) external_build_id = db.Column(db.String(64), nullable=False) hook_id = db.Column(GUID, db.ForeignKey("hook.id", ondelete="CASCADE"), nullable=False, index=True) name = db.Column(db.String(length=256), nullable=False) type = db.Column(db.String(length=64), nullable=True) file = db.Column( File(path="artifacts"), nullable=False, # TODO(dcramer): this is super hacky but not sure a better way to # do it with SQLAlchemy default=lambda: FileData({}, default_path="artifacts"), ) hook = db.relationship("Hook") __tablename__ = "pending_artifact" __table_args__ = (db.Index( "idx_pending_artifact", "repository_id", "provider", "external_job_id", "external_build_id", ), )
class Artifact(RepositoryBoundMixin, StandardAttributes, db.Model): job_id = db.Column( GUID, db.ForeignKey("job.id", ondelete="CASCADE"), nullable=False ) testcase_id = db.Column( GUID, db.ForeignKey("testcase.id", ondelete="CASCADE"), nullable=True ) name = db.Column(db.String(length=256), nullable=False) type = db.Column(db.String(length=64), nullable=True) file = db.Column( File(path="artifacts"), nullable=False, # TODO(dcramer): this is super hacky but not sure a better way to # do it with SQLAlchemy default=lambda: FileData({}, default_path="artifacts"), ) status = db.Column(Enum(Status), nullable=False, default=Status.unknown) date_started = db.Column(db.TIMESTAMP(timezone=True), nullable=True) date_updated = db.Column( db.TIMESTAMP(timezone=True), nullable=True, onupdate=timezone.now ) date_finished = db.Column(db.TIMESTAMP(timezone=True), nullable=True) job = db.relationship("Job", innerjoin=True, uselist=False) testcase = db.relationship("TestCase", uselist=False) __tablename__ = "artifact" __table_args__ = (db.Index("idx_artifact_job", "repository_id", "job_id"),) def save_base64_content(self, base64): content = b64decode(base64) self.file.save( BytesIO(content), "{0}/{1}_{2}".format(self.job_id.hex, self.id.hex, self.name), )
class FailureReason(RepositoryBoundMixin, StandardAttributes, db.Model): class Reason(enum.Enum): failing_tests = "failing_tests" missing_tests = "missing_tests" no_jobs = "no_jobs" unresolvable_ref = "unresolvable_ref" build_id = db.Column(GUID, db.ForeignKey("build.id", ondelete="CASCADE"), nullable=True) job_id = db.Column(GUID, db.ForeignKey("job.id", ondelete="CASCADE"), nullable=True) reason = db.Column(StrEnum(Reason), nullable=False) build = db.relationship("Build") job = db.relationship("Job") __tablename__ = "failurereason" __table_args__ = ( db.UniqueConstraint("build_id", "job_id", "reason", name="unq_failurereason_key"), db.Index( "unq_failurereason_buildonly", build_id, reason, unique=True, postgresql_where=job_id.is_(None), ), ) __repr__ = model_repr("reason")
class Source(RepositoryBoundMixin, StandardAttributes, db.Model): """ A source represents the canonical parameters that a build is running against. """ patch_id = db.Column(GUID, db.ForeignKey("patch.id", ondelete="CASCADE"), unique=True, nullable=True) revision_sha = db.Column(db.String(40), nullable=False) data = db.Column(JSONEncodedDict, nullable=True) author_id = db.Column(GUID, db.ForeignKey("author.id", ondelete="SET NULL"), index=True, nullable=True) author = db.relationship("Author") patch = db.relationship("Patch") revision = db.relationship( "Revision", foreign_keys="[Source.repository_id, Source.revision_sha]", viewonly=True, ) __tablename__ = "source" __table_args__ = ( db.ForeignKeyConstraint( ("repository_id", "revision_sha"), ("revision.repository_id", "revision.sha"), ), db.Index("idx_source_repo_sha", "repository_id", "revision_sha"), db.UniqueConstraint("repository_id", "revision_sha", "patch_id", name="unq_source_revision"), ) __repr__ = model_repr("repository_id", "revision_sha", "patch_id") def is_commit(self): return self.patch_id is None and self.revision_sha def generate_diff(self): if self.patch: return self.patch.diff try: vcs = self.repository.get_vcs() except UnknownRepositoryBackend: return None try: return vcs.export(self.revision_sha) except Exception: # TODO pass
class Source(RepositoryBoundMixin, StandardAttributes, db.Model): """ A source represents the canonical parameters that a build is running against. """ patch_id = db.Column(GUID, db.ForeignKey('patch.id'), unique=True, nullable=True) revision_sha = db.Column(db.String(40), nullable=False) data = db.Column(JSONEncodedDict, nullable=True) author_id = db.Column(GUID, db.ForeignKey('author.id'), index=True) author = db.relationship('Author') patch = db.relationship('Patch', ) revision = db.relationship( 'Revision', foreign_keys='[Source.repository_id, Source.revision_sha]', viewonly=True) __tablename__ = 'source' __table_args__ = ( db.ForeignKeyConstraint(('repository_id', 'revision_sha'), ('revision.repository_id', 'revision.sha')), db.Index('idx_source_repo_sha', 'repository_id', 'revision_sha'), db.UniqueConstraint( 'repository_id', 'revision_sha', 'patch_id', name='unq_source_revision', ), ) __repr__ = model_repr('repository_id', 'revision_sha', 'patch_id') def is_commit(self): return self.patch_id is None and self.revision_sha def generate_diff(self): if self.patch: return self.patch.diff vcs = self.repository.get_vcs() if vcs: try: return vcs.export(self.revision_sha) except Exception: pass return None
class Patch(RepositoryBoundMixin, StandardAttributes, db.Model): parent_revision_sha = db.Column(db.String(40), nullable=False) diff = db.deferred(db.Column(db.Text, nullable=False)) parent_revision = db.relationship( 'Revision', foreign_keys='[Patch.repository_id, Patch.parent_revision_sha]', viewonly=True) __tablename__ = 'patch' __table_args__ = ( db.ForeignKeyConstraint(('repository_id', 'parent_revision_sha'), ('revision.repository_id', 'revision.sha')), db.Index('idx_repo_sha', 'repository_id', 'parent_revision_sha'), ) __repr__ = model_repr('repository_id', 'parent_revision_sha')
class Patch(RepositoryBoundMixin, StandardAttributes, db.Model): parent_revision_sha = db.Column(db.String(40), nullable=False) diff = db.deferred(db.Column(db.Text, nullable=False)) parent_revision = db.relationship( "Revision", foreign_keys="[Patch.repository_id, Patch.parent_revision_sha]", viewonly=True, ) __tablename__ = "patch" __table_args__ = ( db.ForeignKeyConstraint( ("repository_id", "parent_revision_sha"), ("revision.repository_id", "revision.sha"), ), db.Index("idx_repo_sha", "repository_id", "parent_revision_sha"), ) __repr__ = model_repr("repository_id", "parent_revision_sha")
class Build(RepositoryBoundMixin, StandardAttributes, db.Model): """ A single build linked to a source. Each Build contains many Jobs. """ source_id = db.Column( GUID, db.ForeignKey("source.id", ondelete="CASCADE"), nullable=False, index=True ) number = db.Column(db.Integer, nullable=False) label = db.Column(db.String, nullable=False) status = db.Column(Enum(Status), nullable=False, default=Status.unknown) result = db.Column(Enum(Result), nullable=False, default=Result.unknown) date_created = db.Column( db.TIMESTAMP(timezone=True), nullable=False, default=timezone.now, server_default=func.now(), index=True, ) date_started = db.Column(db.TIMESTAMP(timezone=True), nullable=True) date_finished = db.Column(db.TIMESTAMP(timezone=True), nullable=True) data = db.Column(JSONEncodedDict, nullable=True) provider = db.Column(db.String, nullable=True) external_id = db.Column(db.String(64), nullable=True) hook_id = db.Column( GUID, db.ForeignKey("hook.id", ondelete="CASCADE"), nullable=True, index=True ) url = db.Column(db.String, nullable=True) # author_id is inherited from Source.author_id, and is denormalized to speed up # "my builds" type of queries author_id = db.Column( GUID, db.ForeignKey("author.id", ondelete="SET NULL"), index=False, nullable=True, ) author = db.relationship("Author") source = db.relationship("Source", innerjoin=True) hook = db.relationship("Hook") stats = db.relationship( "ItemStat", foreign_keys="[ItemStat.item_id]", primaryjoin="ItemStat.item_id == Build.id", viewonly=True, uselist=True, ) __tablename__ = "build" __table_args__ = ( db.UniqueConstraint("repository_id", "number", name="unq_build_number"), db.UniqueConstraint( "repository_id", "provider", "external_id", name="unq_build_provider" ), db.Index("idx_build_author_date", "author_id", "date_created"), db.Index( "idx_build_outcomes", "repository_id", "status", "result", "date_created" ), ) __repr__ = model_repr("number", "status", "result")
class Build(RepositoryBoundMixin, StandardAttributes, db.Model): """ A single build. Each Build contains many Jobs. """ ref = db.Column(db.String, nullable=True) revision_sha = db.Column(db.String(40), nullable=True) number = db.Column(db.Integer, nullable=False) label = db.Column(db.String, nullable=True) status = db.Column(Enum(Status), nullable=False, default=Status.unknown) result = db.Column(Enum(Result), nullable=False, default=Result.unknown) date_created = db.Column( db.TIMESTAMP(timezone=True), nullable=False, default=timezone.now, server_default=func.now(), index=True, ) date_started = db.Column(db.TIMESTAMP(timezone=True), nullable=True) date_finished = db.Column(db.TIMESTAMP(timezone=True), nullable=True) data = db.Column(JSONEncodedDict, nullable=True) provider = db.Column(db.String, nullable=True) external_id = db.Column(db.String(64), nullable=True) hook_id = db.Column(GUID, db.ForeignKey("hook.id", ondelete="CASCADE"), nullable=True, index=True) url = db.Column(db.String, nullable=True) author_id = db.Column( GUID, db.ForeignKey("author.id", ondelete="SET NULL"), index=False, nullable=True, ) authors = db.relationship("Author", secondary=build_author_table, backref="builds") revision = db.relationship( "Revision", foreign_keys="[Build.repository_id, Build.revision_sha]", viewonly=True, ) hook = db.relationship("Hook") stats = db.relationship( "ItemStat", foreign_keys="[ItemStat.item_id]", primaryjoin="ItemStat.item_id == Build.id", viewonly=True, uselist=True, ) failures = db.relationship( "FailureReason", foreign_keys="[FailureReason.build_id]", primaryjoin="FailureReason.build_id == Build.id", viewonly=True, uselist=True, ) __tablename__ = "build" __table_args__ = ( db.UniqueConstraint("repository_id", "number", name="unq_build_number"), db.UniqueConstraint("repository_id", "provider", "external_id", name="unq_build_provider"), db.ForeignKeyConstraint( ("repository_id", "revision_sha"), ("revision.repository_id", "revision.sha"), ), db.Index("idx_build_repo_sha", "repository_id", "revision_sha"), db.Index("idx_build_author_date", "author_id", "date_created"), db.Index("idx_build_outcomes", "repository_id", "status", "result", "date_created"), ) __repr__ = model_repr("number", "status", "result")