From 81990ac774b08bf74b23cf49aded73c268ee5654 Mon Sep 17 00:00:00 2001 From: David Reed Date: Tue, 23 May 2023 21:18:14 +0000 Subject: [PATCH] WIP --- locales_dev/en/translation.json | 3 ++- metecho/api/model_mixins.py | 3 ++- metecho/api/models.py | 6 +++++- metecho/api/push.py | 3 ++- metecho/api/sf_run_flow.py | 23 ++++++++++++++++++++--- src/js/store/orgs/actions.ts | 30 +++++++++++++++++++++--------- 6 files changed, 52 insertions(+), 16 deletions(-) diff --git a/locales_dev/en/translation.json b/locales_dev/en/translation.json index 1a9803a15..4fbe96834 100644 --- a/locales_dev/en/translation.json +++ b/locales_dev/en/translation.json @@ -613,5 +613,6 @@ "walkthroughPlayMetechoName": "Metecho makes it easier for you to view, test, and contribute to Salesforce Projects without learning GitHub.<1><2><3>Pronunciation: “Met” rhymes with “bet.” “Echo” as in the reflection of sound waves.<5><6>Definition: To share or participate in.", "walkthroughPlayScratchOrg": "This is a sample Scratch Org for this Project. Select “View Org” to see the work on this Project. Your Org will expire after 30 days.", "walkthroughPlayScratchOrgContribute": "To contribute your own work from a Scratch Org, you need “push” permissions on the Project in GitHub. If you do not have the right permissions, ask a Project admin. Select “Contribute Work” to create a Task for your Scratch Org. When your Org expires or is deleted, any work not contributed will be lost.", - "welcomeMessage": "<0>To get started log in with your GitHub account." + "welcomeMessage": "<0>To get started log in with your GitHub account.", + "{{message}}. If you need support, your scratch org id is {{orgId}}.": "{{message}}. If you need support, your scratch org id is {{orgId}}." } diff --git a/metecho/api/model_mixins.py b/metecho/api/model_mixins.py index 9036a6019..3f0076478 100644 --- a/metecho/api/model_mixins.py +++ b/metecho/api/model_mixins.py @@ -113,7 +113,7 @@ def notify_error(self, error, *, type_=None, originating_user_id, message=None): ) def notify_scratch_org_error( - self, *, error, type_, originating_user_id, message=None + self, *, error, type_, originating_user_id, message=None, has_build_log=False ): """ This is only used in the ScratchOrg model currently, but it @@ -126,6 +126,7 @@ def notify_scratch_org_error( type_=type_, originating_user_id=originating_user_id, message=message or {}, + has_build_log=has_build_log, ) diff --git a/metecho/api/models.py b/metecho/api/models.py index 29ce7f37d..8ac0797d1 100644 --- a/metecho/api/models.py +++ b/metecho/api/models.py @@ -1404,6 +1404,7 @@ def finalize_provision(self, *, error=None, originating_user_id): type_="SCRATCH_ORG_PROVISION_FAILED", originating_user_id=originating_user_id, message=self._build_message_extras(), + has_build_log=getattr(error, "has_build_log", False), ) # If the scratch org has already been created on Salesforce, # we need to delete it there as well. @@ -1648,7 +1649,9 @@ def remove_scratch_org(self, error, *, originating_user_id): ) # set should_finalize=False to avoid accidentally sending a # SCRATCH_ORG_DELETE event: - self.delete(should_finalize=False, originating_user_id=originating_user_id) + if self.config and "org_id" in self.config: + # Don't try to delete if the org doesn't exist. + self.delete(should_finalize=False, originating_user_id=originating_user_id) def queue_refresh_org(self, *, originating_user_id): from .jobs import refresh_scratch_org_job @@ -1672,6 +1675,7 @@ def finalize_refresh_org(self, *, error=None, originating_user_id): type_="SCRATCH_ORG_REFRESH_FAILED", originating_user_id=originating_user_id, message=self._build_message_extras(), + has_build_log=getattr(error, "has_build_log", False), ) self.queue_delete(originating_user_id=originating_user_id) diff --git a/metecho/api/push.py b/metecho/api/push.py index 757e30b9e..5b89d989f 100644 --- a/metecho/api/push.py +++ b/metecho/api/push.py @@ -105,7 +105,7 @@ async def report_error(user): async def report_scratch_org_error( - instance, *, error, type_, originating_user_id, message=None + instance, *, error, type_, originating_user_id, has_build_log=False, message=None ): # Unwrap the error in the case that there's only one, # which is the most common case, per this discussion: @@ -125,6 +125,7 @@ async def report_scratch_org_error( "payload": { "message": prepared_message, "originating_user_id": originating_user_id, + "has_build_log": has_build_log, }, } prepared_message["payload"].update(message or {}) diff --git a/metecho/api/sf_run_flow.py b/metecho/api/sf_run_flow.py index 2884e9f40..a6f550dc8 100644 --- a/metecho/api/sf_run_flow.py +++ b/metecho/api/sf_run_flow.py @@ -8,6 +8,7 @@ from datetime import datetime from cumulusci.core.config import OrgConfig, TaskConfig +from cumulusci.core.exceptions import SalesforceCredentialsException from cumulusci.core.runtime import BaseCumulusCI from cumulusci.oauth.client import OAuth2Client, OAuth2ClientConfig from cumulusci.oauth.salesforce import jwt_session @@ -52,13 +53,29 @@ class ScratchOrgError(Exception): - pass + has_build_log: bool + + def __init__(self, message: str, has_build_log: bool): + self.has_build_log = has_build_log + super().__init__(message) @contextlib.contextmanager def delete_org_on_error(scratch_org=None, originating_user_id=None): try: yield + except ScratchOrgError: + raise + except SalesforceCredentialsException as err: + error_msg = _( + f"An authentication-related issue occured. Please report this issue to your administrator: {err.args[0]}" # noqa: B950 + ) + error = ScratchOrgError(error_msg, False) + if scratch_org: + scratch_org.remove_scratch_org( + error, originating_user_id=originating_user_id + ) + raise error except Exception as err: if not scratch_org: raise err @@ -81,7 +98,7 @@ def delete_org_on_error(scratch_org=None, originating_user_id=None): else: error_msg = _(f"Are you certain that the Org still exists? {err.args[0]}") - error = ScratchOrgError(error_msg) + error = ScratchOrgError(error_msg, True) scratch_org.remove_scratch_org(error, originating_user_id=originating_user_id) raise error @@ -239,7 +256,7 @@ def poll_for_scratch_org_completion(devhub_api, org_result): if org_result["Status"] != "Active": error = org_result["ErrorCode"] or _("Org creation timed out") - raise ScratchOrgError(f"Scratch org creation failed: {error}") + raise ScratchOrgError(f"Scratch org creation failed: {error}", False) return org_result diff --git a/src/js/store/orgs/actions.ts b/src/js/store/orgs/actions.ts index ddc3741c3..9a7ef0bce 100644 --- a/src/js/store/orgs/actions.ts +++ b/src/js/store/orgs/actions.ts @@ -161,10 +161,12 @@ export const provisionFailed = model, message, originating_user_id, + has_build_log, }: { model: Org | MinimalOrg; message?: string; originating_user_id: string | null; + has_build_log?: boolean; }): ThunkResult => (dispatch, getState) => { const state = getState(); @@ -183,21 +185,31 @@ export const provisionFailed = ); } - const detailMsg = t( - 'The last line of the log is “{{message}}” If you need support, your scratch org id is {{orgId}}.', - { - message, - orgId: model.id, - }, - ); + const detailMsg = has_build_log + ? t( + 'The last line of the log is “{{message}}” If you need support, your scratch org id is {{orgId}}.', + { + message, + orgId: model.id, + }, + ) + : t( + '{{message}}. If you need support, your scratch org id is {{orgId}}.', + { + message, + orgId: model.id, + }, + ); dispatch( addToast({ heading: msg, details: detailMsg, variant: 'error', - linkUrl: window.api_urls.scratch_org_log(model.id), - linkText: t('Download build log.'), + linkUrl: has_build_log + ? window.api_urls.scratch_org_log(model.id) + : undefined, + linkText: has_build_log ? t('Download build log.') : undefined, linkDownload: true, linkDownloadFilename: t('Metecho Org {{orgId}} Build Log.txt', { message,