imdone-core 1.45.0 → 1.46.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/adapters/file-gateway.js +22 -0
- package/lib/card.js +2 -0
- package/lib/config.js +12 -0
- package/lib/file.js +1 -0
- package/lib/migrate-config.js +19 -5
- package/lib/mixins/repo-fs-store.js +2 -1
- package/lib/plugins/archive-plugin.js +58 -0
- package/lib/plugins/plugin-manager.js +6 -2
- package/lib/project.js +52 -56
- package/lib/repository.js +11 -7
- package/package.json +1 -1
- package/cli.js +0 -225
- package/lib/cli/CliControler.js +0 -327
- package/lib/cli/MDStoryParser.js +0 -139
- package/lib/cli/ProjectConfigFactory.js +0 -114
- package/lib/cli/adapters/ApplicationContext.js +0 -6
- package/lib/cli/adapters/Errors.js +0 -8
- package/lib/cli/adapters/LogAdapter.js +0 -3
- package/lib/cli/adapters/StorageAdapter.js +0 -135
- package/lib/cli/domain/BacklogProject.js +0 -170
- package/lib/cli/domain/StoryProject.js +0 -67
- package/lib/cli/prompts/MarkdownPlanPrompt.js +0 -16
- package/lib/plugins/cli-backlog-plugin.js +0 -152
|
@@ -30,6 +30,11 @@ module.exports = {
|
|
|
30
30
|
return fs.readFileSync.apply({}, args)
|
|
31
31
|
},
|
|
32
32
|
|
|
33
|
+
appendFileSync(...args) {
|
|
34
|
+
console.warn('sync call')
|
|
35
|
+
return fs.appendFileSync.apply({}, args)
|
|
36
|
+
},
|
|
37
|
+
|
|
33
38
|
writeFileSync(...args) {
|
|
34
39
|
console.warn('sync call')
|
|
35
40
|
return fs.writeFileSync.apply({}, args)
|
|
@@ -78,6 +83,7 @@ module.exports = {
|
|
|
78
83
|
console.warn('sync call')
|
|
79
84
|
return fs.readdirSync(path, { withFileTypes: true })
|
|
80
85
|
},
|
|
86
|
+
|
|
81
87
|
sanitizeFileName(fileName, replaceSpacesWith) {
|
|
82
88
|
// Remove markdown emoji
|
|
83
89
|
fileName = fileName.replace(/:\w+:/g, '').trim()
|
|
@@ -85,5 +91,21 @@ module.exports = {
|
|
|
85
91
|
if (replaceSpacesWith)
|
|
86
92
|
fileName = fileName.replace(/ /g, replaceSpacesWith)
|
|
87
93
|
return fileName
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
preparePathForWriting(path) {
|
|
97
|
+
let stat = this.statSync(path)
|
|
98
|
+
if (!stat) {
|
|
99
|
+
let { dir, ext } = _path.parse(path)
|
|
100
|
+
if (!ext) {
|
|
101
|
+
dir = path
|
|
102
|
+
}
|
|
103
|
+
this.mkdirpSync(dir)
|
|
104
|
+
stat = this.statSync(path)
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
isFile: stat && stat.isFile(),
|
|
108
|
+
isDirectory: stat && stat.isDirectory()
|
|
109
|
+
}
|
|
88
110
|
}
|
|
89
111
|
}
|
package/lib/card.js
CHANGED
|
@@ -327,7 +327,9 @@ module.exports = function newCard(task, _project, dontParse) {
|
|
|
327
327
|
)
|
|
328
328
|
const formattedRawMarkdown = this.formatContent(rawMarkdown, true).content
|
|
329
329
|
const { html, truncHtml } = this.getHtml(content)
|
|
330
|
+
const title = this.format(this.text, true)
|
|
330
331
|
return {
|
|
332
|
+
title,
|
|
331
333
|
html,
|
|
332
334
|
truncHtml,
|
|
333
335
|
encodedText,
|
package/lib/config.js
CHANGED
|
@@ -179,6 +179,18 @@ class Config {
|
|
|
179
179
|
return _get(this, 'settings.cards.maxLines', 1)
|
|
180
180
|
}
|
|
181
181
|
|
|
182
|
+
get archiveFolder() {
|
|
183
|
+
return _get(this, 'settings.cards.archiveFolder', '')
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
get archiveCompleted() {
|
|
187
|
+
return _get(this, 'settings.cards.archiveCompleted', false)
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
get doneList() {
|
|
191
|
+
return this.getDoneList()
|
|
192
|
+
}
|
|
193
|
+
|
|
182
194
|
get blankLinesToEndTask() {
|
|
183
195
|
let blankLinesToEndTask = Math.round(
|
|
184
196
|
_get(this, 'settings.cards.blankLinesToEndTask', 1)
|
package/lib/file.js
CHANGED
package/lib/migrate-config.js
CHANGED
|
@@ -36,6 +36,9 @@ module.exports = function (repo, defaultSettings = defaultSettingsObject) {
|
|
|
36
36
|
config.code.include_lists.push(list.name)
|
|
37
37
|
})
|
|
38
38
|
|
|
39
|
+
if (!config.settings.cards) {
|
|
40
|
+
config.settings.cards = {}
|
|
41
|
+
}
|
|
39
42
|
// metaSep
|
|
40
43
|
if (config.settings.metaSep) {
|
|
41
44
|
config.settings.cards.metaSep = config.settings.metaSep
|
|
@@ -47,14 +50,20 @@ module.exports = function (repo, defaultSettings = defaultSettingsObject) {
|
|
|
47
50
|
delete config.settings.defaultList
|
|
48
51
|
}
|
|
49
52
|
|
|
50
|
-
if (!config.settings.cards) {
|
|
51
|
-
config.settings.cards = {}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
53
|
if (!config.settings.cards.defaultList) {
|
|
55
54
|
config.settings.cards.defaultList = lists ? lists[0] : ''
|
|
56
55
|
}
|
|
57
56
|
|
|
57
|
+
// archiveCompleted
|
|
58
|
+
if (config.settings.cards.archiveCompleted === undefined) {
|
|
59
|
+
config.settings.cards.archiveCompleted = false
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// archiveFolder
|
|
63
|
+
if (!config.settings.cards.archiveFolder) {
|
|
64
|
+
config.settings.cards.archiveFolder = config.settings.journalPath ? _path.join(config.settings.journalPath, 'archive') : 'archive'
|
|
65
|
+
}
|
|
66
|
+
|
|
58
67
|
// showTagsAndMeta
|
|
59
68
|
if (config.settings.cards.showTagsAndMeta === undefined) {
|
|
60
69
|
config.settings.cards.showTagsAndMeta = true
|
|
@@ -126,7 +135,12 @@ module.exports = function (repo, defaultSettings = defaultSettingsObject) {
|
|
|
126
135
|
// make sure all lists have an id
|
|
127
136
|
config.lists.forEach((list) => {
|
|
128
137
|
if (!list.id || (list.id + "").length < 4) list.id = uniqid()
|
|
129
|
-
})
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
// Make sure kudosProbability is set
|
|
141
|
+
if (!config.settings.kudosProbability && config.settings.kudosProbability !== 0) {
|
|
142
|
+
config.settings.kudosProbability = 0.33
|
|
143
|
+
}
|
|
130
144
|
|
|
131
145
|
const defaultCardsSettings = _cloneDeep(defaultSettings.cards)
|
|
132
146
|
const cardsSettings = _cloneDeep(config.settings.cards)
|
|
@@ -311,7 +311,8 @@ function mixin(repo, fs = require('fs')) {
|
|
|
311
311
|
cb = tools.cb(cb)
|
|
312
312
|
|
|
313
313
|
if (!File.isFile(file)) return cb(new Error(ERRORS.NOT_A_FILE))
|
|
314
|
-
|
|
314
|
+
if (file.deleted) return cb(null, file)
|
|
315
|
+
|
|
315
316
|
var filePath = repo.getFullPath(file)
|
|
316
317
|
|
|
317
318
|
if (!/\.\.(\/|\\)/.test(file.path)) {
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
const Plugin = require('imdone-api')
|
|
2
|
+
const path = require('path')
|
|
3
|
+
|
|
4
|
+
module.exports = class ArchivePlugin extends Plugin {
|
|
5
|
+
constructor(project) {
|
|
6
|
+
super(project)
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
get config() {
|
|
10
|
+
return this.project.config
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
get fileGateway() {
|
|
14
|
+
return this.project.fileGateway
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
onBeforeBoardUpdate() {
|
|
18
|
+
const config = this.config
|
|
19
|
+
if (!config || !config.archiveCompleted || this.archivingTasks) return
|
|
20
|
+
this.archivingTasks = true
|
|
21
|
+
const cards = this.project.getAllCards(`meta.archived != "true" and list = ${config.doneList}`)
|
|
22
|
+
const messageUser = cards.length > 1
|
|
23
|
+
if (!cards.length) {
|
|
24
|
+
this.archivingTasks = false
|
|
25
|
+
return
|
|
26
|
+
} else {
|
|
27
|
+
if (messageUser) this.project.snackBar({message: `Archiving ${cards.length} card(s)...`})
|
|
28
|
+
}
|
|
29
|
+
cards.forEach(card => this.archiveTask(card))
|
|
30
|
+
if (messageUser) this.project.snackBar({message: ` Done archiving ${cards.length} card(s). Deleting original(s)...`})
|
|
31
|
+
this.project.deleteTasks(cards).then(() => {
|
|
32
|
+
this.archivingTasks = false
|
|
33
|
+
if (messageUser) this.project.snackBar({message: `Done deleting original card(s).`})
|
|
34
|
+
})
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
archiveTask (task, config = this.config) {
|
|
38
|
+
const archiveFolder = config.archiveFolder
|
|
39
|
+
const fileDir = path.dirname(task.relPath)
|
|
40
|
+
|
|
41
|
+
if (fileDir.startsWith(archiveFolder)) return
|
|
42
|
+
|
|
43
|
+
const fileName = this.fileGateway.sanitizeFileName(`${task.text}.md`, config.replaceSpacesWith)
|
|
44
|
+
const newPath = path.join(this.project.path, archiveFolder, fileDir, fileName)
|
|
45
|
+
|
|
46
|
+
const content = this.project.addMetaToContent(
|
|
47
|
+
[
|
|
48
|
+
{ key: 'archived', value: 'true'}
|
|
49
|
+
],
|
|
50
|
+
task.content
|
|
51
|
+
)
|
|
52
|
+
const taskContent = `${task.beforeText}#${task.list} ${content}`
|
|
53
|
+
|
|
54
|
+
this.fileGateway.preparePathForWriting(newPath)
|
|
55
|
+
this.fileGateway.appendFileSync(newPath, taskContent)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
}
|
|
@@ -11,7 +11,11 @@ module.exports = class PluginManager extends Emitter {
|
|
|
11
11
|
constructor(project) {
|
|
12
12
|
super()
|
|
13
13
|
this.project = project
|
|
14
|
-
this.defaultPlugins = [
|
|
14
|
+
this.defaultPlugins = [
|
|
15
|
+
'./archive-plugin',
|
|
16
|
+
'./epic-plugin',
|
|
17
|
+
'./extension-plugin'
|
|
18
|
+
]
|
|
15
19
|
this.pluginsMap = {}
|
|
16
20
|
this.pluginPath = _path.join(project.path, '.imdone', 'plugins')
|
|
17
21
|
this.onDevChange = debounce(this.onDevChange.bind(this), 1000)
|
|
@@ -19,7 +23,7 @@ module.exports = class PluginManager extends Emitter {
|
|
|
19
23
|
}
|
|
20
24
|
|
|
21
25
|
async startDevMode() {
|
|
22
|
-
if (this.project.config.devMode && !this.watcher) {
|
|
26
|
+
if (this.project && this.project.config.devMode && !this.watcher) {
|
|
23
27
|
if (!(await this.exists(this.pluginPath)))
|
|
24
28
|
await fs.promises.mkdir(this.pluginPath)
|
|
25
29
|
this.watcher = sane(this.pluginPath, {
|
package/lib/project.js
CHANGED
|
@@ -47,8 +47,45 @@ module.exports = class WorkerProject extends Project {
|
|
|
47
47
|
super()
|
|
48
48
|
this.repo = repo
|
|
49
49
|
this.innerFilter = ''
|
|
50
|
+
this.fileGateway = fileGateway
|
|
50
51
|
}
|
|
51
52
|
|
|
53
|
+
init(cb) {
|
|
54
|
+
this.repo.project = this
|
|
55
|
+
|
|
56
|
+
this.pluginManager = new PluginManager(this)
|
|
57
|
+
this.pluginManager.on('plugin-installed', () => this.emitUpdate())
|
|
58
|
+
this.pluginManager.on('plugin-uninstalled', () => this.emitUpdate())
|
|
59
|
+
this.pluginManager.on('plugins-reloaded', () => this.emitUpdate())
|
|
60
|
+
|
|
61
|
+
EVENTS.forEach((event) => {
|
|
62
|
+
this.repo.on(event, (data) => onChange(this, event, data))
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
const promise = new Promise((resolve, reject) => {
|
|
66
|
+
this.repo.init((err, files) => {
|
|
67
|
+
if (err) {
|
|
68
|
+
if (cb) cb(err)
|
|
69
|
+
else reject(err)
|
|
70
|
+
return
|
|
71
|
+
}
|
|
72
|
+
this.pluginManager
|
|
73
|
+
.startDevMode()
|
|
74
|
+
.then(() => {
|
|
75
|
+
if (cb) cb(null, files)
|
|
76
|
+
else resolve(files)
|
|
77
|
+
})
|
|
78
|
+
.catch(err => {
|
|
79
|
+
console.log('Error on starting dev mode', err)
|
|
80
|
+
if (cb) cb(err)
|
|
81
|
+
else reject(err)
|
|
82
|
+
})
|
|
83
|
+
})
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
if (!cb) return promise
|
|
87
|
+
}
|
|
88
|
+
|
|
52
89
|
// HACK:-50 To handle circular dependency issue with file
|
|
53
90
|
toJSON() {
|
|
54
91
|
return { path: this.path }
|
|
@@ -114,42 +151,6 @@ module.exports = class WorkerProject extends Project {
|
|
|
114
151
|
}
|
|
115
152
|
}
|
|
116
153
|
|
|
117
|
-
init(cb) {
|
|
118
|
-
this.repo.project = this
|
|
119
|
-
this.pluginManager = new PluginManager(this)
|
|
120
|
-
this.pluginManager.on('plugin-installed', () => this.emitUpdate())
|
|
121
|
-
this.pluginManager.on('plugin-uninstalled', () => this.emitUpdate())
|
|
122
|
-
this.pluginManager.on('plugins-reloaded', () => this.emitUpdate())
|
|
123
|
-
|
|
124
|
-
EVENTS.forEach((event) => {
|
|
125
|
-
this.repo.on(event, (data) => onChange(this, event, data))
|
|
126
|
-
})
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
const promise = new Promise((resolve, reject) => {
|
|
130
|
-
this.repo.init((err, files) => {
|
|
131
|
-
if (err) {
|
|
132
|
-
if (cb) cb(err)
|
|
133
|
-
else reject(err)
|
|
134
|
-
return
|
|
135
|
-
}
|
|
136
|
-
this.pluginManager
|
|
137
|
-
.startDevMode()
|
|
138
|
-
.then(() => {
|
|
139
|
-
if (cb) cb(null, files)
|
|
140
|
-
else resolve(files)
|
|
141
|
-
})
|
|
142
|
-
.catch(err => {
|
|
143
|
-
console.log('Error on starting dev mode', err)
|
|
144
|
-
if (cb) cb(err)
|
|
145
|
-
else reject(err)
|
|
146
|
-
})
|
|
147
|
-
})
|
|
148
|
-
})
|
|
149
|
-
|
|
150
|
-
if (!cb) return promise
|
|
151
|
-
}
|
|
152
|
-
|
|
153
154
|
emit() {}
|
|
154
155
|
|
|
155
156
|
emitUpdate() {
|
|
@@ -371,13 +372,13 @@ module.exports = class WorkerProject extends Project {
|
|
|
371
372
|
|
|
372
373
|
async updateCardContent(task, content) {
|
|
373
374
|
return new Promise((resolve, reject) => {
|
|
374
|
-
this.repo.modifyTaskFromContent(task, content, (err) => {
|
|
375
|
+
this.repo.modifyTaskFromContent(task, content, (err, file) => {
|
|
375
376
|
if (err) {
|
|
376
377
|
console.error(err)
|
|
377
378
|
reject(err)
|
|
378
379
|
}
|
|
379
380
|
this.emitUpdate()
|
|
380
|
-
resolve()
|
|
381
|
+
resolve(file)
|
|
381
382
|
})
|
|
382
383
|
})
|
|
383
384
|
}
|
|
@@ -416,22 +417,6 @@ module.exports = class WorkerProject extends Project {
|
|
|
416
417
|
this.emit('project.saveFile', { file: filePath, content })
|
|
417
418
|
}
|
|
418
419
|
|
|
419
|
-
preparePathForWriting(path) {
|
|
420
|
-
let stat = fileGateway.statSync(path)
|
|
421
|
-
if (!stat) {
|
|
422
|
-
let { dir, ext } = _path.parse(path)
|
|
423
|
-
if (!ext) {
|
|
424
|
-
dir = path
|
|
425
|
-
}
|
|
426
|
-
fileGateway.mkdirpSync(dir)
|
|
427
|
-
stat = fileGateway.statSync(path)
|
|
428
|
-
}
|
|
429
|
-
return {
|
|
430
|
-
isFile: stat && stat.isFile(),
|
|
431
|
-
isDirectory: stat && stat.isDirectory()
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
|
|
435
420
|
/*
|
|
436
421
|
* @param {Object} opts - The options object
|
|
437
422
|
* @param {String} opts.list - The list name to add the card to
|
|
@@ -442,9 +427,10 @@ module.exports = class WorkerProject extends Project {
|
|
|
442
427
|
* @param {Boolean} opts.emit - Whether to emit the new card event
|
|
443
428
|
*/
|
|
444
429
|
newCard({ list, path, template, title, comments, emit = true }) {
|
|
445
|
-
if (!path || !_path.parse(path).ext) path = this.
|
|
430
|
+
if (!path || !_path.parse(path).ext) path = this.getNewCardsFile({title})
|
|
431
|
+
path = this.getFullPath(path)
|
|
446
432
|
|
|
447
|
-
const { isFile, isDirectory } =
|
|
433
|
+
const { isFile, isDirectory } = fileGateway.preparePathForWriting(path)
|
|
448
434
|
|
|
449
435
|
if (!template) template = this.getNewCardTemplate(path, isFile)
|
|
450
436
|
|
|
@@ -559,6 +545,16 @@ module.exports = class WorkerProject extends Project {
|
|
|
559
545
|
})
|
|
560
546
|
}
|
|
561
547
|
|
|
548
|
+
async deleteTasks(tasks) {
|
|
549
|
+
return new Promise((resolve, reject) => {
|
|
550
|
+
this.repo.deleteTasks(tasks, async (err) => {
|
|
551
|
+
if (err) return reject(err)
|
|
552
|
+
resolve()
|
|
553
|
+
})
|
|
554
|
+
})
|
|
555
|
+
|
|
556
|
+
}
|
|
557
|
+
|
|
562
558
|
setFilter(filter) {
|
|
563
559
|
this.emit('project.filter', { filter })
|
|
564
560
|
}
|
package/lib/repository.js
CHANGED
|
@@ -622,12 +622,14 @@ Repository.prototype.readFile = function (file, cb) {
|
|
|
622
622
|
const checksum = this.checksum || function () {}
|
|
623
623
|
cb = tools.cb(cb)
|
|
624
624
|
if (!File.isFile(file)) return cb(new Error(ERRORS.NOT_A_FILE))
|
|
625
|
+
if (file.deleted) return cb(null, file)
|
|
625
626
|
var self = this
|
|
626
627
|
|
|
627
628
|
var currentChecksum = file.checksum
|
|
628
|
-
|
|
629
|
+
const filePath = file.path
|
|
630
|
+
if (!/\.\.(\/|\\)/.test(filePath)) {
|
|
629
631
|
this.readFileContent(file, (err, file) => {
|
|
630
|
-
if (err) return cb(new Error('Unable to read file:' +
|
|
632
|
+
if (err) return cb(new Error('Unable to read file:' + filePath))
|
|
631
633
|
// BACKLOG:-40 Allow user to assign a module for content transformation
|
|
632
634
|
file.checksum = checksum(file.getContent())
|
|
633
635
|
file.updated = currentChecksum !== file.checksum
|
|
@@ -966,13 +968,15 @@ Repository.prototype.deleteTask = function (task, cb) {
|
|
|
966
968
|
if (!cb) throw new Error('task, callback required')
|
|
967
969
|
var self = this
|
|
968
970
|
var file = self.getFileForTask(task)
|
|
971
|
+
if (!file) return cb(null)
|
|
969
972
|
const execute = function (file) {
|
|
970
973
|
file.deleteTask(task, self.getConfig())
|
|
971
|
-
if (
|
|
972
|
-
file.
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
974
|
+
if (file.getContentForFile().trim() === '') {
|
|
975
|
+
if (file.deleted) return
|
|
976
|
+
console.log('Deleting empty file:', file.path)
|
|
977
|
+
self.deleteFile(file.path, cb)
|
|
978
|
+
file.deleted = true
|
|
979
|
+
return
|
|
976
980
|
}
|
|
977
981
|
self.writeAndExtract(file, true, cb)
|
|
978
982
|
}
|
package/package.json
CHANGED
package/cli.js
DELETED
|
@@ -1,225 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
const { program } = require('commander');
|
|
4
|
-
const ora = require('ora')
|
|
5
|
-
const chalk = require('chalk')
|
|
6
|
-
const { ChangesExistError } = require('./lib/cli/adapters/Errors')
|
|
7
|
-
const {
|
|
8
|
-
imdoneInit,
|
|
9
|
-
planStory,
|
|
10
|
-
startTask,
|
|
11
|
-
addTask,
|
|
12
|
-
listTasks ,
|
|
13
|
-
completeTask,
|
|
14
|
-
openBoard,
|
|
15
|
-
openTaskFile,
|
|
16
|
-
exportProject
|
|
17
|
-
} = require('./lib/cli/CliControler')
|
|
18
|
-
const {
|
|
19
|
-
STORY_ID
|
|
20
|
-
} = require('./lib/cli/domain/BacklogProject').constants
|
|
21
|
-
const package = require('./package.json')
|
|
22
|
-
|
|
23
|
-
const { log } = hideLogs()
|
|
24
|
-
const spinner = ora('Loading unicorns')
|
|
25
|
-
|
|
26
|
-
setTimeout(() => {
|
|
27
|
-
spinner.color = 'yellow';
|
|
28
|
-
spinner.text = 'Loading rainbows';
|
|
29
|
-
}, 1000);
|
|
30
|
-
|
|
31
|
-
function actionCancelled() {
|
|
32
|
-
log(chalk.bgRed('Action canceled'))
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const STORY_OPTION = `-s, --${STORY_ID} `
|
|
36
|
-
const STORY_OPTION_OPTIONAL = `${STORY_OPTION}[${STORY_ID}]`
|
|
37
|
-
const STORY_OPTION_REQUIRED = `${STORY_OPTION}<${STORY_ID}>`
|
|
38
|
-
|
|
39
|
-
const mainCmd = program
|
|
40
|
-
.version(package.version, '-v, --version', 'output the current version')
|
|
41
|
-
|
|
42
|
-
mainCmd
|
|
43
|
-
.command('export')
|
|
44
|
-
.description('Export the current project')
|
|
45
|
-
.action(async function () {
|
|
46
|
-
try {
|
|
47
|
-
await exportProject(log)
|
|
48
|
-
} catch (e) {
|
|
49
|
-
console.error(e)
|
|
50
|
-
actionCancelled()
|
|
51
|
-
} finally {
|
|
52
|
-
process.exit(0)
|
|
53
|
-
}
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
// addDevCmd(mainCmd)
|
|
57
|
-
|
|
58
|
-
program.parse();
|
|
59
|
-
|
|
60
|
-
function hideLogs() {
|
|
61
|
-
const log = console.log
|
|
62
|
-
const info = console.info
|
|
63
|
-
const warn = console.warn
|
|
64
|
-
const logQueue = {warn: [], info: [], log: []}
|
|
65
|
-
if (!process.env.DEBUG) {
|
|
66
|
-
Object.keys(logQueue).forEach((key) => {
|
|
67
|
-
console[key] = function(...args) {
|
|
68
|
-
logQueue[key].push(args)
|
|
69
|
-
}
|
|
70
|
-
})
|
|
71
|
-
}
|
|
72
|
-
return {log, info, warn, logQueue}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
async function planAStory(markdown, storyId, log) {
|
|
77
|
-
try {
|
|
78
|
-
await planStory(markdown, storyId, log)
|
|
79
|
-
} catch (e) {
|
|
80
|
-
log(chalk.yellowBright(e.message))
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
function addDevCmd(mainCmd) {
|
|
85
|
-
const devCmd = mainCmd
|
|
86
|
-
.command('dev')
|
|
87
|
-
.description('Plan and track your storys and tasks')
|
|
88
|
-
|
|
89
|
-
devCmd
|
|
90
|
-
.command('init')
|
|
91
|
-
.description('initialize backlog')
|
|
92
|
-
.action(async function () {
|
|
93
|
-
try {
|
|
94
|
-
await imdoneInit()
|
|
95
|
-
} catch (e) {
|
|
96
|
-
log(chalk.yellowBright(e.message))
|
|
97
|
-
} finally {
|
|
98
|
-
process.exit(0)
|
|
99
|
-
}
|
|
100
|
-
})
|
|
101
|
-
|
|
102
|
-
devCmd
|
|
103
|
-
.command('plan')
|
|
104
|
-
.option(STORY_OPTION_OPTIONAL, 'Update an existing story\'s tasks')
|
|
105
|
-
.description('Plan a story with tasks and DoD')
|
|
106
|
-
.action(async function () {
|
|
107
|
-
let markdown
|
|
108
|
-
let { storyId } = this.opts()
|
|
109
|
-
if (process.stdin.isTTY) {
|
|
110
|
-
await planAStory(markdown, storyId, log)
|
|
111
|
-
process.exit(0)
|
|
112
|
-
} else {
|
|
113
|
-
|
|
114
|
-
const stdin = process.stdin;
|
|
115
|
-
spinner.start()
|
|
116
|
-
|
|
117
|
-
markdown = ''
|
|
118
|
-
|
|
119
|
-
stdin.on('readable', function() {
|
|
120
|
-
var chunk = stdin.read();
|
|
121
|
-
if(chunk !== null){
|
|
122
|
-
markdown += chunk;
|
|
123
|
-
}
|
|
124
|
-
});
|
|
125
|
-
stdin.on('end', async function() {
|
|
126
|
-
await planAStory(markdown, storyId, log)
|
|
127
|
-
spinner.stop()
|
|
128
|
-
process.exit(0)
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
})
|
|
132
|
-
|
|
133
|
-
devCmd
|
|
134
|
-
.command('open')
|
|
135
|
-
.description('Open the current or selected task in the default markdown editor')
|
|
136
|
-
.action(async function () {
|
|
137
|
-
try {
|
|
138
|
-
await openTaskFile(log)
|
|
139
|
-
} catch (e) {
|
|
140
|
-
log(chalk.yellowBright(e.message))
|
|
141
|
-
} finally {
|
|
142
|
-
process.exit(0)
|
|
143
|
-
}
|
|
144
|
-
})
|
|
145
|
-
|
|
146
|
-
devCmd
|
|
147
|
-
.command('board')
|
|
148
|
-
.description('Open the current task in imdone')
|
|
149
|
-
.action(async function () {
|
|
150
|
-
try {
|
|
151
|
-
spinner.start()
|
|
152
|
-
await openBoard(log)
|
|
153
|
-
spinner.stop()
|
|
154
|
-
} catch (e) {
|
|
155
|
-
log(chalk.yellowBright(e.message))
|
|
156
|
-
} finally {
|
|
157
|
-
process.exit(0)
|
|
158
|
-
}
|
|
159
|
-
})
|
|
160
|
-
|
|
161
|
-
devCmd
|
|
162
|
-
.command('start [task-id]')
|
|
163
|
-
.description('Start a task by id')
|
|
164
|
-
.action(async function () {
|
|
165
|
-
const taskId = this.args.length > 0 ? this.args[0]: null
|
|
166
|
-
try {
|
|
167
|
-
await startTask(taskId, log)
|
|
168
|
-
} catch (e) {
|
|
169
|
-
if (e instanceof ChangesExistError) {
|
|
170
|
-
log(chalk.yellowBright(e.message))
|
|
171
|
-
} else {
|
|
172
|
-
actionCancelled()
|
|
173
|
-
}
|
|
174
|
-
} finally {
|
|
175
|
-
process.exit(0)
|
|
176
|
-
}
|
|
177
|
-
})
|
|
178
|
-
|
|
179
|
-
devCmd
|
|
180
|
-
.command('done')
|
|
181
|
-
.description('Mark the current task as done')
|
|
182
|
-
.action(async function () {
|
|
183
|
-
try {
|
|
184
|
-
await completeTask(log)
|
|
185
|
-
} catch (e) {
|
|
186
|
-
actionCancelled()
|
|
187
|
-
} finally {
|
|
188
|
-
process.exit(0)
|
|
189
|
-
}
|
|
190
|
-
})
|
|
191
|
-
|
|
192
|
-
devCmd
|
|
193
|
-
.command('add-task <task-content>')
|
|
194
|
-
.description('Add a task to a story')
|
|
195
|
-
.option(STORY_OPTION_REQUIRED, 'The story to add this task to')
|
|
196
|
-
.option('-g, --group <group>', 'The group to add this task to')
|
|
197
|
-
.action(async function () {
|
|
198
|
-
let { storyId, group } = this.opts()
|
|
199
|
-
try {
|
|
200
|
-
await addTask({content: this.args[0], storyId, group, log})
|
|
201
|
-
} catch (e) {
|
|
202
|
-
actionCancelled()
|
|
203
|
-
} finally {
|
|
204
|
-
process.exit(0)
|
|
205
|
-
}
|
|
206
|
-
})
|
|
207
|
-
|
|
208
|
-
devCmd
|
|
209
|
-
.command('ls')
|
|
210
|
-
.description('list tasks')
|
|
211
|
-
.option(STORY_OPTION_REQUIRED, 'The story to list tasks for')
|
|
212
|
-
.option('-f, --filter <filter>', 'The filter to use')
|
|
213
|
-
.option('-j, --json', 'Output as json')
|
|
214
|
-
.action(async function () {
|
|
215
|
-
let {storyId, filter, json } = this.opts()
|
|
216
|
-
try {
|
|
217
|
-
await listTasks({storyId, filter, json, log})
|
|
218
|
-
} catch (e) {
|
|
219
|
-
|
|
220
|
-
actionCancelled()
|
|
221
|
-
} finally {
|
|
222
|
-
process.exit(0)
|
|
223
|
-
}
|
|
224
|
-
})
|
|
225
|
-
}
|