Skip to content

increased unknown error handling #263

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 13, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
317 changes: 175 additions & 142 deletions src/channel/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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':
Expand All @@ -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
Expand Down
7 changes: 7 additions & 0 deletions web-app/src/services/state/machine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ export const createMachine = (options: any) => {
onEntry: ['startup'],
onExit: ['clearError'],
on: {
EDITOR_STARTUP_FAILED: {
actions: ['setError'],
},
NO_WORKSPACE: {
actions: ['setError'],
},
Expand Down Expand Up @@ -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: {
Expand Down