imdone-cli 0.1.4 → 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/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
- }
@@ -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
- }