imdone-cli 0.1.5 → 0.1.6
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/dist/index.min.cjs +1 -1
- package/dist/index.min.cjs.map +1 -1
- package/package.json +2 -2
- package/dist/index.cjs +0 -102973
- package/dist/index.cjs.map +0 -7
- package/src/adapters/__tests__/create-jwt.sh +0 -11
- package/src/adapters/__tests__/jwt-private.pem +0 -28
- package/src/adapters/__tests__/jwt-public.pem +0 -9
- package/src/adapters/__tests__/license.spec.js +0 -27
- package/src/adapters/env.js +0 -21
- package/src/adapters/git.js +0 -113
- package/src/adapters/imdone-config-template.js +0 -79
- package/src/adapters/imdone.js +0 -76
- package/src/adapters/license.js +0 -83
- package/src/bin.js +0 -173
- package/src/index.js +0 -3
- package/src/ui/prompt.js +0 -192
- package/src/usecases/__tests__/headless-pull-from-jira.spec.js +0 -60
- package/src/usecases/__tests__/test-project/.imdone/config.yml +0 -100
- package/src/usecases/headless-pull-from-jira.js +0 -58
- package/src/usecases/headless-push-to-jira.js +0 -42
- package/src/usecases/init.js +0 -27
package/src/ui/prompt.js
DELETED
@@ -1,192 +0,0 @@
|
|
1
|
-
import { dirname, basename } from 'path';
|
2
|
-
import { isImdoneProject } from 'imdone-core/lib/adapters/storage/config.js';
|
3
|
-
import { isGitRepo, gitIgnoreExists } from '../adapters/git.js';
|
4
|
-
import { envExists } from '../adapters/env.js';
|
5
|
-
import { validateEnvLicense } from '../adapters/license.js';
|
6
|
-
import inquirer from 'inquirer';
|
7
|
-
import chalk from 'chalk';
|
8
|
-
|
9
|
-
const bang = chalk.bgWhite.bold(' ❗ ');
|
10
|
-
|
11
|
-
export async function gitRepoCheck(projectPath) {
|
12
|
-
if (!await isGitRepo(projectPath)) {
|
13
|
-
return true
|
14
|
-
}
|
15
|
-
|
16
|
-
const { proceed } = await inquirer.prompt({
|
17
|
-
type: 'confirm',
|
18
|
-
name: 'proceed',
|
19
|
-
message: `
|
20
|
-
${bang} It looks like you are in a git repository.
|
21
|
-
|
22
|
-
If you are in the root of your project repo:
|
23
|
-
|
24
|
-
1. Create a backlog directory (mkdir backlog)
|
25
|
-
2. Navigate to the backlog directory (cd backlog)
|
26
|
-
3. Run "imdone init" to initialize the project
|
27
|
-
|
28
|
-
Do you want to proceed anyway?`,
|
29
|
-
default: false
|
30
|
-
});
|
31
|
-
|
32
|
-
return proceed
|
33
|
-
}
|
34
|
-
export async function checkLicense() {
|
35
|
-
const licenseCheck = await validateEnvLicense();
|
36
|
-
if (!licenseCheck.valid) {
|
37
|
-
console.error('Invalid or expired license. Please check your license or purchase one at https://imdone.io : ', licenseCheck.reason);
|
38
|
-
process.exit(1);
|
39
|
-
}
|
40
|
-
}
|
41
|
-
|
42
|
-
export async function promptForLicense() {
|
43
|
-
try {
|
44
|
-
const answers = await inquirer.prompt([
|
45
|
-
{
|
46
|
-
type: 'password',
|
47
|
-
name: 'licenseToken',
|
48
|
-
message: 'Enter your Imdone license token:',
|
49
|
-
validate: input => input.trim() !== '' ? true : 'License token is required'
|
50
|
-
}
|
51
|
-
]);
|
52
|
-
|
53
|
-
return answers.licenseToken;
|
54
|
-
} catch (error) {
|
55
|
-
console.log('License input cancelled');
|
56
|
-
process.exit(1);
|
57
|
-
}
|
58
|
-
}
|
59
|
-
|
60
|
-
export async function imdoneProjectCheck(projectPath) {
|
61
|
-
if (!await isImdoneProject(projectPath)) {
|
62
|
-
return true
|
63
|
-
}
|
64
|
-
|
65
|
-
const { proceed } = await inquirer.prompt({
|
66
|
-
type: 'confirm',
|
67
|
-
name: 'proceed',
|
68
|
-
message: `
|
69
|
-
${bang} It looks like you are in an imdone project.
|
70
|
-
|
71
|
-
Imdone will overwrite the existing project config with the settings we're collecting now.
|
72
|
-
|
73
|
-
Do you want to proceed anyway?`,
|
74
|
-
default: false
|
75
|
-
});
|
76
|
-
|
77
|
-
return proceed
|
78
|
-
}
|
79
|
-
|
80
|
-
export async function dotEnvCheck(projectPath) {
|
81
|
-
if (!await envExists(projectPath)) {
|
82
|
-
return true
|
83
|
-
}
|
84
|
-
|
85
|
-
const { proceed } = await inquirer.prompt({
|
86
|
-
type: 'confirm',
|
87
|
-
name: 'proceed',
|
88
|
-
message: `
|
89
|
-
${bang} It looks like you have a .env file.
|
90
|
-
|
91
|
-
Imdone will append your credentials to the .env file
|
92
|
-
and .env will be added to the .gitignore file.
|
93
|
-
|
94
|
-
Do you want to proceed?`,
|
95
|
-
default: false
|
96
|
-
});
|
97
|
-
|
98
|
-
return proceed
|
99
|
-
}
|
100
|
-
|
101
|
-
export async function gitIgnoreCheck(projectPath) {
|
102
|
-
if (
|
103
|
-
await gitIgnoreExists(dirname(projectPath), basename(projectPath))
|
104
|
-
) {
|
105
|
-
return true
|
106
|
-
}
|
107
|
-
|
108
|
-
const { proceed } = await inquirer.prompt({
|
109
|
-
type: 'confirm',
|
110
|
-
name: 'proceed',
|
111
|
-
message: `
|
112
|
-
${bang } It looks like you don't have your project ignored.
|
113
|
-
|
114
|
-
Imdone will append the backlog directory to the .gitignore file.
|
115
|
-
|
116
|
-
Do you want to proceed?`,
|
117
|
-
default: false
|
118
|
-
});
|
119
|
-
|
120
|
-
return proceed
|
121
|
-
}
|
122
|
-
|
123
|
-
export async function promptForConfig(options) {
|
124
|
-
const config = { ...options };
|
125
|
-
const questions = [];
|
126
|
-
|
127
|
-
if (!config.name) {
|
128
|
-
questions.push({
|
129
|
-
type: 'input',
|
130
|
-
name: 'name',
|
131
|
-
message: 'Project name:',
|
132
|
-
validate: input => input ? true : 'Name is required'
|
133
|
-
});
|
134
|
-
}
|
135
|
-
|
136
|
-
if (!config.jiraUrl) {
|
137
|
-
questions.push({
|
138
|
-
type: 'input',
|
139
|
-
name: 'jiraUrl',
|
140
|
-
message: 'Jira URL (e.g. https://yourcompany.atlassian.net):',
|
141
|
-
validate: value => value.startsWith('http') ? true : 'URL must start with http:// or https://'
|
142
|
-
});
|
143
|
-
}
|
144
|
-
|
145
|
-
if (!config.jiraProjectKey) {
|
146
|
-
questions.push({
|
147
|
-
type: 'input',
|
148
|
-
name: 'jiraProjectKey',
|
149
|
-
message: 'Jira project key (e.g. ABC):',
|
150
|
-
validate: input => input ? true : 'Project key is required'
|
151
|
-
});
|
152
|
-
}
|
153
|
-
|
154
|
-
if (!config.jiraUsername) {
|
155
|
-
questions.push({
|
156
|
-
type: 'input',
|
157
|
-
name: 'jiraUsername',
|
158
|
-
message: 'Jira username (email):',
|
159
|
-
validate: value => value.includes('@') ? true : 'Please enter a valid email address'
|
160
|
-
});
|
161
|
-
}
|
162
|
-
|
163
|
-
if (!config.jiraApiToken) {
|
164
|
-
questions.push({
|
165
|
-
type: 'password',
|
166
|
-
name: 'jiraApiToken',
|
167
|
-
message: 'Jira API token:',
|
168
|
-
validate: input => input ? true : 'API token is required'
|
169
|
-
});
|
170
|
-
}
|
171
|
-
|
172
|
-
if (!config.jql) {
|
173
|
-
questions.push({
|
174
|
-
type: 'input',
|
175
|
-
name: 'jql',
|
176
|
-
default: "Sprint in openSprints() and status != 'Done'",
|
177
|
-
message: "JQL query (e.g. Sprint in openSprints() and status != 'Done'):",
|
178
|
-
validate: input => input ? true : 'JQL query is required'
|
179
|
-
});
|
180
|
-
}
|
181
|
-
|
182
|
-
if (questions.length > 0) {
|
183
|
-
try {
|
184
|
-
const answers = await inquirer.prompt(questions);
|
185
|
-
Object.assign(config, answers);
|
186
|
-
} catch (error) {
|
187
|
-
console.log('Configuration cancelled');
|
188
|
-
process.exit(1);
|
189
|
-
}
|
190
|
-
}
|
191
|
-
return config;
|
192
|
-
}
|
@@ -1,60 +0,0 @@
|
|
1
|
-
import { describe, it, expect, beforeEach } from "vitest";
|
2
|
-
import { pullFromJira } from "../headless-pull-from-jira.js";
|
3
|
-
import path from 'node:path'
|
4
|
-
import fs from 'node:fs/promises'
|
5
|
-
import os from 'node:os'
|
6
|
-
import { simpleGit } from 'simple-git'
|
7
|
-
|
8
|
-
describe("pullFromJira", async () => {
|
9
|
-
let projectPath;
|
10
|
-
|
11
|
-
beforeEach(async () => {
|
12
|
-
const projectSource = path.join(__dirname, 'test-project')
|
13
|
-
// create a temp directory
|
14
|
-
const testDirPrefix = path.join(os.tmpdir(), 'test-project-')
|
15
|
-
projectPath = await fs.mkdtemp(testDirPrefix)
|
16
|
-
// copy the project source to a temp directory
|
17
|
-
await fs.cp(projectSource, projectPath, { recursive: true })
|
18
|
-
// console.log('projectPath', projectPath)
|
19
|
-
const git = simpleGit({ baseDir: projectPath })
|
20
|
-
await git.init()
|
21
|
-
await git.add('.')
|
22
|
-
await git.commit('Initial commit')
|
23
|
-
|
24
|
-
});
|
25
|
-
|
26
|
-
it("should pull tasks from Jira and return the files and tasks updated", async () => {
|
27
|
-
const { projectState, result } = await pullFromJira(projectPath, {
|
28
|
-
hasLocalChanges: () => false,
|
29
|
-
stashChanges: () => {},
|
30
|
-
stashPop: () => {},
|
31
|
-
getProject: () => {
|
32
|
-
return {
|
33
|
-
project: {
|
34
|
-
refresh: () => {},
|
35
|
-
performBoardAction: async () => {
|
36
|
-
return [
|
37
|
-
{ id: '1', title: 'Task 1' },
|
38
|
-
{ id: '2', title: 'Task 2' }
|
39
|
-
]
|
40
|
-
},
|
41
|
-
toImdoneJSON: async () => {
|
42
|
-
return {
|
43
|
-
totalCards: 2
|
44
|
-
}
|
45
|
-
},
|
46
|
-
destroy: async () => {}
|
47
|
-
},
|
48
|
-
jiraPlugin: {
|
49
|
-
pullFromJiraAction: {}
|
50
|
-
}
|
51
|
-
}
|
52
|
-
},
|
53
|
-
expectNoChanges: async () => {},
|
54
|
-
addAndCommitChanges: async () => {}
|
55
|
-
});
|
56
|
-
const { totalCards } = projectState
|
57
|
-
expect(totalCards).toBe(2)
|
58
|
-
expect(result.length).toBe(2)
|
59
|
-
});
|
60
|
-
})
|
@@ -1,100 +0,0 @@
|
|
1
|
-
keepEmptyPriority: true
|
2
|
-
code:
|
3
|
-
include_lists:
|
4
|
-
- TODO
|
5
|
-
- DOING
|
6
|
-
- DONE
|
7
|
-
- PLANNING
|
8
|
-
- FIXME
|
9
|
-
- ARCHIVE
|
10
|
-
- HACK
|
11
|
-
- CHANGED
|
12
|
-
- XXX
|
13
|
-
- IDEA
|
14
|
-
- NOTE
|
15
|
-
- REVIEW
|
16
|
-
lists:
|
17
|
-
- name: NOTE
|
18
|
-
hidden: false
|
19
|
-
ignore: false
|
20
|
-
id: 13huexl3bm725378z
|
21
|
-
- name: Past Due Reminders
|
22
|
-
hidden: true
|
23
|
-
ignore: false
|
24
|
-
id: 13huexl3bm7253790
|
25
|
-
filter: 'remind = /./ and remind < "${now}" and list != DONE -remind'
|
26
|
-
- name: What's Due?
|
27
|
-
hidden: true
|
28
|
-
ignore: false
|
29
|
-
id: 13huexl3bm7253791
|
30
|
-
filter: 'dueDate < "${in 15 days}" AND list != DONE +dueDate +order'
|
31
|
-
- name: TODO
|
32
|
-
hidden: false
|
33
|
-
ignore: false
|
34
|
-
id: 13huexl3bm7253792
|
35
|
-
- name: DOING
|
36
|
-
hidden: false
|
37
|
-
ignore: false
|
38
|
-
id: 13huexl3bm7253793
|
39
|
-
- name: DONE
|
40
|
-
hidden: false
|
41
|
-
ignore: true
|
42
|
-
id: 13huexl3bm7253794
|
43
|
-
- name: Recently Completed
|
44
|
-
hidden: true
|
45
|
-
ignore: false
|
46
|
-
id: 13huexl3bm7253795
|
47
|
-
filter: 'completedDate > "${14 days ago}" -completed'
|
48
|
-
settings:
|
49
|
-
openIn: code
|
50
|
-
openCodeIn: default
|
51
|
-
journalType: New File
|
52
|
-
journalPath: current-sprint
|
53
|
-
appendNewCardsTo: imdone-tasks.md
|
54
|
-
newCardSyntax: HASHTAG
|
55
|
-
replaceSpacesWith: '-'
|
56
|
-
plugins:
|
57
|
-
JiraPlugin:
|
58
|
-
jql: >-
|
59
|
-
Sprint in openSprints() or status = "In Progress"
|
60
|
-
issueType: Story
|
61
|
-
projectKeys:
|
62
|
-
- key: SCRUM
|
63
|
-
statuses:
|
64
|
-
- jira: To Do
|
65
|
-
list: TODO
|
66
|
-
- jira: In Progress
|
67
|
-
list: DOING
|
68
|
-
- jira: Done
|
69
|
-
list: DONE
|
70
|
-
url: 'https://imdoneio.atlassian.net'
|
71
|
-
defaultList: DOING
|
72
|
-
defaultDirectory: current-sprint
|
73
|
-
devMode: false
|
74
|
-
journalTemplate: null
|
75
|
-
markdownOnly: false
|
76
|
-
kudosProbability: 0.33
|
77
|
-
name: "Test Project"
|
78
|
-
views: []
|
79
|
-
cards:
|
80
|
-
colors: []
|
81
|
-
template: '${template_user_story}'
|
82
|
-
trackChanges: false
|
83
|
-
metaNewLine: true
|
84
|
-
addCompletedMeta: true
|
85
|
-
addCheckBoxTasks: false
|
86
|
-
doingList: DOING
|
87
|
-
doneList: DONE
|
88
|
-
tokenPrefix: '#'
|
89
|
-
taskPrefix: '#'
|
90
|
-
tagPrefix: '#'
|
91
|
-
metaSep: ':'
|
92
|
-
orderMeta: true
|
93
|
-
maxLines: 3
|
94
|
-
addNewCardsToTop: true
|
95
|
-
showTagsAndMeta: false
|
96
|
-
addStartedMeta: false
|
97
|
-
defaultList: TODO
|
98
|
-
archiveCompleted: true
|
99
|
-
archiveFolder: completed-stories
|
100
|
-
dirty: true
|
@@ -1,58 +0,0 @@
|
|
1
|
-
import {
|
2
|
-
expectNoChanges,
|
3
|
-
hasLocalChanges,
|
4
|
-
addAndCommitChanges,
|
5
|
-
stashChanges,
|
6
|
-
stashPop
|
7
|
-
} from '../adapters/git.js'
|
8
|
-
import { getProject } from '../adapters/imdone.js'
|
9
|
-
|
10
|
-
export const dependencies = {
|
11
|
-
getProject,
|
12
|
-
addAndCommitChanges,
|
13
|
-
expectNoChanges,
|
14
|
-
hasLocalChanges,
|
15
|
-
stashChanges,
|
16
|
-
stashPop,
|
17
|
-
feedback: {
|
18
|
-
text: ''
|
19
|
-
},
|
20
|
-
}
|
21
|
-
|
22
|
-
export async function pullFromJira(projectPath, {
|
23
|
-
getProject,
|
24
|
-
addAndCommitChanges,
|
25
|
-
expectNoChanges,
|
26
|
-
hasLocalChanges,
|
27
|
-
stashChanges,
|
28
|
-
stashPop,
|
29
|
-
feedback} = dependencies
|
30
|
-
) {
|
31
|
-
try {
|
32
|
-
const { project, jiraPlugin } = await getProject(projectPath, feedback)
|
33
|
-
const { pullFromJiraAction } = jiraPlugin
|
34
|
-
|
35
|
-
const changesExist = await hasLocalChanges(projectPath)
|
36
|
-
if (changesExist) {
|
37
|
-
await stashChanges(projectPath)
|
38
|
-
}
|
39
|
-
await project.refresh()
|
40
|
-
await expectNoChanges(projectPath, 'pulling from Jira')
|
41
|
-
|
42
|
-
const result = await project.performBoardAction(pullFromJiraAction)
|
43
|
-
|
44
|
-
const projectState = await project.toImdoneJSON()
|
45
|
-
|
46
|
-
await addAndCommitChanges(projectPath, 'Pull from Jira')
|
47
|
-
if (changesExist) {
|
48
|
-
await stashPop(projectPath)
|
49
|
-
}
|
50
|
-
await project.refresh()
|
51
|
-
await project.toImdoneJSON()
|
52
|
-
|
53
|
-
return { projectState, project, jiraPlugin, result }
|
54
|
-
} catch (error) {
|
55
|
-
console.error('Error in pullFromJira:', error)
|
56
|
-
throw error
|
57
|
-
}
|
58
|
-
}
|
@@ -1,42 +0,0 @@
|
|
1
|
-
import { addAndCommitChanges, status } from '../adapters/git.js'
|
2
|
-
import { getProject } from '../adapters/imdone.js'
|
3
|
-
|
4
|
-
export const dependencies = {
|
5
|
-
getProject,
|
6
|
-
addAndCommitChanges,
|
7
|
-
status,
|
8
|
-
feedback: {
|
9
|
-
text: ''
|
10
|
-
},
|
11
|
-
}
|
12
|
-
|
13
|
-
export async function pushToJira(projectPath, { getProject, addAndCommitChanges, status, feedback } = dependencies) {
|
14
|
-
const { project, jiraPlugin } = await getProject(projectPath, feedback)
|
15
|
-
const { pushToJiraAction, pullFromJiraAction } = jiraPlugin
|
16
|
-
|
17
|
-
await project.refresh()
|
18
|
-
await project.toImdoneJSON()
|
19
|
-
const changes = await status(projectPath)
|
20
|
-
|
21
|
-
// loop through the changes and publish each task
|
22
|
-
const allTasks = []
|
23
|
-
for (const change of changes) {
|
24
|
-
if (change.path.endsWith('.md')) {
|
25
|
-
const filter = `source.path = "${change.path}"`
|
26
|
-
const tasks = await project.getAllCards(filter)
|
27
|
-
allTasks.push(...tasks)
|
28
|
-
}
|
29
|
-
}
|
30
|
-
const results = []
|
31
|
-
|
32
|
-
for (const task of allTasks) {
|
33
|
-
const result = await project.performBoardAction(pushToJiraAction, task)
|
34
|
-
await addAndCommitChanges(projectPath, 'Push to Jira: ' + task.source.path)
|
35
|
-
await project.performBoardAction(pullFromJiraAction)
|
36
|
-
await addAndCommitChanges(projectPath, 'Pull from Jira')
|
37
|
-
results.push(result)
|
38
|
-
}
|
39
|
-
const projectState = await project.toImdoneJSON()
|
40
|
-
await addAndCommitChanges(projectPath, 'Push to Jira')
|
41
|
-
return { projectState, project, jiraPlugin, result: results }
|
42
|
-
}
|
package/src/usecases/init.js
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
import { createRepo, appendToGitignore } from '../adapters/git.js'
|
2
|
-
import { storeJiraCredentials } from '../../src/adapters/env.js'
|
3
|
-
import { dirname, basename } from 'path'
|
4
|
-
import { initProject, appendToImdoneIgnore } from '../adapters/imdone.js'
|
5
|
-
import { logger } from 'imdone-core/lib/adapters/logger.js'
|
6
|
-
|
7
|
-
export async function imdoneInit(projectPath, { name, jiraUrl, jiraProjectKey, jiraUsername, jiraApiToken, jql }) {
|
8
|
-
const imdoneConfig = {
|
9
|
-
name,
|
10
|
-
jiraUrl,
|
11
|
-
jiraProjectKey,
|
12
|
-
jql
|
13
|
-
}
|
14
|
-
// Set up the git repo
|
15
|
-
await createRepo(projectPath)
|
16
|
-
// append projectPath basename to the .gitignore file in the dirname of projectPath
|
17
|
-
await appendToGitignore(dirname(projectPath), basename(projectPath))
|
18
|
-
// add .env to .gitignore
|
19
|
-
await appendToGitignore(projectPath, '.env')
|
20
|
-
// append jira credentials to the .env file
|
21
|
-
await storeJiraCredentials(projectPath, jiraUsername, jiraApiToken)
|
22
|
-
// append archive folder to .imdoneignore
|
23
|
-
await appendToImdoneIgnore(projectPath, 'archive')
|
24
|
-
// Initialize imdone with these config overrides
|
25
|
-
initProject(projectPath, imdoneConfig)
|
26
|
-
logger.info('Imdone project initialized successfully:', imdoneConfig)
|
27
|
-
}
|