jirallm 0.1.0 → 0.2.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/README.md +87 -9
- package/dist/cli/commands/assign.d.ts +9 -0
- package/dist/cli/commands/assign.d.ts.map +1 -0
- package/dist/cli/commands/assign.js +37 -0
- package/dist/cli/commands/assign.js.map +1 -0
- package/dist/cli/commands/assign.test.d.ts +2 -0
- package/dist/cli/commands/assign.test.d.ts.map +1 -0
- package/dist/cli/commands/assign.test.js +69 -0
- package/dist/cli/commands/assign.test.js.map +1 -0
- package/dist/cli/commands/attach.d.ts +16 -0
- package/dist/cli/commands/attach.d.ts.map +1 -0
- package/dist/cli/commands/attach.js +52 -0
- package/dist/cli/commands/attach.js.map +1 -0
- package/dist/cli/commands/attach.test.d.ts +2 -0
- package/dist/cli/commands/attach.test.d.ts.map +1 -0
- package/dist/cli/commands/attach.test.js +92 -0
- package/dist/cli/commands/attach.test.js.map +1 -0
- package/dist/cli/commands/board.d.ts +10 -0
- package/dist/cli/commands/board.d.ts.map +1 -0
- package/dist/cli/commands/board.js +54 -0
- package/dist/cli/commands/board.js.map +1 -0
- package/dist/cli/commands/boards.d.ts +11 -0
- package/dist/cli/commands/boards.d.ts.map +1 -0
- package/dist/cli/commands/boards.js +27 -0
- package/dist/cli/commands/boards.js.map +1 -0
- package/dist/cli/commands/boards.test.d.ts +2 -0
- package/dist/cli/commands/boards.test.d.ts.map +1 -0
- package/dist/cli/commands/boards.test.js +80 -0
- package/dist/cli/commands/boards.test.js.map +1 -0
- package/dist/cli/commands/comment.d.ts +15 -0
- package/dist/cli/commands/comment.d.ts.map +1 -0
- package/dist/cli/commands/comment.js +61 -0
- package/dist/cli/commands/comment.js.map +1 -0
- package/dist/cli/commands/create.d.ts +16 -0
- package/dist/cli/commands/create.d.ts.map +1 -0
- package/dist/cli/commands/create.js +44 -0
- package/dist/cli/commands/create.js.map +1 -0
- package/dist/cli/commands/create.test.d.ts +2 -0
- package/dist/cli/commands/create.test.d.ts.map +1 -0
- package/dist/cli/commands/create.test.js +98 -0
- package/dist/cli/commands/create.test.js.map +1 -0
- package/dist/cli/commands/doctor.js +8 -8
- package/dist/cli/commands/doctor.js.map +1 -1
- package/dist/cli/commands/edit.d.ts +15 -0
- package/dist/cli/commands/edit.d.ts.map +1 -0
- package/dist/cli/commands/edit.js +47 -0
- package/dist/cli/commands/edit.js.map +1 -0
- package/dist/cli/commands/edit.test.d.ts +2 -0
- package/dist/cli/commands/edit.test.d.ts.map +1 -0
- package/dist/cli/commands/edit.test.js +77 -0
- package/dist/cli/commands/edit.test.js.map +1 -0
- package/dist/cli/commands/fetch.d.ts +7 -0
- package/dist/cli/commands/fetch.d.ts.map +1 -0
- package/dist/cli/commands/fetch.js +32 -0
- package/dist/cli/commands/fetch.js.map +1 -0
- package/dist/cli/commands/fetch.test.d.ts +2 -0
- package/dist/cli/commands/fetch.test.d.ts.map +1 -0
- package/dist/cli/commands/fetch.test.js +93 -0
- package/dist/cli/commands/fetch.test.js.map +1 -0
- package/dist/cli/commands/init.js +3 -3
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/issuetypes.d.ts +7 -0
- package/dist/cli/commands/issuetypes.d.ts.map +1 -0
- package/dist/cli/commands/issuetypes.js +23 -0
- package/dist/cli/commands/issuetypes.js.map +1 -0
- package/dist/cli/commands/issuetypes.test.d.ts +2 -0
- package/dist/cli/commands/issuetypes.test.d.ts.map +1 -0
- package/dist/cli/commands/issuetypes.test.js +62 -0
- package/dist/cli/commands/issuetypes.test.js.map +1 -0
- package/dist/cli/commands/link.d.ts +18 -0
- package/dist/cli/commands/link.d.ts.map +1 -0
- package/dist/cli/commands/link.js +51 -0
- package/dist/cli/commands/link.js.map +1 -0
- package/dist/cli/commands/link.test.d.ts +2 -0
- package/dist/cli/commands/link.test.d.ts.map +1 -0
- package/dist/cli/commands/link.test.js +96 -0
- package/dist/cli/commands/link.test.js.map +1 -0
- package/dist/cli/commands/linktypes.d.ts +6 -0
- package/dist/cli/commands/linktypes.d.ts.map +1 -0
- package/dist/cli/commands/linktypes.js +21 -0
- package/dist/cli/commands/linktypes.js.map +1 -0
- package/dist/cli/commands/linktypes.test.d.ts +2 -0
- package/dist/cli/commands/linktypes.test.d.ts.map +1 -0
- package/dist/cli/commands/linktypes.test.js +55 -0
- package/dist/cli/commands/linktypes.test.js.map +1 -0
- package/dist/cli/commands/me.d.ts +6 -0
- package/dist/cli/commands/me.d.ts.map +1 -0
- package/dist/cli/commands/me.js +17 -0
- package/dist/cli/commands/me.js.map +1 -0
- package/dist/cli/commands/me.test.d.ts +2 -0
- package/dist/cli/commands/me.test.d.ts.map +1 -0
- package/dist/cli/commands/me.test.js +58 -0
- package/dist/cli/commands/me.test.js.map +1 -0
- package/dist/cli/commands/projects.d.ts +9 -0
- package/dist/cli/commands/projects.d.ts.map +1 -0
- package/dist/cli/commands/projects.js +25 -0
- package/dist/cli/commands/projects.js.map +1 -0
- package/dist/cli/commands/projects.test.d.ts +2 -0
- package/dist/cli/commands/projects.test.d.ts.map +1 -0
- package/dist/cli/commands/projects.test.js +73 -0
- package/dist/cli/commands/projects.test.js.map +1 -0
- package/dist/cli/commands/search.d.ts +11 -0
- package/dist/cli/commands/search.d.ts.map +1 -0
- package/dist/cli/commands/search.js +41 -0
- package/dist/cli/commands/search.js.map +1 -0
- package/dist/cli/commands/search.test.d.ts +2 -0
- package/dist/cli/commands/search.test.d.ts.map +1 -0
- package/dist/cli/commands/search.test.js +106 -0
- package/dist/cli/commands/search.test.js.map +1 -0
- package/dist/cli/commands/setup.d.ts.map +1 -1
- package/dist/cli/commands/setup.js +5 -13
- package/dist/cli/commands/setup.js.map +1 -1
- package/dist/cli/commands/sprints.d.ts +10 -0
- package/dist/cli/commands/sprints.d.ts.map +1 -0
- package/dist/cli/commands/sprints.js +28 -0
- package/dist/cli/commands/sprints.js.map +1 -0
- package/dist/cli/commands/sprints.test.d.ts +2 -0
- package/dist/cli/commands/sprints.test.d.ts.map +1 -0
- package/dist/cli/commands/sprints.test.js +68 -0
- package/dist/cli/commands/sprints.test.js.map +1 -0
- package/dist/cli/commands/transition.d.ts +8 -0
- package/dist/cli/commands/transition.d.ts.map +1 -0
- package/dist/cli/commands/transition.js +46 -0
- package/dist/cli/commands/transition.js.map +1 -0
- package/dist/cli/commands/upgrade.d.ts +16 -0
- package/dist/cli/commands/upgrade.d.ts.map +1 -0
- package/dist/cli/commands/upgrade.js +83 -0
- package/dist/cli/commands/upgrade.js.map +1 -0
- package/dist/cli/commands/upgrade.test.d.ts +2 -0
- package/dist/cli/commands/upgrade.test.d.ts.map +1 -0
- package/dist/cli/commands/upgrade.test.js +146 -0
- package/dist/cli/commands/upgrade.test.js.map +1 -0
- package/dist/cli/commands/watchers.d.ts +10 -0
- package/dist/cli/commands/watchers.d.ts.map +1 -0
- package/dist/cli/commands/watchers.js +43 -0
- package/dist/cli/commands/watchers.js.map +1 -0
- package/dist/cli/commands/watchers.test.d.ts +2 -0
- package/dist/cli/commands/watchers.test.d.ts.map +1 -0
- package/dist/cli/commands/watchers.test.js +90 -0
- package/dist/cli/commands/watchers.test.js.map +1 -0
- package/dist/cli/commands/worklog.d.ts +8 -0
- package/dist/cli/commands/worklog.d.ts.map +1 -0
- package/dist/cli/commands/worklog.js +100 -0
- package/dist/cli/commands/worklog.js.map +1 -0
- package/dist/cli/commands/worklog.test.d.ts +2 -0
- package/dist/cli/commands/worklog.test.d.ts.map +1 -0
- package/dist/cli/commands/worklog.test.js +195 -0
- package/dist/cli/commands/worklog.test.js.map +1 -0
- package/dist/cli/index.js +648 -6
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/issueKey.d.ts.map +1 -1
- package/dist/cli/issueKey.js +6 -2
- package/dist/cli/issueKey.js.map +1 -1
- package/dist/cli/issueKey.test.js +36 -1
- package/dist/cli/issueKey.test.js.map +1 -1
- package/dist/cli/jsonOutput.d.ts +6 -0
- package/dist/cli/jsonOutput.d.ts.map +1 -0
- package/dist/cli/jsonOutput.js +7 -0
- package/dist/cli/jsonOutput.js.map +1 -0
- package/dist/cli/jsonOutput.test.d.ts +2 -0
- package/dist/cli/jsonOutput.test.d.ts.map +1 -0
- package/dist/cli/jsonOutput.test.js +44 -0
- package/dist/cli/jsonOutput.test.js.map +1 -0
- package/dist/cli/resolveOrg.d.ts +2 -0
- package/dist/cli/resolveOrg.d.ts.map +1 -0
- package/dist/cli/resolveOrg.js +15 -0
- package/dist/cli/resolveOrg.js.map +1 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/chunkMarkdown.d.ts +6 -0
- package/dist/lib/chunkMarkdown.d.ts.map +1 -0
- package/dist/lib/chunkMarkdown.js +73 -0
- package/dist/lib/chunkMarkdown.js.map +1 -0
- package/dist/lib/chunkMarkdown.test.d.ts +2 -0
- package/dist/lib/chunkMarkdown.test.d.ts.map +1 -0
- package/dist/lib/chunkMarkdown.test.js +171 -0
- package/dist/lib/chunkMarkdown.test.js.map +1 -0
- package/dist/lib/config.d.ts +6 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +25 -0
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/config.test.js +73 -6
- package/dist/lib/config.test.js.map +1 -1
- package/dist/lib/configSchema.d.ts +44 -0
- package/dist/lib/configSchema.d.ts.map +1 -1
- package/dist/lib/configSchema.js +20 -0
- package/dist/lib/configSchema.js.map +1 -1
- package/dist/lib/credentials.d.ts.map +1 -1
- package/dist/lib/credentials.js +32 -31
- package/dist/lib/credentials.js.map +1 -1
- package/dist/lib/credentials.test.js +18 -11
- package/dist/lib/credentials.test.js.map +1 -1
- package/dist/lib/exportFields.d.ts +30 -0
- package/dist/lib/exportFields.d.ts.map +1 -0
- package/dist/lib/exportFields.js +169 -0
- package/dist/lib/exportFields.js.map +1 -0
- package/dist/lib/exportFields.test.d.ts +2 -0
- package/dist/lib/exportFields.test.d.ts.map +1 -0
- package/dist/lib/exportFields.test.js +145 -0
- package/dist/lib/exportFields.test.js.map +1 -0
- package/dist/lib/exporter.d.ts +25 -3
- package/dist/lib/exporter.d.ts.map +1 -1
- package/dist/lib/exporter.js +195 -18
- package/dist/lib/exporter.js.map +1 -1
- package/dist/lib/exporter.test.d.ts +2 -0
- package/dist/lib/exporter.test.d.ts.map +1 -0
- package/dist/lib/exporter.test.js +227 -0
- package/dist/lib/exporter.test.js.map +1 -0
- package/dist/lib/jiraClient.d.ts +248 -1
- package/dist/lib/jiraClient.d.ts.map +1 -1
- package/dist/lib/jiraClient.discovery.test.d.ts +2 -0
- package/dist/lib/jiraClient.discovery.test.d.ts.map +1 -0
- package/dist/lib/jiraClient.discovery.test.js +209 -0
- package/dist/lib/jiraClient.discovery.test.js.map +1 -0
- package/dist/lib/jiraClient.js +624 -17
- package/dist/lib/jiraClient.js.map +1 -1
- package/dist/lib/jiraClient.test.d.ts +2 -0
- package/dist/lib/jiraClient.test.d.ts.map +1 -0
- package/dist/lib/jiraClient.test.js +383 -0
- package/dist/lib/jiraClient.test.js.map +1 -0
- package/dist/lib/jiraClient.write.test.d.ts +2 -0
- package/dist/lib/jiraClient.write.test.d.ts.map +1 -0
- package/dist/lib/jiraClient.write.test.js +268 -0
- package/dist/lib/jiraClient.write.test.js.map +1 -0
- package/dist/lib/markdownToWiki.d.ts +2 -0
- package/dist/lib/markdownToWiki.d.ts.map +1 -0
- package/dist/lib/markdownToWiki.js +110 -0
- package/dist/lib/markdownToWiki.js.map +1 -0
- package/dist/lib/markdownToWiki.test.d.ts +2 -0
- package/dist/lib/markdownToWiki.test.d.ts.map +1 -0
- package/dist/lib/markdownToWiki.test.js +122 -0
- package/dist/lib/markdownToWiki.test.js.map +1 -0
- package/dist/lib/platform.d.ts +2 -0
- package/dist/lib/platform.d.ts.map +1 -1
- package/dist/lib/platform.js +8 -0
- package/dist/lib/platform.js.map +1 -1
- package/dist/lib/runCommand.d.ts +1 -0
- package/dist/lib/runCommand.d.ts.map +1 -1
- package/dist/lib/runCommand.js +8 -1
- package/dist/lib/runCommand.js.map +1 -1
- package/dist/lib/worklog.d.ts +36 -0
- package/dist/lib/worklog.d.ts.map +1 -0
- package/dist/lib/worklog.js +188 -0
- package/dist/lib/worklog.js.map +1 -0
- package/dist/lib/worklog.test.d.ts +2 -0
- package/dist/lib/worklog.test.d.ts.map +1 -0
- package/dist/lib/worklog.test.js +118 -0
- package/dist/lib/worklog.test.js.map +1 -0
- package/package.json +42 -12
- package/dist/cli/commands/profiles.d.ts +0 -2
- package/dist/cli/commands/profiles.d.ts.map +0 -1
- package/dist/cli/commands/profiles.js +0 -20
- package/dist/cli/commands/profiles.js.map +0 -1
package/README.md
CHANGED
|
@@ -9,13 +9,13 @@ Export Jira Cloud issues as LLM-ready context bundles — markdown, attachments,
|
|
|
9
9
|
|
|
10
10
|
## Why it exists
|
|
11
11
|
|
|
12
|
-
Pasting Jira tickets into an LLM is painful: descriptions are ADF (Atlassian Document Format), comments live in a separate API, attachments are URLs behind auth, and video recordings are useless to a text model. `jirallm` turns a Jira issue
|
|
12
|
+
Pasting Jira tickets into an LLM is painful: descriptions are ADF (Atlassian Document Format), comments live in a separate API, attachments are URLs behind auth, and video recordings are useless to a text model. `jirallm` turns a Jira issue into a self-contained folder of clean markdown plus extracted media — ready to drop into Claude, ChatGPT, Cursor, or any RAG pipeline.
|
|
13
13
|
|
|
14
14
|
It exists because every team that uses Jira + LLMs ends up writing the same brittle scraping script. This is the version you wish you had.
|
|
15
15
|
|
|
16
16
|
## Features
|
|
17
17
|
|
|
18
|
-
- Export
|
|
18
|
+
- Export one or more issues by key into a structured folder
|
|
19
19
|
- Renders Jira ADF descriptions and comments to clean Markdown
|
|
20
20
|
- Downloads all attachments with original filenames (auth handled)
|
|
21
21
|
- Extracts frames from attached videos via `ffmpeg` and deduplicates near-identical frames using `pixelmatch`
|
|
@@ -41,6 +41,15 @@ pnpm add -g jirallm
|
|
|
41
41
|
pnpm add jirallm
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
+
### Updating
|
|
45
|
+
|
|
46
|
+
`jirallm` checks for new versions once a day in the background and prints a notice on the next invocation. To upgrade:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
jirallm upgrade # auto-detects npm / pnpm / yarn / Homebrew
|
|
50
|
+
jirallm upgrade --check # just report whether an update is available
|
|
51
|
+
```
|
|
52
|
+
|
|
44
53
|
## Configuration
|
|
45
54
|
|
|
46
55
|
The recommended way to configure `jirallm` is the interactive wizard:
|
|
@@ -83,8 +92,8 @@ user_email = "user@acme.example"
|
|
|
83
92
|
[orgs.acme.projects.PROJ]
|
|
84
93
|
output_dir = "~/jira/acme/proj"
|
|
85
94
|
|
|
86
|
-
[orgs.acme.projects.
|
|
87
|
-
output_dir = "~/jira/acme/
|
|
95
|
+
[orgs.acme.projects.DOCS]
|
|
96
|
+
output_dir = "~/jira/acme/docs"
|
|
88
97
|
|
|
89
98
|
[orgs.acme.projects.LIB]
|
|
90
99
|
```
|
|
@@ -167,11 +176,11 @@ jira-export/
|
|
|
167
176
|
import { JiraExporter, loadProfile } from 'jirallm';
|
|
168
177
|
|
|
169
178
|
// Resolve an org/project (config file + keychain), with the same precedence as the CLI
|
|
170
|
-
const { config, apiToken, org, project } = await loadProfile({ org: 'acme', project: '
|
|
179
|
+
const { config, apiToken, org, project } = await loadProfile({ org: 'acme', project: 'DOCS' });
|
|
171
180
|
|
|
172
181
|
const exporter = new JiraExporter(config, apiToken);
|
|
173
182
|
|
|
174
|
-
const result = await exporter.exportIssues(['
|
|
183
|
+
const result = await exporter.exportIssues(['DOCS-123'], {
|
|
175
184
|
outputDir: project.outputDir ?? './jira-export',
|
|
176
185
|
includeSubtasks: org.includeSubtasks ?? false,
|
|
177
186
|
videoFrames: { enabled: true, fps: 5, maxFrames: 10 },
|
|
@@ -191,11 +200,80 @@ jirallm PROJ-123 PROJ-124 --output-dir ./triage-bundle
|
|
|
191
200
|
cat ./triage-bundle/PROJ-123/index.md | pbcopy
|
|
192
201
|
```
|
|
193
202
|
|
|
203
|
+
## For agents (CLI commands)
|
|
204
|
+
|
|
205
|
+
Every read command supports `--json` (and automatically switches to JSON when stdout is not a TTY), so they're safe to pipe into `jq` or feed back into an agent. Every write command supports `--dry-run`.
|
|
206
|
+
|
|
207
|
+
Discovery & search:
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
jirallm me --org acme --json
|
|
211
|
+
jirallm projects --org acme --json
|
|
212
|
+
jirallm boards --org acme --project PROJ --json
|
|
213
|
+
jirallm sprints 123 --org acme --state active --json
|
|
214
|
+
jirallm issuetypes --org acme --project PROJ --json
|
|
215
|
+
jirallm linktypes --org acme --json
|
|
216
|
+
jirallm search 'assignee = currentUser() AND statusCategory != Done' --org acme --limit 25 --json
|
|
217
|
+
jirallm fetch PROJ-123 --json
|
|
218
|
+
jirallm transition PROJ-123 --list --json
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
Mutations (all accept `--dry-run`):
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
jirallm comment PROJ-123 --file ./summary.md
|
|
225
|
+
jirallm transition PROJ-123 --to "In Review"
|
|
226
|
+
jirallm worklog -f ./worklogs.json
|
|
227
|
+
jirallm create --org acme --project PROJ --type Task --summary "Spike" --description-file ./spike.md
|
|
228
|
+
jirallm edit PROJ-123 --labels a,b --priority High
|
|
229
|
+
jirallm assign PROJ-123 me
|
|
230
|
+
jirallm link PROJ-1 "blocks" PROJ-2 --comment "blocked by infra work"
|
|
231
|
+
jirallm link:rm 10042 --org acme
|
|
232
|
+
jirallm attach PROJ-123 ./screenshot.png ./recording.mp4
|
|
233
|
+
jirallm attach:rm 99021 --org acme
|
|
234
|
+
jirallm watchers PROJ-123 --add me
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
## Library usage
|
|
238
|
+
|
|
239
|
+
The package re-exports `JiraClient` plus all the domain types so you can drive Jira directly from your own TypeScript:
|
|
240
|
+
|
|
241
|
+
```ts
|
|
242
|
+
import { JiraClient, loadProfile } from 'jirallm';
|
|
243
|
+
|
|
244
|
+
const { config, apiToken } = await loadProfile({ org: 'acme' });
|
|
245
|
+
const client = new JiraClient(config, apiToken);
|
|
246
|
+
|
|
247
|
+
// Search (single page; pass nextPageToken for the next one)
|
|
248
|
+
const page = await client.searchIssues('project = PROJ AND statusCategory != Done', {
|
|
249
|
+
fields: ['summary', 'status'],
|
|
250
|
+
limit: 50,
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
// Create + comment
|
|
254
|
+
const created = await client.createIssue({
|
|
255
|
+
projectKey: 'PROJ',
|
|
256
|
+
issueType: 'Task',
|
|
257
|
+
summary: 'Investigate flaky test',
|
|
258
|
+
descriptionMarkdown: '**Repro**\n\n1. step\n2. step',
|
|
259
|
+
});
|
|
260
|
+
await client.addComment(created.key, 'Auto-filed from triage script.');
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
See `examples/` for runnable scripts:
|
|
264
|
+
|
|
265
|
+
- `examples/search-my-issues.ts` — paginated JQL
|
|
266
|
+
- `examples/create-bug.ts` — create + comment
|
|
267
|
+
- `examples/board-snapshot.ts` — boards → sprints → issues
|
|
268
|
+
|
|
194
269
|
## Platform support
|
|
195
270
|
|
|
196
|
-
-
|
|
197
|
-
|
|
198
|
-
-
|
|
271
|
+
Native binaries (via [`@napi-rs/keyring`](https://www.npmjs.com/package/@napi-rs/keyring)) ship prebuilt — no compile step on install.
|
|
272
|
+
|
|
273
|
+
- **macOS** (arm64, x64) — fully supported. Tokens stored in macOS Keychain.
|
|
274
|
+
- **Linux** (x64, arm64, arm, riscv64; glibc and musl) — fully supported. Tokens stored via Secret Service (`libsecret`); requires a running keyring daemon (e.g. `gnome-keyring` or KWallet). Headless servers without a keyring backend will fail the keychain step in `jirallm doctor`.
|
|
275
|
+
- **Windows** (x64, arm64, ia32) — fully supported. Tokens stored in Windows Credential Manager. `ffmpeg` must be on `PATH` for video frame extraction.
|
|
276
|
+
- **FreeBSD** (x64) — keychain works; other features untested.
|
|
199
277
|
|
|
200
278
|
## Contributing
|
|
201
279
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assign.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/assign.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,wBAAsB,SAAS,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CA8BlE"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { loadProfile } from '../../lib/config.js';
|
|
2
|
+
import { JiraClient } from '../../lib/jiraClient.js';
|
|
3
|
+
import { parseIssueKey } from '../issueKey.js';
|
|
4
|
+
import { resolveOrg } from '../resolveOrg.js';
|
|
5
|
+
import { printJson, shouldOutputJson } from '../jsonOutput.js';
|
|
6
|
+
export async function runAssign(opts) {
|
|
7
|
+
const parsed = parseIssueKey(opts.issueKey);
|
|
8
|
+
const org = resolveOrg(parsed.org, opts.org, parsed.projectKey);
|
|
9
|
+
const profile = await loadProfile({ org, project: parsed.projectKey });
|
|
10
|
+
const client = new JiraClient(profile.config, profile.apiToken);
|
|
11
|
+
let accountId;
|
|
12
|
+
if (opts.assignee === 'none' || opts.assignee === '-') {
|
|
13
|
+
accountId = null;
|
|
14
|
+
}
|
|
15
|
+
else if (opts.assignee === 'me') {
|
|
16
|
+
const me = await client.getCurrentUser();
|
|
17
|
+
accountId = me.accountId;
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
accountId = opts.assignee;
|
|
21
|
+
}
|
|
22
|
+
if (opts.dryRun) {
|
|
23
|
+
const payload = { dryRun: true, issueKey: parsed.key, accountId };
|
|
24
|
+
if (shouldOutputJson(opts))
|
|
25
|
+
printJson(payload);
|
|
26
|
+
else
|
|
27
|
+
console.log(`Dry run — would assign ${parsed.key} to ${accountId ?? 'none'}`);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
await client.assignIssue(parsed.key, accountId);
|
|
31
|
+
if (shouldOutputJson(opts)) {
|
|
32
|
+
printJson({ issueKey: parsed.key, accountId });
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
console.log(`✓ ${parsed.key} assigned to ${accountId ?? 'nobody'}`);
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=assign.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assign.js","sourceRoot":"","sources":["../../../src/cli/commands/assign.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAU/D,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,IAAmB;IACjD,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC5C,MAAM,GAAG,GAAG,UAAU,CAAC,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC;IAChE,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;IACvE,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;IAEhE,IAAI,SAAwB,CAAC;IAC7B,IAAI,IAAI,CAAC,QAAQ,KAAK,MAAM,IAAI,IAAI,CAAC,QAAQ,KAAK,GAAG,EAAE,CAAC;QACtD,SAAS,GAAG,IAAI,CAAC;IACnB,CAAC;SAAM,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI,EAAE,CAAC;QAClC,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,cAAc,EAAE,CAAC;QACzC,SAAS,GAAG,EAAE,CAAC,SAAS,CAAC;IAC3B,CAAC;SAAM,CAAC;QACN,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC;IAC5B,CAAC;IAED,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,MAAM,OAAO,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,CAAC,GAAG,EAAE,SAAS,EAAE,CAAC;QAClE,IAAI,gBAAgB,CAAC,IAAI,CAAC;YAAE,SAAS,CAAC,OAAO,CAAC,CAAC;;YAC1C,OAAO,CAAC,GAAG,CAAC,0BAA0B,MAAM,CAAC,GAAG,OAAO,SAAS,IAAI,MAAM,EAAE,CAAC,CAAC;QACnF,OAAO;IACT,CAAC;IAED,MAAM,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;IAEhD,IAAI,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3B,SAAS,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,GAAG,EAAE,SAAS,EAAE,CAAC,CAAC;QAC/C,OAAO;IACT,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,KAAK,MAAM,CAAC,GAAG,gBAAgB,SAAS,IAAI,QAAQ,EAAE,CAAC,CAAC;AACtE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assign.test.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/assign.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
vi.mock('../../lib/config.js', () => ({
|
|
3
|
+
loadProfile: vi.fn(async () => ({
|
|
4
|
+
config: { baseUrl: 'https://x', userEmail: 'u@x', projectKey: 'PROJ' },
|
|
5
|
+
apiToken: 'tok',
|
|
6
|
+
})),
|
|
7
|
+
findOrgsByProjectKey: vi.fn(() => ['solo']),
|
|
8
|
+
}));
|
|
9
|
+
const assignIssueMock = vi.fn();
|
|
10
|
+
const getCurrentUserMock = vi.fn();
|
|
11
|
+
vi.mock('../../lib/jiraClient.js', () => ({
|
|
12
|
+
JiraClient: class {
|
|
13
|
+
assignIssue = assignIssueMock;
|
|
14
|
+
getCurrentUser = getCurrentUserMock;
|
|
15
|
+
},
|
|
16
|
+
}));
|
|
17
|
+
import { runAssign } from './assign.js';
|
|
18
|
+
let logs;
|
|
19
|
+
let writes;
|
|
20
|
+
const originalIsTTY = process.stdout.isTTY;
|
|
21
|
+
beforeEach(() => {
|
|
22
|
+
logs = [];
|
|
23
|
+
writes = [];
|
|
24
|
+
vi.spyOn(console, 'log').mockImplementation((...a) => { logs.push(a.map(String).join(' ')); });
|
|
25
|
+
vi.spyOn(process.stdout, 'write').mockImplementation((c) => { writes.push(String(c)); return true; });
|
|
26
|
+
assignIssueMock.mockReset();
|
|
27
|
+
getCurrentUserMock.mockReset();
|
|
28
|
+
});
|
|
29
|
+
afterEach(() => {
|
|
30
|
+
vi.restoreAllMocks();
|
|
31
|
+
Object.defineProperty(process.stdout, 'isTTY', { value: originalIsTTY, configurable: true });
|
|
32
|
+
});
|
|
33
|
+
describe('runAssign', () => {
|
|
34
|
+
it('resolves "me" to current user accountId', async () => {
|
|
35
|
+
getCurrentUserMock.mockResolvedValue({ accountId: 'acc-me', displayName: 'Me' });
|
|
36
|
+
Object.defineProperty(process.stdout, 'isTTY', { value: true, configurable: true });
|
|
37
|
+
await runAssign({ issueKey: 'PROJ-1', assignee: 'me' });
|
|
38
|
+
expect(assignIssueMock).toHaveBeenCalledWith('PROJ-1', 'acc-me');
|
|
39
|
+
});
|
|
40
|
+
it('resolves "none" to null (unassign)', async () => {
|
|
41
|
+
Object.defineProperty(process.stdout, 'isTTY', { value: true, configurable: true });
|
|
42
|
+
await runAssign({ issueKey: 'PROJ-1', assignee: 'none' });
|
|
43
|
+
expect(assignIssueMock).toHaveBeenCalledWith('PROJ-1', null);
|
|
44
|
+
expect(getCurrentUserMock).not.toHaveBeenCalled();
|
|
45
|
+
});
|
|
46
|
+
it('treats "-" as unassign sugar', async () => {
|
|
47
|
+
Object.defineProperty(process.stdout, 'isTTY', { value: true, configurable: true });
|
|
48
|
+
await runAssign({ issueKey: 'PROJ-1', assignee: '-' });
|
|
49
|
+
expect(assignIssueMock).toHaveBeenCalledWith('PROJ-1', null);
|
|
50
|
+
});
|
|
51
|
+
it('passes through a literal accountId', async () => {
|
|
52
|
+
Object.defineProperty(process.stdout, 'isTTY', { value: true, configurable: true });
|
|
53
|
+
await runAssign({ issueKey: 'PROJ-1', assignee: 'acc-42' });
|
|
54
|
+
expect(assignIssueMock).toHaveBeenCalledWith('PROJ-1', 'acc-42');
|
|
55
|
+
});
|
|
56
|
+
it('does NOT call assignIssue on --dry-run', async () => {
|
|
57
|
+
Object.defineProperty(process.stdout, 'isTTY', { value: true, configurable: true });
|
|
58
|
+
await runAssign({ issueKey: 'PROJ-1', assignee: 'acc-1', dryRun: true, json: true });
|
|
59
|
+
expect(assignIssueMock).not.toHaveBeenCalled();
|
|
60
|
+
const parsed = JSON.parse(writes.join(''));
|
|
61
|
+
expect(parsed).toEqual({ dryRun: true, issueKey: 'PROJ-1', accountId: 'acc-1' });
|
|
62
|
+
});
|
|
63
|
+
it('emits {issueKey, accountId} JSON on success', async () => {
|
|
64
|
+
Object.defineProperty(process.stdout, 'isTTY', { value: true, configurable: true });
|
|
65
|
+
await runAssign({ issueKey: 'PROJ-1', assignee: 'acc-1', json: true });
|
|
66
|
+
expect(JSON.parse(writes.join(''))).toEqual({ issueKey: 'PROJ-1', accountId: 'acc-1' });
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
//# sourceMappingURL=assign.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assign.test.js","sourceRoot":"","sources":["../../../src/cli/commands/assign.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type AttachOptions = {
|
|
2
|
+
issueKey: string;
|
|
3
|
+
files: string[];
|
|
4
|
+
org?: string;
|
|
5
|
+
dryRun?: boolean;
|
|
6
|
+
json?: boolean;
|
|
7
|
+
};
|
|
8
|
+
export declare function runAttach(opts: AttachOptions): Promise<void>;
|
|
9
|
+
export type AttachRemoveOptions = {
|
|
10
|
+
attachmentId: string;
|
|
11
|
+
org: string;
|
|
12
|
+
dryRun?: boolean;
|
|
13
|
+
json?: boolean;
|
|
14
|
+
};
|
|
15
|
+
export declare function runAttachRemove(opts: AttachRemoveOptions): Promise<void>;
|
|
16
|
+
//# sourceMappingURL=attach.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attach.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/attach.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,wBAAsB,SAAS,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CA2BlE;AAED,MAAM,MAAM,mBAAmB,GAAG;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,wBAAsB,eAAe,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAe9E"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { loadProfile } from '../../lib/config.js';
|
|
2
|
+
import { JiraClient } from '../../lib/jiraClient.js';
|
|
3
|
+
import { parseIssueKey } from '../issueKey.js';
|
|
4
|
+
import { resolveOrg } from '../resolveOrg.js';
|
|
5
|
+
import { printJson, shouldOutputJson } from '../jsonOutput.js';
|
|
6
|
+
export async function runAttach(opts) {
|
|
7
|
+
const parsed = parseIssueKey(opts.issueKey);
|
|
8
|
+
const org = resolveOrg(parsed.org, opts.org, parsed.projectKey);
|
|
9
|
+
const profile = await loadProfile({ org, project: parsed.projectKey });
|
|
10
|
+
if (opts.dryRun) {
|
|
11
|
+
const payload = { dryRun: true, issueKey: parsed.key, files: opts.files };
|
|
12
|
+
if (shouldOutputJson(opts))
|
|
13
|
+
printJson(payload);
|
|
14
|
+
else
|
|
15
|
+
console.log(`Dry run — would attach ${opts.files.length} file(s) to ${parsed.key}:\n ${opts.files.join('\n ')}`);
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const client = new JiraClient(profile.config, profile.apiToken);
|
|
19
|
+
const uploaded = [];
|
|
20
|
+
for (const file of opts.files) {
|
|
21
|
+
const result = await client.uploadAttachment(parsed.key, file);
|
|
22
|
+
for (const a of result)
|
|
23
|
+
uploaded.push(a);
|
|
24
|
+
}
|
|
25
|
+
if (shouldOutputJson(opts)) {
|
|
26
|
+
printJson({ issueKey: parsed.key, attachments: uploaded });
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
console.log(`✓ Uploaded ${uploaded.length} attachment(s) to ${parsed.key}:`);
|
|
30
|
+
for (const a of uploaded) {
|
|
31
|
+
console.log(` [${a.id}] ${a.filename} (${a.size}b)`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export async function runAttachRemove(opts) {
|
|
35
|
+
if (opts.dryRun) {
|
|
36
|
+
const payload = { dryRun: true, attachmentId: opts.attachmentId };
|
|
37
|
+
if (shouldOutputJson(opts))
|
|
38
|
+
printJson(payload);
|
|
39
|
+
else
|
|
40
|
+
console.log(`Dry run — would delete attachment ${opts.attachmentId}`);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const profile = await loadProfile({ org: opts.org });
|
|
44
|
+
const client = new JiraClient(profile.config, profile.apiToken);
|
|
45
|
+
await client.deleteAttachment(opts.attachmentId);
|
|
46
|
+
if (shouldOutputJson(opts)) {
|
|
47
|
+
printJson({ attachmentId: opts.attachmentId, removed: true });
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
console.log(`✓ Removed attachment ${opts.attachmentId}`);
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=attach.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attach.js","sourceRoot":"","sources":["../../../src/cli/commands/attach.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAU/D,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,IAAmB;IACjD,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC5C,MAAM,GAAG,GAAG,UAAU,CAAC,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC;IAChE,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;IAEvE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,MAAM,OAAO,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;QAC1E,IAAI,gBAAgB,CAAC,IAAI,CAAC;YAAE,SAAS,CAAC,OAAO,CAAC,CAAC;;YAC1C,OAAO,CAAC,GAAG,CAAC,0BAA0B,IAAI,CAAC,KAAK,CAAC,MAAM,eAAe,MAAM,CAAC,GAAG,QAAQ,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACxH,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;IAChE,MAAM,QAAQ,GAA0D,EAAE,CAAC;IAC3E,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QAC9B,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,gBAAgB,CAAC,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAC/D,KAAK,MAAM,CAAC,IAAI,MAAM;YAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC3C,CAAC;IAED,IAAI,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3B,SAAS,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,GAAG,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC3D,OAAO;IACT,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,cAAc,QAAQ,CAAC,MAAM,qBAAqB,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC;IAC7E,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC;IACxD,CAAC;AACH,CAAC;AASD,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAAyB;IAC7D,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,MAAM,OAAO,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,CAAC,YAAY,EAAE,CAAC;QAClE,IAAI,gBAAgB,CAAC,IAAI,CAAC;YAAE,SAAS,CAAC,OAAO,CAAC,CAAC;;YAC1C,OAAO,CAAC,GAAG,CAAC,qCAAqC,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC;QAC3E,OAAO;IACT,CAAC;IACD,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IACrD,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;IAChE,MAAM,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IACjD,IAAI,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3B,SAAS,CAAC,EAAE,YAAY,EAAE,IAAI,CAAC,YAAY,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9D,OAAO;IACT,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,wBAAwB,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC;AAC3D,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attach.test.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/attach.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
vi.mock('../../lib/config.js', () => ({
|
|
3
|
+
loadProfile: vi.fn(async () => ({
|
|
4
|
+
config: { baseUrl: 'https://x', userEmail: 'u@x', projectKey: 'PROJ' },
|
|
5
|
+
apiToken: 'tok',
|
|
6
|
+
})),
|
|
7
|
+
findOrgsByProjectKey: vi.fn(() => ['solo']),
|
|
8
|
+
}));
|
|
9
|
+
const uploadAttachmentMock = vi.fn();
|
|
10
|
+
const deleteAttachmentMock = vi.fn();
|
|
11
|
+
vi.mock('../../lib/jiraClient.js', () => ({
|
|
12
|
+
JiraClient: class {
|
|
13
|
+
uploadAttachment = uploadAttachmentMock;
|
|
14
|
+
deleteAttachment = deleteAttachmentMock;
|
|
15
|
+
},
|
|
16
|
+
}));
|
|
17
|
+
import { runAttach, runAttachRemove } from './attach.js';
|
|
18
|
+
let logs;
|
|
19
|
+
let writes;
|
|
20
|
+
const originalIsTTY = process.stdout.isTTY;
|
|
21
|
+
beforeEach(() => {
|
|
22
|
+
logs = [];
|
|
23
|
+
writes = [];
|
|
24
|
+
vi.spyOn(console, 'log').mockImplementation((...a) => { logs.push(a.map(String).join(' ')); });
|
|
25
|
+
vi.spyOn(process.stdout, 'write').mockImplementation((c) => { writes.push(String(c)); return true; });
|
|
26
|
+
uploadAttachmentMock.mockReset();
|
|
27
|
+
deleteAttachmentMock.mockReset();
|
|
28
|
+
});
|
|
29
|
+
afterEach(() => {
|
|
30
|
+
vi.restoreAllMocks();
|
|
31
|
+
Object.defineProperty(process.stdout, 'isTTY', { value: originalIsTTY, configurable: true });
|
|
32
|
+
});
|
|
33
|
+
describe('runAttach', () => {
|
|
34
|
+
it('uploads each file sequentially and aggregates results', async () => {
|
|
35
|
+
uploadAttachmentMock
|
|
36
|
+
.mockResolvedValueOnce([{ id: 'a1', filename: 'a.png', size: 10 }])
|
|
37
|
+
.mockResolvedValueOnce([{ id: 'b1', filename: 'b.txt', size: 5 }]);
|
|
38
|
+
Object.defineProperty(process.stdout, 'isTTY', { value: true, configurable: true });
|
|
39
|
+
await runAttach({
|
|
40
|
+
issueKey: 'PROJ-1',
|
|
41
|
+
files: ['./a.png', './b.txt'],
|
|
42
|
+
json: true,
|
|
43
|
+
});
|
|
44
|
+
expect(uploadAttachmentMock).toHaveBeenCalledTimes(2);
|
|
45
|
+
expect(uploadAttachmentMock).toHaveBeenNthCalledWith(1, 'PROJ-1', './a.png');
|
|
46
|
+
expect(uploadAttachmentMock).toHaveBeenNthCalledWith(2, 'PROJ-1', './b.txt');
|
|
47
|
+
const parsed = JSON.parse(writes.join(''));
|
|
48
|
+
expect(parsed.issueKey).toBe('PROJ-1');
|
|
49
|
+
expect(parsed.attachments).toHaveLength(2);
|
|
50
|
+
});
|
|
51
|
+
it('does NOT call uploadAttachment on --dry-run', async () => {
|
|
52
|
+
Object.defineProperty(process.stdout, 'isTTY', { value: true, configurable: true });
|
|
53
|
+
await runAttach({
|
|
54
|
+
issueKey: 'PROJ-1',
|
|
55
|
+
files: ['./a.png'],
|
|
56
|
+
dryRun: true,
|
|
57
|
+
json: true,
|
|
58
|
+
});
|
|
59
|
+
expect(uploadAttachmentMock).not.toHaveBeenCalled();
|
|
60
|
+
const parsed = JSON.parse(writes.join(''));
|
|
61
|
+
expect(parsed).toEqual({ dryRun: true, issueKey: 'PROJ-1', files: ['./a.png'] });
|
|
62
|
+
});
|
|
63
|
+
it('prints per-attachment summary on TTY', async () => {
|
|
64
|
+
uploadAttachmentMock.mockResolvedValueOnce([
|
|
65
|
+
{ id: 'a1', filename: 'a.png', size: 10 },
|
|
66
|
+
]);
|
|
67
|
+
Object.defineProperty(process.stdout, 'isTTY', { value: true, configurable: true });
|
|
68
|
+
await runAttach({ issueKey: 'PROJ-1', files: ['./a.png'] });
|
|
69
|
+
const out = logs.join('\n');
|
|
70
|
+
expect(out).toContain('Uploaded 1 attachment(s)');
|
|
71
|
+
expect(out).toContain('[a1] a.png (10b)');
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
describe('runAttachRemove', () => {
|
|
75
|
+
it('calls deleteAttachment with the id', async () => {
|
|
76
|
+
Object.defineProperty(process.stdout, 'isTTY', { value: true, configurable: true });
|
|
77
|
+
await runAttachRemove({ attachmentId: 'att-9', org: 'acme' });
|
|
78
|
+
expect(deleteAttachmentMock).toHaveBeenCalledWith('att-9');
|
|
79
|
+
});
|
|
80
|
+
it('does NOT call deleteAttachment on --dry-run', async () => {
|
|
81
|
+
Object.defineProperty(process.stdout, 'isTTY', { value: true, configurable: true });
|
|
82
|
+
await runAttachRemove({ attachmentId: 'att-9', org: 'acme', dryRun: true, json: true });
|
|
83
|
+
expect(deleteAttachmentMock).not.toHaveBeenCalled();
|
|
84
|
+
expect(JSON.parse(writes.join(''))).toEqual({ dryRun: true, attachmentId: 'att-9' });
|
|
85
|
+
});
|
|
86
|
+
it('emits {attachmentId, removed:true} when --json after success', async () => {
|
|
87
|
+
Object.defineProperty(process.stdout, 'isTTY', { value: true, configurable: true });
|
|
88
|
+
await runAttachRemove({ attachmentId: 'att-9', org: 'acme', json: true });
|
|
89
|
+
expect(JSON.parse(writes.join(''))).toEqual({ attachmentId: 'att-9', removed: true });
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
//# sourceMappingURL=attach.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attach.test.js","sourceRoot":"","sources":["../../../src/cli/commands/attach.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type BoardIssuesOptions = {
|
|
2
|
+
board: string;
|
|
3
|
+
column: string;
|
|
4
|
+
org: string;
|
|
5
|
+
project?: string;
|
|
6
|
+
assignee?: string;
|
|
7
|
+
json?: boolean;
|
|
8
|
+
};
|
|
9
|
+
export declare function runBoardIssues(opts: BoardIssuesOptions): Promise<void>;
|
|
10
|
+
//# sourceMappingURL=board.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"board.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/board.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,kBAAkB,GAAG;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,CAAC;AAUF,wBAAsB,cAAc,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CA8D5E"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { loadProfile } from '../../lib/config.js';
|
|
2
|
+
import { JiraClient } from '../../lib/jiraClient.js';
|
|
3
|
+
export async function runBoardIssues(opts) {
|
|
4
|
+
const profile = await loadProfile({ org: opts.org, project: opts.project });
|
|
5
|
+
const client = new JiraClient(profile.config, profile.apiToken);
|
|
6
|
+
const statusIds = await client.getBoardColumnStatusIds(opts.board, opts.column);
|
|
7
|
+
if (statusIds.length === 0) {
|
|
8
|
+
if (opts.json) {
|
|
9
|
+
process.stdout.write('[]\n');
|
|
10
|
+
}
|
|
11
|
+
else {
|
|
12
|
+
console.error(`Column "${opts.column}" has no mapped statuses.`);
|
|
13
|
+
}
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const clauses = [
|
|
17
|
+
`project = ${profile.project.key}`,
|
|
18
|
+
`status in (${statusIds.map((id) => `"${id}"`).join(', ')})`,
|
|
19
|
+
];
|
|
20
|
+
if (opts.assignee) {
|
|
21
|
+
if (opts.assignee === 'me' || opts.assignee === 'currentUser') {
|
|
22
|
+
clauses.push('assignee = currentUser()');
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
clauses.push(`assignee = "${opts.assignee}"`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
const jql = clauses.join(' AND ') + ' ORDER BY rank ASC';
|
|
29
|
+
const issues = await client.searchByJql(jql);
|
|
30
|
+
const rows = issues.map((issue) => {
|
|
31
|
+
const fields = issue.fields;
|
|
32
|
+
return {
|
|
33
|
+
key: issue.key,
|
|
34
|
+
summary: fields.summary ?? '',
|
|
35
|
+
status: fields.status?.name ?? 'Unknown',
|
|
36
|
+
assignee: fields.assignee?.displayName,
|
|
37
|
+
issueType: fields.issuetype?.name,
|
|
38
|
+
};
|
|
39
|
+
});
|
|
40
|
+
if (opts.json) {
|
|
41
|
+
process.stdout.write(JSON.stringify({ board: opts.board, column: opts.column, issues: rows }, null, 2) + '\n');
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (rows.length === 0) {
|
|
45
|
+
console.log(`No issues in "${opts.column}" on board "${opts.board}".`);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
console.log(`Board "${opts.board}" / column "${opts.column}" — ${rows.length} issue(s):`);
|
|
49
|
+
for (const row of rows) {
|
|
50
|
+
const assignee = row.assignee ? ` [${row.assignee}]` : '';
|
|
51
|
+
console.log(` ${row.key} ${row.summary}${assignee}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=board.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"board.js","sourceRoot":"","sources":["../../../src/cli/commands/board.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type BoardsOptions = {
|
|
2
|
+
org: string;
|
|
3
|
+
project?: string;
|
|
4
|
+
type?: 'scrum' | 'kanban' | 'simple';
|
|
5
|
+
name?: string;
|
|
6
|
+
limit?: string;
|
|
7
|
+
startAt?: string;
|
|
8
|
+
json?: boolean;
|
|
9
|
+
};
|
|
10
|
+
export declare function runBoards(opts: BoardsOptions): Promise<void>;
|
|
11
|
+
//# sourceMappingURL=boards.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"boards.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/boards.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,aAAa,GAAG;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAC;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,wBAAsB,SAAS,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAyBlE"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { loadProfile } from '../../lib/config.js';
|
|
2
|
+
import { JiraClient } from '../../lib/jiraClient.js';
|
|
3
|
+
import { printJson, shouldOutputJson } from '../jsonOutput.js';
|
|
4
|
+
export async function runBoards(opts) {
|
|
5
|
+
const profile = await loadProfile({ org: opts.org, project: opts.project });
|
|
6
|
+
const client = new JiraClient(profile.config, profile.apiToken);
|
|
7
|
+
const page = await client.listBoards({
|
|
8
|
+
projectKey: opts.project ?? profile.project.key,
|
|
9
|
+
type: opts.type,
|
|
10
|
+
name: opts.name,
|
|
11
|
+
limit: opts.limit ? parseInt(opts.limit, 10) : undefined,
|
|
12
|
+
startAt: opts.startAt ? parseInt(opts.startAt, 10) : undefined,
|
|
13
|
+
});
|
|
14
|
+
if (shouldOutputJson(opts)) {
|
|
15
|
+
printJson(page);
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
if (page.values.length === 0) {
|
|
19
|
+
console.log('No boards found.');
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
console.log(`${page.values.length} board(s):`);
|
|
23
|
+
for (const b of page.values) {
|
|
24
|
+
console.log(` [${b.id}] ${b.name} (${b.type})`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=boards.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"boards.js","sourceRoot":"","sources":["../../../src/cli/commands/boards.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAY/D,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,IAAmB;IACjD,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;IAC5E,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;IAEhE,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC;QACnC,UAAU,EAAE,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,GAAG;QAC/C,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS;QACxD,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS;KAC/D,CAAC,CAAC;IAEH,IAAI,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3B,SAAS,CAAC,IAAI,CAAC,CAAC;QAChB,OAAO;IACT,CAAC;IAED,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC7B,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;QAChC,OAAO;IACT,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,YAAY,CAAC,CAAC;IAC/C,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAC5B,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC;IACnD,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"boards.test.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/boards.test.ts"],"names":[],"mappings":""}
|