From 5de3c97a8ef10c13476c6eb92682a8fe7d9f3fe4 Mon Sep 17 00:00:00 2001 From: shmck Date: Sun, 12 Apr 2020 21:17:16 -0700 Subject: [PATCH] increased unknown error handling Signed-off-by: shmck --- src/channel/index.ts | 317 ++++++++++++++------------ web-app/src/services/state/machine.ts | 7 + 2 files changed, 182 insertions(+), 142 deletions(-) diff --git a/src/channel/index.ts b/src/channel/index.ts index a0637fdb..59cbf41a 100644 --- a/src/channel/index.ts +++ b/src/channel/index.ts @@ -49,49 +49,57 @@ class Channel implements Channel { switch (actionType) { case 'EDITOR_STARTUP': - // check if a workspace is open, otherwise nothing works - const noActiveWorksapce = !WORKSPACE_ROOT.length - if (noActiveWorksapce) { - const error: E.ErrorMessage = { - type: 'NoWorkspaceFound', - message: '', - actions: [ - { - label: 'Open Workspace', - transition: 'REQUEST_WORKSPACE', - }, - ], + try { + // check if a workspace is open, otherwise nothing works + const noActiveWorksapce = !WORKSPACE_ROOT.length + if (noActiveWorksapce) { + const error: E.ErrorMessage = { + type: 'NoWorkspaceFound', + message: '', + actions: [ + { + label: 'Open Workspace', + transition: 'REQUEST_WORKSPACE', + }, + ], + } + this.send({ type: 'NO_WORKSPACE', payload: { error } }) + return } - this.send({ type: 'NO_WORKSPACE', payload: { error } }) - return - } - const env = { - machineId: vscode.env.machineId, - sessionId: vscode.env.sessionId, - } + const env = { + machineId: vscode.env.machineId, + sessionId: vscode.env.sessionId, + } - // continue from tutorial from local storage - const tutorial: TT.Tutorial | null = this.context.tutorial.get() + // continue from tutorial from local storage + const tutorial: TT.Tutorial | null = this.context.tutorial.get() - // new tutorial - if (!tutorial || !tutorial.id) { - this.send({ type: 'START_NEW_TUTORIAL', payload: { env } }) - return - } + // new tutorial + if (!tutorial || !tutorial.id) { + this.send({ type: 'START_NEW_TUTORIAL', payload: { env } }) + return + } - // set tutorial - const { position, progress } = await this.context.setTutorial(this.workspaceState, tutorial) + // set tutorial + const { position, progress } = await this.context.setTutorial(this.workspaceState, tutorial) + + if (progress.complete) { + // tutorial is already complete + this.send({ type: 'TUTORIAL_ALREADY_COMPLETE', payload: { env } }) + return + } + // communicate to client the tutorial & stepProgress state + this.send({ type: 'LOAD_STORED_TUTORIAL', payload: { env, tutorial, progress, position } }) - if (progress.complete) { - // tutorial is already complete - this.send({ type: 'TUTORIAL_ALREADY_COMPLETE', payload: { env } }) return + } catch (e) { + const error = { + type: 'UnknownError', + message: `Location: Editor startup\n\n${e.message}`, + } + this.send({ type: 'EDITOR_STARTUP_FAILED', payload: { error } }) } - // communicate to client the tutorial & stepProgress state - this.send({ type: 'LOAD_STORED_TUTORIAL', payload: { env, tutorial, progress, position } }) - - return // clear tutorial local storage case 'TUTORIAL_CLEAR': @@ -100,134 +108,159 @@ class Channel implements Channel { return // configure test runner, language, git case 'EDITOR_TUTORIAL_CONFIG': - const data: TT.Tutorial = action.payload.tutorial - // setup tutorial config (save watcher, test runner, etc) - await this.context.setTutorial(this.workspaceState, data) + try { + const data: TT.Tutorial = action.payload.tutorial + // setup tutorial config (save watcher, test runner, etc) + await this.context.setTutorial(this.workspaceState, data) - // validate dependencies - const dependencies = data.config.dependencies - if (dependencies && dependencies.length) { - for (const dep of dependencies) { - // check dependency is installed - const currentVersion: string | null = await version(dep.name) - if (!currentVersion) { - // use a custom error message - const error = { - type: 'MissingTutorialDependency', - message: dep.message || `Process "${dep.name}" is required but not found. It may need to be installed`, - actions: [ - { - label: 'Check Again', - transition: 'TRY_AGAIN', - }, - ], + // validate dependencies + const dependencies = data.config.dependencies + if (dependencies && dependencies.length) { + for (const dep of dependencies) { + // check dependency is installed + const currentVersion: string | null = await version(dep.name) + if (!currentVersion) { + // use a custom error message + const error = { + type: 'MissingTutorialDependency', + message: + dep.message || `Process "${dep.name}" is required but not found. It may need to be installed`, + actions: [ + { + label: 'Check Again', + transition: 'TRY_AGAIN', + }, + ], + } + this.send({ type: 'TUTORIAL_CONFIGURE_FAIL', payload: { error } }) + return } - this.send({ type: 'TUTORIAL_CONFIGURE_FAIL', payload: { error } }) - return - } - // check dependency version - const satisfiedDependency = await compareVersions(currentVersion, dep.version) + // check dependency version + const satisfiedDependency = await compareVersions(currentVersion, dep.version) - if (!satisfiedDependency) { - const error = { - type: 'UnmetTutorialDependency', - message: `Expected ${dep.name} to have version ${dep.version}, but found version ${currentVersion}`, - actions: [ - { - label: 'Check Again', - transition: 'TRY_AGAIN', - }, - ], + if (!satisfiedDependency) { + const error = { + type: 'UnmetTutorialDependency', + message: `Expected ${dep.name} to have version ${dep.version}, but found version ${currentVersion}`, + actions: [ + { + label: 'Check Again', + transition: 'TRY_AGAIN', + }, + ], + } + this.send({ type: 'TUTORIAL_CONFIGURE_FAIL', payload: { error } }) + return } - this.send({ type: 'TUTORIAL_CONFIGURE_FAIL', payload: { error } }) - return - } - if (satisfiedDependency !== true) { - const error = satisfiedDependency || { - type: 'UnknownError', - message: `Something went wrong comparing dependency for ${name}`, - actions: [ - { - label: 'Try Again', - transition: 'TRY_AGAIN', - }, - ], + if (satisfiedDependency !== true) { + const error = satisfiedDependency || { + type: 'UnknownError', + message: `Something went wrong comparing dependency for ${name}`, + actions: [ + { + label: 'Try Again', + transition: 'TRY_AGAIN', + }, + ], + } + this.send({ type: 'TUTORIAL_CONFIGURE_FAIL', payload: { error } }) + return } - this.send({ type: 'TUTORIAL_CONFIGURE_FAIL', payload: { error } }) - return } } - } - const error: E.ErrorMessage | void = await tutorialConfig({ config: data.config }).catch((error: Error) => ({ - type: 'UnknownError', - message: `Location: tutorial config.\n\n${error.message}`, - })) + const error: E.ErrorMessage | void = await tutorialConfig({ config: data.config }).catch((error: Error) => ({ + type: 'UnknownError', + message: `Location: tutorial config.\n\n${error.message}`, + })) - // has error - if (error && error.type) { - this.send({ type: 'TUTORIAL_CONFIGURE_FAIL', payload: { error } }) + // has error + if (error && error.type) { + this.send({ type: 'TUTORIAL_CONFIGURE_FAIL', payload: { error } }) + return + } + + // report back to the webview that setup is complete + this.send({ type: 'TUTORIAL_CONFIGURED' }) return + } catch (e) { + const error = { + type: 'UnknownError', + message: `Location: EditorTutorialConfig.\n\n ${e.message}`, + } + this.send({ type: 'TUTORIAL_CONFIGURE_FAIL', payload: { error } }) } - - // report back to the webview that setup is complete - this.send({ type: 'TUTORIAL_CONFIGURED' }) - return case 'EDITOR_TUTORIAL_CONTINUE_CONFIG': - const tutorialContinue: TT.Tutorial | null = this.context.tutorial.get() - if (!tutorialContinue) { - throw new Error('Invalid tutorial to continue') + try { + const tutorialContinue: TT.Tutorial | null = this.context.tutorial.get() + if (!tutorialContinue) { + throw new Error('Invalid tutorial to continue') + } + const continueConfig: TT.TutorialConfig = tutorialContinue.config + await tutorialConfig({ + config: continueConfig, + alreadyConfigured: true, + }) + // update the current stepId on startup + vscode.commands.executeCommand(COMMANDS.SET_CURRENT_STEP, action.payload) + return + } catch (e) { + const error = { + type: 'UnknownError', + message: `Location: Editor tutorial continue config.\n\n ${e.message}`, + } + this.send({ type: 'CONTINUE_FAILED', payload: { error } }) } - const continueConfig: TT.TutorialConfig = tutorialContinue.config - await tutorialConfig({ - config: continueConfig, - alreadyConfigured: true, - }) - // update the current stepId on startup - vscode.commands.executeCommand(COMMANDS.SET_CURRENT_STEP, action.payload) - return case 'EDITOR_VALIDATE_SETUP': - // check workspace is selected - const isEmptyWorkspace = await checkWorkspaceEmpty() - if (!isEmptyWorkspace) { - const error: E.ErrorMessage = { - type: 'WorkspaceNotEmpty', - message: '', - actions: [ - { - label: 'Open Workspace', - transition: 'REQUEST_WORKSPACE', - }, - { - label: 'Check Again', - transition: 'RETRY', - }, - ], + try { + // check workspace is selected + const isEmptyWorkspace = await checkWorkspaceEmpty() + if (!isEmptyWorkspace) { + const error: E.ErrorMessage = { + type: 'WorkspaceNotEmpty', + message: '', + actions: [ + { + label: 'Open Workspace', + transition: 'REQUEST_WORKSPACE', + }, + { + label: 'Check Again', + transition: 'RETRY', + }, + ], + } + this.send({ type: 'VALIDATE_SETUP_FAILED', payload: { error } }) + return } - this.send({ type: 'VALIDATE_SETUP_FAILED', payload: { error } }) + // check Git is installed. + // Should wait for workspace before running otherwise requires access to root folder + const isGitInstalled = await version('git') + if (!isGitInstalled) { + const error: E.ErrorMessage = { + type: 'GitNotFound', + message: '', + actions: [ + { + label: 'Check Again', + transition: 'RETRY', + }, + ], + } + this.send({ type: 'VALIDATE_SETUP_FAILED', payload: { error } }) + return + } + this.send({ type: 'SETUP_VALIDATED' }) return - } - // check Git is installed. - // Should wait for workspace before running otherwise requires access to root folder - const isGitInstalled = await version('git') - if (!isGitInstalled) { - const error: E.ErrorMessage = { - type: 'GitNotFound', - message: '', - actions: [ - { - label: 'Check Again', - transition: 'RETRY', - }, - ], + } catch (e) { + const error = { + type: 'UknownError', + message: e.message, } this.send({ type: 'VALIDATE_SETUP_FAILED', payload: { error } }) - return } - this.send({ type: 'SETUP_VALIDATED' }) - return case 'EDITOR_REQUEST_WORKSPACE': openWorkspace() return diff --git a/web-app/src/services/state/machine.ts b/web-app/src/services/state/machine.ts index befba922..643a0aba 100644 --- a/web-app/src/services/state/machine.ts +++ b/web-app/src/services/state/machine.ts @@ -37,6 +37,9 @@ export const createMachine = (options: any) => { onEntry: ['startup'], onExit: ['clearError'], on: { + EDITOR_STARTUP_FAILED: { + actions: ['setError'], + }, NO_WORKSPACE: { actions: ['setError'], }, @@ -74,12 +77,16 @@ export const createMachine = (options: any) => { }, }, Start: { + onExit: ['clearError'], on: { NEW_TUTORIAL: 'ValidateSetup', CONTINUE_TUTORIAL: { target: '#tutorial-level', actions: ['continueConfig'], }, + CONTINUE_FAILED: { + actions: ['setError'], + }, }, }, SelectTutorial: {