def get(self, app): app = App.query.filter(App.name == app).first() if app is None: return self.error('Invalid app', name='invalid_resource', status_code=404) deploy_config = TaskConfig.query.filter( TaskConfig.app_id == app.id, TaskConfig.type == TaskConfigType.deploy, ).first() if deploy_config is None: return self.error('Missing deploy config', name='missing_conf', status_code=404) context = serialize(app) context.update({ 'provider': deploy_config.provider, 'provider_config': deploy_config.provider_config, 'notifiers': deploy_config.notifiers, 'checks': deploy_config.checks, }) return self.respond(context)
def put(self, **kwargs): deploy = self._get_deploy(**kwargs) if deploy is None: return self.error("Invalid deploy", name="invalid_resource", status_code=404) with lock(redis, f"deploy:{deploy.id}", timeout=5): # we have to refetch in order to ensure lock state changes deploy = Deploy.query.get(deploy.id) task = Task.query.get(deploy.task_id) args = self.put_parser.parse_args() if args.status: assert task.status in (TaskStatus.pending, TaskStatus.in_progress) assert args.status == "cancelled" did_cancel = task.status == TaskStatus.pending task.status = TaskStatus.cancelled db.session.add(task) db.session.commit() if args.status and did_cancel: send_task_notifications(task, NotifierEvent.TASK_FINISHED) return self.respond(serialize(deploy))
def test_locked(self): user = self.create_user() repo = self.create_repo() app = self.create_app(repository=repo) result = serialize(app) assert result['id'] == str(app.id) assert result['name'] == app.name
def get(self, **kwargs): """ Retrive a task. """ task = self._get_task(**kwargs) if task is None: return self.error('Invalid task', name='invalid_resource', status_code=404) return self.respond(serialize(task))
def get(self, **kwargs): """ Retrive a task. """ deploy = self._get_deploy(**kwargs) if deploy is None: return self.error('Invalid deploy', name='invalid_resource', status_code=404) return self.respond(serialize(deploy))
def get(self, task_id): """ Retrive a task. """ task = Task.query.get(task_id) if task is None: return self.error('Invalid task', name='invalid_resource', status_code=404) return self.respond(serialize(task))
def put(self, **kwargs): task = self._get_task(**kwargs) if task is None: return self.error('Invalid task', name='invalid_resource', status_code=404) args = self.put_parser.parse_args() if args.status: assert task.status in (TaskStatus.pending, TaskStatus.in_progress) assert args.status == 'cancelled' task.status = TaskStatus.cancelled db.session.add(task) db.session.commit() return self.respond(serialize(task))
def get(self, app): app = App.query.filter(App.name == app).first() if app is None: return self.error('Invalid app', name='invalid_resource', status_code=404) context = serialize(app) context.update({ 'provider': app.provider, 'provider_config': app.provider_config, 'notifiers': app.notifiers, 'checks': app.checks, }) return self.respond(context)
def get(self): """ Retrieve a list of apps. """ args = self.get_parser.parse_args() qs_filters = [] if args.name: qs_filters.append(App.name == args.name) app_qs = App.query.filter(*qs_filters).order_by(App.name.asc()) return self.respond(serialize(list(app_qs)))
def post(self): """ Create a new app. """ args = self.post_parser.parse_args() provider_config = parse_provider_config(args.provider, args.provider_config or {}) checks_config = parse_checks_config(args.checks or []) notifiers_config = parse_notifiers_config(args.notifiers or []) environments_config = parse_environments_config(args.environments or {}) # TODO(dcramer): this needs to be a get_or_create pattern repo = Repository.query.filter( Repository.url == args.repository, ).first() if repo is None: repo = Repository(url=args.repository, vcs='git') db.session.add(repo) db.session.flush() app = App( name=args.name, repository_id=repo.id, data={ 'environments': environments_config, }, ) db.session.add(app) db.session.flush() # For backwards compatibility, we assume that we need a deploy TaskConfig # on the app at all times. deploy_config = TaskConfig( app_id=app.id, type=TaskConfigType.deploy, provider=args.provider, data={ 'provider_config': provider_config, 'notifiers': notifiers_config, 'checks': checks_config, }, ) db.session.add(deploy_config) db.session.commit() return self.respond(serialize(app), status_code=201)
def test_locked(self): user = self.create_user() repo = self.create_repo() app = self.create_app(repository=repo) task = self.create_task(app=app, user=user, status=TaskStatus.pending) result = serialize(task) assert result["id"] == str(task.id) assert result["status"] == "pending" assert result["ref"] == task.ref assert result["sha"] == task.sha assert result["environment"] == task.environment assert result["number"] == task.number assert result["app"]["id"] == str(app.id) assert result["app"]["name"] == app.name
def test_locked(self): user = self.create_user() repo = self.create_repo() app = self.create_app(repository=repo) task = self.create_task(app=app, user=user, status=TaskStatus.pending) result = serialize(task) assert result['id'] == str(task.id) assert result['status'] == 'pending' assert result['ref'] == task.ref assert result['sha'] == task.sha assert result['environment'] == task.environment assert result['number'] == task.number assert result['app']['id'] == str(app.id) assert result['app']['name'] == app.name
def put(self, task_id): task = Task.query.get(task_id) if task is None: return self.error('Invalid task', name='invalid_resource', status_code=404) args = self.put_parser.parse_args() if args.status: assert task.status in (TaskStatus.pending, TaskStatus.in_progress) assert args.status == 'cancelled' task.status = TaskStatus.cancelled db.session.add(task) db.session.commit() return self.respond(serialize(task))
def post(self): """ Create a new app. """ args = self.post_parser.parse_args() provider_config = parse_provider_config( args.provider, args.provider_config or {} ) checks_config = parse_checks_config(args.checks or []) notifiers_config = parse_notifiers_config(args.notifiers or []) environments_config = parse_environments_config(args.environments or {}) # TODO(dcramer): this needs to be a get_or_create pattern repo = Repository.query.filter(Repository.url == args.repository).first() if repo is None: repo = Repository(url=args.repository, vcs="git") db.session.add(repo) db.session.flush() app = App( name=args.name, repository_id=repo.id, data={"environments": environments_config}, ) db.session.add(app) db.session.flush() # For backwards compatibility, we assume that we need a deploy TaskConfig # on the app at all times. deploy_config = TaskConfig( app_id=app.id, type=TaskConfigType.deploy, provider=args.provider, data={ "provider_config": provider_config, "notifiers": notifiers_config, "checks": checks_config, }, ) db.session.add(deploy_config) db.session.commit() return self.respond(serialize(app), status_code=201)
def test_locked(self): user = self.create_user() repo = self.create_repo() app = self.create_app(repository=repo) self.create_taskconfig(app=app) task = self.create_task(app=app, user=user, status=TaskStatus.pending) deploy = self.create_deploy(app=app, task=task) result = serialize(deploy) assert result['id'] == str(deploy.id) assert result['status'] == 'pending' assert result['ref'] == task.ref assert result['sha'] == task.sha assert result['environment'] == deploy.environment assert result['number'] == deploy.number assert result['app']['id'] == str(app.id) assert result['app']['name'] == app.name
def get(self, app): app = App.query.filter(App.name == app).first() if app is None: return self.error('Invalid app', name='invalid_resource', status_code=404) context = serialize(app) context.update({ 'provider': app.provider, 'provider_config': app.provider_config, 'notifiers': app.notifiers, 'checks': app.checks, 'environments': app.environments, }) return self.respond(context)
def get(self): """ Retrieve daily statistics for tasks. """ end_date = date.today() - timedelta(days=30) results = dict( db.session.query(func.date(Task.date_started), func.count()) .filter(Task.date_started > end_date) .group_by(func.date(Task.date_started)) ) points = [] for day in range(31): point_date = end_date + timedelta(days=day) points.append((int(point_date.strftime("%s")), results.get(point_date, 0))) return self.respond(serialize(points), status_code=200)
def put(self, **kwargs): task = self._get_task(**kwargs) if task is None: return self.error('Invalid task', name='invalid_resource', status_code=404) with lock(redis, 'task:{}'.format(task.id), timeout=5): # we have to refetch in order to ensure lock state changes task = Task.query.get(task.id) args = self.put_parser.parse_args() if args.status: assert task.status in (TaskStatus.pending, TaskStatus.in_progress) assert args.status == 'cancelled' did_cancel = task.status == TaskStatus.pending task.status = TaskStatus.cancelled db.session.add(task) db.session.commit() if args.status and did_cancel: send_task_notifications(task, NotifierEvent.TASK_FINISHED) return self.respond(serialize(task))
def post(self): """ Create a new app. """ args = self.post_parser.parse_args() provider_config = parse_provider_config(args.provider, args.provider_config or {}) checks_config = parse_checks_config(args.checks or []) notifiers_config = parse_notifiers_config(args.notifiers or []) environments_config = parse_environments_config(args.environments or {}) # TODO(dcramer): this needs to be a get_or_create pattern repo = Repository.query.filter( Repository.url == args.repository, ).first() if repo is None: repo = Repository(url=args.repository, vcs='git') db.session.add(repo) db.session.flush() app = App( name=args.name, repository_id=repo.id, provider=args.provider, data={ 'provider_config': provider_config, 'notifiers': notifiers_config, 'checks': checks_config, 'environments': environments_config, }, ) db.session.add(app) db.session.commit() return self.respond(serialize(app), status_code=201)
def get(self, app): app = App.query.filter(App.name == app).first() if app is None: return self.error("Invalid app", name="invalid_resource", status_code=404) deploy_config = TaskConfig.query.filter( TaskConfig.app_id == app.id, TaskConfig.type == TaskConfigType.deploy).first() if deploy_config is None: return self.error("Missing deploy config", name="missing_conf", status_code=404) context = serialize(app) context.update({ "provider": deploy_config.provider, "provider_config": deploy_config.provider_config, "notifiers": deploy_config.notifiers, "checks": deploy_config.checks, }) return self.respond(context)
def get(self): """ Retrieve daily statistics for tasks. """ end_date = date.today() - timedelta(days=30) results = dict(db.session.query( func.date(Task.date_started), func.count(), ).filter( Task.date_started > end_date, ).group_by( func.date(Task.date_started), )) points = [] for day in range(31): point_date = end_date + timedelta(days=day) points.append(( int(point_date.strftime('%s')), results.get(point_date, 0), )) return self.respond(serialize(points), status_code=200)
def post(self): """ Given any constraints for a task are within acceptable bounds, create a new task and enqueue it. """ args = self.post_parser.parse_args() user = get_current_user() if not user: username = args.user if not username: return self.error('Missing required argument "user"', status_code=400) with lock(redis, f"user:create:{username}", timeout=5): # TODO(dcramer): this needs to be a get_or_create pattern and # ideally moved outside of the lock user = User.query.filter(User.name == username).first() if not user: user = User(name=username) db.session.add(user) db.session.flush() elif args.user: return self.error( "Cannot specify user when using session authentication.", status_code=400, ) app = App.query.filter(App.name == args.app).first() if not app: return self.error("Invalid app", name="invalid_resource", status_code=404) deploy_config = TaskConfig.query.filter( TaskConfig.app_id == app.id, TaskConfig.type == TaskConfigType.deploy).first() if not deploy_config: return self.error("Missing deploy config", name="missing_conf", status_code=404) params = None repo = Repository.query.get(app.repository_id) workspace = Workspace(path=repo.get_path()) vcs_backend = vcs.get(repo.vcs, url=repo.url, workspace=workspace) with lock(redis, f"repo:update:{repo.id}"): vcs_backend.clone_or_update() ref = args.ref or app.get_default_ref(args.env) # look for our special refs (prefixed via a colon) # TODO(dcramer): this should be supported outside of just this endpoint if ref.startswith(":"): sha = self._get_internal_ref(app, args.env, ref) if not sha: return self.error("Invalid ref", name="invalid_ref", status_code=400) else: try: sha = vcs_backend.get_sha(ref) except vcs.UnknownRevision: return self.error("Invalid ref", name="invalid_ref", status_code=400) if args.params is not None: params = args.params if not args.force: for check_config in deploy_config.checks: check = checks.get(check_config["type"]) try: check.check(app, sha, check_config["config"]) except CheckPending: pass except CheckError as e: return self.error(message=str(e), name="check_failed") with lock(redis, f"deploy:create:{app.id}", timeout=5): task = Task( app_id=app.id, # TODO(dcramer): ref should default based on app config ref=ref, sha=sha, params=params, status=TaskStatus.pending, user_id=user.id, provider=deploy_config.provider, data={ "force": args.force, "provider_config": deploy_config.provider_config, "notifiers": deploy_config.notifiers, "checks": deploy_config.checks, }, ) db.session.add(task) db.session.flush() db.session.refresh(task) deploy = Deploy( task_id=task.id, app_id=app.id, environment=args.env, number=DeploySequence.get_clause(app.id, args.env), ) db.session.add(deploy) db.session.commit() send_task_notifications(task, NotifierEvent.TASK_QUEUED) return self.respond(serialize(deploy), status_code=201)
def put(self, app_id): """ Update an app. """ args = self.put_parser.parse_args() app = App.query.get(app_id) if app is None: return self.error('Invalid app', name='invalid_resource', status_code=404) if args.provider or args.provider_config: if args.provider is not None: provider = args.provider else: provider = app.provider if args.provider_config is not None: provider_config = args.provider_config else: provider_config = app.provider_config app.provider = provider app.data['provider_config'] = parse_provider_config( provider, provider_config ) if args.notifiers is not None: app.data['notifiers'] = parse_notifiers_config(args.notifiers) if args.checks is not None: app.data['checks'] = parse_checks_config(args.checks) if args.environments is not None: app.data['environments'] = parse_environments_config(args.environments) if args.name: app.name = args.name # TODO(dcramer): this needs to be a get_or_create pattern if args.repository: repo = Repository.query.filter( Repository.url == args.repository, ).first() if repo is None: repo = Repository(url=args.repository, vcs='git') db.session.add(repo) db.session.flush() app.repository_id = repo.id db.session.add(app) db.session.commit() context = serialize(app) context.update({ 'provider': app.provider, 'provider_config': app.provider_config, 'notifiers': app.notifiers, 'checks': app.checks, }) return self.respond(context)
def put(self, app): """ Update an app. """ args = self.put_parser.parse_args() app = App.query.filter(App.name == app).first() if app is None: return self.error('Invalid app', name='invalid_resource', status_code=404) # For backwards compatibility, we assume that we need a deploy TaskConfig # on the app at all times. deploy_config = TaskConfig.query.filter( TaskConfig.app_id == app.id, TaskConfig.type == TaskConfigType.deploy, ).first() if deploy_config is None: deploy_config = TaskConfig(app_id=app.id, type=TaskConfigType.deploy) db.session.add(deploy_config) db.session.flush() if args.provider or args.provider_config: if args.provider is not None: provider = args.provider else: provider = deploy_config.provider if args.provider_config is not None: provider_config = args.provider_config else: provider_config = deploy_config.provider_config deploy_config.provider = provider deploy_config.data['provider_config'] = parse_provider_config( provider, provider_config ) if args.notifiers is not None: deploy_config.data['notifiers'] = parse_notifiers_config(args.notifiers) if args.checks is not None: deploy_config.data['checks'] = parse_checks_config(args.checks) if args.environments is not None: app.data['environments'] = parse_environments_config(args.environments) if args.name: app.name = args.name # TODO(dcramer): this needs to be a get_or_create pattern if args.repository: repo = Repository.query.filter( Repository.url == args.repository, ).first() if repo is None: repo = Repository(url=args.repository, vcs='git') db.session.add(repo) db.session.flush() app.repository_id = repo.id db.session.add(app) db.session.add(deploy_config) db.session.commit() context = serialize(app) context.update({ 'provider': deploy_config.provider, 'provider_config': deploy_config.provider_config, 'notifiers': deploy_config.notifiers, 'checks': deploy_config.checks, }) return self.respond(context)
def post(self): """ Given any constraints for a task are within acceptable bounds, create a new task and enqueue it. """ args = self.post_parser.parse_args() app = App.query.filter(App.name == args.app).first() if not app: return self.error('Invalid app', name='invalid_resource', status_code=404) repo = Repository.query.get(app.repository_id) workspace = Workspace( path=repo.get_path(), ) vcs_backend = vcs.get( repo.vcs, url=repo.url, workspace=workspace, ) with lock(redis, 'repo:update:{}'.format(repo.id)): vcs_backend.clone_or_update() ref = app.get_default_ref(args.env) try: sha = vcs_backend.describe(ref) except vcs.UnknownRevision: return self.error('Invalid ref', name='invalid_ref', status_code=400) if not args.force: for check_config in app.checks: check = checks.get(check_config['type']) try: check.check(app, sha, check_config['config']) except CheckPending: pass except CheckError as e: return self.error( message=unicode(e), name='check_failed', ) with lock(redis, 'task:create:{}'.format(app.id), timeout=5): # TODO(dcramer): this needs to be a get_or_create pattern and # ideally moved outside of the lock user = User.query.filter(User.name == args.user).first() if not user: user = User(name=args.user) db.session.add(user) db.session.flush() if not args.force and self._has_active_task(app, args.env): return self.error( message='Another task is already in progress for this app/environment', name='locked', ) task = Task( app_id=app.id, environment=args.env, number=TaskSequence.get_clause(app.id, args.env), name=TaskName.deploy, # TODO(dcramer): ref should default based on app config ref=ref, sha=sha, status=TaskStatus.pending, user_id=user.id, provider=app.provider, data={ 'force': args.force, 'provider_config': app.provider_config, 'notifiers': app.notifiers, 'checks': app.checks, }, ) db.session.add(task) db.session.commit() celery.send_task("freight.execute_task", [task.id]) return self.respond(serialize(task), status_code=201)
def test_simple(self): user = self.create_user() result = serialize(user) assert result['id'] == str(user.id) assert result['name'] == user.name
def put(self, app): """ Update an app. """ args = self.put_parser.parse_args() app = App.query.filter(App.name == app).first() if app is None: return self.error('Invalid app', name='invalid_resource', status_code=404) if args.provider or args.provider_config: if args.provider is not None: provider = args.provider else: provider = app.provider if args.provider_config is not None: provider_config = args.provider_config else: provider_config = app.provider_config app.provider = provider app.data['provider_config'] = parse_provider_config( provider, provider_config) if args.notifiers is not None: app.data['notifiers'] = parse_notifiers_config(args.notifiers) if args.checks is not None: app.data['checks'] = parse_checks_config(args.checks) if args.environments is not None: app.data['environments'] = parse_environments_config( args.environments) if args.name: app.name = args.name # TODO(dcramer): this needs to be a get_or_create pattern if args.repository: repo = Repository.query.filter( Repository.url == args.repository, ).first() if repo is None: repo = Repository(url=args.repository, vcs='git') db.session.add(repo) db.session.flush() app.repository_id = repo.id db.session.add(app) db.session.commit() context = serialize(app) context.update({ 'provider': app.provider, 'provider_config': app.provider_config, 'notifiers': app.notifiers, 'checks': app.checks, }) return self.respond(context)
def post(self): """ Given any constraints for a task are within acceptable bounds, create a new task and enqueue it. """ args = self.post_parser.parse_args() user = get_current_user() if not user: username = args.user if not username: return self.error('Missing required argument "user"', status_code=400) with lock(redis, 'user:create:{}'.format(username), timeout=5): # TODO(dcramer): this needs to be a get_or_create pattern and # ideally moved outside of the lock user = User.query.filter(User.name == username).first() if not user: user = User(name=username) db.session.add(user) db.session.flush() elif args.user: return self.error( 'Cannot specify user when using session authentication.', status_code=400) app = App.query.filter(App.name == args.app).first() if not app: return self.error('Invalid app', name='invalid_resource', status_code=404) params = None repo = Repository.query.get(app.repository_id) workspace = Workspace(path=repo.get_path(), ) vcs_backend = vcs.get( repo.vcs, url=repo.url, workspace=workspace, ) with lock(redis, 'repo:update:{}'.format(repo.id)): vcs_backend.clone_or_update() ref = args.ref or app.get_default_ref(args.env) # look for our special refs (prefixed via a colon) # TODO(dcramer): this should be supported outside of just this endpoint if ref.startswith(':'): sha = self._get_internal_ref(app, args.env, ref) if not sha: return self.error('Invalid ref', name='invalid_ref', status_code=400) else: try: sha = vcs_backend.get_sha(ref) except vcs.UnknownRevision: return self.error('Invalid ref', name='invalid_ref', status_code=400) if args.params is not None: params = args.params if not args.force: for check_config in app.checks: check = checks.get(check_config['type']) try: check.check(app, sha, check_config['config']) except CheckPending: pass except CheckError as e: return self.error( message=unicode(e), name='check_failed', ) with lock(redis, 'task:create:{}'.format(app.id), timeout=5): task = Task( app_id=app.id, environment=args.env, number=TaskSequence.get_clause(app.id, args.env), # TODO(dcramer): ref should default based on app config ref=ref, sha=sha, params=params, status=TaskStatus.pending, user_id=user.id, provider=app.provider, data={ 'force': args.force, 'provider_config': app.provider_config, 'notifiers': app.notifiers, 'checks': app.checks, }, ) db.session.add(task) db.session.commit() send_task_notifications(task, NotifierEvent.TASK_QUEUED) return self.respond(serialize(task), status_code=201)
def test_simple(self): user = self.create_user() result = serialize(user) assert result["id"] == str(user.id) assert result["name"] == user.name
def post(self): """ Given any constraints for a task are within acceptable bounds, create a new task and enqueue it. """ args = self.post_parser.parse_args() app = App.query.filter(App.name == args.app).first() if not app: return self.error('Invalid app', name='invalid_resource', status_code=404) repo = Repository.query.get(app.repository_id) workspace = Workspace( path=repo.get_path(), ) vcs_backend = vcs.get( repo.vcs, url=repo.url, workspace=workspace, ) with lock(redis, 'repo:update:{}'.format(repo.id)): vcs_backend.clone_or_update() ref = args.ref or app.get_default_ref(args.env) # look for our special refs (prefixed via a colon) # TODO(dcramer): this should be supported outside of just this endpoint if ref.startswith(':'): sha = self._get_internal_ref(app, args.env, ref) if not sha: return self.error('Invalid ref', name='invalid_ref', status_code=400) else: try: sha = vcs_backend.get_sha(ref) except vcs.UnknownRevision: return self.error('Invalid ref', name='invalid_ref', status_code=400) if not args.force: for check_config in app.checks: check = checks.get(check_config['type']) try: check.check(app, sha, check_config['config']) except CheckPending: pass except CheckError as e: return self.error( message=unicode(e), name='check_failed', ) with lock(redis, 'task:create:{}'.format(app.id), timeout=5): # TODO(dcramer): this needs to be a get_or_create pattern and # ideally moved outside of the lock user = User.query.filter(User.name == args.user).first() if not user: user = User(name=args.user) db.session.add(user) db.session.flush() task = Task( app_id=app.id, environment=args.env, number=TaskSequence.get_clause(app.id, args.env), name=TaskName.deploy, # TODO(dcramer): ref should default based on app config ref=ref, sha=sha, status=TaskStatus.pending, user_id=user.id, provider=app.provider, data={ 'force': args.force, 'provider_config': app.provider_config, 'notifiers': app.notifiers, 'checks': app.checks, }, ) db.session.add(task) db.session.commit() send_task_notifications(task, NotifierEvent.TASK_QUEUED) return self.respond(serialize(task), status_code=201)
def post(self): """ Given any constraints for a task are within acceptable bounds, create a new task and enqueue it. """ args = self.post_parser.parse_args() app = App.query.filter(App.name == args.app).first() if not app: return self.error('Invalid app', name='invalid_resource', status_code=404) repo = Repository.query.get(app.repository_id) workspace = Workspace(path=repo.get_path(), ) vcs_backend = vcs.get( repo.vcs, url=repo.url, workspace=workspace, ) with lock(redis, 'repo:update:{}'.format(repo.id)): vcs_backend.clone_or_update() ref = app.get_default_ref(args.env) try: sha = vcs_backend.describe(ref) except vcs.UnknownRevision: return self.error('Invalid ref', name='invalid_ref', status_code=400) if not args.force: for check_config in app.checks: check = checks.get(check_config['type']) try: check.check(app, sha, check_config['config']) except CheckPending: pass except CheckError as e: return self.error( message=unicode(e), name='check_failed', ) with lock(redis, 'task:create:{}'.format(app.id), timeout=5): # TODO(dcramer): this needs to be a get_or_create pattern and # ideally moved outside of the lock user = User.query.filter(User.name == args.user).first() if not user: user = User(name=args.user) db.session.add(user) db.session.flush() if not args.force and self._has_active_task(app, args.env): return self.error( message= 'Another task is already in progress for this app/environment', name='locked', ) task = Task( app_id=app.id, environment=args.env, number=TaskSequence.get_clause(app.id, args.env), name=TaskName.deploy, # TODO(dcramer): ref should default based on app config ref=ref, sha=sha, status=TaskStatus.pending, user_id=user.id, provider=app.provider, data={ 'force': args.force, 'provider_config': app.provider_config, 'notifiers': app.notifiers, 'checks': app.checks, }, ) db.session.add(task) db.session.commit() celery.send_task("freight.execute_task", [task.id]) return self.respond(serialize(task), status_code=201)