class OrganizationMember(db.Model): __tablename__ = 'organization_members' user_id = db.Column( postgresql.UUID(as_uuid=True), db.ForeignKey('users.id'), primary_key=True ) organization_id = db.Column( postgresql.UUID(as_uuid=True), db.ForeignKey('organizations.id'), primary_key=True ) admin = db.Column( db.Boolean, nullable=False, default=False ) user = db.relationship( 'User', back_populates="organizations" ) organization = db.relationship( 'Organization', back_populates="members" )
class TeamMember(db.Model): __tablename__ = 'team_members' user_id = db.Column( postgresql.UUID(as_uuid=True), db.ForeignKey('users.id'), primary_key=True ) team_id = db.Column( postgresql.UUID(as_uuid=True), db.ForeignKey('teams.id'), primary_key=True ) admin = db.Column( db.Boolean, nullable=False, default=False ) user = db.relationship( 'User', back_populates="teams" ) team = db.relationship( 'Team', back_populates="members" )
class Project(db.Model, Timestamp): __versioned__ = {} __tablename__ = 'projects' def __init__(self, *args, **kwargs): if 'slug' not in kwargs: kwargs['slug'] = slugify(kwargs.get('name')) super().__init__(*args, **kwargs) id = db.Column( postgresql.UUID(as_uuid=True), server_default=text("gen_random_uuid()"), nullable=False, primary_key=True, ) organization_id = db.Column( postgresql.UUID(as_uuid=True), db.ForeignKey('organizations.id'), ) name = db.Column(db.Text(), nullable=False) slug = db.Column(CIText(), nullable=False) project_applications = db.relationship( "Application", backref="project", cascade="all, delete-orphan", ) UniqueConstraint(organization_id, slug)
class OrganizationTeam(db.Model): __tablename__ = 'organization_teams' organization_id = db.Column( postgresql.UUID(as_uuid=True), db.ForeignKey('organizations.id'), primary_key=True ) team_id = db.Column( postgresql.UUID(as_uuid=True), db.ForeignKey('teams.id'), primary_key=True ) organization = db.relationship( 'Organization', back_populates="teams" ) team = db.relationship( 'Team', back_populates="organizations" )
class Application(db.Model, Timestamp): __versioned__ = {} __tablename__ = 'project_applications' id = db.Column(postgresql.UUID(as_uuid=True), server_default=text("gen_random_uuid()"), nullable=False, primary_key=True) project_id = db.Column( postgresql.UUID(as_uuid=True), db.ForeignKey('projects.id'), nullable=False, ) name = db.Column(db.Text(), nullable=False) slug = db.Column(CIText(), nullable=False) platform = db.Column(platform_version, nullable=False, default='wind') process_counts = db.Column(postgresql.JSONB(), server_default=text("json_object('{}')")) process_pod_classes = db.Column(postgresql.JSONB(), server_default=text("json_object('{}')")) images = db.relationship( "Image", backref="application", cascade="all, delete-orphan", lazy="dynamic", ) configurations = db.relationship( "Configuration", backref="application", cascade="all, delete-orphan", ) releases = db.relationship( "Release", backref="application", cascade="all, delete-orphan", lazy="dynamic", ) deployments = db.relationship( "Deployment", backref="application", cascade="all, delete-orphan", lazy="dynamic", ) version_id = db.Column(db.Integer, nullable=False) github_app_installation_id = db.Column( db.Integer, nullable=True, ) github_repository = db.Column( db.Text(), nullable=True, ) auto_deploy_branch = db.Column( db.Text(), nullable=True, ) @property def release_candidate(self): release = Release( application_id=self.id, image=self.latest_image.asdict if self.latest_image else {}, configuration={c.name: c.asdict for c in self.configurations}, platform=self.platform, ) return release.asdict @property def latest_release(self): return self.releases.filter_by().order_by( Release.version.desc()).first() @property def latest_release_built(self): return self.releases.filter_by(built=True).order_by( Release.version.desc()).first() @property def latest_release_error(self): return self.releases.filter_by(error=True).order_by( Release.version.desc()).first() @property def latest_release_building(self): return self.releases.filter_by(built=False, error=False).order_by( Release.version.desc()).first() @property def current_release(self): if self.latest_release: return self.latest_release.asdict return {} @property def latest_deployment(self): return self.deployments.filter_by().order_by( Deployment.version.desc()).first() @property def latest_deployment_completed(self): return self.deployments.filter_by(complete=True).order_by( Deployment.version.desc()).first() @property def latest_deployment_error(self): return self.deployments.filter_by(error=True).order_by( Deployment.version.desc()).first() @property def latest_deployment_running(self): return self.deployments.filter_by( complete=False, error=False).order_by(Deployment.version.desc()).first() @property def current_deployment(self): if self.latest_deployment: return self.latest_deployment.asdict return {} @property def recent_deployments(self): return self.deployments.order_by(Deployment.created.desc()).limit(5) @property def ready_for_deployment(self): current = self.current_release candidate = self.release_candidate configuration_diff = DictDiffer( candidate.get('configuration', {}), current.get('configuration', {}), ignored_keys=['id', 'version_id'], ) image_diff = DictDiffer( candidate.get('image', {}), current.get('image', {}), ignored_keys=['id', 'version_id'], ) return image_diff, configuration_diff def create_release(self): image_diff, configuration_diff = self.ready_for_deployment organization_slug = self.project.organization.slug project_slug = self.project.slug application_slug = self.slug repository_name = f"cabotage/{organization_slug}/{project_slug}/{application_slug}" release = Release( application_id=self.id, image=self.latest_image.asdict, repository_name=repository_name, configuration={c.name: c.asdict for c in self.configurations}, image_changes=image_diff.asdict, configuration_changes=configuration_diff.asdict, platform=self.platform, ) return release @property def latest_image(self): return self.images.filter_by().order_by(Image.version.desc()).first() @property def latest_image_built(self): return self.images.filter_by(built=True).order_by( Image.version.desc()).first() @property def latest_image_error(self): return self.images.filter_by(error=True).order_by( Image.version.desc()).first() @property def latest_image_building(self): return self.images.filter_by(built=False, error=False).order_by( Image.version.desc()).first() UniqueConstraint(project_id, slug) __mapper_args__ = {"version_id_col": version_id}