Beispiel #1
0
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]
Beispiel #2
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",
    ), )
Beispiel #3
0
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),
        )
Beispiel #4
0
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")
Beispiel #5
0
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
Beispiel #6
0
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
Beispiel #7
0
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')
Beispiel #8
0
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")
Beispiel #9
0
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")
Beispiel #10
0
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")