Esempio n. 1
0
class Build(ProjectBoundMixin, 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_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)

    source = db.relationship('Source')
    stats = db.relationship(
        'ItemStat',
        foreign_keys='[ItemStat.item_id]',
        primaryjoin='ItemStat.item_id == Build.id',
        lazy='subquery',
        viewonly=True,
        uselist=True
    )

    __tablename__ = 'build'
    __table_args__ = (
        db.UniqueConstraint('project_id', 'number', name='unq_build_number'),
        db.UniqueConstraint('project_id', 'provider', 'external_id', name='unq_build_provider')
    )
    __repr__ = model_repr('number', 'status', 'result')
Esempio n. 2
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'

    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)
        )
Esempio n. 3
0
class Repository(OrganizationBoundMixin, StandardAttributes, db.Model):
    """
    Represents a single repository.
    """
    query_class = RepositoryAccessBoundQuery

    provider = db.Column(StrEnum(RepositoryProvider),
                         default=RepositoryProvider.native,
                         nullable=False)
    external_id = db.Column(db.String(64))
    url = db.Column(db.String(200), nullable=False)
    backend = db.Column(Enum(RepositoryBackend),
                        default=RepositoryBackend.unknown,
                        nullable=False)
    status = db.Column(Enum(RepositoryStatus),
                       default=RepositoryStatus.inactive,
                       nullable=False)
    data = db.Column(JSONEncodedDict, nullable=True)
    last_update = db.Column(db.TIMESTAMP(timezone=True), nullable=True)
    last_update_attempt = db.Column(db.TIMESTAMP(timezone=True), nullable=True)

    options = db.relationship(
        'ItemOption',
        foreign_keys='[ItemOption.item_id]',
        primaryjoin='ItemOption.item_id == Repository.id',
        lazy='subquery',
        viewonly=True,
        uselist=True)

    __tablename__ = 'repository'
    __table_args__ = (db.UniqueConstraint('organization_id',
                                          'provider',
                                          'external_id',
                                          name='unq_external_id'), )
    __repr__ = model_repr('url', 'provider', 'external_id')

    def get_vcs(self):
        from zeus.models import ItemOption
        from zeus.vcs.git import GitVcs

        options = dict(
            db.session.query(ItemOption.name, ItemOption.value).filter(
                ItemOption.item_id == self.id,
                ItemOption.name.in_([
                    'auth.username',
                ])))

        kwargs = {
            'path': os.path.join(current_app.config['REPO_ROOT'], self.id.hex),
            'url': self.url,
            'username': options.get('auth.username'),
        }

        if self.backend == RepositoryBackend.git:
            return GitVcs(**kwargs)
        else:
            raise NotImplementedError('Invalid backend: {}'.format(
                self.backend))
Esempio n. 4
0
class Job(RepositoryBoundMixin, StandardAttributes, db.Model):
    """
    A single job, which is the actual execution unit for a build.
    """

    id = db.Column(GUID, primary_key=True, default=GUID.default_value)
    build_id = db.Column(GUID,
                         db.ForeignKey("build.id", ondelete="CASCADE"),
                         nullable=False,
                         index=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)
    allow_failure = db.Column(db.Boolean,
                              nullable=False,
                              default=False,
                              server_default="0")
    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)
    data = db.Column(JSONEncodedDict, 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)

    build = db.relationship("Build",
                            backref=db.backref("jobs",
                                               order_by="Job.date_created"),
                            innerjoin=True)
    stats = db.relationship(
        "ItemStat",
        foreign_keys="[ItemStat.item_id]",
        primaryjoin="ItemStat.item_id == Job.id",
        viewonly=True,
        uselist=True,
    )
    failures = db.relationship(
        "FailureReason",
        foreign_keys="[FailureReason.job_id]",
        primaryjoin="FailureReason.job_id == Job.id",
        viewonly=True,
        uselist=True,
    )

    __tablename__ = "job"
    __table_args__ = (
        db.UniqueConstraint("build_id", "number", name="unq_job_number"),
        db.UniqueConstraint("build_id",
                            "provider",
                            "external_id",
                            name="unq_job_provider"),
    )
    __repr__ = model_repr("build_id", "number", "status", "result")
Esempio n. 5
0
class Revision(db.Model):
    # XXX(dcramer): the primary_key doesnt include repo_id at the moment, which is wrong, but
    # we need to deal w/ that in a followup change
    repository_id = db.Column(
        GUID, db.ForeignKey("repository.id", ondelete="CASCADE"), primary_key=True
    )
    sha = db.Column(db.String(40), primary_key=True)
    author_id = db.Column(
        GUID, db.ForeignKey("author.id", ondelete="SET NULL"), index=True, nullable=True
    )
    committer_id = db.Column(
        GUID, db.ForeignKey("author.id", ondelete="SET NULL"), index=True, nullable=True
    )
    message = db.Column(db.Text, nullable=True)
    parents = db.Column(ARRAY(db.String(40)), nullable=True)
    # TODO: remove this column, we dont use it and its wrong
    branches = db.Column(ARRAY(db.String(128)), nullable=True)
    date_created = db.Column(
        db.TIMESTAMP(timezone=True),
        default=timezone.now,
        server_default=func.now(),
        nullable=False,
    )
    date_committed = db.Column(
        db.TIMESTAMP(timezone=True),
        default=timezone.now,
        server_default=func.now(),
        nullable=False,
    )

    authors = db.relationship(
        "Author", secondary=revision_author_table, backref="revisions"
    )
    committer = db.relationship("Author", foreign_keys=[committer_id])
    repository = db.relationship("Repository", foreign_keys=[repository_id])

    query_class = RepositoryBoundQuery

    __tablename__ = "revision"
    # XXX(dcramer): the primary_key doesnt include repo_id at the moment, which is wrong, but
    # we need to deal w/ that in a followup change
    __table_args__ = (db.UniqueConstraint("repository_id", "sha", name="unq_revision"),)
    __repr__ = model_repr("repository_id", "sha", "subject")

    @property
    def subject(self):
        return self.message.splitlines()[0]

    def generate_diff(self):
        from zeus.vcs import vcs_client

        try:
            return vcs_client.export(self.repository_id, self.sha)
        except Exception:
            current_app.logger.exception("generate_diff failure")
Esempio n. 6
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)
    url = db.Column(db.String, nullable=True)

    source = db.relationship("Source", innerjoin=True)
    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"),
    )
    __repr__ = model_repr("number", "status", "result")
Esempio n. 7
0
 def date_created(cls):
     return db.Column(
         db.TIMESTAMP(timezone=True),
         default=timezone.now,
         server_default=func.now(),
         nullable=False,
     )
Esempio n. 8
0
class Job(RepositoryBoundMixin, StandardAttributes, db.Model):
    """
    A single job, which is the actual execution unit for a build.
    """
    id = db.Column(GUID, primary_key=True, default=GUID.default_value)
    build_id = db.Column(GUID,
                         db.ForeignKey('build.id', ondelete='CASCADE'),
                         nullable=False,
                         index=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_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)
    url = db.Column(db.String, nullable=True)

    build = db.relationship('Build',
                            backref=db.backref('jobs',
                                               order_by='Job.date_created'),
                            innerjoin=True)
    stats = db.relationship('ItemStat',
                            foreign_keys='[ItemStat.item_id]',
                            primaryjoin='ItemStat.item_id == Job.id',
                            viewonly=True,
                            uselist=True)
    failures = db.relationship(
        'FailureReason',
        foreign_keys='[FailureReason.job_id]',
        primaryjoin='FailureReason.job_id == Job.id',
        viewonly=True,
        uselist=True,
    )

    __tablename__ = 'job'
    __table_args__ = (db.UniqueConstraint('build_id',
                                          'number',
                                          name='unq_job_number'),
                      db.UniqueConstraint('build_id',
                                          'provider',
                                          'external_id',
                                          name='unq_job_provider'))
    __repr__ = model_repr('build_id', 'number', 'status', 'result')
Esempio n. 9
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]
Esempio n. 10
0
class Revision(RepositoryBoundMixin, db.Model):
    sha = db.Column(db.String(40), primary_key=True)
    author_id = db.Column(GUID,
                          db.ForeignKey("author.id"),
                          index=True,
                          nullable=True)
    committer_id = db.Column(GUID,
                             db.ForeignKey("author.id"),
                             index=True,
                             nullable=True)
    message = db.Column(db.Text, nullable=True)
    parents = db.Column(ARRAY(db.String(40)), nullable=True)
    branches = db.Column(ARRAY(db.String(128)), nullable=True)
    date_created = db.Column(
        db.TIMESTAMP(timezone=True),
        default=timezone.now,
        server_default=func.now(),
        nullable=False,
    )
    date_committed = db.Column(
        db.TIMESTAMP(timezone=True),
        default=timezone.now,
        server_default=func.now(),
        nullable=False,
    )

    author = db.relationship("Author", foreign_keys=[author_id])
    committer = db.relationship("Author", foreign_keys=[committer_id])

    __tablename__ = "revision"
    __table_args__ = (db.UniqueConstraint("repository_id",
                                          "sha",
                                          name="unq_revision"), )
    __repr__ = model_repr("repository_id", "sha", "subject")

    @property
    def subject(self):
        return self.message.splitlines()[0]
Esempio n. 11
0
class ApiToken(StandardAttributes, db.Model):
    """
    An API token.
    """

    access_token = db.Column(
        db.String(64),
        default=lambda: ApiToken.generate_token(),
        unique=True,
        nullable=False,
    )
    refresh_token = db.Column(
        db.String(64),
        default=lambda: ApiToken.generate_token(),
        unique=True,
        nullable=False,
    )
    expires_at = db.Column(
        db.TIMESTAMP(timezone=True),
        nullable=True,
        default=lambda: timezone.now() + DEFAULT_EXPIRATION,
    )

    __tablename__ = "api_token"
    __repr__ = model_repr("id")

    @classmethod
    def generate_token(cls) -> str:
        return token_hex(32)

    def is_expired(self) -> bool:
        if not self.expires_at:
            return False

        return timezone.now() >= self.expires_at

    def refresh(self, expires_at=None):
        if expires_at is None:
            expires_at = timezone.now() + DEFAULT_EXPIRATION

        with db.session.begin_nested():
            self.token = type(self).generate_token()
            self.refresh_token = type(self).generate_token()
            self.expires_at = expires_at
            db.session.add(self)
            db.session.commit()
Esempio n. 12
0
class User(StandardAttributes, db.Model):
    """
    Actors within Zeus.
    """

    email = db.Column(db.String(128), unique=True, nullable=False)
    date_active = db.Column(
        db.TIMESTAMP(timezone=True),
        nullable=False,
        default=timezone.now,
        server_default=func.now(),
        index=True,
    )

    options = db.relationship(
        "ItemOption",
        foreign_keys="[ItemOption.item_id]",
        primaryjoin="ItemOption.item_id == User.id",
        viewonly=True,
        uselist=True,
    )

    __tablename__ = "user"
    __repr__ = model_repr("email")
Esempio n. 13
0
class Repository(StandardAttributes, db.Model):
    """
    Represents a single repository.
    """
    # TODO(dcramer): we dont want to be coupled to GitHub (the concept of orgs)
    # but right now we simply dont care, and this can be refactored later (URLs
    # are tricky)
    owner_name = db.Column(db.String(200), nullable=False)
    name = db.Column(db.String(200), nullable=False)
    url = db.Column(db.String(200), nullable=False)
    backend = db.Column(
        Enum(RepositoryBackend), default=RepositoryBackend.unknown, nullable=False
    )
    status = db.Column(
        Enum(RepositoryStatus), default=RepositoryStatus.inactive, nullable=False
    )
    provider = db.Column(StrEnum(RepositoryProvider), nullable=False)
    external_id = db.Column(db.String(64))
    data = db.Column(JSONEncodedDict, nullable=True)
    public = db.Column(
        db.Boolean, default=False, server_default="false", nullable=False, index=True
    )
    last_update = db.Column(db.TIMESTAMP(timezone=True), nullable=True)
    last_update_attempt = db.Column(db.TIMESTAMP(timezone=True), nullable=True)

    options = db.relationship(
        "ItemOption",
        foreign_keys="[ItemOption.item_id]",
        primaryjoin="ItemOption.item_id == Repository.id",
        viewonly=True,
        uselist=True,
    )

    query_class = RepositoryAccessBoundQuery

    __tablename__ = "repository"
    __table_args__ = (
        db.UniqueConstraint("provider", "external_id", name="unq_repo_external_id"),
        db.UniqueConstraint("provider", "owner_name", "name", name="unq_repo_name"),
    )
    __repr__ = model_repr("name", "url", "provider")

    def get_vcs(self):
        from zeus.models import ItemOption
        from zeus.vcs.git import GitVcs

        options = dict(
            db.session.query(ItemOption.name, ItemOption.value).filter(
                ItemOption.item_id == self.id, ItemOption.name.in_(["auth.username"])
            )
        )

        kwargs = {
            "path": os.path.join(current_app.config["REPO_ROOT"], self.id.hex),
            "id": self.id.hex,
            "url": self.url,
            "username": options.get("auth.username"),
        }

        if self.backend == RepositoryBackend.git:
            return GitVcs(**kwargs)

        else:
            raise NotImplementedError("Invalid backend: {}".format(self.backend))

    def get_full_name(self):
        return "{}/{}/{}".format(self.provider, self.owner_name, self.name)
Esempio n. 14
0
class Repository(StandardAttributes, db.Model):
    """
    Represents a single repository.
    """
    # TODO(dcramer): we dont want to be coupled to GitHub (the concept of orgs)
    # but right now we simply dont care, and this can be refactored later (URLs
    # are tricky)
    owner_name = db.Column(db.String(200), nullable=False)
    name = db.Column(db.String(200), nullable=False)
    url = db.Column(db.String(200), nullable=False)
    backend = db.Column(Enum(RepositoryBackend),
                        default=RepositoryBackend.unknown,
                        nullable=False)
    status = db.Column(Enum(RepositoryStatus),
                       default=RepositoryStatus.inactive,
                       nullable=False)
    provider = db.Column(StrEnum(RepositoryProvider), nullable=False)
    external_id = db.Column(db.String(64))
    data = db.Column(JSONEncodedDict, nullable=True)
    last_update = db.Column(db.TIMESTAMP(timezone=True), nullable=True)
    last_update_attempt = db.Column(db.TIMESTAMP(timezone=True), nullable=True)

    options = db.relationship(
        'ItemOption',
        foreign_keys='[ItemOption.item_id]',
        primaryjoin='ItemOption.item_id == Repository.id',
        viewonly=True,
        uselist=True)

    query_class = RepositoryAccessBoundQuery

    __tablename__ = 'repository'
    __table_args__ = (
        db.UniqueConstraint('provider',
                            'external_id',
                            name='unq_repo_external_id'),
        db.UniqueConstraint('provider',
                            'owner_name',
                            'name',
                            name='unq_repo_name'),
    )
    __repr__ = model_repr('name', 'url', 'provider')

    def get_vcs(self):
        from zeus.models import ItemOption
        from zeus.vcs.git import GitVcs

        options = dict(
            db.session.query(ItemOption.name, ItemOption.value).filter(
                ItemOption.item_id == self.id,
                ItemOption.name.in_([
                    'auth.username',
                ])))

        kwargs = {
            'path': os.path.join(current_app.config['REPO_ROOT'], self.id.hex),
            'id': self.id.hex,
            'url': self.url,
            'username': options.get('auth.username'),
        }

        if self.backend == RepositoryBackend.git:
            return GitVcs(**kwargs)
        else:
            raise NotImplementedError('Invalid backend: {}'.format(
                self.backend))

    def get_full_name(self):
        return '{}/{}/{}'.format(self.provider, self.owner_name, self.name)
Esempio n. 15
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")
Esempio n. 16
0
class Repository(StandardAttributes, db.Model):
    """
    Represents a single repository.
    """

    # TODO(dcramer): we dont want to be coupled to GitHub (the concept of orgs)
    # but right now we simply dont care, and this can be refactored later (URLs
    # are tricky)
    owner_name = db.Column(db.String(200), nullable=False)
    name = db.Column(db.String(200), nullable=False)
    url = db.Column(db.String(200), nullable=False)
    backend = db.Column(Enum(RepositoryBackend),
                        default=RepositoryBackend.unknown,
                        nullable=False)
    status = db.Column(Enum(RepositoryStatus),
                       default=RepositoryStatus.inactive,
                       nullable=False)
    provider = db.Column(StrEnum(RepositoryProvider), nullable=False)
    external_id = db.Column(db.String(64))
    data = db.Column(JSONEncodedDict, nullable=True)
    public = db.Column(db.Boolean,
                       default=False,
                       server_default="false",
                       nullable=False,
                       index=True)
    last_update = db.Column(db.TIMESTAMP(timezone=True), nullable=True)
    last_update_attempt = db.Column(db.TIMESTAMP(timezone=True), nullable=True)
    next_update = db.Column(db.TIMESTAMP(timezone=True), nullable=True)

    options = db.relationship(
        "ItemOption",
        foreign_keys="[ItemOption.item_id]",
        primaryjoin="ItemOption.item_id == Repository.id",
        viewonly=True,
        uselist=True,
    )

    query_class = RepositoryAccessBoundQuery

    __tablename__ = "repository"
    __table_args__ = (
        db.UniqueConstraint("provider",
                            "external_id",
                            name="unq_repo_external_id"),
        db.UniqueConstraint("provider",
                            "owner_name",
                            "name",
                            name="unq_repo_name"),
    )
    __repr__ = model_repr("name", "url", "provider")

    def get_full_name(self):
        return "{}/{}/{}".format(self.provider, self.owner_name, self.name)

    @staticmethod
    def get_lock_key(provider: str, owner_name: str, repo_name: str) -> str:
        return "repo:{provider}/{owner_name}/{repo_name}".format(
            provider=provider, owner_name=owner_name, repo_name=repo_name)

    @classmethod
    def from_full_name(cls, full_name):
        provider, owner_name, name = full_name.split("/", 2)

        return cls.query.filter_by(provider=RepositoryProvider(provider),
                                   owner_name=owner_name,
                                   name=name).first()