2
0
mirror of https://github.com/thumbsup/thumbsup synced 2024-11-15 18:12:46 +00:00

refactor(components): bring ListrWorkQueue into this repo to simplify the build process

- This component was not published to the rpm registry anyway
- We depended on the repo’s master branch which can break things for everyone
- Its repo was not getting much attention which meant
  * no tests, no coverage report
  * no linting
  * no package linting (e.g. had 2 dependencies that weren’t actually used)

It will be simpler to manage this way
This commit is contained in:
Romain 2018-07-13 21:29:52 +02:00
parent 90cb3994eb
commit bf60ae4677
6 changed files with 190 additions and 16 deletions

14
package-lock.json generated
View File

@ -2886,20 +2886,6 @@
} }
} }
}, },
"listr-work-queue": {
"version": "git+https://github.com/thumbsup/listr-work-queue.git#867d499747af33a36b2c7c722239e1cbbee21986",
"requires": {
"async": "2.6.1",
"zen-observable": "0.6.1"
},
"dependencies": {
"zen-observable": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/zen-observable/-/zen-observable-0.6.1.tgz",
"integrity": "sha512-DKjFTL7siVLIUMZOFZ0alqMEdTsXPUxoCZzrvB2tdWEVN/6606Qh1nCfSTCAOZMrtcPzzFI3BXmwBKLAew52NA=="
}
}
},
"load-json-file": { "load-json-file": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz",

View File

@ -43,7 +43,6 @@
"insight": "^0.10.1", "insight": "^0.10.1",
"less": "^3.0.4", "less": "^3.0.4",
"listr": "^0.14.1", "listr": "^0.14.1",
"listr-work-queue": "https://github.com/thumbsup/listr-work-queue.git",
"lodash": "^4.17.10", "lodash": "^4.17.10",
"micromatch": "^3.1.10", "micromatch": "^3.1.10",
"moment": "^2.22.1", "moment": "^2.22.1",

View File

@ -0,0 +1,56 @@
const _ = require('lodash')
const Listr = require('listr')
class ListrWorkQueue extends Listr {
constructor (jobs, options) {
options = _.defaults(options, {
concurrent: 1,
exitOnError: true
})
const threads = _.times(options.concurrent, i => {
return {
title: 'Waiting',
task: (ctx, task) => {
task.id = i
return new Promise((resolve, reject) => {
this.createWorker(task, jobs, err => {
err ? reject(err) : resolve()
})
})
}
}
})
super(threads, options)
this.options = options
this.jobsTotal = jobs.length
this.jobsDone = 0
}
createWorker (task, jobs, done) {
task.title = 'Finished'
const job = jobs.shift()
if (!job) {
return done()
} else {
task.title = job.title
}
const nextJob = () => {
setImmediate(() => this.createWorker(task, jobs, done))
}
job.task(null, task).then(() => {
++this.jobsDone
if (this.options.update) {
this.options.update(this.jobsDone, this.jobsTotal)
}
nextJob()
}).catch(err => {
if (this.exitOnError) {
done(new Error(`Error: ${err}`))
} else {
nextJob()
}
})
}
}
module.exports = ListrWorkQueue

View File

@ -2,7 +2,7 @@ const debug = require('debug')('thumbsup:debug')
const error = require('debug')('thumbsup:error') const error = require('debug')('thumbsup:error')
const fs = require('fs-extra') const fs = require('fs-extra')
const info = require('debug')('thumbsup:info') const info = require('debug')('thumbsup:info')
const ListrWorkQueue = require('listr-work-queue') const ListrWorkQueue = require('../components/listr-work-queue/index')
const path = require('path') const path = require('path')
const actions = require('./actions') const actions = require('./actions')

View File

@ -0,0 +1,43 @@
/*
Special Listr renderer that
- on every change, renders the whole task list in memory
- accumulates all rendered data into an array
- has this array available as `listr._renderer.output`
*/
module.exports = class ListrTestRenderer {
static get nonTTY () {
return true
}
constructor (tasks) {
this._tasks = tasks
this.output = []
}
render () {
for (let task of this._tasks) {
this.subscribe(task)
}
}
subscribe (task) {
task.subscribe(
event => {
if (event.type === 'SUBTASKS') {
// new subtasks: subscribe to them too
task.subtasks.forEach(sub => this.subscribe(sub))
} else {
// something else happened, capture all titles
const titles = this.allTitles(this._tasks, 0)
this.output.push(titles)
}
}
)
}
allTitles (tasks, indent) {
return tasks.map(task => {
const subTitles = this.allTitles(task.subtasks, indent + 1)
return ' '.repeat(indent) + task.title + '\n' + subTitles
}).join('')
}
end () {
}
}

View File

@ -0,0 +1,90 @@
const _ = require('lodash')
const Listr = require('listr')
const should = require('should/as-function')
const ListrWorkQueue = require('../../../src/components/listr-work-queue/index')
const ListrTestRenderer = require('./listr-test-renderer.js')
describe('Listr work queue', function () {
this.slow(2000)
this.timeout(2000)
it('processes all jobs in parallel', done => {
const jobs = makeJobs(10)
const listr = createWorkQueue(jobs, 3, null)
listr.run().then(() => {
const output = listr._renderer.output
for (let i = 1; i <= 10; ++i) {
hasItemMatching(output, `Job ${i}`)
}
done()
})
})
it('renders thread-like entries which keep changing title', done => {
const jobs = makeJobs(10)
const listr = createWorkQueue(jobs, 3, null)
listr.run().then(() => {
const output = listr._renderer.output
// At some point a thread should have been waiting
hasItemMatching(output, `Waiting`)
// And a thread should have finished
hasItemMatching(output, `Finished`)
// And every single render should conform to a particular format
const regex = /^Running jobs\n((\s\s(Waiting|Finished|Job \d+)\n){3})?$/
for (let line of output) {
if (!regex.test(line)) {
should.fail(`Listr output does not match expected format: ${line}`)
}
}
done()
})
})
it('reports progress', done => {
const jobs = makeJobs(10)
const listr = createWorkQueue(jobs, 3, (done, total) => {
const progress = done === total ? '' : ` (${done}/${total})`
return `Running jobs${progress}`
})
listr.run().then(() => {
const output = listr._renderer.output
for (let i = 1; i < 10; ++i) {
hasItemMatching(output, `Running jobs (${i}/10)`)
}
done()
})
})
})
function createWorkQueue (jobs, concurrency, updater) {
const task = {
title: 'Running jobs',
task: (ctx, task) => new ListrWorkQueue(jobs, {
concurrent: concurrency,
update: (done, total) => {
if (updater) {
task.title = updater(done, total)
}
}
})
}
return new Listr([task], {
renderer: ListrTestRenderer
})
}
function makeJobs (count) {
return _.times(count, i => {
return {
title: `Job ${i + 1}`,
task: () => new Promise(resolve => setTimeout(resolve, 100))
}
})
}
function hasItemMatching (list, substring) {
const match = _.some(list, item => item.includes(substring))
if (!match) {
should.fail(`Excepted ${substring} to be present in ${list}`)
}
}