def send_deploy(self, deploy, task, config, event): webhook_url = config["webhook_url"] app = App.query.get(deploy.app_id) payload = { "number": deploy.number, "app_name": app.name, "params": dict(task.params or {}), "env": deploy.environment, "ref": task.ref, "sha": task.sha, "duration": task.duration, "event": "started" if event == NotifierEvent.TASK_STARTED else "finished", "dateStarted": task.date_started.isoformat() + "Z" if task.date_started else None, "dateReleased": task.date_finished.isoformat() + "Z" if task.date_finished else None, "link": http.absolute_uri( f"/deploys/{app.name}/{deploy.environment}/{deploy.number}/" ), } http.post(webhook_url, json=payload)
def send_deploy(self, deploy, task, config, event): webhook_url = config['webhook_url'] app = App.query.get(deploy.app_id) payload = { 'number': deploy.number, 'app_name': app.name, 'params': dict(task.params or {}), 'env': deploy.environment, 'ref': task.ref, 'sha': task.sha, 'duration': task.duration, 'event': 'started' if event == NotifierEvent.TASK_STARTED else 'finished', 'dateStarted': task.date_started.isoformat() + 'Z' if task.date_started else None, 'dateFinished': task.date_finished.isoformat() + 'Z' if task.date_finished else None, 'link': http.absolute_uri('/deploys/{}/{}/{}/'.format( app.name, deploy.environment, deploy.number)), } http.post(webhook_url, json=payload)
def generate_event_title(app, deploy, task, user, event): number = deploy.number app_name = app.name params = dict(task.params or {}) env = deploy.environment ref = task.ref sha = task.sha[:7] if task.sha else task.ref status_label = task.status_label duration = task.duration user = user.name.split( "@", 1)[0] # Usernames can either be 'user' or '*****@*****.**' link = http.absolute_uri( f"/deploys/{app.name}/{deploy.environment}/{deploy.number}") # TODO(dcramer): show the ref when it differs from the sha if event == NotifierEvent.TASK_QUEUED: return f"[{app_name}/{env}] {user} queued deploy <{link}|#{number}> ({sha})" if event == NotifierEvent.TASK_STARTED: return f"[{app_name}/{env}] {user} started deploy <{link}|#{number}> ({sha})" if task.status == TaskStatus.failed: return f"[{app_name}/{env}] Failed to finish {user}'s deploy <{link}|#{number}> ({sha}) after {duration}s" if task.status == TaskStatus.cancelled: return f"[{app_name}/{env}] {user}'s deploy <{link}|#{number}> ({sha}) was cancelled after {duration}s" if task.status == TaskStatus.finished: return f"[{app_name}/{env}] Successfully finished {user}'s deploy <{link}|#{number}> ({sha}) after {duration}s" raise NotImplementedError(task.status)
def send_deploy(self, deploy, task, config, event): webhook_url = config['webhook_url'] app = App.query.get(deploy.app_id) task = Task.query.get(deploy.task_id) user = User.query.get(task.user_id) params = { 'number': deploy.number, 'app_name': app.name, 'params': dict(task.params or {}), 'env': deploy.environment, 'ref': task.ref, 'sha': task.sha[:7] if task.sha else task.ref, 'status_label': task.status_label, 'duration': task.duration, 'user': user.name.split( '@', 1)[0], # Usernames can either be 'user' or '*****@*****.**' 'link': http.absolute_uri('/deploys/{}/{}/{}'.format( app.name, deploy.environment, deploy.number)), } # TODO(dcramer): show the ref when it differs from the sha if event == NotifierEvent.TASK_QUEUED: title = "[{app_name}/{env}] {user} queued deploy <{link}|#{number}> ({sha})".format( **params) elif event == NotifierEvent.TASK_STARTED: title = "[{app_name}/{env}] {user} started deploy <{link}|#{number}> ({sha})".format( **params) elif task.status == TaskStatus.failed: title = "[{app_name}/{env}] Failed to finish {user}'s deploy <{link}|#{number}> ({sha}) after {duration}s".format( **params) elif task.status == TaskStatus.cancelled: title = "[{app_name}/{env}] {user}'s deploy <{link}|#{number}> ({sha}) was cancelled after {duration}s".format( **params) elif task.status == TaskStatus.finished: title = "[{app_name}/{env}] Successfully finished {user}'s deploy <{link}|#{number}> ({sha}) after {duration}s".format( **params) else: raise NotImplementedError(task.status) payload = { 'parse': 'none', 'text': title, } values = {'payload': json.dumps(payload)} http.post(webhook_url, values)
def send(self, task, config, event): webhook_url = config['webhook_url'] app = App.query.get(task.app_id) params = { 'number': task.number, 'app_name': app.name, 'params': dict(task.params or {}), 'env': task.environment, 'ref': task.ref, 'sha': task.sha[:7] if task.sha else task.ref, 'status_label': task.status_label, 'duration': task.duration, 'link': http.absolute_uri('/{}/{}/{}'.format(app.name, task.environment, task.number)), } # TODO(dcramer): show the ref when it differs from the sha if event == NotifierEvent.TASK_QUEUED: title = "[{app_name}/{env}] Queued deploy <{link}|#{number}> ({sha})".format( **params) elif event == NotifierEvent.TASK_STARTED: title = "[{app_name}/{env}] Starting deploy <{link}|#{number}> ({sha})".format( **params) elif task.status == TaskStatus.failed: title = "[{app_name}/{env}] Failed to deploy <{link}|#{number}> ({sha}) after {duration}s".format( **params) elif task.status == TaskStatus.cancelled: title = "[{app_name}/{env}] Deploy <{link}|#{number}> ({sha}) was cancelled after {duration}s".format( **params) elif task.status == TaskStatus.finished: title = "[{app_name}/{env}] Successfully deployed <{link}|#{number}> ({sha}) after {duration}s".format( **params) else: raise NotImplementedError(task.status) payload = { 'parse': 'none', 'text': title, } values = {'payload': json.dumps(payload)} http.post(webhook_url, values)
def send_deploy(self, deploy, task, config, event): token = current_app.config['GITHUB_TOKEN'] if not token: raise ValueError('GITHUB_TOKEN is not set') headers = { 'Accept': 'application/vnd.github.v3+json', 'Authorization': 'token {}'.format(token), } app = App.query.get(deploy.app_id) task = Task.query.get(deploy.task_id) api_root = (config.get('api_root') or current_app.config['GITHUB_API_ROOT']).rstrip('/') url = '{api_root}/repos/{repo}/statuses/{sha}'.format( api_root=api_root, repo=config['repo'], sha=task.sha, ) target_url = http.absolute_uri('/deploys/{}/{}/{}'.format( app.name, deploy.environment, deploy.number)) if event == NotifierEvent.TASK_QUEUED: state = 'pending' description = 'Freight deploy #{number} is currently queued.' elif event == NotifierEvent.TASK_STARTED: state = 'pending' description = 'Freight deploy #{number} has started.' elif task.status == TaskStatus.failed: state = 'failure' description = 'Freight deploy #{number} has failed.' elif task.status == TaskStatus.cancelled: state = 'error' description = 'Freight deploy #{number} has been cancelled.' elif task.status == TaskStatus.finished: state = 'success' description = 'Freight deploy #{number} has finished successfully.' else: raise NotImplementedError(task.status) payload = { 'state': state, 'target_url': target_url, 'description': description.format(number=deploy.number), 'context': 'continuous-integration/freight/deploy', } http.post(url, headers=headers, json=payload)
def send_deploy(self, deploy, task, config, event): token = current_app.config["GITHUB_TOKEN"] if not token: raise ValueError("GITHUB_TOKEN is not set") headers = { "Accept": "application/vnd.github.v3+json", "Authorization": f"token {token}", } app = App.query.get(deploy.app_id) task = Task.query.get(deploy.task_id) api_root = (config.get("api_root") or current_app.config["GITHUB_API_ROOT"]).rstrip("/") url = f"{api_root}/repos/{config['repo']}/statuses/{task.sha}" target_url = http.absolute_uri( f"/deploys/{app.name}/{deploy.environment}/{deploy.number}") if event == NotifierEvent.TASK_QUEUED: state = "pending" description = f"Freight deploy #{deploy.number} is currently queued." elif event == NotifierEvent.TASK_STARTED: state = "pending" description = f"Freight deploy #{deploy.number} has started." elif task.status == TaskStatus.failed: state = "failure" description = f"Freight deploy #{deploy.number} has failed." elif task.status == TaskStatus.cancelled: state = "error" description = f"Freight deploy #{deploy.number} has been cancelled." elif task.status == TaskStatus.finished: state = "success" description = f"Freight deploy #{deploy.number} has finished successfully." else: raise NotImplementedError(task.status) payload = { "state": state, "target_url": target_url, "description": description, "context": "continuous-integration/freight/deploy", } http.post(url, headers=headers, json=payload)
def send_deploy(self, deploy, task, config, event): url = config["url"] app = App.query.get(deploy.app_id) task = Task.query.get(deploy.task_id) user = User.query.get(task.user_id) title = generate_event_title(app, deploy, task, user, event) payload = { "app_name": app.name, "date_created": stringify_date(task.date_created), "date_started": stringify_date(task.date_started), "date_finished": stringify_date(task.date_finished), "deploy_number": deploy.number, "duration": task.duration, "environment": deploy.environment, "link": http.absolute_uri( f"/deploys/{app.name}/{deploy.environment}/{deploy.number}/"), "params": dict(task.params or {}), "previous_sha": app.get_previous_sha(deploy.environment, current_sha=task.sha), "ref": task.ref, "sha": task.sha, "status": str(event), "title": title, "user": user.name, "user_id": user.id, } http.post(url, headers=config.get("headers", {}), json=payload)
def generate_event_title(app, deploy, task, user, event): params = { 'number': deploy.number, 'app_name': app.name, 'params': dict(task.params or {}), 'env': deploy.environment, 'ref': task.ref, 'sha': task.sha[:7] if task.sha else task.ref, 'status_label': task.status_label, 'duration': task.duration, 'user': user.name.split( '@', 1)[0], # Usernames can either be 'user' or '*****@*****.**' 'link': http.absolute_uri('/deploys/{}/{}/{}'.format(app.name, deploy.environment, deploy.number)), } # TODO(dcramer): show the ref when it differs from the sha if event == NotifierEvent.TASK_QUEUED: return "[{app_name}/{env}] {user} queued deploy <{link}|#{number}> ({sha})".format( **params) if event == NotifierEvent.TASK_STARTED: return "[{app_name}/{env}] {user} started deploy <{link}|#{number}> ({sha})".format( **params) if task.status == TaskStatus.failed: return "[{app_name}/{env}] Failed to finish {user}'s deploy <{link}|#{number}> ({sha}) after {duration}s".format( **params) if task.status == TaskStatus.cancelled: return "[{app_name}/{env}] {user}'s deploy <{link}|#{number}> ({sha}) was cancelled after {duration}s".format( **params) if task.status == TaskStatus.finished: return "[{app_name}/{env}] Successfully finished {user}'s deploy <{link}|#{number}> ({sha}) after {duration}s".format( **params) raise NotImplementedError(task.status)
def send_deploy(self, deploy, task, config, event): webhook_url = config['webhook_url'] app = App.query.get(deploy.app_id) task = Task.query.get(deploy.task_id) user = User.query.get(task.user_id) params = { 'number': deploy.number, 'app_name': app.name, 'params': dict(task.params or {}), 'env': deploy.environment, 'ref': task.ref, 'sha': task.sha[:7] if task.sha else task.ref, 'status_label': task.status_label, 'duration': task.duration, 'user': user.name.split('@', 1)[0], # Usernames can either be 'user' or '*****@*****.**' 'link': http.absolute_uri('/deploys/{}/{}/{}'.format(app.name, deploy.environment, deploy.number)), } # TODO(dcramer): show the ref when it differs from the sha if event == NotifierEvent.TASK_QUEUED: title = "[{app_name}/{env}] {user} queued deploy <{link}|#{number}> ({sha})".format(**params) elif event == NotifierEvent.TASK_STARTED: title = "[{app_name}/{env}] {user} started deploy <{link}|#{number}> ({sha})".format(**params) elif task.status == TaskStatus.failed: title = "[{app_name}/{env}] Failed to finish {user}'s deploy <{link}|#{number}> ({sha}) after {duration}s".format(**params) elif task.status == TaskStatus.cancelled: title = "[{app_name}/{env}] {user}'s deploy <{link}|#{number}> ({sha}) was cancelled after {duration}s".format(**params) elif task.status == TaskStatus.finished: title = "[{app_name}/{env}] Successfully finished {user}'s deploy <{link}|#{number}> ({sha}) after {duration}s".format(**params) else: raise NotImplementedError(task.status) payload = { 'parse': 'none', 'text': title, } values = {'payload': json.dumps(payload)} http.post(webhook_url, values)
def send(self, task, config, event): webhook_url = config['webhook_url'] app = App.query.get(task.app_id) payload = { 'number': task.number, 'app_name': app.name, 'task_name': task.name, 'env': task.environment, 'ref': task.ref, 'sha': task.sha, 'duration': task.duration, 'event': 'started' if event == NotifierEvent.TASK_STARTED else 'finished', 'dateStarted': task.date_started.isoformat() + 'Z' if task.date_started else None, 'dateFinished': task.date_finished.isoformat() + 'Z' if task.date_finished else None, 'link': http.absolute_uri('/tasks/{}/{}/{}/'.format(app.name, task.environment, task.number)), } http.post(webhook_url, json=payload)
def send(self, task, config, event): webhook_url = config['webhook_url'] app = App.query.get(task.app_id) params = { 'number': task.number, 'app_name': app.name, 'task_name': task.name, 'env': task.environment, 'ref': task.ref, 'sha': task.sha[:7] if task.sha else task.ref, 'status_label': task.status_label, 'duration': task.duration, 'link': http.absolute_uri('/tasks/{}/{}/{}/'.format(app.name, task.environment, task.number)), } # TODO(dcramer): show the ref when it differs from the sha if event == NotifierEvent.TASK_QUEUED: title = "[{app_name}/{env}] Queued deploy <{link}|#{number}> ({sha})".format(**params) elif event == NotifierEvent.TASK_STARTED: title = "[{app_name}/{env}] Starting deploy <{link}|#{number}> ({sha})".format(**params) elif task.status == TaskStatus.failed: title = "[{app_name}/{env}] Failed to deploy <{link}|#{number}> ({sha}) after {duration}s".format(**params) elif task.status == TaskStatus.cancelled: title = "[{app_name}/{env}] Deploy <{link}|#{number}> ({sha}) was cancelled after {duration}s".format(**params) elif task.status == TaskStatus.finished: title = "[{app_name}/{env}] Successfully deployed <{link}|#{number}> ({sha}) after {duration}s".format(**params) else: raise NotImplementedError(task.status) payload = { 'parse': 'none', 'text': title, } values = {'payload': json.dumps(payload)} http.post(webhook_url, values)
def send(self, task, config, event): webhook_url = config["webhook_url"] app = App.query.get(task.app_id) params = { "number": task.number, "app_name": app.name, "task_name": task.name, "env": task.environment, "ref": task.ref, "sha": task.sha[:7] if task.sha else task.ref, "status_label": task.status_label, "duration": task.duration, "link": http.absolute_uri("/tasks/{}/{}/{}/".format(app.name, task.environment, task.number)), } if event == NotifierEvent.TASK_STARTED: title = "[{app_name}/{env}] Starting deploy <{link}|#{number}> ({sha})".format(**params) elif task.status == TaskStatus.failed: title = "[{app_name}/{env}] Failed to deploy <{link}|#{number}> ({sha}) after {duration}s".format(**params) elif task.status == TaskStatus.cancelled: title = "[{app_name}/{env}] Deploy <{link}|#{number}> ({sha}) was cancelled after {duration}s".format( **params ) elif task.status == TaskStatus.finished: title = "[{app_name}/{env}] Successfully deployed <{link}|#{number}> ({sha}) after {duration}s".format( **params ) else: raise NotImplementedError(task.status) payload = {"parse": "none", "text": title} values = {"payload": json.dumps(payload)} http.post(webhook_url, values)
def execute_deploy(self, workspace, deploy, task) -> None: date_started = datetime.utcnow() app = App.query.get(task.app_id) prev_sha = app.get_previous_sha(deploy.environment, current_sha=task.sha) or "" config = self.get_config(workspace, task) sentry_context: Optional[SentryContext] if config.get("sentry", {}): sentry_context = make_sentry_context(config["sentry"]) else: sentry_context = None kube_context: Optional[KubernetesContext] if config.get("kubernetes", {}): kube_context = make_kube_context(config["kubernetes"]) else: kube_context = None ssh_key = self.get_ssh_key() task_context = TaskContext( id=str(deploy.id), date_created=str(task.date_created), name=app.name, environment=deploy.environment, sha=task.sha, prev_sha=prev_sha, ref=task.ref, url=http.absolute_uri( f"/deploys/{app.name}/{deploy.environment}/{deploy.number}"), ssh_key=ssh_key.name, ) context = PipelineContext(task=task_context, kube=kube_context, workspace=workspace) if not config["steps"]: raise StepFailed("No steps to run") if sentry_context: workspace.log.info( f"Creating new Sentry release: {sentry_context.repository}@{task_context.sha}" ) sentry_context.client.post( f"https://sentry.io/api/0/organizations/{sentry_context.organization}/releases/", json={ "version": task_context.sha, "refs": [{ "repository": sentry_context.repository, "previousCommit": task_context.prev_sha, "commit": task_context.sha, }], "projects": [sentry_context.project], }, ).raise_for_status() for i, step in enumerate(config["steps"]): workspace.log.info(f"Running Step {i+1} ({step['kind']})") run_step(step, context) workspace.log.info(f"Finished Step {i+1}") date_finished = datetime.utcnow() if sentry_context: workspace.log.info(f"Tagging Sentry release as deployed.") sentry_context.client.put( f"https://sentry.io/api/0/organizations/{sentry_context.organization}/releases/{task_context.sha}/", json={ "dateReleased": date_finished.isoformat() + "Z" }, ).raise_for_status() sentry_context.client.post( f"https://sentry.io/api/0/organizations/{sentry_context.organization}/releases/{task_context.sha}/deploys/", json={ "environment": deploy.environment, "url": task_context.url, "dateStarted": date_started.isoformat() + "Z", "dateFinished": date_finished.isoformat() + "Z", }, ).raise_for_status()