imdone-core 1.34.0 → 1.34.2

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/cli.js CHANGED
@@ -3,6 +3,7 @@
3
3
  const { program } = require('commander');
4
4
  const ora = require('ora')
5
5
  const chalk = require('chalk')
6
+ const { ChangesExistError } = require('./lib/cli/adapters/Errors')
6
7
  const {
7
8
  imdoneInit,
8
9
  planStory,
@@ -10,10 +11,13 @@ const {
10
11
  addTask,
11
12
  listTasks ,
12
13
  completeTask,
13
- showCurrentTask,
14
14
  openBoard,
15
- openTaskFile
15
+ openTaskFile,
16
+ exportProject
16
17
  } = require('./lib/cli/CliControler')
18
+ const {
19
+ STORY_ID
20
+ } = require('./lib/cli/domain/BacklogProject').constants
17
21
  const package = require('./package.json')
18
22
 
19
23
  const { log } = hideLogs()
@@ -28,114 +32,29 @@ function actionCancelled() {
28
32
  log(chalk.bgRed('Action canceled'))
29
33
  }
30
34
 
31
- const STORY_OPTION = ['-s, --story-id <story-id>', 'The story to add this task to']
32
- program
33
- .version(package.version, '-v, --version', 'output the current version')
34
- .command('init')
35
- .description('initialize backlog')
36
- .action(async function () {
37
- await imdoneInit()
38
- })
39
-
40
- program
41
- .command('plan')
42
- .description('Plan a story with tasks and DoD')
43
- .action(async function () {
44
- let markdown
45
- if (process.stdin.isTTY) return (await planStory(markdown, log))
46
-
47
- const stdin = process.stdin;
48
- spinner.start()
49
-
50
- markdown = ''
51
-
52
- stdin.on('readable', function() {
53
- var chunk = stdin.read();
54
- if(chunk !== null){
55
- markdown += chunk;
56
- }
57
- });
58
- stdin.on('end', async function() {
59
- await planStory(markdown, log)
60
- spinner.stop()
61
- });
62
- })
63
-
64
- program
65
- .command('open')
66
- .description('open the current or selected task in the default markdown editor')
67
- .action(async function () {
68
- await openTaskFile(log)
69
- })
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}>`
70
38
 
71
- program
72
- .command('board')
73
- .description('open the current task in imdone')
74
- .action(async function () {
75
- spinner.start()
76
- await openBoard(log)
77
- spinner.stop()
78
- })
79
-
80
- program
81
- .command('task')
82
- .description('Show the current task')
83
- .action(async function () {
84
- await showCurrentTask(log)
85
- })
39
+ const mainCmd = program
40
+ .version(package.version, '-v, --version', 'output the current version')
86
41
 
87
- program
88
- .command('start [task-id]')
89
- .description('start a task by id')
42
+ mainCmd
43
+ .command('export')
44
+ .description('Export the current project')
90
45
  .action(async function () {
91
- const taskId = this.args.length > 0 ? this.args[0]: null
92
46
  try {
93
- await startTask(taskId, log)
47
+ await exportProject(log)
94
48
  } catch (e) {
95
49
  console.error(e)
96
50
  actionCancelled()
51
+ } finally {
52
+ process.exit(0)
97
53
  }
98
54
  })
99
55
 
100
- program
101
- .command('done')
102
- .description('Mark the current task as done')
103
- .action(async function () {
104
- try {
105
- await completeTask(log)
106
- } catch (e) {
107
- actionCancelled()
108
- }
109
- })
56
+ // addDevCmd(mainCmd)
110
57
 
111
- program
112
- .command('add-task <task-content>')
113
- .description('add a task')
114
- .option(...STORY_OPTION)
115
- .option('-g, --group <group>', 'The group to add this task to')
116
- .action(async function () {
117
- let { storyId, group } = this.opts()
118
- try {
119
- await addTask({content: this.args[0], storyId, group, log})
120
- } catch (e) {
121
- actionCancelled()
122
- }
123
- })
124
-
125
- program
126
- .command('ls')
127
- .description('list tasks')
128
- .option(...STORY_OPTION)
129
- .option('-f, --filter <filter>', 'The filter to use')
130
- .option('-j, --json', 'Output as json')
131
- .action(async function () {
132
- let {storyId, filter, json } = this.opts()
133
- try {
134
- await listTasks({storyId, filter, json, log})
135
- } catch (e) {
136
- actionCancelled()
137
- }
138
- })
139
58
  program.parse();
140
59
 
141
60
  function hideLogs() {
@@ -143,10 +62,164 @@ function hideLogs() {
143
62
  const info = console.info
144
63
  const warn = console.warn
145
64
  const logQueue = {warn: [], info: [], log: []}
146
- Object.keys(logQueue).forEach((key) => {
147
- console[key] = function(...args) {
148
- logQueue[key].push(args)
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)
149
223
  }
150
224
  })
151
- return {log, info, warn, logQueue}
152
225
  }
package/lib/card.js CHANGED
@@ -43,6 +43,7 @@ module.exports = function newCard(task, _project, dontParse) {
43
43
  }
44
44
 
45
45
  init(totals = project.totals) {
46
+ this.updateLastLine()
46
47
  this.totals = totals
47
48
  this.onTaskUpdate()
48
49
  this.initProps()
@@ -5,8 +5,10 @@ const eol = require('eol')
5
5
  const chalk = require('chalk')
6
6
  const BacklogProject = require('./domain/BacklogProject')
7
7
  const StoryProject = require('./domain/StoryProject')
8
+ const { createFileSystemProject } = require('../project-factory.js')
8
9
  const commandExists = require('command-exists')
9
10
  const git = simpleGit()
11
+ const _path = require('path')
10
12
  const {
11
13
  importMarkdown,
12
14
  } = require('./MDStoryParser')
@@ -21,7 +23,8 @@ const applicationContext = () => {
21
23
 
22
24
  const {
23
25
  configureProject,
24
- defaultProjectPath
26
+ defaultProjectPath,
27
+ projectExists,
25
28
  } = require('./ProjectConfigFactory')
26
29
 
27
30
  const {promptForMarkdownPlan} = require('./prompts/MarkdownPlanPrompt.js')
@@ -30,10 +33,64 @@ const {
30
33
  UNGROUPED_TASKS
31
34
  } = BacklogProject.constants
32
35
 
36
+ const replacer = (key, value) =>
37
+ value instanceof Object && !(value instanceof Array) ?
38
+ Object.keys(value)
39
+ .sort()
40
+ .reduce((sorted, key) => {
41
+ sorted[key] = value[key];
42
+ return sorted
43
+ }, {}) :
44
+ value;
45
+
33
46
  module.exports = CliController = {}
34
47
 
48
+ CliController.exportProject = async function (log, verbose = false) {
49
+ const project = createFileSystemProject({path: process.env.PWD})
50
+ await project.init()
51
+ let jsonOutput = verbose
52
+ ? project.toImdoneJSON()
53
+ : (() => {
54
+ const result = {}
55
+ const imdoneJSON = project.toImdoneJSON()
56
+ const lists = imdoneJSON.lists.map(list => {
57
+ list.tasks = list.tasks.map(task => {
58
+ const result = {
59
+ created: task.created,
60
+ completed: task.completed,
61
+ due: task.due,
62
+ path: _path.join(task.source.repoId, task.source.path),
63
+ meta: task.allMeta,
64
+ tags: task.allTags,
65
+ context: task.allContext,
66
+ line: task.line,
67
+ content: task.content,
68
+ interpretedContent: task.interpretedContent,
69
+ lastLine: task.lastLine,
70
+ list: task.list,
71
+ progress: task.progress,
72
+ order: task.order,
73
+ beforeText: task.beforeText,
74
+ props: task.props,
75
+ }
76
+ return result
77
+ })
78
+ return list
79
+ })
80
+ result.lists = lists
81
+ result.totals = imdoneJSON.totals
82
+ result.tags = imdoneJSON.tags
83
+
84
+ return result
85
+ })()
86
+
87
+ log(JSON.stringify(jsonOutput, replacer, 3))
88
+ }
35
89
 
36
90
  CliController.imdoneInit = async function () {
91
+ if (await projectExists(defaultProjectPath())) {
92
+ throw new Error('Imdone backlog is already initialized!')
93
+ }
37
94
  const defaultBranch = await promptForDefaultBranch()
38
95
  const remote = await promptForRemote()
39
96
  await configureProject({defaultBranch, remote})
@@ -66,8 +123,9 @@ CliController.openTaskFile = async function (log) {
66
123
  const storyId = await promptForStoryId()
67
124
  const taskId = await promptForTaskId(storyId)
68
125
  const storyProject = await StoryProject.createAndInit(defaultProjectPath(), null, storyId, applicationContext)
69
- task = storyProject.getTask(taskId)
126
+ task = storyProject.getTask(taskId) || storyProject.getStory()
70
127
  }
128
+
71
129
  open(task.fullPath)
72
130
  }
73
131
 
@@ -75,7 +133,7 @@ CliController.openTaskFile = async function (log) {
75
133
  // TODO: This should ask for a group to add a task to
76
134
  CliController.addTask = async function ({content, storyId, group, log}) {
77
135
  consoleLog = log
78
- storyId = await determineStoryId(applicationContext, storyId)
136
+ storyId = await determineStoryId(storyId)
79
137
  const storyProject = await StoryProject.createAndInit(defaultProjectPath(), null, storyId, applicationContext)
80
138
 
81
139
  const task = await storyProject.addTask({group, content})
@@ -85,7 +143,7 @@ CliController.addTask = async function ({content, storyId, group, log}) {
85
143
 
86
144
  CliController.listTasks = async function ({storyId, filter=null, json, log}) {
87
145
  consoleLog = log
88
- storyId = storyId || await determineStoryId(applicationContext, storyId)
146
+ storyId = storyId || await determineStoryId(storyId)
89
147
 
90
148
  const storyProject = await StoryProject.createAndInit(defaultProjectPath(), null, storyId, applicationContext)
91
149
 
@@ -105,20 +163,26 @@ CliController.listTasks = async function ({storyId, filter=null, json, log}) {
105
163
  logGroupedTasks(log, storyProject, groupedTasks)
106
164
  }
107
165
 
108
- CliController.planStory = async function(markdown, log) {
166
+ CliController.planStory = async function(markdown, storyId, log = console.log) {
109
167
  consoleLog = log
110
- if (!markdown) markdown = await promptForMarkdownPlan()
111
- return await importMarkdown(
112
- defaultProjectPath(),
168
+ if (storyId) {
169
+ storyId = await determineStoryId(storyId)
170
+ }
171
+ if (!markdown) {
172
+ markdown = await promptForMarkdownPlan()
173
+ }
174
+ return await importMarkdown({
175
+ projectPath: defaultProjectPath(),
176
+ existingStoryId: storyId,
113
177
  markdown,
114
178
  applicationContext
115
- )
179
+ })
116
180
  }
117
181
 
118
182
  CliController.startTask = async function (taskId, log) {
119
183
  consoleLog = log
120
184
  if (!taskId) {
121
- const storyId = await determineStoryId(applicationContext)
185
+ const storyId = await determineStoryId()
122
186
  taskId = await promptForTaskId(storyId)
123
187
  }
124
188
 
@@ -127,14 +191,6 @@ CliController.startTask = async function (taskId, log) {
127
191
  await project.startTask(taskId)
128
192
  }
129
193
 
130
- CliController.showCurrentTask = async function (log) {
131
- consoleLog = log
132
- const { storyProject, task} = await getCurrentTask()
133
- if (!task) return noTaskStarted(log)
134
- log()
135
- logTask(log, storyProject, task)
136
- }
137
-
138
194
  CliController.completeTask = async function (log) {
139
195
  consoleLog = log
140
196
  const {storyProject, task} = await getCurrentTask()
@@ -166,8 +222,8 @@ async function getCurrentTask() {
166
222
  return { backlogProject, storyProject, storyId, task }
167
223
  }
168
224
 
169
- async function determineStoryId(ApplicationContext, storyId) {
170
- const project = await BacklogProject.createAndInit(defaultProjectPath(), null, ApplicationContext)
225
+ async function determineStoryId(storyId) {
226
+ const project = await BacklogProject.createAndInit(defaultProjectPath(), null, applicationContext)
171
227
  storyId = storyId || project.getCurrentStoryId()
172
228
  storyId = await promptForStoryId(storyId)
173
229
  return storyId
@@ -243,8 +299,7 @@ function getGroupedTasks(tasks) {
243
299
  }
244
300
 
245
301
  function logGroupedTasks(log, project, groupedTasks) {
246
- log('## Tasks')
247
- log('')
302
+ log('\n## Tasks\n')
248
303
  Object.keys(groupedTasks).forEach((group) => {
249
304
  if (group !== UNGROUPED_TASKS) {
250
305
  log('')
@@ -1,13 +1,13 @@
1
+ const { parseMD } = require('../tools')
2
+ const StoryProject = require('./domain/StoryProject')
3
+ const BacklogProject = require('./domain/BacklogProject')
1
4
  const {
2
5
  UNGROUPED_TASKS,
3
6
  TODO,
4
7
  DONE,
5
8
  ORDER
6
- } = require('./domain/BacklogProject').constants
7
- const StoryProject = require('./domain/StoryProject')
8
- const { newBacklogProject } = require('./ProjectConfigFactory')
9
- const { parseMD } = require('../tools')
10
- const BacklogProject = require('./domain/BacklogProject')
9
+ } = BacklogProject.constants
10
+ const ApplicationContext = require('./adapters/ApplicationContext')
11
11
 
12
12
  function isOpen(token, type, tag = token.tag) {
13
13
  return token.type === type + '_open' && token.tag === tag
@@ -33,7 +33,6 @@ function parse(markdown) {
33
33
  let inParagraph = false
34
34
  let inBulletList = false
35
35
  let inListItem = false
36
- let listItemMarkup = ''
37
36
  let inTasks = false
38
37
  let headingLevel = 0
39
38
  const ast = parseMD(markdown)
@@ -55,7 +54,6 @@ function parse(markdown) {
55
54
 
56
55
  if (isOpen(token, listItem)) {
57
56
  inListItem = true
58
- listItemMarkup = markup
59
57
  } else if (isClose(token, listItem)) {
60
58
  inListItem = false
61
59
  }
@@ -88,28 +86,30 @@ function parse(markdown) {
88
86
  }
89
87
  })
90
88
 
91
- const result = new RegExp(`# ${storyText}\n(.*)## Tasks`, 'gms').exec(markdown)
92
- description = result && result.length > 1 ? result[1].trim() : ''
89
+ if (storyText) {
90
+ const result = new RegExp(`# ${storyText}\n(.*)## Tasks`, 'gms').exec(markdown)
91
+ description = result && result.length > 1 ? result[1].trim() : ''
92
+ }
93
93
 
94
94
  return { storyText, description, tasks }
95
95
  }
96
96
 
97
- async function importMarkdown(projectPath, markdown, ApplicationContext) {
98
- const { log } = ApplicationContext()
97
+ async function importMarkdown({projectPath, existingStoryId, markdown, applicationContext = ApplicationContext}) {
98
+ const { log } = applicationContext()
99
99
 
100
- const backlogProject = await BacklogProject.createAndInit(projectPath, null, ApplicationContext)
100
+ const backlogProject = await BacklogProject.createAndInit(projectPath, null, applicationContext)
101
101
 
102
102
  let { storyText, description, tasks } = parse(markdown)
103
103
 
104
- const storyId = backlogProject.toStoryId(storyText)
104
+ const storyId = existingStoryId || backlogProject.toStoryId(storyText)
105
105
 
106
106
  log(`Importing story ${storyId}\n${description}`)
107
107
 
108
108
  await backlogProject.storageAdapter.initStoryPlan(storyId)
109
109
 
110
- await backlogProject.addStory(`${storyText}\n${description}`)
110
+ if (!existingStoryId) await backlogProject.addStory(`${storyText}\n${description}`)
111
111
 
112
- const storyProject = await StoryProject.createAndInit(projectPath, null, storyId, ApplicationContext)
112
+ const storyProject = await StoryProject.createAndInit(projectPath, null, storyId, applicationContext)
113
113
 
114
114
  await addStoryTasks(storyProject, tasks)
115
115
 
@@ -16,6 +16,20 @@ const BACKLOG_IGNORE_PATH = path.join(CONFIG_PATH, 'backlog.imdoneignore')
16
16
 
17
17
  const defaultProjectPath = (baseDir = process.env.PWD) => path.join(baseDir, DEFAULT_PROJECT_DIR)
18
18
 
19
+ const getProjectConfigPath = (projectPath = defaultProjectPath()) => path.join(projectPath, '.imdone', 'config.yml')
20
+
21
+ const projectExists = async (
22
+ projectPath = defaultProjectPath()
23
+ ) => {
24
+ const projectConfigPath = getProjectConfigPath(projectPath)
25
+ try {
26
+ await access(projectConfigPath)
27
+ return projectConfigPath
28
+ } catch (e) {
29
+ return false
30
+ }
31
+ }
32
+
19
33
  const configureProject = async ({
20
34
  projectPath = defaultProjectPath(),
21
35
  configPath = BACKLOG_CONFIG_PATH,
@@ -27,11 +41,11 @@ const configureProject = async ({
27
41
  projectPath = resolve(projectPath)
28
42
  configPath = resolve(configPath)
29
43
 
30
- const projectConfigPath = path.join(projectPath, '.imdone', 'config.yml')
31
- try {
32
- await access(projectConfigPath)
33
- return { projectPath, config: await newConfigFromFile(projectConfigPath) }
34
- } catch (e) {}
44
+ if (await projectExists(projectPath)) {
45
+ return { projectPath, config: await newConfigFromFile(projectConfigPath)}
46
+ }
47
+
48
+ const projectConfigPath = getProjectConfigPath(projectPath)
35
49
 
36
50
  await mkdir(path.join(projectPath, tasksDir), {recursive: true})
37
51
  await mkdir(path.join(projectPath, '.imdone'), { recursive: true })
@@ -92,6 +106,7 @@ function logFsError(ApplicationContext, e) {
92
106
  }
93
107
 
94
108
  module.exports = {
109
+ projectExists,
95
110
  configureProject,
96
111
  newBacklogProject,
97
112
  newStoryProject,
@@ -0,0 +1,8 @@
1
+ module.exports = {
2
+ ChangesExistError: class extends Error {
3
+ constructor(action) {
4
+ super(`There are changes on the current branch. Please commit or stash them before you ${action}.`)
5
+ this.name = "ChangesExistError"
6
+ }
7
+ }
8
+ }
@@ -1,4 +1,6 @@
1
1
  const simpleGit = require('simple-git')
2
+ const {changesExistError, ChangesExistError} = require('./Errors')
3
+
2
4
  module.exports = class {
3
5
 
4
6
  constructor(project) {
@@ -24,7 +26,7 @@ module.exports = class {
24
26
 
25
27
  async initTaskUpdate(task) {
26
28
  if (await this.changesExist()) {
27
- throw new Error('There are changes on the current branch. Please commit or stash them before starting a task.')
29
+ throw new ChangesExistError('start a task')
28
30
  }
29
31
 
30
32
  await this.checkoutStoryBranch({task})
@@ -40,7 +42,7 @@ module.exports = class {
40
42
 
41
43
  async initStoryPlan(storyId) {
42
44
  if (await this.changesExist()) {
43
- throw new Error('There are changes on the current branch. Please commit or stash them before starting a task.')
45
+ throw new ChangesExistError('plan a story')
44
46
  }
45
47
 
46
48
  await this.checkoutStoryBranch({storyId})
@@ -98,18 +98,12 @@ class BacklogProject {
98
98
  const storyFilter = `tags=story AND meta.${STORY_ID}="${storyId}"`
99
99
  const story = this.project.getAllCards(storyFilter)[0]
100
100
 
101
- try {
102
- await this.storageAdapter.initTaskUpdate(task)
103
- await this.moveTask(task, DOING, 0)
104
- await this.project.addMetadata(task, 'branch', this.storageAdapter.getTaskBranchName(task))
105
- this.project.rollBackFileForTask(task)
106
- await this.moveTask(story, DOING, 0)
107
- await this.storageAdapter.commitTaskUpdate(task)
108
- } catch (e) {
109
- console.log('e', e)
110
- const error = new Error('Error starting task')
111
- error.cause = e
112
- }
101
+ await this.storageAdapter.initTaskUpdate(task)
102
+ await this.moveTask(task, DOING, 0)
103
+ await this.project.addMetadata(task, 'branch', this.storageAdapter.getTaskBranchName(task))
104
+ this.project.rollBackFileForTask(task)
105
+ await this.moveTask(story, DOING, 0)
106
+ await this.storageAdapter.commitTaskUpdate(task)
113
107
  }
114
108
 
115
109
  async saveStory(storyId) {
@@ -1,3 +1,7 @@
1
+ const defaultStory = `# Story Title
2
+
3
+ Story description
4
+ `
1
5
  module.exports.promptForMarkdownPlan = async function () {
2
6
  const editor = (await import('@inquirer/editor')).default
3
7
 
@@ -7,10 +11,6 @@ module.exports.promptForMarkdownPlan = async function () {
7
11
  if (!text) return 'Please enter a description'
8
12
  return true
9
13
  },
10
- default: `# Story Title
11
-
12
- Story description
13
- `
14
-
14
+ default: defaultStory
15
15
  });
16
16
  }
@@ -214,13 +214,19 @@ function mixin(repo, fs = require('fs')) {
214
214
  const currentConfig = repo.config
215
215
  if (currentConfig && currentConfig.code)
216
216
  include_lists = _union(include_lists, currentConfig.code.include_lists)
217
+
218
+ if (currentConfig && currentConfig.settings)
219
+ loadedConfig.settings = {...loadedConfig.settings, ...currentConfig.settings}
220
+
217
221
  if (loadedConfig && loadedConfig.code)
218
222
  include_lists = _union(include_lists, loadedConfig.code.include_lists)
223
+
219
224
  if (loadedConfig && loadedConfig.sync)
220
225
  loadedConfig.sync = {
221
226
  ...loadedConfig.sync,
222
227
  useImdoneioForPriority: false,
223
228
  }
229
+
224
230
  const newConfig = new Config(
225
231
  _assign({}, baseConfig, repo.config, loadedConfig, { path: repo.path })
226
232
  )
package/lib/project.js CHANGED
@@ -428,7 +428,17 @@ module.exports = class WorkerProject extends Project {
428
428
  if (!/^['"]/.test(value) && /\s/.test(value)) value = `"${value}"`
429
429
  const metaData = `${key}${this.repo.config.getMetaSep()}${value}`
430
430
  if (content.includes(metaData)) return
431
- metaContent = `${metaContent} ${metaData}`
431
+ const existingMetadata = Task.parseMetaData(this.config, content)[key]
432
+ if (existingMetadata) {
433
+ content = Task.removeMetaData({
434
+ config: this.config,
435
+ content,
436
+ key,
437
+ value: existingMetadata[0],
438
+ })
439
+ }
440
+ const spaceOrNewLine = this.config.isMetaNewLine() ? '\n' : ' '
441
+ metaContent = `${metaContent}${spaceOrNewLine}${metaData}`
432
442
  })
433
443
  content = Task.addToLastCommentInContent(content, metaContent.trim(), this.config.isMetaNewLine())
434
444
  }
package/lib/task.js CHANGED
@@ -430,7 +430,7 @@ Task.getMetaOrderRegex = function (config) {
430
430
  Task.prototype.updateOrderMeta = function (config, descContent = this.description.join(lineEnd)) {
431
431
  if (config.orderMeta) {
432
432
  if (!Task.isNumber(this.order)) return this.order = ''
433
- const newLine = config.isMetaNewLine()
433
+ const addNewLine = config.isMetaNewLine()
434
434
  const metaSep = config.getMetaSep()
435
435
  if (this.meta.order) {
436
436
  const regex = Task.getMetaOrderRegex(config)
@@ -439,7 +439,7 @@ Task.prototype.updateOrderMeta = function (config, descContent = this.descriptio
439
439
  descContent = this.addToLastCommentInContent(
440
440
  descContent,
441
441
  `order${metaSep}${this.order}`,
442
- newLine
442
+ addNewLine
443
443
  )
444
444
  }
445
445
  this.meta.order = [this.order]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "imdone-core",
3
- "version": "1.34.0",
3
+ "version": "1.34.2",
4
4
  "description": "imdone-core",
5
5
  "main": "index.js",
6
6
  "bin": {