Source code for changes.models.step
from uuid import uuid4
from copy import deepcopy
from datetime import datetime
from sqlalchemy import Column, DateTime, ForeignKey, String, Integer
from sqlalchemy.orm import relationship, backref
from sqlalchemy.schema import UniqueConstraint, CheckConstraint
from changes.config import db
from changes.db.types.guid import GUID
from changes.db.types.json import JSONEncodedDict
from changes.db.utils import model_repr
from changes.utils.imports import import_string
STEP_OPTIONS = {
# name => default value,
'build.timeout': '0',
}
[docs]class Step(db.Model):
"""
A specific description of how to do some work for a build.
In theory, a plan can have multiple steps. In practice, every plan has only
one step and plan is just a thin wrapper around step. Steps are not
freeform, rather, each step is just configuration data for specific step
implementations that are hard-coded in python.
"""
# TODO(dcramer): only a single step is currently supported
id = Column(GUID, primary_key=True, default=uuid4)
plan_id = Column(GUID, ForeignKey('plan.id', ondelete='CASCADE'), nullable=False)
date_created = Column(DateTime, default=datetime.utcnow, nullable=False)
date_modified = Column(DateTime, default=datetime.utcnow, nullable=False)
# implementation should be class path notation
implementation = Column(String(128), nullable=False)
order = Column(Integer, nullable=False)
data = Column(JSONEncodedDict)
plan = relationship('Plan', backref=backref('steps', order_by='Step.order'))
__repr__ = model_repr('plan_id', 'implementation')
__tablename__ = 'step'
__table_args__ = (
UniqueConstraint('plan_id', 'order', name='unq_plan_key'),
CheckConstraint(order >= 0, name='chk_step_order_positive'),
)
def __init__(self, **kwargs):
super(Step, self).__init__(**kwargs)
if self.id is None:
self.id = uuid4()
if self.date_created is None:
self.date_created = datetime.utcnow()
if self.date_modified is None:
self.date_modified = self.date_created
def get_implementation(self, load=True):
try:
cls = import_string(self.implementation)
except Exception:
return None
if not load:
return cls
try:
# It's important that we deepcopy data so any
# mutations within the BuildStep don't propagate into the db
return cls(**deepcopy(self.data))
except Exception:
return None