From 2018a575434cc4a40770be1f710a4feeaea72c41 Mon Sep 17 00:00:00 2001 From: "Jay.Udey" Date: Mon, 27 Feb 2017 10:34:12 -0600 Subject: [PATCH 1/2] updates to include: live logging of task output on completion, fail fast strategy, when failure occurs more robust logging --- lib/src/tasks/task_runner/api.dart | 63 +++++++------------ lib/src/tasks/task_runner/cli.dart | 9 ++- test/integration/task_runner_test.dart | 15 +++-- .../failing_tasks/test/simple_test.dart | 5 +- 4 files changed, 43 insertions(+), 49 deletions(-) diff --git a/lib/src/tasks/task_runner/api.dart b/lib/src/tasks/task_runner/api.dart index 500601ce..796406da 100644 --- a/lib/src/tasks/task_runner/api.dart +++ b/lib/src/tasks/task_runner/api.dart @@ -1,5 +1,4 @@ import 'dart:async'; -import 'dart:io'; import 'package:dart_dev/util.dart' show reporter, TaskProcess; @@ -7,23 +6,19 @@ import 'package:dart_dev/src/tasks/task.dart'; Future runTasks(tasksToRun) async { var taskGroup = new TaskGroup(tasksToRun); - await taskGroup.start(); - taskGroup.output(); + await taskGroup.run(); - TaskRunner task = new TaskRunner(await taskGroup.checkExitCodes(), - taskGroup.taskGroupStdout, taskGroup.taskGroupStderr); + TaskRunner task = + new TaskRunner(taskGroup.successful, taskGroup.taskGroupStderr); return task; } class TaskRunner extends Task { final Future done = new Future.value(); - final String stdout; final String stderr; bool successful; - TaskRunner(int exitCode, String this.stdout, String this.stderr) { - this.successful = exitCode == 0; - } + TaskRunner(bool this.successful, String this.stderr); } class SubTask { @@ -50,7 +45,6 @@ class SubTask { this.taskOutput += '\n$line'; }); taskProcess.stderr.listen((line) { - this.taskOutput += '\n$line'; this.taskError += '\n$line'; }); } @@ -63,12 +57,12 @@ class TaskGroup { /// List of the subtasks making up the TaskGroup List subTasks = []; - /// TaskGroup stdout - String taskGroupStdout = ''; - /// TaskGroup stderr String taskGroupStderr = ''; + /// Status of TaskGroup + bool successful = true; + TaskGroup(this.subTaskCommands) { for (String taskCommand in subTaskCommands) { SubTask task = new SubTask(taskCommand); @@ -77,42 +71,29 @@ class TaskGroup { } /// Begin each subtask and wait for completion - Future start() async { + Future run() async { List futures = []; var timer = new Timer.periodic(new Duration(seconds: 30), (_) { reporter.log('Tasks running...'); }); for (SubTask task in subTasks) { task.startProcess(); - futures.add(task.taskProcess.exitCode); + task.taskProcess.exitCode.then((int exitCode) { + reporter.log(task.taskOutput); + if (exitCode != 0) { + successful = false; + reporter.log(task.taskError); + this.taskGroupStderr += + 'The command, ${task.command}, contained this in the stderr; ${task.taskOutput}\n ${task.taskError}\n'; + for (SubTask task in subTasks) { + task.taskProcess.kill(); + } + } + }); + futures.add(task.taskProcess.done); } await Future.wait(futures); - timer.cancel(); - } - - /// Retrieve output from subtasks - void output() { - String output = ''; - for (SubTask task in subTasks) { - output += task.taskOutput + '\n'; - } - this.taskGroupStdout = output; - } - /// Determine if subtasks completed successfully - Future checkExitCodes() async { - for (SubTask task in subTasks) { - if (await task.taskProcess.exitCode != 0) { - exitCode = 1; - this.taskGroupStderr += - 'The command, ${task.command}, contained this in the stderr; \n${task.taskError}\n'; - } - } - if (exitCode != 0) { - this.taskGroupStderr = - 'One of your subtasks exited with a non-zero exit code. ' - 'See the output below for more information: \n${this.taskGroupStderr}'; - } - return exitCode; + timer.cancel(); } } diff --git a/lib/src/tasks/task_runner/cli.dart b/lib/src/tasks/task_runner/cli.dart index 2678f7fb..fd8a99da 100644 --- a/lib/src/tasks/task_runner/cli.dart +++ b/lib/src/tasks/task_runner/cli.dart @@ -26,10 +26,13 @@ class TaskRunnerCli extends TaskCli { TaskRunner task = await runTasks(tasksToRun); - reporter.logGroup('Tasks run: \'${tasksToRun.join('\', \'')}\'', - output: task.stdout); + reporter.logGroup('Tasks run: \'${tasksToRun.join('\', \'')}\''); if (!task.successful) { - reporter.logGroup('Failure output:', error: task.stderr); + reporter.logGroup( + 'Failure output: ' + 'One of your subtasks exited with a non-zero exit code. ' + 'See the output below for more information:', + error: task.stderr); } return task.successful diff --git a/test/integration/task_runner_test.dart b/test/integration/task_runner_test.dart index 04e8115a..6470c6d3 100644 --- a/test/integration/task_runner_test.dart +++ b/test/integration/task_runner_test.dart @@ -23,13 +23,15 @@ const String projectPassingTasks = 'test_fixtures/task_runner/passing_tasks'; const String projectFailingTasks = 'test_fixtures/task_runner/failing_tasks'; const String failedFormatting = 'The Dart formatter needs to be run.'; +const String failedTesting = 'Some tests failed.'; const String successfulFormatting = 'Your Dart code is good to go!'; const String successfulAnalysis = 'Analysis completed.'; const String successfulTesting = 'All tests passed!'; /// Runs the task-runner task via dart_dev on a given project. Future runTasks(String projectPath) async { - await Process.run('pub', ['get'], workingDirectory: projectPath); + await Process.run('pub', ['get', '--packages-dir'], + workingDirectory: projectPath); var args = ['run', 'dart_dev', 'task-runner']; TaskProcess process = new TaskProcess('pub', args, workingDirectory: projectPath); @@ -37,6 +39,8 @@ Future runTasks(String projectPath) async { List successfulTasks = []; process.stdout.listen((line) { + // leaving this logging in to help debug issues + print(line); if (line.contains(successfulFormatting)) { successfulTasks.add(successfulFormatting); } @@ -49,6 +53,9 @@ Future runTasks(String projectPath) async { if (line.contains(successfulTesting)) { successfulTasks.add(successfulTesting); } + if (line.contains(failedTesting)) { + failedTasks.add(failedTesting); + } }); await process.done; @@ -73,13 +80,13 @@ void main() { expect(tasks.successfulTasks.contains(successfulTesting), isTrue); }); - test('a task failed', () async { + test('a task failed causing the task runner to exit', () async { TasksRun tasks = await runTasks(projectFailingTasks); expect(tasks.exitCode, isNonZero); - expect(tasks.successfulTasks.contains(successfulAnalysis), isTrue); expect(tasks.successfulTasks.contains(successfulFormatting), isFalse); + expect(tasks.successfulTasks.contains(successfulTesting), isFalse); expect(tasks.failedTasks.contains(failedFormatting), isTrue); - expect(tasks.successfulTasks.contains(successfulTesting), isTrue); + expect(tasks.failedTasks.contains(failedTesting), isFalse); }); }); } diff --git a/test_fixtures/task_runner/failing_tasks/test/simple_test.dart b/test_fixtures/task_runner/failing_tasks/test/simple_test.dart index c0beec99..1e7aa086 100644 --- a/test_fixtures/task_runner/failing_tasks/test/simple_test.dart +++ b/test_fixtures/task_runner/failing_tasks/test/simple_test.dart @@ -1,7 +1,10 @@ +import 'dart:async'; + import 'package:test/test.dart'; void main() { - test('passes', () { + test('passes', () async { + await new Future.delayed(new Duration(seconds:5)); expect(true, isTrue); }); } From c4af51bd143d953dc095b36ad587ff2b8491dbb6 Mon Sep 17 00:00:00 2001 From: "Jay.Udey" Date: Wed, 10 May 2017 08:55:35 -0500 Subject: [PATCH 2/2] logging failing command and commands stopped prior to finishing on task-runner completion --- lib/src/tasks/task_runner/api.dart | 24 +++++++++++++++---- lib/src/tasks/task_runner/cli.dart | 4 +++- test/integration/task_runner_test.dart | 3 +-- .../coverage/functional_test/pubspec.yaml | 3 ++- 4 files changed, 26 insertions(+), 8 deletions(-) diff --git a/lib/src/tasks/task_runner/api.dart b/lib/src/tasks/task_runner/api.dart index 796406da..d4b16679 100644 --- a/lib/src/tasks/task_runner/api.dart +++ b/lib/src/tasks/task_runner/api.dart @@ -8,17 +8,20 @@ Future runTasks(tasksToRun) async { var taskGroup = new TaskGroup(tasksToRun); await taskGroup.run(); - TaskRunner task = - new TaskRunner(taskGroup.successful, taskGroup.taskGroupStderr); + TaskRunner task = new TaskRunner(taskGroup.failedTask, taskGroup.successful, + taskGroup.taskGroupStderr, taskGroup.tasksNotCompleted); return task; } class TaskRunner extends Task { final Future done = new Future.value(); + String failedTask; final String stderr; bool successful; + List tasksNotCompleted; - TaskRunner(bool this.successful, String this.stderr); + TaskRunner(this.failedTask, bool this.successful, String this.stderr, + List this.tasksNotCompleted); } class SubTask { @@ -51,6 +54,9 @@ class SubTask { } class TaskGroup { + /// Failed task + String failedTask = ''; + /// List of the individual subtasks executed List subTaskCommands = []; @@ -63,6 +69,9 @@ class TaskGroup { /// Status of TaskGroup bool successful = true; + /// Tasks cancelled prior to completion + List tasksNotCompleted = []; + TaskGroup(this.subTaskCommands) { for (String taskCommand in subTaskCommands) { SubTask task = new SubTask(taskCommand); @@ -80,7 +89,9 @@ class TaskGroup { task.startProcess(); task.taskProcess.exitCode.then((int exitCode) { reporter.log(task.taskOutput); - if (exitCode != 0) { + // if the task runner kills outstanding tasks it currently sets the exit code to -15 + if (exitCode != 0 && exitCode != -15) { + failedTask = task.command; successful = false; reporter.log(task.taskError); this.taskGroupStderr += @@ -94,6 +105,11 @@ class TaskGroup { } await Future.wait(futures); + for (SubTask task in subTasks) { + if (await task.taskProcess.exitCode == -15) { + tasksNotCompleted.add(task.command); + } + } timer.cancel(); } } diff --git a/lib/src/tasks/task_runner/cli.dart b/lib/src/tasks/task_runner/cli.dart index fd8a99da..83266726 100644 --- a/lib/src/tasks/task_runner/cli.dart +++ b/lib/src/tasks/task_runner/cli.dart @@ -37,6 +37,8 @@ class TaskRunnerCli extends TaskCli { return task.successful ? new CliResult.success('Tasks completed successfuly.') - : new CliResult.fail('Some task / tasks failed.'); + : new CliResult.fail('Some task failed: ${task.failedTask}' + '\n\nThe following tasks were stopped prior to completion:' + '\n${task.tasksNotCompleted.join('\n')}'); } } diff --git a/test/integration/task_runner_test.dart b/test/integration/task_runner_test.dart index 6470c6d3..600bc4d9 100644 --- a/test/integration/task_runner_test.dart +++ b/test/integration/task_runner_test.dart @@ -30,8 +30,7 @@ const String successfulTesting = 'All tests passed!'; /// Runs the task-runner task via dart_dev on a given project. Future runTasks(String projectPath) async { - await Process.run('pub', ['get', '--packages-dir'], - workingDirectory: projectPath); + await Process.run('pub', ['get'], workingDirectory: projectPath); var args = ['run', 'dart_dev', 'task-runner']; TaskProcess process = new TaskProcess('pub', args, workingDirectory: projectPath); diff --git a/test_fixtures/coverage/functional_test/pubspec.yaml b/test_fixtures/coverage/functional_test/pubspec.yaml index 3f3dee98..73a0db86 100644 --- a/test_fixtures/coverage/functional_test/pubspec.yaml +++ b/test_fixtures/coverage/functional_test/pubspec.yaml @@ -1,8 +1,9 @@ name: functional_test version: 0.0.0 dev_dependencies: + analyzer: 0.29.7 browser: any - coverage: "^0.7.2" + coverage: "^0.7.3" test: '^0.12.0' webdriver: '^1.0.0' dart_dev: