conjira-cli 0.2.5__tar.gz → 0.2.6__tar.gz
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.
- {conjira_cli-0.2.5/src/conjira_cli.egg-info → conjira_cli-0.2.6}/PKG-INFO +48 -3
- {conjira_cli-0.2.5 → conjira_cli-0.2.6}/README.md +47 -2
- {conjira_cli-0.2.5 → conjira_cli-0.2.6}/pyproject.toml +1 -1
- {conjira_cli-0.2.5 → conjira_cli-0.2.6}/src/conjira_cli/__init__.py +1 -1
- {conjira_cli-0.2.5 → conjira_cli-0.2.6}/src/conjira_cli/cli.py +48 -12
- {conjira_cli-0.2.5 → conjira_cli-0.2.6}/src/conjira_cli/client.py +336 -39
- {conjira_cli-0.2.5 → conjira_cli-0.2.6}/src/conjira_cli/config.py +67 -0
- conjira_cli-0.2.6/src/conjira_cli/footer_comments.py +97 -0
- {conjira_cli-0.2.5 → conjira_cli-0.2.6/src/conjira_cli.egg-info}/PKG-INFO +48 -3
- {conjira_cli-0.2.5 → conjira_cli-0.2.6}/src/conjira_cli.egg-info/SOURCES.txt +1 -0
- {conjira_cli-0.2.5 → conjira_cli-0.2.6}/tests/test_cli.py +84 -0
- {conjira_cli-0.2.5 → conjira_cli-0.2.6}/tests/test_client.py +148 -1
- {conjira_cli-0.2.5 → conjira_cli-0.2.6}/tests/test_config.py +11 -1
- {conjira_cli-0.2.5 → conjira_cli-0.2.6}/LICENSE +0 -0
- {conjira_cli-0.2.5 → conjira_cli-0.2.6}/setup.cfg +0 -0
- {conjira_cli-0.2.5 → conjira_cli-0.2.6}/setup.py +0 -0
- {conjira_cli-0.2.5 → conjira_cli-0.2.6}/src/conjira_cli/__main__.py +0 -0
- {conjira_cli-0.2.5 → conjira_cli-0.2.6}/src/conjira_cli/inline_comments.py +0 -0
- {conjira_cli-0.2.5 → conjira_cli-0.2.6}/src/conjira_cli/markdown_export.py +0 -0
- {conjira_cli-0.2.5 → conjira_cli-0.2.6}/src/conjira_cli/markdown_import.py +0 -0
- {conjira_cli-0.2.5 → conjira_cli-0.2.6}/src/conjira_cli/section_edit.py +0 -0
- {conjira_cli-0.2.5 → conjira_cli-0.2.6}/src/conjira_cli/setup_macos.py +0 -0
- {conjira_cli-0.2.5 → conjira_cli-0.2.6}/src/conjira_cli/tree_export.py +0 -0
- {conjira_cli-0.2.5 → conjira_cli-0.2.6}/src/conjira_cli.egg-info/dependency_links.txt +0 -0
- {conjira_cli-0.2.5 → conjira_cli-0.2.6}/src/conjira_cli.egg-info/entry_points.txt +0 -0
- {conjira_cli-0.2.5 → conjira_cli-0.2.6}/src/conjira_cli.egg-info/top_level.txt +0 -0
- {conjira_cli-0.2.5 → conjira_cli-0.2.6}/tests/test_inline_comments.py +0 -0
- {conjira_cli-0.2.5 → conjira_cli-0.2.6}/tests/test_markdown_export.py +0 -0
- {conjira_cli-0.2.5 → conjira_cli-0.2.6}/tests/test_markdown_import.py +0 -0
- {conjira_cli-0.2.5 → conjira_cli-0.2.6}/tests/test_section_edit.py +0 -0
- {conjira_cli-0.2.5 → conjira_cli-0.2.6}/tests/test_setup_macos.py +0 -0
- {conjira_cli-0.2.5 → conjira_cli-0.2.6}/tests/test_tree_export.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: conjira-cli
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.6
|
|
4
4
|
Summary: Unofficial agent-friendly CLI for self-hosted Confluence and Jira
|
|
5
5
|
Author: quanttraderkim
|
|
6
6
|
License-Expression: MIT
|
|
@@ -56,6 +56,7 @@ For report-style pages, it can also preserve a small set of Confluence-native pr
|
|
|
56
56
|
- create or update Confluence pages from either storage HTML or Markdown
|
|
57
57
|
- detect stale Markdown exports and refresh them from the live page
|
|
58
58
|
- fetch and export grouped Confluence inline comment threads
|
|
59
|
+
- fetch Confluence page footer comments and replies
|
|
59
60
|
- upload attachments to Confluence pages
|
|
60
61
|
- read Jira issues, search with JQL, inspect create metadata, create issues, and add comments
|
|
61
62
|
- preview writes with `--dry-run`, then enforce them with `--allow-write` plus optional allowlists
|
|
@@ -260,7 +261,33 @@ security add-generic-password -U -s conjira-cli -a jira-prod -w "$PAT"
|
|
|
260
261
|
unset PAT
|
|
261
262
|
```
|
|
262
263
|
|
|
263
|
-
On
|
|
264
|
+
On Windows, use Windows Credential Manager as the closest Keychain-style path. Keep `local/agent.env` non-secret, remove or comment out `CONFLUENCE_PAT_KEYCHAIN_*` and `JIRA_PAT_KEYCHAIN_*`, then load PATs into the current PowerShell session right before running `conjira`.
|
|
265
|
+
|
|
266
|
+
Set up the PowerShell `CredentialManager` module and store the PATs once:
|
|
267
|
+
|
|
268
|
+
```powershell
|
|
269
|
+
Install-Module CredentialManager -Scope CurrentUser
|
|
270
|
+
|
|
271
|
+
$cred = Get-Credential -UserName confluence-prod -Message "Enter Confluence PAT as password"
|
|
272
|
+
New-StoredCredential -Target "conjira-cli/confluence-prod" -UserName $cred.UserName -Password $cred.GetNetworkCredential().Password -Persist LocalMachine
|
|
273
|
+
Remove-Variable cred
|
|
274
|
+
|
|
275
|
+
$cred = Get-Credential -UserName jira-prod -Message "Enter Jira PAT as password"
|
|
276
|
+
New-StoredCredential -Target "conjira-cli/jira-prod" -UserName $cred.UserName -Password $cred.GetNetworkCredential().Password -Persist LocalMachine
|
|
277
|
+
Remove-Variable cred
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
Before running the CLI in a new PowerShell session, read those credentials into environment variables. The values only live in that session:
|
|
281
|
+
|
|
282
|
+
```powershell
|
|
283
|
+
$env:CONFLUENCE_PAT = (Get-StoredCredential -Target "conjira-cli/confluence-prod").GetNetworkCredential().Password
|
|
284
|
+
$env:JIRA_PAT = (Get-StoredCredential -Target "conjira-cli/jira-prod").GetNetworkCredential().Password
|
|
285
|
+
|
|
286
|
+
conjira --env-file .\local\agent.env auth-check
|
|
287
|
+
conjira --env-file .\local\agent.env jira-auth-check
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
If Windows Credential Manager is unavailable, or on Linux, use environment variables or token files instead. For example:
|
|
264
291
|
|
|
265
292
|
```dotenv
|
|
266
293
|
CONFLUENCE_BASE_URL=https://confluence.example.com
|
|
@@ -318,6 +345,12 @@ Export grouped inline comment threads:
|
|
|
318
345
|
conjira --env-file ./local/agent.env export-inline-comments-md --page-id 123456 --status open --output-dir "/path/to/work-folder"
|
|
319
346
|
```
|
|
320
347
|
|
|
348
|
+
Read page footer comments and replies:
|
|
349
|
+
|
|
350
|
+
```bash
|
|
351
|
+
conjira --env-file ./local/agent.env get-footer-comments --page-id 123456
|
|
352
|
+
```
|
|
353
|
+
|
|
321
354
|
Create or update a Confluence page:
|
|
322
355
|
|
|
323
356
|
```bash
|
|
@@ -413,6 +446,17 @@ Jira settings:
|
|
|
413
446
|
- `JIRA_ALLOWED_PROJECT_KEYS`
|
|
414
447
|
- `JIRA_ALLOWED_ISSUE_KEYS`
|
|
415
448
|
|
|
449
|
+
Shared rate-limit settings:
|
|
450
|
+
|
|
451
|
+
- `CONJIRA_RATE_LIMIT_ENABLED`: set to `false` to disable client-side throttling
|
|
452
|
+
- `CONJIRA_RATE_LIMIT_RPS`: default `4.0`
|
|
453
|
+
- `CONJIRA_RATE_LIMIT_BURST`: default `8`
|
|
454
|
+
- `CONJIRA_MAX_RETRIES`: default `5` retries after the first failed request
|
|
455
|
+
- `CONJIRA_RETRY_BASE_SECONDS`: default `1.0`
|
|
456
|
+
- `CONJIRA_RETRY_MAX_SECONDS`: default `30.0`
|
|
457
|
+
|
|
458
|
+
Product-specific overrides such as `CONFLUENCE_RATE_LIMIT_RPS` and `JIRA_RATE_LIMIT_RPS` take precedence over the shared `CONJIRA_*` values. The throttle state is shared across local CLI processes for the same product, base URL, and token, so separate agent calls are paced together.
|
|
459
|
+
|
|
416
460
|
## Safety model
|
|
417
461
|
|
|
418
462
|
This CLI intentionally does not implement delete commands for Confluence pages or Jira issues.
|
|
@@ -429,7 +473,8 @@ When the CLI hits a common API failure, it now returns a `guidance` field alongs
|
|
|
429
473
|
- `403`: check product permissions and any configured allowlists
|
|
430
474
|
- `404`: check the page ID, issue key, or target path and confirm the PAT owner can see it in the web UI
|
|
431
475
|
- `409`: refresh live content and retry, especially for Confluence updates after concurrent edits
|
|
432
|
-
- `429
|
|
476
|
+
- `429`: the CLI automatically retries with backoff and honors `Retry-After` when the server sends it
|
|
477
|
+
- `5xx`: retry after a short delay and reduce request volume if you are looping
|
|
433
478
|
|
|
434
479
|
## Export strategy
|
|
435
480
|
|
|
@@ -27,6 +27,7 @@ For report-style pages, it can also preserve a small set of Confluence-native pr
|
|
|
27
27
|
- create or update Confluence pages from either storage HTML or Markdown
|
|
28
28
|
- detect stale Markdown exports and refresh them from the live page
|
|
29
29
|
- fetch and export grouped Confluence inline comment threads
|
|
30
|
+
- fetch Confluence page footer comments and replies
|
|
30
31
|
- upload attachments to Confluence pages
|
|
31
32
|
- read Jira issues, search with JQL, inspect create metadata, create issues, and add comments
|
|
32
33
|
- preview writes with `--dry-run`, then enforce them with `--allow-write` plus optional allowlists
|
|
@@ -231,7 +232,33 @@ security add-generic-password -U -s conjira-cli -a jira-prod -w "$PAT"
|
|
|
231
232
|
unset PAT
|
|
232
233
|
```
|
|
233
234
|
|
|
234
|
-
On
|
|
235
|
+
On Windows, use Windows Credential Manager as the closest Keychain-style path. Keep `local/agent.env` non-secret, remove or comment out `CONFLUENCE_PAT_KEYCHAIN_*` and `JIRA_PAT_KEYCHAIN_*`, then load PATs into the current PowerShell session right before running `conjira`.
|
|
236
|
+
|
|
237
|
+
Set up the PowerShell `CredentialManager` module and store the PATs once:
|
|
238
|
+
|
|
239
|
+
```powershell
|
|
240
|
+
Install-Module CredentialManager -Scope CurrentUser
|
|
241
|
+
|
|
242
|
+
$cred = Get-Credential -UserName confluence-prod -Message "Enter Confluence PAT as password"
|
|
243
|
+
New-StoredCredential -Target "conjira-cli/confluence-prod" -UserName $cred.UserName -Password $cred.GetNetworkCredential().Password -Persist LocalMachine
|
|
244
|
+
Remove-Variable cred
|
|
245
|
+
|
|
246
|
+
$cred = Get-Credential -UserName jira-prod -Message "Enter Jira PAT as password"
|
|
247
|
+
New-StoredCredential -Target "conjira-cli/jira-prod" -UserName $cred.UserName -Password $cred.GetNetworkCredential().Password -Persist LocalMachine
|
|
248
|
+
Remove-Variable cred
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
Before running the CLI in a new PowerShell session, read those credentials into environment variables. The values only live in that session:
|
|
252
|
+
|
|
253
|
+
```powershell
|
|
254
|
+
$env:CONFLUENCE_PAT = (Get-StoredCredential -Target "conjira-cli/confluence-prod").GetNetworkCredential().Password
|
|
255
|
+
$env:JIRA_PAT = (Get-StoredCredential -Target "conjira-cli/jira-prod").GetNetworkCredential().Password
|
|
256
|
+
|
|
257
|
+
conjira --env-file .\local\agent.env auth-check
|
|
258
|
+
conjira --env-file .\local\agent.env jira-auth-check
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
If Windows Credential Manager is unavailable, or on Linux, use environment variables or token files instead. For example:
|
|
235
262
|
|
|
236
263
|
```dotenv
|
|
237
264
|
CONFLUENCE_BASE_URL=https://confluence.example.com
|
|
@@ -289,6 +316,12 @@ Export grouped inline comment threads:
|
|
|
289
316
|
conjira --env-file ./local/agent.env export-inline-comments-md --page-id 123456 --status open --output-dir "/path/to/work-folder"
|
|
290
317
|
```
|
|
291
318
|
|
|
319
|
+
Read page footer comments and replies:
|
|
320
|
+
|
|
321
|
+
```bash
|
|
322
|
+
conjira --env-file ./local/agent.env get-footer-comments --page-id 123456
|
|
323
|
+
```
|
|
324
|
+
|
|
292
325
|
Create or update a Confluence page:
|
|
293
326
|
|
|
294
327
|
```bash
|
|
@@ -384,6 +417,17 @@ Jira settings:
|
|
|
384
417
|
- `JIRA_ALLOWED_PROJECT_KEYS`
|
|
385
418
|
- `JIRA_ALLOWED_ISSUE_KEYS`
|
|
386
419
|
|
|
420
|
+
Shared rate-limit settings:
|
|
421
|
+
|
|
422
|
+
- `CONJIRA_RATE_LIMIT_ENABLED`: set to `false` to disable client-side throttling
|
|
423
|
+
- `CONJIRA_RATE_LIMIT_RPS`: default `4.0`
|
|
424
|
+
- `CONJIRA_RATE_LIMIT_BURST`: default `8`
|
|
425
|
+
- `CONJIRA_MAX_RETRIES`: default `5` retries after the first failed request
|
|
426
|
+
- `CONJIRA_RETRY_BASE_SECONDS`: default `1.0`
|
|
427
|
+
- `CONJIRA_RETRY_MAX_SECONDS`: default `30.0`
|
|
428
|
+
|
|
429
|
+
Product-specific overrides such as `CONFLUENCE_RATE_LIMIT_RPS` and `JIRA_RATE_LIMIT_RPS` take precedence over the shared `CONJIRA_*` values. The throttle state is shared across local CLI processes for the same product, base URL, and token, so separate agent calls are paced together.
|
|
430
|
+
|
|
387
431
|
## Safety model
|
|
388
432
|
|
|
389
433
|
This CLI intentionally does not implement delete commands for Confluence pages or Jira issues.
|
|
@@ -400,7 +444,8 @@ When the CLI hits a common API failure, it now returns a `guidance` field alongs
|
|
|
400
444
|
- `403`: check product permissions and any configured allowlists
|
|
401
445
|
- `404`: check the page ID, issue key, or target path and confirm the PAT owner can see it in the web UI
|
|
402
446
|
- `409`: refresh live content and retry, especially for Confluence updates after concurrent edits
|
|
403
|
-
- `429
|
|
447
|
+
- `429`: the CLI automatically retries with backoff and honors `Retry-After` when the server sends it
|
|
448
|
+
- `5xx`: retry after a short delay and reduce request volume if you are looping
|
|
404
449
|
|
|
405
450
|
## Export strategy
|
|
406
451
|
|
|
@@ -49,6 +49,12 @@ def _read_text_arg(raw_text: Optional[str], file_path: Optional[str]) -> str:
|
|
|
49
49
|
return ""
|
|
50
50
|
|
|
51
51
|
|
|
52
|
+
def _normalize_id(value: str) -> str:
|
|
53
|
+
# Strip whitespace and trailing slashes so URL-derived IDs like
|
|
54
|
+
# "1025003939/" (from a pasted Confluence URL) don't break path joins.
|
|
55
|
+
return value.strip().strip("/")
|
|
56
|
+
|
|
57
|
+
|
|
52
58
|
def _read_json_arg(raw_json: Optional[str], file_path: Optional[str]) -> Dict[str, Any]:
|
|
53
59
|
if raw_json is not None:
|
|
54
60
|
return json.loads(raw_json)
|
|
@@ -303,14 +309,14 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
303
309
|
subparsers.add_parser("auth-check", help="Validate Confluence base URL and PAT")
|
|
304
310
|
|
|
305
311
|
get_page = subparsers.add_parser("get-page", help="Fetch a Confluence page by ID")
|
|
306
|
-
get_page.add_argument("--page-id", required=True)
|
|
312
|
+
get_page.add_argument("--page-id", required=True, type=_normalize_id)
|
|
307
313
|
get_page.add_argument("--expand")
|
|
308
314
|
|
|
309
315
|
export_page_md = subparsers.add_parser(
|
|
310
316
|
"export-page-md",
|
|
311
317
|
help="Export a Confluence page to a Markdown file",
|
|
312
318
|
)
|
|
313
|
-
export_page_md.add_argument("--page-id", required=True)
|
|
319
|
+
export_page_md.add_argument("--page-id", required=True, type=_normalize_id)
|
|
314
320
|
export_page_md.add_argument("--output-file")
|
|
315
321
|
export_page_md.add_argument("--output-dir")
|
|
316
322
|
export_page_md.add_argument("--filename")
|
|
@@ -320,7 +326,7 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
320
326
|
"export-tree-md",
|
|
321
327
|
help="Export a Confluence page tree to nested Markdown folders",
|
|
322
328
|
)
|
|
323
|
-
export_tree_md.add_argument("--page-id", required=True)
|
|
329
|
+
export_tree_md.add_argument("--page-id", required=True, type=_normalize_id)
|
|
324
330
|
export_tree_md.add_argument("--output-dir")
|
|
325
331
|
export_tree_md.add_argument("--staging-local", action="store_true")
|
|
326
332
|
|
|
@@ -340,7 +346,7 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
340
346
|
"get-inline-comments",
|
|
341
347
|
help="Fetch Confluence inline comments and group them into threads",
|
|
342
348
|
)
|
|
343
|
-
get_inline_comments.add_argument("--page-id", required=True)
|
|
349
|
+
get_inline_comments.add_argument("--page-id", required=True, type=_normalize_id)
|
|
344
350
|
get_inline_comments.add_argument("--limit", type=int, default=200)
|
|
345
351
|
get_inline_comments.add_argument(
|
|
346
352
|
"--status",
|
|
@@ -348,11 +354,19 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
348
354
|
default="all",
|
|
349
355
|
)
|
|
350
356
|
|
|
357
|
+
get_footer_comments = subparsers.add_parser(
|
|
358
|
+
"get-footer-comments",
|
|
359
|
+
aliases=["get-page-comments"],
|
|
360
|
+
help="Fetch Confluence page footer comments, including replies",
|
|
361
|
+
)
|
|
362
|
+
get_footer_comments.add_argument("--page-id", required=True)
|
|
363
|
+
get_footer_comments.add_argument("--limit", type=int, default=200)
|
|
364
|
+
|
|
351
365
|
export_inline_comments_md = subparsers.add_parser(
|
|
352
366
|
"export-inline-comments-md",
|
|
353
367
|
help="Export grouped Confluence inline comments to a Markdown file",
|
|
354
368
|
)
|
|
355
|
-
export_inline_comments_md.add_argument("--page-id", required=True)
|
|
369
|
+
export_inline_comments_md.add_argument("--page-id", required=True, type=_normalize_id)
|
|
356
370
|
export_inline_comments_md.add_argument("--limit", type=int, default=200)
|
|
357
371
|
export_inline_comments_md.add_argument(
|
|
358
372
|
"--status",
|
|
@@ -377,7 +391,7 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
377
391
|
create_page_body_group.add_argument("--body-markdown-file")
|
|
378
392
|
|
|
379
393
|
update_page = subparsers.add_parser("update-page", help="Update an existing Confluence page")
|
|
380
|
-
update_page.add_argument("--page-id", required=True)
|
|
394
|
+
update_page.add_argument("--page-id", required=True, type=_normalize_id)
|
|
381
395
|
update_page.add_argument("--allow-write", action="store_true")
|
|
382
396
|
update_page.add_argument("--dry-run", action="store_true")
|
|
383
397
|
update_page.add_argument("--title")
|
|
@@ -396,7 +410,7 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
396
410
|
"replace-section",
|
|
397
411
|
help="Replace the content under a specific Confluence heading",
|
|
398
412
|
)
|
|
399
|
-
replace_section.add_argument("--page-id", required=True)
|
|
413
|
+
replace_section.add_argument("--page-id", required=True, type=_normalize_id)
|
|
400
414
|
replace_section.add_argument("--heading", required=True)
|
|
401
415
|
replace_section.add_argument("--allow-write", action="store_true")
|
|
402
416
|
replace_section.add_argument("--dry-run", action="store_true")
|
|
@@ -410,7 +424,7 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
410
424
|
"insert-after-heading",
|
|
411
425
|
help="Insert content immediately after a specific Confluence heading",
|
|
412
426
|
)
|
|
413
|
-
insert_after_heading.add_argument("--page-id", required=True)
|
|
427
|
+
insert_after_heading.add_argument("--page-id", required=True, type=_normalize_id)
|
|
414
428
|
insert_after_heading.add_argument("--heading", required=True)
|
|
415
429
|
insert_after_heading.add_argument("--allow-write", action="store_true")
|
|
416
430
|
insert_after_heading.add_argument("--dry-run", action="store_true")
|
|
@@ -426,7 +440,7 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
426
440
|
"move-page",
|
|
427
441
|
help="Move an existing Confluence page under a different parent page",
|
|
428
442
|
)
|
|
429
|
-
move_page.add_argument("--page-id", required=True)
|
|
443
|
+
move_page.add_argument("--page-id", required=True, type=_normalize_id)
|
|
430
444
|
move_page.add_argument("--new-parent-id", required=True)
|
|
431
445
|
move_page.add_argument("--allow-write", action="store_true")
|
|
432
446
|
move_page.add_argument("--dry-run", action="store_true")
|
|
@@ -435,7 +449,7 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
435
449
|
"upload-attachment",
|
|
436
450
|
help="Upload or update a Confluence attachment on a page",
|
|
437
451
|
)
|
|
438
|
-
upload_attachment.add_argument("--page-id", required=True)
|
|
452
|
+
upload_attachment.add_argument("--page-id", required=True, type=_normalize_id)
|
|
439
453
|
upload_attachment.add_argument("--file", required=True)
|
|
440
454
|
upload_attachment.add_argument("--comment")
|
|
441
455
|
upload_attachment.add_argument("--allow-write", action="store_true")
|
|
@@ -451,7 +465,7 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
451
465
|
subparsers.add_parser("jira-auth-check", help="Validate Jira base URL and PAT")
|
|
452
466
|
|
|
453
467
|
jira_get_issue = subparsers.add_parser("jira-get-issue", help="Fetch a Jira issue by key")
|
|
454
|
-
jira_get_issue.add_argument("--issue-key", required=True)
|
|
468
|
+
jira_get_issue.add_argument("--issue-key", required=True, type=_normalize_id)
|
|
455
469
|
jira_get_issue.add_argument("--fields")
|
|
456
470
|
jira_get_issue.add_argument("--expand")
|
|
457
471
|
jira_get_issue.add_argument("--include-comments", action="store_true")
|
|
@@ -488,7 +502,7 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
488
502
|
jira_create_issue_fields_group.add_argument("--fields-file")
|
|
489
503
|
|
|
490
504
|
jira_add_comment = subparsers.add_parser("jira-add-comment", help="Add a Jira issue comment")
|
|
491
|
-
jira_add_comment.add_argument("--issue-key", required=True)
|
|
505
|
+
jira_add_comment.add_argument("--issue-key", required=True, type=_normalize_id)
|
|
492
506
|
jira_add_comment.add_argument("--allow-write", action="store_true")
|
|
493
507
|
jira_add_comment.add_argument("--dry-run", action="store_true")
|
|
494
508
|
jira_comment_group = jira_add_comment.add_mutually_exclusive_group(required=True)
|
|
@@ -923,6 +937,12 @@ def _handle_confluence(args: argparse.Namespace) -> Dict[str, Any]:
|
|
|
923
937
|
base_url=settings.base_url,
|
|
924
938
|
token=settings.token,
|
|
925
939
|
timeout_seconds=settings.timeout_seconds,
|
|
940
|
+
rate_limit_enabled=settings.rate_limit_enabled,
|
|
941
|
+
rate_limit_rps=settings.rate_limit_rps,
|
|
942
|
+
rate_limit_burst=settings.rate_limit_burst,
|
|
943
|
+
max_retries=settings.max_retries,
|
|
944
|
+
retry_base_seconds=settings.retry_base_seconds,
|
|
945
|
+
retry_max_seconds=settings.retry_max_seconds,
|
|
926
946
|
)
|
|
927
947
|
|
|
928
948
|
if args.command == "auth-check":
|
|
@@ -1074,6 +1094,16 @@ def _handle_confluence(args: argparse.Namespace) -> Dict[str, Any]:
|
|
|
1074
1094
|
comments=comments,
|
|
1075
1095
|
status_filter=args.status,
|
|
1076
1096
|
)
|
|
1097
|
+
if args.command in {"get-footer-comments", "get-page-comments"}:
|
|
1098
|
+
page = client.get_page(args.page_id, expand="version,space")
|
|
1099
|
+
comments = client.list_footer_comments(
|
|
1100
|
+
args.page_id,
|
|
1101
|
+
limit=args.limit,
|
|
1102
|
+
)
|
|
1103
|
+
return client.summarize_footer_comments(
|
|
1104
|
+
page=page,
|
|
1105
|
+
comments=comments,
|
|
1106
|
+
)
|
|
1077
1107
|
if args.command == "export-inline-comments-md":
|
|
1078
1108
|
page = client.get_page(args.page_id, expand="version,space")
|
|
1079
1109
|
comments = client.list_inline_comments(
|
|
@@ -1376,6 +1406,12 @@ def _handle_jira(args: argparse.Namespace) -> Dict[str, Any]:
|
|
|
1376
1406
|
base_url=settings.base_url,
|
|
1377
1407
|
token=settings.token,
|
|
1378
1408
|
timeout_seconds=settings.timeout_seconds,
|
|
1409
|
+
rate_limit_enabled=settings.rate_limit_enabled,
|
|
1410
|
+
rate_limit_rps=settings.rate_limit_rps,
|
|
1411
|
+
rate_limit_burst=settings.rate_limit_burst,
|
|
1412
|
+
max_retries=settings.max_retries,
|
|
1413
|
+
retry_base_seconds=settings.retry_base_seconds,
|
|
1414
|
+
retry_max_seconds=settings.retry_max_seconds,
|
|
1379
1415
|
)
|
|
1380
1416
|
|
|
1381
1417
|
if args.command == "jira-auth-check":
|