-
-
Notifications
You must be signed in to change notification settings - Fork 108
added suspending update renderer for task #136
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
Open
bunysae
wants to merge
13
commits into
SamVerschueren:master
Choose a base branch
from
bunysae:master
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
5a1272a
added suspending update renderer for task
470a8b8
fixed clinton && xo && nyc ava errors
bunysae c0317c7
unit-test for suspending update-rendering added
bunysae e440c18
documentation for suspending-feature
bunysae 7a74f5d
Moved feature from listr-update-renderer to listr according to
bunysae 4b2c801
fixed issue in unit-test
bunysae f2e2750
fixed xo-error
bunysae 8455f63
Added suspending update renderer for task:
bunysae 6eeb4c4
Refactoring test-module
bunysae 47fb5a2
Removed mockery dependency
bunysae 1cf0f10
Refactoring suspend-testclass
bunysae 0327ff7
Add testclass for user-input-verification
bunysae 607a7f6
Integrate lint fixes
bunysae File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| 'use strict'; | ||
| const chalk = require('chalk'); | ||
| const logSymbols = require('log-symbols'); | ||
| const figures = require('figures'); | ||
| const elegantSpinner = require('elegant-spinner'); | ||
|
|
||
| const pointer = chalk.yellow(figures.pointer); | ||
| const skipped = chalk.yellow(figures.arrowDown); | ||
|
|
||
| exports.isDefined = x => x !== null && x !== undefined; | ||
|
|
||
| exports.getSymbol = (task, options) => { | ||
| if (!task.spinner) { | ||
| task.spinner = elegantSpinner(); | ||
| } | ||
|
|
||
| if (task.isPending()) { | ||
| return options.showSubtasks !== false && task.subtasks.length > 0 ? pointer : chalk.yellow(task.spinner()); | ||
| } | ||
|
|
||
| if (task.isCompleted()) { | ||
| return logSymbols.success; | ||
| } | ||
|
|
||
| if (task.hasFailed()) { | ||
| return task.subtasks.length > 0 ? pointer : logSymbols.error; | ||
| } | ||
|
|
||
| if (task.isSkipped()) { | ||
| return skipped; | ||
| } | ||
|
|
||
| return ' '; | ||
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| #!/usr/bin/env node | ||
| 'use strict'; | ||
| const Listr = require('../..'); | ||
| const updateRenderer = require('./update-renderer'); | ||
|
|
||
| function getTasks(suspendUpdateRenderer) { | ||
| const task = () => { | ||
| return new Promise((resolve, reject) => { | ||
| console.log('Continue?'); | ||
| process.stdin.on('data', chunk => { | ||
| const received = chunk.toString().replace('\n', ''); | ||
| if (received === 'yes') { | ||
| resolve(received); | ||
| } else { | ||
| reject(new Error(`invalid input ${received}`)); | ||
| } | ||
| }); | ||
| }); | ||
| }; | ||
|
|
||
| const result = new Listr([ | ||
| { | ||
| title: `receive user input from task with renderer is ${suspendUpdateRenderer ? 'suspended' : 'running'}`, | ||
| task, | ||
| options: {suspendUpdateRenderer} | ||
| } | ||
| ]); | ||
| result.setRenderer(updateRenderer); | ||
| return result; | ||
| } | ||
|
|
||
| (async () => { | ||
| let suspendUpdateRenderer = false; | ||
| if (process.argv[2] === 'true') { | ||
| suspendUpdateRenderer = true; | ||
| } | ||
|
|
||
| await getTasks(suspendUpdateRenderer).run(); | ||
| process.exit(0); | ||
| })(); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,99 @@ | ||
| 'use strict'; | ||
| const logUpdate = require('log-update'); | ||
| const chalk = require('chalk'); | ||
| const figures = require('figures'); | ||
| const indentString = require('indent-string'); | ||
| const cliTruncate = require('cli-truncate'); | ||
| const stripAnsi = require('strip-ansi'); | ||
| const utils = require('./renderer-utils'); | ||
|
|
||
| const renderHelper = (tasks, options, level) => { | ||
| level = level || 0; | ||
|
|
||
| let output = []; | ||
|
|
||
| for (const task of tasks) { | ||
| if (task.isEnabled()) { | ||
| const skipped = task.isSkipped() ? ` ${chalk.dim('[skipped]')}` : ''; | ||
|
|
||
| output.push(indentString(` ${utils.getSymbol(task, options)} ${task.title}${skipped}`, level, ' ')); | ||
|
|
||
| if ((task.isPending() || task.isSkipped() || task.hasFailed()) && utils.isDefined(task.output)) { | ||
| let data = task.output; | ||
|
|
||
| if (typeof data === 'string') { | ||
| data = stripAnsi(data.trim().split('\n').filter(Boolean).pop()); | ||
|
|
||
| if (data === '') { // eslint-disable-line max-depth | ||
| data = undefined; | ||
| } | ||
| } | ||
|
|
||
| if (utils.isDefined(data)) { | ||
| const out = indentString(`${figures.arrowRight} ${data}`, level, ' '); | ||
| output.push(` ${chalk.gray(cliTruncate(out, process.stdout.columns - 3))}`); | ||
| } | ||
| } | ||
|
|
||
| if ((task.isPending() || task.hasFailed() || options.collapse === false) && (task.hasFailed() || options.showSubtasks !== false) && task.subtasks.length > 0) { | ||
| output = output.concat(renderHelper(task.subtasks, options, level + 1)); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| return output.join('\n'); | ||
| }; | ||
|
|
||
| const shouldSuspendUpdateRenderer = tasks => { | ||
| return tasks.some(task => task.shouldSuspendUpdateRenderer()); | ||
| }; | ||
|
|
||
| const render = (tasks, options) => { | ||
| if (!shouldSuspendUpdateRenderer(tasks)) { | ||
| logUpdate(renderHelper(tasks, options)); | ||
| } | ||
| }; | ||
|
|
||
| class UpdateRenderer { | ||
| constructor(tasks, options) { | ||
| this._tasks = tasks; | ||
| this._options = { | ||
| showSubtasks: true, | ||
| collapse: true, | ||
| clearOutput: false, | ||
| ...options | ||
| }; | ||
| } | ||
|
|
||
| static get nonTTY() { | ||
| return true; | ||
| } | ||
|
|
||
| render() { | ||
| if (this._id) { | ||
| // Do not render if we are already rendering | ||
| return; | ||
| } | ||
|
|
||
| this._id = setInterval(() => { | ||
| render(this._tasks, this._options); | ||
| }, 100); | ||
| } | ||
|
|
||
| end(err) { | ||
| if (this._id) { | ||
| clearInterval(this._id); | ||
| this._id = undefined; | ||
| } | ||
|
|
||
| render(this._tasks, this._options); | ||
|
|
||
| if (this._options.clearOutput && err === undefined) { | ||
| logUpdate.clear(); | ||
| } else { | ||
| logUpdate.done(); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| module.exports = UpdateRenderer; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,71 @@ | ||
| const test = require('ava'); | ||
| const mockery = require('mockery'); | ||
| const elegantSpinner = require('elegant-spinner'); | ||
|
|
||
| function getTasks() { | ||
| const Listr = require('..'); | ||
| const tasks = new Listr([ | ||
| { | ||
| title: 'first', | ||
| task: () => { | ||
| return new Promise(resolve => { | ||
| setTimeout(() => { | ||
| resolve('predefined output'); | ||
| }, 150); | ||
| }); | ||
| } | ||
| }, | ||
| { | ||
| title: 'second', | ||
| task: () => { | ||
| return new Promise(resolve => { | ||
| setTimeout(() => { | ||
| resolve('predefined output'); | ||
| }, 300); | ||
| }); | ||
| }, | ||
| options: {suspendUpdateRenderer: true} | ||
| }, | ||
| { | ||
| title: 'last', | ||
| task: () => { | ||
| return new Promise(resolve => { | ||
| setTimeout(() => { | ||
| resolve('predefined output'); | ||
| }, 100); | ||
| }); | ||
| } | ||
| } | ||
| ]); | ||
| tasks.setRenderer(require('./fixtures/update-renderer')); | ||
|
|
||
| return tasks; | ||
| } | ||
|
|
||
| test('should not erase output from suspended task, as long as this task is running', async t => { | ||
| const countOutputIsErasedWhenTaskRunning = {first: 0, second: 0, last: 0}; | ||
|
|
||
| const logUpdate = output => { | ||
| const taskPendingPattern = new RegExp(elegantSpinner.frames.join('|')); | ||
| const tasks = output.split('\n'); | ||
| for (const task of tasks) { | ||
| if (task.search(taskPendingPattern) > 0) { | ||
| const title = task.match(/first|second|last/); | ||
| countOutputIsErasedWhenTaskRunning[title]++; | ||
| } | ||
| } | ||
| }; | ||
|
|
||
| logUpdate.done = () => {}; | ||
|
|
||
| mockery.registerAllowable('..'); | ||
| mockery.registerMock('log-update', logUpdate); | ||
| mockery.enable({useCleanCache: true, warnOnUnregistered: false}); | ||
|
|
||
| await getTasks().run(); | ||
|
|
||
| mockery.deregisterAll(); | ||
| mockery.disable(); | ||
|
|
||
| t.deepEqual(countOutputIsErasedWhenTaskRunning, {first: 1, second: 0, last: 1}); | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| 'use strict'; | ||
| const {spawn} = require('child_process'); | ||
| const path = require('path'); | ||
| const test = require('ava'); | ||
|
|
||
| const executeTask = async (t, suspendUpdateRenderer) => { | ||
| const promise = new Promise((resolve, reject) => { | ||
| const childProcess = spawn('./task-with-input.js', [suspendUpdateRenderer], {cwd: path.resolve('test', 'fixtures')}); | ||
| childProcess.stdout.pipe(process.stdout); | ||
| childProcess.on('close', code => { | ||
| if (code !== 0) { | ||
| reject(new Error(`exit code ${code}`)); | ||
| } | ||
|
|
||
| resolve(); | ||
| }); | ||
| setTimeout(() => { | ||
| childProcess.stdin.write('yes'); | ||
| }, 50); | ||
| }); | ||
| await promise; | ||
| t.pass(); | ||
| }; | ||
|
|
||
| test('should receive user input from task with running renderer', executeTask); | ||
| test('should receive user input from task with suspended renderer', executeTask, 'true'); |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is moot. You can already access it as
this.task.options.Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, but
this.taskcan be just a function.task.optionsrefers to input-variabletaskgiven in the constructor and not tothis.task. We will need here a separate variable to store the options.