Skip to content

Commit 99cd654

Browse files
authored
feat: improve error handling when taskfiles contain errors (#25)
1 parent 3bf7fd9 commit 99cd654

File tree

5 files changed

+78
-14
lines changed

5 files changed

+78
-14
lines changed

CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
## Unreleased
44

5-
- Added the ability to sort tasks in the tree view.
5+
- Improve error handling in when Taskfiles contain errors (#25 by @pd93).
6+
- Added a new command: `Task: Show Debug Panel` to show the Task debug panel (#25 by @pd93).
7+
- Added the ability to sort tasks in the tree view (#20 by @pd93).
68
- Configurable via `task.tree.sort` setting (values: `"default"` (default), `"alphanumeric"` or `"none"`).
79

810
## v0.1.1 - 2021-03-27

package.json

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,12 @@
102102
"title": "Open Usage",
103103
"category": "Task",
104104
"icon": "$(globe)"
105+
},
106+
{
107+
"command": "vscode-task.showDebugPanel",
108+
"title": "Show Debug Panel",
109+
"category": "Task",
110+
"icon": "$(debug)"
105111
}
106112
],
107113
"viewsContainers": {
@@ -124,18 +130,23 @@
124130
"viewsWelcome": [
125131
{
126132
"view": "vscode-task.tasks",
127-
"contents": "Task not installed. Click the button below to install it.\n[Install Task](command:vscode-task.openInstallation)\nTo learn more about how to use Task [read our docs](https://taskfile.dev).",
133+
"contents": "Task not installed. Click the button below to install it.\n[Install Task](command:vscode-task.openInstallation)\nTo learn more about how to use Task, [read our docs](https://taskfile.dev).",
128134
"when": "vscode-task:status == 'notInstalled'"
129135
},
130136
{
131137
"view": "vscode-task.tasks",
132-
"contents": "Task is out of date. Click the button below to update it.\n[Update Task](command:vscode-task.openInstallation)\nTo learn more about how to use Task [read our docs](https://taskfile.dev).",
138+
"contents": "Task is out of date. Click the button below to update it.\n[Update Task](command:vscode-task.openInstallation)\nTo learn more about how to use Task, [read our docs](https://taskfile.dev).",
133139
"when": "vscode-task:status == 'outOfDate'"
134140
},
135141
{
136142
"view": "vscode-task.tasks",
137-
"contents": "No Taskfile found in this workspace. Click the button below to get started and initialize a new Taskfile.\n[Initialize Taskfile](command:vscode-task.init)\nTo learn more about how to use Task [read our docs](https://taskfile.dev).",
143+
"contents": "No Taskfile found in this workspace. Click the button below to get started and initialize a new Taskfile.\n[Initialize Taskfile](command:vscode-task.init)\nTo learn more about how to use Task, [read our docs](https://taskfile.dev).",
138144
"when": "vscode-task:status == 'noTaskfile'"
145+
},
146+
{
147+
"view": "vscode-task.tasks",
148+
"contents": "An error occurred while reading the Taskfile. [Check the output panel](command:vscode-task.showDebugPanel) for more information\nTo learn more about how to use Task, [read our docs](https://taskfile.dev).",
149+
"when": "vscode-task:status == 'error'"
139150
}
140151
],
141152
"menus": {

src/services/taskfile.ts

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,23 @@ type ReleaseResponse = Endpoints["GET /repos/{owner}/{repo}/releases/latest"]["r
1414

1515
const minimumRequiredVersion = '3.23.0';
1616
const minimumRequiredVersionForSorting = '3.24.0';
17+
const minimumRequiredVersionForExitCodes = '3.24.0';
18+
19+
// General exit codes
20+
const errCodeOK = 0;
21+
const errCodeUnknown = 1;
22+
23+
// Taskfile related exit codes
24+
const errCodeTaskfileNotFound = 100;
25+
const errCodeTaskfileAlreadyExists = 101;
26+
const errCodeTaskfileInvalid = 102;
27+
28+
// Task related exit codes
29+
const errCodeTaskNotFound = 200;
30+
const errCodeTaskRunError = 201;
31+
const errCodeTaskInternal = 202;
32+
const errCodeTaskNameConflict = 203;
33+
const errCodeTaskCalledTooManyTimes = 204;
1734

1835
class TaskfileService {
1936
private static _instance: TaskfileService;
@@ -150,7 +167,7 @@ class TaskfileService {
150167
}
151168
}
152169

153-
public async read(dir: string): Promise<models.Taskfile> {
170+
public async read(dir: string): Promise<models.Taskfile | undefined> {
154171
log.info(`Searching for taskfile in: "${dir}"`);
155172
return await new Promise((resolve, reject) => {
156173
let additionalFlags = "";
@@ -163,10 +180,29 @@ class TaskfileService {
163180
}
164181
}
165182
let command = this.command(`--list-all --json${additionalFlags}`);
166-
cp.exec(command, { cwd: dir }, (err: cp.ExecException | null, stdout: string) => {
183+
cp.exec(command, { cwd: dir }, (err: cp.ExecException | null, stdout: string, stderr: string) => {
167184
if (err) {
168185
log.error(err);
169-
return reject();
186+
// TODO: Bump the minimum required version to remove this conditional
187+
let shouldDisplayError = false;
188+
if (err.code && this.version && this.version.compare(minimumRequiredVersionForExitCodes) >= 0) {
189+
let exitCodesToDisplayErrorsFor = [
190+
errCodeTaskfileInvalid,
191+
];
192+
if (exitCodesToDisplayErrorsFor.includes(err.code)) {
193+
shouldDisplayError = true;
194+
}
195+
} else {
196+
if (err.message.toLowerCase().includes("failed to parse")) {
197+
shouldDisplayError = true;
198+
}
199+
}
200+
// Display an error message
201+
if (shouldDisplayError) {
202+
vscode.window.showErrorMessage(stderr);
203+
return reject();
204+
}
205+
return resolve(undefined);
170206
}
171207
var taskfile: models.Taskfile = JSON.parse(stdout);
172208
if (path.dirname(taskfile.location) !== dir) {

src/task.ts

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export class TaskExtension {
1717

1818
public async update(checkForUpdates?: boolean): Promise<void> {
1919
// Do version checks
20-
await services.taskfile.checkInstallation(checkForUpdates).then((status): Promise<PromiseSettledResult<models.Taskfile>[]> => {
20+
await services.taskfile.checkInstallation(checkForUpdates).then((status): Promise<PromiseSettledResult<models.Taskfile | undefined>[]> => {
2121

2222
// Set the status
2323
vscode.commands.executeCommand('setContext', 'vscode-task:status', status);
@@ -28,16 +28,26 @@ export class TaskExtension {
2828
}
2929

3030
// Read taskfiles
31-
let p: Promise<models.Taskfile>[] = [];
31+
let p: Promise<models.Taskfile | undefined>[] = [];
3232
vscode.workspace.workspaceFolders?.forEach((folder) => {
3333
p.push(services.taskfile.read(folder.uri.fsPath));
3434
});
3535
return Promise.allSettled(p);
3636

3737
// If there are no valid taskfiles, set the status to "noTaskfile"
3838
}).then(results => {
39-
this._taskfiles = results.filter(result => result.status === "fulfilled").map(result => <PromiseFulfilledResult<any>>result).map(result => result.value);
40-
if (this._taskfiles.length === 0) {
39+
this._taskfiles = results
40+
.filter(result => result.status === "fulfilled")
41+
.map(result => <PromiseFulfilledResult<any>>result)
42+
.map(result => result.value)
43+
.filter(value => value !== undefined);
44+
let rejected = results
45+
.filter(result => result.status === "rejected")
46+
.map(result => <PromiseRejectedResult>result)
47+
.map(result => result.reason);
48+
if (rejected.length > 0) {
49+
vscode.commands.executeCommand('setContext', 'vscode-task:status', "error");
50+
} else if (this._taskfiles.length === 0) {
4151
vscode.commands.executeCommand('setContext', 'vscode-task:status', "noTaskfile");
4252
}
4353
});
@@ -180,6 +190,11 @@ export class TaskExtension {
180190
log.info("Command: vscode-task.openUsage");
181191
vscode.env.openExternal(vscode.Uri.parse('https://taskfile.dev/usage'));
182192
}));
193+
194+
// Show debug window
195+
context.subscriptions.push(vscode.commands.registerCommand('vscode-task.showDebugPanel', () => {
196+
log.channel.show();
197+
}));
183198
}
184199

185200
public registerListeners(context: vscode.ExtensionContext): void {

src/utils/log.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ class Log {
44
private static _instance: Log;
55

66
constructor(
7-
private _channel: vscode.OutputChannel = vscode.window.createOutputChannel("Task (Debug)")
7+
public channel: vscode.OutputChannel = vscode.window.createOutputChannel("Task (Debug)")
88
) { }
99

1010
public static get instance() {
@@ -13,12 +13,12 @@ class Log {
1313

1414
info(v: any) {
1515
console.log(v);
16-
this._channel.appendLine(v);
16+
this.channel.appendLine(v);
1717
}
1818

1919
error(err: any) {
2020
console.error(err);
21-
this._channel.appendLine(err);
21+
this.channel.appendLine(err);
2222
}
2323
}
2424

0 commit comments

Comments
 (0)