confpub-cli 1.16.0__tar.gz → 1.16.2__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.
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/PKG-INFO +20 -1
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/README.md +18 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/__init__.py +1 -1
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/applier.py +31 -4
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/assets.py +25 -9
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/cli.py +82 -4
- confpub_cli-1.16.2/confpub/config.py +479 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/converter.py +112 -3
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/front_matter.py +35 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/guide.py +55 -11
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/html_macro_plugin.py +2 -2
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/planner.py +31 -4
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/publish.py +31 -4
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/reverse_converter.py +21 -2
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_data/SKILL.md +3 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_data/references/syntax-html-macro.md +79 -2
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_data/references/workflow.md +8 -1
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/pyproject.toml +1 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/test_assets.py +44 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/test_config.py +94 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/test_front_matter.py +23 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/test_html_macro_plugin.py +74 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/test_integration.py +10 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/test_publish.py +36 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/test_skill_installer.py +15 -0
- confpub_cli-1.16.0/confpub/config.py +0 -269
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/.github/copilot-instructions.md +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/.github/workflows/publish.yml +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/.gitignore +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/AGENTS.md +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/CLAUDE.md +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/LICENSE +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/PRD.md +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/SCORE.md +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/__main__.py +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/confluence.py +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/envelope.py +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/errors.py +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/lockfile.py +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/macro_plugin.py +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/manifest.py +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/output.py +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/puller.py +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/py.typed +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_data/__init__.py +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_data/references/design-principles.md +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_data/references/design-styling.md +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_data/references/layouts.md +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_data/references/page-management.md +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_data/references/patterns/adr.md +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_data/references/patterns/api-docs.md +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_data/references/patterns/change-request.md +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_data/references/patterns/design-doc.md +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_data/references/patterns/meeting-notes.md +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_data/references/patterns/onboarding.md +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_data/references/patterns/post-mortem.md +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_data/references/patterns/raid-log.md +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_data/references/patterns/release-notes.md +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_data/references/patterns/retrospective.md +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_data/references/patterns/rfc.md +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_data/references/patterns/runbook.md +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_data/references/patterns/service-catalog.md +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_data/references/patterns/sprint-status.md +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_data/references/syntax-containers.md +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_data/references/syntax-formatting.md +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_data/references/syntax-macros.md +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_data/references/trust-scoring.md +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_installer.py +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/trust/__init__.py +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/trust/anchors.py +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/trust/body_parser.py +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/trust/cache.py +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/trust/models.py +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/trust/profiles.py +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/trust/scoring.py +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/trust/tui.py +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/validator.py +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/verifier.py +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub.lock +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/__init__.py +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/conftest.py +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/test_applier.py +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/test_confluence.py +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/test_converter.py +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/test_envelope.py +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/test_errors.py +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/test_guide.py +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/test_lockfile.py +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/test_macro_plugin.py +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/test_manifest.py +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/test_output.py +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/test_planner.py +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/test_puller.py +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/test_reverse_converter.py +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/test_trust_cache.py +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/test_trust_cli.py +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/test_trust_models.py +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/test_trust_scoring.py +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/test_validator.py +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/test_verifier.py +0 -0
- {confpub_cli-1.16.0 → confpub_cli-1.16.2}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: confpub-cli
|
|
3
|
-
Version: 1.16.
|
|
3
|
+
Version: 1.16.2
|
|
4
4
|
Summary: Agent-first CLI to publish Markdown to Confluence
|
|
5
5
|
Project-URL: Homepage, https://github.com/ThomasRohde/confpub-cli
|
|
6
6
|
Project-URL: Repository, https://github.com/ThomasRohde/confpub-cli.git
|
|
@@ -26,6 +26,7 @@ Classifier: Typing :: Typed
|
|
|
26
26
|
Requires-Python: >=3.10
|
|
27
27
|
Requires-Dist: atlassian-python-api>=3.41
|
|
28
28
|
Requires-Dist: beautifulsoup4>=4.12
|
|
29
|
+
Requires-Dist: click>=8.0
|
|
29
30
|
Requires-Dist: keyring>=24.0
|
|
30
31
|
Requires-Dist: markdown-it-py[linkify,plugins]>=3.0
|
|
31
32
|
Requires-Dist: markdownify>=0.14
|
|
@@ -505,6 +506,18 @@ Confluence strips `<style>`, `<script>`, `<iframe>`, and other tags from normal
|
|
|
505
506
|
|
|
506
507
|
The macro name is selected from your Confluence type: `html` for Data Center/Server and `html-macro` as the Cloud fallback. Confluence Cloud HTML macro apps can register different macro keys, including `macro-html`, so override per publish with `--html-macro-name` or `html_macro_name` in front-matter when needed. To persist the setting, run `confpub config set html_macro_name macro-html` or set `CONFPUB_HTML_MACRO_NAME`.
|
|
507
508
|
|
|
509
|
+
Forge-based Cloud HTML apps, such as Appfire "HTML for Confluence", use a different storage shape (`ac:adf-extension`) rather than the classic `ac:structured-macro`. For those sites, also set `--html-macro-format forge-adf-extension` and provide the Forge `extension-key` and `extension-id` copied from a working macro:
|
|
510
|
+
|
|
511
|
+
```bash
|
|
512
|
+
confpub config set html_macro_name macro-html
|
|
513
|
+
confpub config set html_macro_format forge-adf-extension
|
|
514
|
+
confpub config set html_macro_forge_extension_key "7dc8a3ac/.../static/macro-html"
|
|
515
|
+
confpub config set html_macro_forge_extension_id "ari:cloud:ecosystem::extension/7dc8a3ac/.../static/macro-html"
|
|
516
|
+
confpub config set html_macro_forge_cloud_id "CLOUD_ID"
|
|
517
|
+
confpub config set html_macro_forge_context_ids "ari:cloud:confluence:site/CLOUD_ID"
|
|
518
|
+
confpub config set html_macro_forge_account_id "ACCOUNT_ID"
|
|
519
|
+
```
|
|
520
|
+
|
|
508
521
|
### Interactive JavaScript Applications
|
|
509
522
|
|
|
510
523
|
`::: html` blocks can reference external JavaScript and CSS files. confpub automatically:
|
|
@@ -626,6 +639,12 @@ confpub guide --section commands # Just commands
|
|
|
626
639
|
| `CONFPUB_SPACE` | Default space key |
|
|
627
640
|
| `CONFPUB_SSL_VERIFY` | SSL verification (`true`/`false` or CA bundle path) |
|
|
628
641
|
| `CONFPUB_HTML_MACRO_NAME` | HTML macro key for `::: html` blocks, if your Confluence Cloud app differs from the built-in fallback |
|
|
642
|
+
| `CONFPUB_HTML_MACRO_FORMAT` | HTML macro storage format: `classic` or `forge-adf-extension` |
|
|
643
|
+
| `CONFPUB_HTML_MACRO_FORGE_EXTENSION_KEY` | Forge HTML macro `extension-key` copied from a working macro |
|
|
644
|
+
| `CONFPUB_HTML_MACRO_FORGE_EXTENSION_ID` | Forge HTML macro `extension-id` copied from a working macro |
|
|
645
|
+
| `CONFPUB_HTML_MACRO_FORGE_CLOUD_ID` | Optional Forge `cloud-id` copied from a working macro |
|
|
646
|
+
| `CONFPUB_HTML_MACRO_FORGE_CONTEXT_IDS` | Optional Forge `context-ids` copied from a working macro |
|
|
647
|
+
| `CONFPUB_HTML_MACRO_FORGE_ACCOUNT_ID` | Optional Forge `account-id` copied from a working macro |
|
|
629
648
|
|
|
630
649
|
---
|
|
631
650
|
|
|
@@ -463,6 +463,18 @@ Confluence strips `<style>`, `<script>`, `<iframe>`, and other tags from normal
|
|
|
463
463
|
|
|
464
464
|
The macro name is selected from your Confluence type: `html` for Data Center/Server and `html-macro` as the Cloud fallback. Confluence Cloud HTML macro apps can register different macro keys, including `macro-html`, so override per publish with `--html-macro-name` or `html_macro_name` in front-matter when needed. To persist the setting, run `confpub config set html_macro_name macro-html` or set `CONFPUB_HTML_MACRO_NAME`.
|
|
465
465
|
|
|
466
|
+
Forge-based Cloud HTML apps, such as Appfire "HTML for Confluence", use a different storage shape (`ac:adf-extension`) rather than the classic `ac:structured-macro`. For those sites, also set `--html-macro-format forge-adf-extension` and provide the Forge `extension-key` and `extension-id` copied from a working macro:
|
|
467
|
+
|
|
468
|
+
```bash
|
|
469
|
+
confpub config set html_macro_name macro-html
|
|
470
|
+
confpub config set html_macro_format forge-adf-extension
|
|
471
|
+
confpub config set html_macro_forge_extension_key "7dc8a3ac/.../static/macro-html"
|
|
472
|
+
confpub config set html_macro_forge_extension_id "ari:cloud:ecosystem::extension/7dc8a3ac/.../static/macro-html"
|
|
473
|
+
confpub config set html_macro_forge_cloud_id "CLOUD_ID"
|
|
474
|
+
confpub config set html_macro_forge_context_ids "ari:cloud:confluence:site/CLOUD_ID"
|
|
475
|
+
confpub config set html_macro_forge_account_id "ACCOUNT_ID"
|
|
476
|
+
```
|
|
477
|
+
|
|
466
478
|
### Interactive JavaScript Applications
|
|
467
479
|
|
|
468
480
|
`::: html` blocks can reference external JavaScript and CSS files. confpub automatically:
|
|
@@ -584,6 +596,12 @@ confpub guide --section commands # Just commands
|
|
|
584
596
|
| `CONFPUB_SPACE` | Default space key |
|
|
585
597
|
| `CONFPUB_SSL_VERIFY` | SSL verification (`true`/`false` or CA bundle path) |
|
|
586
598
|
| `CONFPUB_HTML_MACRO_NAME` | HTML macro key for `::: html` blocks, if your Confluence Cloud app differs from the built-in fallback |
|
|
599
|
+
| `CONFPUB_HTML_MACRO_FORMAT` | HTML macro storage format: `classic` or `forge-adf-extension` |
|
|
600
|
+
| `CONFPUB_HTML_MACRO_FORGE_EXTENSION_KEY` | Forge HTML macro `extension-key` copied from a working macro |
|
|
601
|
+
| `CONFPUB_HTML_MACRO_FORGE_EXTENSION_ID` | Forge HTML macro `extension-id` copied from a working macro |
|
|
602
|
+
| `CONFPUB_HTML_MACRO_FORGE_CLOUD_ID` | Optional Forge `cloud-id` copied from a working macro |
|
|
603
|
+
| `CONFPUB_HTML_MACRO_FORGE_CONTEXT_IDS` | Optional Forge `context-ids` copied from a working macro |
|
|
604
|
+
| `CONFPUB_HTML_MACRO_FORGE_ACCOUNT_ID` | Optional Forge `account-id` copied from a working macro |
|
|
587
605
|
|
|
588
606
|
---
|
|
589
607
|
|
|
@@ -12,7 +12,7 @@ from pathlib import Path
|
|
|
12
12
|
from typing import Any
|
|
13
13
|
|
|
14
14
|
from confpub.assets import AssetRef, discover_assets, rewrite_html_macro_urls, rewrite_image_urls, upload_assets
|
|
15
|
-
from confpub.config import load_config,
|
|
15
|
+
from confpub.config import load_config, resolve_html_macro_settings
|
|
16
16
|
from confpub.confluence import ConfluenceClient, build_page_url
|
|
17
17
|
from confpub.converter import convert_markdown, fingerprint_content
|
|
18
18
|
from confpub.errors import ERR_CONFLICT_FINGERPRINT, ERR_IO_FILE_NOT_FOUND, ConfpubError
|
|
@@ -28,6 +28,13 @@ def apply_plan(
|
|
|
28
28
|
skip_fingerprint_check: bool = False,
|
|
29
29
|
cascade: bool = False,
|
|
30
30
|
html_macro_name: str | None = None,
|
|
31
|
+
html_macro_format: str | None = None,
|
|
32
|
+
html_macro_forge_extension_key: str | None = None,
|
|
33
|
+
html_macro_forge_extension_id: str | None = None,
|
|
34
|
+
html_macro_forge_environment: str | None = None,
|
|
35
|
+
html_macro_forge_cloud_id: str | None = None,
|
|
36
|
+
html_macro_forge_context_ids: str | None = None,
|
|
37
|
+
html_macro_forge_account_id: str | None = None,
|
|
31
38
|
) -> dict[str, Any]:
|
|
32
39
|
"""Apply a plan to Confluence.
|
|
33
40
|
|
|
@@ -39,8 +46,18 @@ def apply_plan(
|
|
|
39
46
|
config = load_config()
|
|
40
47
|
client = ConfluenceClient(config)
|
|
41
48
|
|
|
42
|
-
# Resolve
|
|
43
|
-
|
|
49
|
+
# Resolve HTML macro settings: explicit > config/env > platform default.
|
|
50
|
+
html_macro_settings = resolve_html_macro_settings(
|
|
51
|
+
config,
|
|
52
|
+
name_override=html_macro_name,
|
|
53
|
+
format_override=html_macro_format,
|
|
54
|
+
forge_extension_key_override=html_macro_forge_extension_key,
|
|
55
|
+
forge_extension_id_override=html_macro_forge_extension_id,
|
|
56
|
+
forge_environment_override=html_macro_forge_environment,
|
|
57
|
+
forge_cloud_id_override=html_macro_forge_cloud_id,
|
|
58
|
+
forge_context_ids_override=html_macro_forge_context_ids,
|
|
59
|
+
forge_account_id_override=html_macro_forge_account_id,
|
|
60
|
+
)
|
|
44
61
|
|
|
45
62
|
# Load or create lockfile
|
|
46
63
|
lockfile_path = plan_dir / "confpub.lock"
|
|
@@ -90,7 +107,17 @@ def apply_plan(
|
|
|
90
107
|
|
|
91
108
|
# Read and convert
|
|
92
109
|
md_text = source_path.read_text(encoding="utf-8")
|
|
93
|
-
storage = convert_markdown(
|
|
110
|
+
storage = convert_markdown(
|
|
111
|
+
md_text,
|
|
112
|
+
html_macro_name=html_macro_settings.name,
|
|
113
|
+
html_macro_format=html_macro_settings.format,
|
|
114
|
+
html_macro_forge_extension_key=html_macro_settings.forge_extension_key,
|
|
115
|
+
html_macro_forge_extension_id=html_macro_settings.forge_extension_id,
|
|
116
|
+
html_macro_forge_environment=html_macro_settings.forge_environment,
|
|
117
|
+
html_macro_forge_cloud_id=html_macro_settings.forge_cloud_id,
|
|
118
|
+
html_macro_forge_context_ids=html_macro_settings.forge_context_ids,
|
|
119
|
+
html_macro_forge_account_id=html_macro_settings.forge_account_id,
|
|
120
|
+
)
|
|
94
121
|
|
|
95
122
|
# Discover and process assets
|
|
96
123
|
assets = discover_assets(md_text, source_path.parent, None)
|
|
@@ -9,6 +9,8 @@ from __future__ import annotations
|
|
|
9
9
|
|
|
10
10
|
import glob
|
|
11
11
|
import re
|
|
12
|
+
from html import escape as html_escape
|
|
13
|
+
from html import unescape as html_unescape
|
|
12
14
|
from pathlib import Path
|
|
13
15
|
from typing import Any
|
|
14
16
|
|
|
@@ -52,6 +54,10 @@ _LINK_HREF_RE = re.compile(r'<link\b[^>]*\bhref=["\']([^"\']+)["\']', re.IGNOREC
|
|
|
52
54
|
|
|
53
55
|
# Regex to find local resource references in CDATA blocks (for rewriting)
|
|
54
56
|
_CDATA_BLOCK_RE = re.compile(r"(<!\[CDATA\[)(.*?)(\]\]>)", re.DOTALL)
|
|
57
|
+
_ADF_BODY_CONTENT_RE = re.compile(
|
|
58
|
+
r'(<ac:adf-parameter key="__body-content">)(.*?)(</ac:adf-parameter>)',
|
|
59
|
+
re.DOTALL,
|
|
60
|
+
)
|
|
55
61
|
|
|
56
62
|
|
|
57
63
|
def _is_local_path(src: str) -> bool:
|
|
@@ -215,10 +221,11 @@ def rewrite_html_macro_urls(
|
|
|
215
221
|
is_cloud: bool,
|
|
216
222
|
page_id: str,
|
|
217
223
|
) -> str:
|
|
218
|
-
"""Rewrite local file references inside HTML macro
|
|
224
|
+
"""Rewrite local file references inside HTML macro bodies to attachment URLs.
|
|
219
225
|
|
|
220
226
|
Transforms script src and link href pointing to local files into full
|
|
221
|
-
Confluence attachment download URLs.
|
|
227
|
+
Confluence attachment download URLs. Handles classic HTML macro CDATA
|
|
228
|
+
bodies and Forge ADF ``__body-content`` values.
|
|
222
229
|
"""
|
|
223
230
|
if not uploaded_assets:
|
|
224
231
|
return storage_format
|
|
@@ -236,11 +243,7 @@ def rewrite_html_macro_urls(
|
|
|
236
243
|
asset = by_filename.get(Path(src).name)
|
|
237
244
|
return asset
|
|
238
245
|
|
|
239
|
-
def
|
|
240
|
-
prefix = match.group(1) # <![CDATA[
|
|
241
|
-
content = match.group(2)
|
|
242
|
-
suffix = match.group(3) # ]]>
|
|
243
|
-
|
|
246
|
+
def _rewrite_refs(content: str) -> str:
|
|
244
247
|
def _rewrite_attr(attr_match: re.Match) -> str:
|
|
245
248
|
full = attr_match.group(0)
|
|
246
249
|
src = attr_match.group(1)
|
|
@@ -253,10 +256,23 @@ def rewrite_html_macro_urls(
|
|
|
253
256
|
return full
|
|
254
257
|
|
|
255
258
|
content = _SCRIPT_SRC_RE.sub(_rewrite_attr, content)
|
|
256
|
-
|
|
259
|
+
return _LINK_HREF_RE.sub(_rewrite_attr, content)
|
|
260
|
+
|
|
261
|
+
def _rewrite_cdata(match: re.Match) -> str:
|
|
262
|
+
prefix = match.group(1) # <![CDATA[
|
|
263
|
+
content = _rewrite_refs(match.group(2))
|
|
264
|
+
suffix = match.group(3) # ]]>
|
|
257
265
|
return prefix + content + suffix
|
|
258
266
|
|
|
259
|
-
|
|
267
|
+
def _rewrite_adf_body(match: re.Match) -> str:
|
|
268
|
+
prefix = match.group(1)
|
|
269
|
+
content = html_unescape(match.group(2))
|
|
270
|
+
content = _rewrite_refs(content)
|
|
271
|
+
suffix = match.group(3)
|
|
272
|
+
return prefix + html_escape(content, quote=False) + suffix
|
|
273
|
+
|
|
274
|
+
storage_format = _CDATA_BLOCK_RE.sub(_rewrite_cdata, storage_format)
|
|
275
|
+
return _ADF_BODY_CONTENT_RE.sub(_rewrite_adf_body, storage_format)
|
|
260
276
|
|
|
261
277
|
|
|
262
278
|
def upload_assets(
|
|
@@ -373,6 +373,13 @@ def page_publish(
|
|
|
373
373
|
backup: bool = typer.Option(False, "--backup", help="Backup existing page before overwriting"),
|
|
374
374
|
label: Optional[list[str]] = typer.Option(None, "--label", help="Label to apply (repeatable)"),
|
|
375
375
|
html_macro_name: Optional[str] = typer.Option(None, "--html-macro-name", help="HTML macro name (html for DC; Cloud apps vary, default html-macro)"),
|
|
376
|
+
html_macro_format: Optional[str] = typer.Option(None, "--html-macro-format", help="HTML macro storage format: classic or forge-adf-extension"),
|
|
377
|
+
html_macro_forge_extension_key: Optional[str] = typer.Option(None, "--html-macro-forge-extension-key", help="Forge HTML macro extension-key copied from a working macro"),
|
|
378
|
+
html_macro_forge_extension_id: Optional[str] = typer.Option(None, "--html-macro-forge-extension-id", help="Forge HTML macro extension-id copied from a working macro"),
|
|
379
|
+
html_macro_forge_environment: Optional[str] = typer.Option(None, "--html-macro-forge-environment", help="Forge environment for the HTML macro (default PRODUCTION)"),
|
|
380
|
+
html_macro_forge_cloud_id: Optional[str] = typer.Option(None, "--html-macro-forge-cloud-id", help="Optional Forge cloud-id copied from a working macro"),
|
|
381
|
+
html_macro_forge_context_ids: Optional[str] = typer.Option(None, "--html-macro-forge-context-ids", help="Optional Forge context-ids copied from a working macro"),
|
|
382
|
+
html_macro_forge_account_id: Optional[str] = typer.Option(None, "--html-macro-forge-account-id", help="Optional Forge account-id copied from a working macro"),
|
|
376
383
|
) -> None:
|
|
377
384
|
"""Publish a single Markdown file to Confluence."""
|
|
378
385
|
from pathlib import Path as _Path
|
|
@@ -439,6 +446,32 @@ def page_publish(
|
|
|
439
446
|
# Resolve html_macro_name: CLI flag > front-matter > config/env/default in publish_page
|
|
440
447
|
fm_html_macro = fm.html_macro_name if fm else None
|
|
441
448
|
effective_html_macro = html_macro_name or fm_html_macro
|
|
449
|
+
fm_html_macro_format = fm.html_macro_format if fm else None
|
|
450
|
+
effective_html_macro_format = html_macro_format or fm_html_macro_format
|
|
451
|
+
fm_html_macro_forge_extension_key = fm.html_macro_forge_extension_key if fm else None
|
|
452
|
+
effective_html_macro_forge_extension_key = (
|
|
453
|
+
html_macro_forge_extension_key or fm_html_macro_forge_extension_key
|
|
454
|
+
)
|
|
455
|
+
fm_html_macro_forge_extension_id = fm.html_macro_forge_extension_id if fm else None
|
|
456
|
+
effective_html_macro_forge_extension_id = (
|
|
457
|
+
html_macro_forge_extension_id or fm_html_macro_forge_extension_id
|
|
458
|
+
)
|
|
459
|
+
fm_html_macro_forge_environment = fm.html_macro_forge_environment if fm else None
|
|
460
|
+
effective_html_macro_forge_environment = (
|
|
461
|
+
html_macro_forge_environment or fm_html_macro_forge_environment
|
|
462
|
+
)
|
|
463
|
+
fm_html_macro_forge_cloud_id = fm.html_macro_forge_cloud_id if fm else None
|
|
464
|
+
effective_html_macro_forge_cloud_id = (
|
|
465
|
+
html_macro_forge_cloud_id or fm_html_macro_forge_cloud_id
|
|
466
|
+
)
|
|
467
|
+
fm_html_macro_forge_context_ids = fm.html_macro_forge_context_ids if fm else None
|
|
468
|
+
effective_html_macro_forge_context_ids = (
|
|
469
|
+
html_macro_forge_context_ids or fm_html_macro_forge_context_ids
|
|
470
|
+
)
|
|
471
|
+
fm_html_macro_forge_account_id = fm.html_macro_forge_account_id if fm else None
|
|
472
|
+
effective_html_macro_forge_account_id = (
|
|
473
|
+
html_macro_forge_account_id or fm_html_macro_forge_account_id
|
|
474
|
+
)
|
|
442
475
|
|
|
443
476
|
from confpub.publish import publish_page
|
|
444
477
|
result = publish_page(
|
|
@@ -452,6 +485,13 @@ def page_publish(
|
|
|
452
485
|
progress_callback=ctx,
|
|
453
486
|
labels=merged_labels,
|
|
454
487
|
html_macro_name=effective_html_macro,
|
|
488
|
+
html_macro_format=effective_html_macro_format,
|
|
489
|
+
html_macro_forge_extension_key=effective_html_macro_forge_extension_key,
|
|
490
|
+
html_macro_forge_extension_id=effective_html_macro_forge_extension_id,
|
|
491
|
+
html_macro_forge_environment=effective_html_macro_forge_environment,
|
|
492
|
+
html_macro_forge_cloud_id=effective_html_macro_forge_cloud_id,
|
|
493
|
+
html_macro_forge_context_ids=effective_html_macro_forge_context_ids,
|
|
494
|
+
html_macro_forge_account_id=effective_html_macro_forge_account_id,
|
|
455
495
|
)
|
|
456
496
|
ctx.result = result
|
|
457
497
|
if not dry_run:
|
|
@@ -644,6 +684,13 @@ def plan_create(
|
|
|
644
684
|
space: Optional[str] = typer.Option(None, "--space", help="Confluence space key (or CONFPUB_SPACE env var)"),
|
|
645
685
|
parent: Optional[str] = typer.Option(None, "--parent", help="Override manifest parent"),
|
|
646
686
|
html_macro_name: Optional[str] = typer.Option(None, "--html-macro-name", help="HTML macro name (html for DC; Cloud apps vary, default html-macro)"),
|
|
687
|
+
html_macro_format: Optional[str] = typer.Option(None, "--html-macro-format", help="HTML macro storage format: classic or forge-adf-extension"),
|
|
688
|
+
html_macro_forge_extension_key: Optional[str] = typer.Option(None, "--html-macro-forge-extension-key", help="Forge HTML macro extension-key copied from a working macro"),
|
|
689
|
+
html_macro_forge_extension_id: Optional[str] = typer.Option(None, "--html-macro-forge-extension-id", help="Forge HTML macro extension-id copied from a working macro"),
|
|
690
|
+
html_macro_forge_environment: Optional[str] = typer.Option(None, "--html-macro-forge-environment", help="Forge environment for the HTML macro (default PRODUCTION)"),
|
|
691
|
+
html_macro_forge_cloud_id: Optional[str] = typer.Option(None, "--html-macro-forge-cloud-id", help="Optional Forge cloud-id copied from a working macro"),
|
|
692
|
+
html_macro_forge_context_ids: Optional[str] = typer.Option(None, "--html-macro-forge-context-ids", help="Optional Forge context-ids copied from a working macro"),
|
|
693
|
+
html_macro_forge_account_id: Optional[str] = typer.Option(None, "--html-macro-forge-account-id", help="Optional Forge account-id copied from a working macro"),
|
|
647
694
|
) -> None:
|
|
648
695
|
"""Generate a plan artifact from a manifest."""
|
|
649
696
|
with command_context("plan.create", target={"manifest": manifest}) as ctx:
|
|
@@ -655,6 +702,13 @@ def plan_create(
|
|
|
655
702
|
space_override=space,
|
|
656
703
|
parent_override=parent,
|
|
657
704
|
html_macro_name=html_macro_name,
|
|
705
|
+
html_macro_format=html_macro_format,
|
|
706
|
+
html_macro_forge_extension_key=html_macro_forge_extension_key,
|
|
707
|
+
html_macro_forge_extension_id=html_macro_forge_extension_id,
|
|
708
|
+
html_macro_forge_environment=html_macro_forge_environment,
|
|
709
|
+
html_macro_forge_cloud_id=html_macro_forge_cloud_id,
|
|
710
|
+
html_macro_forge_context_ids=html_macro_forge_context_ids,
|
|
711
|
+
html_macro_forge_account_id=html_macro_forge_account_id,
|
|
658
712
|
)
|
|
659
713
|
ctx.result = result
|
|
660
714
|
|
|
@@ -678,6 +732,13 @@ def plan_apply(
|
|
|
678
732
|
skip_fingerprint_check: bool = typer.Option(False, "--skip-fingerprint-check", help="Skip stale-state detection"),
|
|
679
733
|
cascade: bool = typer.Option(False, "--cascade", help="Allow cascading deletes"),
|
|
680
734
|
html_macro_name: Optional[str] = typer.Option(None, "--html-macro-name", help="HTML macro name (html for DC; Cloud apps vary, default html-macro)"),
|
|
735
|
+
html_macro_format: Optional[str] = typer.Option(None, "--html-macro-format", help="HTML macro storage format: classic or forge-adf-extension"),
|
|
736
|
+
html_macro_forge_extension_key: Optional[str] = typer.Option(None, "--html-macro-forge-extension-key", help="Forge HTML macro extension-key copied from a working macro"),
|
|
737
|
+
html_macro_forge_extension_id: Optional[str] = typer.Option(None, "--html-macro-forge-extension-id", help="Forge HTML macro extension-id copied from a working macro"),
|
|
738
|
+
html_macro_forge_environment: Optional[str] = typer.Option(None, "--html-macro-forge-environment", help="Forge environment for the HTML macro (default PRODUCTION)"),
|
|
739
|
+
html_macro_forge_cloud_id: Optional[str] = typer.Option(None, "--html-macro-forge-cloud-id", help="Optional Forge cloud-id copied from a working macro"),
|
|
740
|
+
html_macro_forge_context_ids: Optional[str] = typer.Option(None, "--html-macro-forge-context-ids", help="Optional Forge context-ids copied from a working macro"),
|
|
741
|
+
html_macro_forge_account_id: Optional[str] = typer.Option(None, "--html-macro-forge-account-id", help="Optional Forge account-id copied from a working macro"),
|
|
681
742
|
) -> None:
|
|
682
743
|
"""Apply a plan to Confluence."""
|
|
683
744
|
with command_context("plan.apply", target={"plan": plan}) as ctx:
|
|
@@ -689,6 +750,13 @@ def plan_apply(
|
|
|
689
750
|
skip_fingerprint_check=skip_fingerprint_check,
|
|
690
751
|
cascade=cascade,
|
|
691
752
|
html_macro_name=html_macro_name,
|
|
753
|
+
html_macro_format=html_macro_format,
|
|
754
|
+
html_macro_forge_extension_key=html_macro_forge_extension_key,
|
|
755
|
+
html_macro_forge_extension_id=html_macro_forge_extension_id,
|
|
756
|
+
html_macro_forge_environment=html_macro_forge_environment,
|
|
757
|
+
html_macro_forge_cloud_id=html_macro_forge_cloud_id,
|
|
758
|
+
html_macro_forge_context_ids=html_macro_forge_context_ids,
|
|
759
|
+
html_macro_forge_account_id=html_macro_forge_account_id,
|
|
692
760
|
)
|
|
693
761
|
ctx.result = result
|
|
694
762
|
|
|
@@ -718,7 +786,7 @@ def auth_inspect() -> None:
|
|
|
718
786
|
|
|
719
787
|
@config_app.command("set")
|
|
720
788
|
def config_set(
|
|
721
|
-
key: str = typer.Argument(..., help="Configuration key (base_url, user, token, ssl_verify, html_macro_name)"),
|
|
789
|
+
key: str = typer.Argument(..., help="Configuration key (base_url, user, token, ssl_verify, html_macro_name, html_macro_format, html_macro_forge_extension_key, html_macro_forge_extension_id, html_macro_forge_environment, html_macro_forge_cloud_id, html_macro_forge_context_ids, html_macro_forge_account_id)"),
|
|
722
790
|
value: str = typer.Argument(..., help="Configuration value"),
|
|
723
791
|
) -> None:
|
|
724
792
|
"""Set a configuration value."""
|
|
@@ -856,11 +924,21 @@ def comment_add(
|
|
|
856
924
|
md_text = text
|
|
857
925
|
|
|
858
926
|
from confpub.config import load_config as _load_comment_config
|
|
859
|
-
from confpub.config import
|
|
927
|
+
from confpub.config import resolve_html_macro_settings as _resolve_comment_html_macro_settings
|
|
860
928
|
from confpub.converter import convert_markdown
|
|
861
929
|
_comment_config = _load_comment_config()
|
|
862
|
-
_comment_html_macro =
|
|
863
|
-
storage_body = convert_markdown(
|
|
930
|
+
_comment_html_macro = _resolve_comment_html_macro_settings(_comment_config)
|
|
931
|
+
storage_body = convert_markdown(
|
|
932
|
+
md_text,
|
|
933
|
+
html_macro_name=_comment_html_macro.name,
|
|
934
|
+
html_macro_format=_comment_html_macro.format,
|
|
935
|
+
html_macro_forge_extension_key=_comment_html_macro.forge_extension_key,
|
|
936
|
+
html_macro_forge_extension_id=_comment_html_macro.forge_extension_id,
|
|
937
|
+
html_macro_forge_environment=_comment_html_macro.forge_environment,
|
|
938
|
+
html_macro_forge_cloud_id=_comment_html_macro.forge_cloud_id,
|
|
939
|
+
html_macro_forge_context_ids=_comment_html_macro.forge_context_ids,
|
|
940
|
+
html_macro_forge_account_id=_comment_html_macro.forge_account_id,
|
|
941
|
+
)
|
|
864
942
|
|
|
865
943
|
from confpub.confluence import build_client
|
|
866
944
|
client = build_client()
|