mkdocs2confluence 0.11.0__tar.gz → 0.12.0__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.
Files changed (91) hide show
  1. mkdocs2confluence-0.12.0/PKG-INFO +196 -0
  2. mkdocs2confluence-0.12.0/README.md +155 -0
  3. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/pyproject.toml +1 -1
  4. mkdocs2confluence-0.12.0/src/mkdocs2confluence.egg-info/PKG-INFO +196 -0
  5. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/src/mkdocs2confluence.egg-info/SOURCES.txt +1 -0
  6. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/src/mkdocs_to_confluence/loader/config.py +25 -0
  7. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/src/mkdocs_to_confluence/loader/nav.py +8 -1
  8. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/src/mkdocs_to_confluence/publisher/client.py +75 -36
  9. mkdocs2confluence-0.12.0/src/mkdocs_to_confluence/publisher/http_retry.py +50 -0
  10. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/src/mkdocs_to_confluence/transforms/assets.py +4 -3
  11. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/tests/test_images.py +41 -0
  12. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/tests/test_loader.py +70 -0
  13. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/tests/test_publish_client.py +106 -0
  14. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/tests/test_publish_config.py +71 -0
  15. mkdocs2confluence-0.11.0/PKG-INFO +0 -534
  16. mkdocs2confluence-0.11.0/README.md +0 -493
  17. mkdocs2confluence-0.11.0/src/mkdocs2confluence.egg-info/PKG-INFO +0 -534
  18. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/LICENSE +0 -0
  19. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/setup.cfg +0 -0
  20. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/src/mkdocs2confluence.egg-info/dependency_links.txt +0 -0
  21. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/src/mkdocs2confluence.egg-info/entry_points.txt +0 -0
  22. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/src/mkdocs2confluence.egg-info/requires.txt +0 -0
  23. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/src/mkdocs2confluence.egg-info/top_level.txt +0 -0
  24. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/src/mkdocs_to_confluence/__init__.py +0 -0
  25. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/src/mkdocs_to_confluence/cli.py +0 -0
  26. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/src/mkdocs_to_confluence/emitter/__init__.py +0 -0
  27. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/src/mkdocs_to_confluence/emitter/xhtml.py +0 -0
  28. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/src/mkdocs_to_confluence/ir/__init__.py +0 -0
  29. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/src/mkdocs_to_confluence/ir/document.py +0 -0
  30. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/src/mkdocs_to_confluence/ir/nodes.py +0 -0
  31. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/src/mkdocs_to_confluence/ir/treeutil.py +0 -0
  32. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/src/mkdocs_to_confluence/loader/__init__.py +0 -0
  33. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/src/mkdocs_to_confluence/loader/extra_css.py +0 -0
  34. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/src/mkdocs_to_confluence/loader/page.py +0 -0
  35. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/src/mkdocs_to_confluence/parser/__init__.py +0 -0
  36. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/src/mkdocs_to_confluence/parser/markdown.py +0 -0
  37. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/src/mkdocs_to_confluence/pdf/__init__.py +0 -0
  38. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/src/mkdocs_to_confluence/pdf/generator.py +0 -0
  39. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/src/mkdocs_to_confluence/pdf/render.py +0 -0
  40. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/src/mkdocs_to_confluence/preprocess/__init__.py +0 -0
  41. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/src/mkdocs_to_confluence/preprocess/abbrevs.py +0 -0
  42. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/src/mkdocs_to_confluence/preprocess/fence.py +0 -0
  43. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/src/mkdocs_to_confluence/preprocess/frontmatter.py +0 -0
  44. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/src/mkdocs_to_confluence/preprocess/icons.py +0 -0
  45. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/src/mkdocs_to_confluence/preprocess/includes.py +0 -0
  46. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/src/mkdocs_to_confluence/preprocess/linkdefs.py +0 -0
  47. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/src/mkdocs_to_confluence/preview/__init__.py +0 -0
  48. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/src/mkdocs_to_confluence/preview/render.py +0 -0
  49. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/src/mkdocs_to_confluence/preview/server.py +0 -0
  50. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/src/mkdocs_to_confluence/publisher/__init__.py +0 -0
  51. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/src/mkdocs_to_confluence/publisher/pipeline.py +0 -0
  52. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/src/mkdocs_to_confluence/sync/__init__.py +0 -0
  53. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/src/mkdocs_to_confluence/sync/anchoring.py +0 -0
  54. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/src/mkdocs_to_confluence/sync/command.py +0 -0
  55. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/src/mkdocs_to_confluence/sync/comments.py +0 -0
  56. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/src/mkdocs_to_confluence/sync/github.py +0 -0
  57. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/src/mkdocs_to_confluence/sync/platform.py +0 -0
  58. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/src/mkdocs_to_confluence/sync/state.py +0 -0
  59. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/src/mkdocs_to_confluence/transforms/__init__.py +0 -0
  60. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/src/mkdocs_to_confluence/transforms/abbrevs.py +0 -0
  61. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/src/mkdocs_to_confluence/transforms/editlink.py +0 -0
  62. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/src/mkdocs_to_confluence/transforms/footer.py +0 -0
  63. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/src/mkdocs_to_confluence/transforms/images.py +0 -0
  64. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/src/mkdocs_to_confluence/transforms/internallinks.py +0 -0
  65. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/src/mkdocs_to_confluence/transforms/mermaid.py +0 -0
  66. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/tests/test_abbrevs.py +0 -0
  67. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/tests/test_children_macro.py +0 -0
  68. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/tests/test_cli.py +0 -0
  69. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/tests/test_editlink.py +0 -0
  70. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/tests/test_emitter.py +0 -0
  71. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/tests/test_extra_css.py +0 -0
  72. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/tests/test_footer.py +0 -0
  73. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/tests/test_frontmatter.py +0 -0
  74. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/tests/test_icons.py +0 -0
  75. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/tests/test_internallinks.py +0 -0
  76. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/tests/test_ir.py +0 -0
  77. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/tests/test_linkdefs.py +0 -0
  78. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/tests/test_mermaid.py +0 -0
  79. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/tests/test_page_loader.py +0 -0
  80. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/tests/test_parser.py +0 -0
  81. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/tests/test_pdf.py +0 -0
  82. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/tests/test_preprocess.py +0 -0
  83. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/tests/test_preview.py +0 -0
  84. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/tests/test_publish_pipeline.py +0 -0
  85. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/tests/test_server.py +0 -0
  86. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/tests/test_sync_anchoring.py +0 -0
  87. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/tests/test_sync_command.py +0 -0
  88. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/tests/test_sync_comments.py +0 -0
  89. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/tests/test_sync_github.py +0 -0
  90. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/tests/test_sync_state.py +0 -0
  91. {mkdocs2confluence-0.11.0 → mkdocs2confluence-0.12.0}/tests/test_treeutil.py +0 -0
@@ -0,0 +1,196 @@
1
+ Metadata-Version: 2.4
2
+ Name: mkdocs2confluence
3
+ Version: 0.12.0
4
+ Summary: Publish MkDocs Material pages to Confluence Cloud — admonitions, Mermaid diagrams, tabs, page properties and more
5
+ Author: Anders Hybertz
6
+ License: GPL-3.0-or-later
7
+ Project-URL: Homepage, https://github.com/jeckyl2010/mkdocs2confluence
8
+ Project-URL: Repository, https://github.com/jeckyl2010/mkdocs2confluence
9
+ Project-URL: Issues, https://github.com/jeckyl2010/mkdocs2confluence/issues
10
+ Project-URL: Changelog, https://github.com/jeckyl2010/mkdocs2confluence/releases
11
+ Keywords: mkdocs,confluence,atlassian,documentation,publishing,material-for-mkdocs,markdown,storage-format
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Documentation
20
+ Classifier: Topic :: Software Development :: Documentation
21
+ Classifier: Topic :: Text Processing :: Markup
22
+ Classifier: Topic :: Utilities
23
+ Requires-Python: >=3.12
24
+ Description-Content-Type: text/markdown
25
+ License-File: LICENSE
26
+ Requires-Dist: PyYAML>=6.0.3
27
+ Requires-Dist: httpx>=0.27
28
+ Requires-Dist: tinycss2>=1.5.1
29
+ Provides-Extra: pdf
30
+ Requires-Dist: weasyprint>=60.0; extra == "pdf"
31
+ Provides-Extra: dev
32
+ Requires-Dist: pytest; extra == "dev"
33
+ Requires-Dist: pytest-cov; extra == "dev"
34
+ Requires-Dist: ruff; extra == "dev"
35
+ Requires-Dist: mypy; extra == "dev"
36
+ Requires-Dist: types-PyYAML; extra == "dev"
37
+ Requires-Dist: bandit; extra == "dev"
38
+ Requires-Dist: build; extra == "dev"
39
+ Requires-Dist: pre-commit; extra == "dev"
40
+ Dynamic: license-file
41
+
42
+ # mk2conf — MkDocs / Zensical to Confluence
43
+
44
+ [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
45
+ [![Python 3.12+](https://img.shields.io/badge/python-3.12+-blue.svg)](https://www.python.org/downloads/)
46
+ [![PyPI](https://img.shields.io/pypi/v/mkdocs2confluence)](https://pypi.org/project/mkdocs2confluence/)
47
+ [![Downloads](https://img.shields.io/pypi/dm/mkdocs2confluence)](https://pypi.org/project/mkdocs2confluence/)
48
+ [![Latest Release](https://img.shields.io/github/v/release/jeckyl2010/mkdocs2confluence)](https://github.com/jeckyl2010/mkdocs2confluence/releases/latest)
49
+ [![CI](https://github.com/jeckyl2010/mkdocs2confluence/actions/workflows/ci.yml/badge.svg)](https://github.com/jeckyl2010/mkdocs2confluence/actions/workflows/ci.yml)
50
+ [![Release](https://github.com/jeckyl2010/mkdocs2confluence/actions/workflows/release.yml/badge.svg)](https://github.com/jeckyl2010/mkdocs2confluence/actions/workflows/release.yml)
51
+ [![codecov](https://codecov.io/gh/jeckyl2010/mkdocs2confluence/graph/badge.svg)](https://codecov.io/gh/jeckyl2010/mkdocs2confluence)
52
+ [![Ruff](https://img.shields.io/badge/code%20style-ruff-000000.svg)](https://github.com/astral-sh/ruff)
53
+ [![mypy](https://img.shields.io/badge/type--checked-mypy-blue.svg)](https://mypy-lang.org/)
54
+ [![security: bandit](https://img.shields.io/badge/security-bandit-yellow.svg)](https://github.com/PyCQA/bandit)
55
+ [![SLSA Level 3](https://slsa.dev/images/gh-badge-level3.svg)](https://slsa.dev)
56
+ [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/jeckyl2010/mkdocs2confluence/badge)](https://securityscorecards.dev/viewer/?uri=github.com/jeckyl2010/mkdocs2confluence)
57
+
58
+ A Python CLI tool that compiles MkDocs-flavoured Markdown into **native Confluence storage XHTML** and publishes it directly to Confluence Cloud. It is a **compiler/transpiler**, not an HTML converter — every construct maps to its native Confluence equivalent, so pages look and behave like hand-authored Confluence content.
59
+
60
+ It also bridges the gap between Confluence reviewers and developers: the `sync-comments` command turns open Confluence page comments into GitHub pull request review threads, and auto-resolves them in Confluence when the PR is merged.
61
+
62
+ > **Zensical compatible** — [Zensical](https://zensical.org/) is the modern successor to MkDocs + Material for MkDocs. Since it uses the same `mkdocs.yml` format and Python Markdown extensions, your Zensical project works with mk2conf today with no changes required.
63
+
64
+ ---
65
+
66
+ ## Installation
67
+
68
+ Requires Python 3.12+. The PyPI package is `mkdocs2confluence`; the CLI command is `mk2conf`.
69
+
70
+ ```bash
71
+ pip install mkdocs2confluence
72
+ # or, for an isolated install:
73
+ pipx install mkdocs2confluence
74
+ ```
75
+
76
+ **From source** (see [Setup.md](Setup.md)):
77
+
78
+ ```bash
79
+ git clone https://github.com/jeckyl2010/mkdocs2confluence.git
80
+ cd mkdocs2confluence && uv sync
81
+ ```
82
+
83
+ ---
84
+
85
+ ## GitHub Actions
86
+
87
+ Publish docs automatically on every push — no local install needed:
88
+
89
+ ```yaml
90
+ - name: Publish docs to Confluence
91
+ uses: jeckyl2010/mkdocs2confluence@v1
92
+ with:
93
+ token: ${{ secrets.CONFLUENCE_API_TOKEN }}
94
+ ```
95
+
96
+ **Full workflow** — triggers on changes to `docs/` or `mkdocs.yml`:
97
+
98
+ ```yaml
99
+ name: Publish docs
100
+
101
+ on:
102
+ push:
103
+ branches: [main]
104
+ paths: ['docs/**', 'mkdocs.yml']
105
+
106
+ jobs:
107
+ publish:
108
+ runs-on: ubuntu-latest
109
+ steps:
110
+ - uses: actions/checkout@v4
111
+ - uses: jeckyl2010/mkdocs2confluence@v1
112
+ with:
113
+ token: ${{ secrets.CONFLUENCE_API_TOKEN }}
114
+ prune: 'true'
115
+ ```
116
+
117
+ Available inputs: `token` (required), `config`, `version`, `dry-run`, `section`, `page`, `prune`, `quiet`. See [docs/commands.md](docs/commands.md) for details.
118
+
119
+ ---
120
+
121
+ ## Quick start
122
+
123
+ ```bash
124
+ # Preview a page locally (no Confluence API calls)
125
+ mk2conf preview --page index.md --watch
126
+
127
+ # Dry-run: see what would be published
128
+ mk2conf publish --dry-run
129
+
130
+ # Publish all nav pages
131
+ mk2conf publish
132
+
133
+ # Export a section to PDF
134
+ mk2conf pdf --section Guide --out guide.pdf
135
+
136
+ # Sync Confluence comments to GitHub PR review threads
137
+ mk2conf sync-comments
138
+ ```
139
+
140
+ ---
141
+
142
+ ## Configuration
143
+
144
+ Add a `confluence:` block to your `mkdocs.yml`:
145
+
146
+ ```yaml
147
+ confluence:
148
+ base_url: https://yourorg.atlassian.net
149
+ space_key: TECH
150
+ email: user@example.com
151
+ token: !ENV CONFLUENCE_API_TOKEN # never hardcode the token
152
+ parent_page_id: "123456" # optional root page
153
+ mermaid_render: kroki # "kroki" (default) | "kroki:https://your-kroki" | "none"
154
+ full_width: true # default: true
155
+ ```
156
+
157
+ The `confluence:` block is also accepted under `extra:` for MkDocs strict-mode compatibility. The API token is read from `token:` in `mkdocs.yml`, then `CONFLUENCE_API_TOKEN`, then `MK2CONF_TOKEN`.
158
+
159
+ **Your first publish:**
160
+
161
+ ```bash
162
+ export CONFLUENCE_API_TOKEN=your_api_token_here
163
+ mk2conf preview --page docs/index.md --watch # verify output locally
164
+ mk2conf publish --dry-run # check the plan
165
+ mk2conf publish # go live
166
+ ```
167
+
168
+ ---
169
+
170
+ ## Documentation
171
+
172
+ | | |
173
+ |---|---|
174
+ | [docs/commands.md](docs/commands.md) | Full flag reference for all four commands |
175
+ | [docs/features.md](docs/features.md) | Supported Markdown / Material features and known limitations |
176
+ | [Setup.md](Setup.md) | Development environment setup |
177
+
178
+ ---
179
+
180
+ ## Architecture
181
+
182
+ ![Architecture](https://raw.githubusercontent.com/jeckyl2010/mkdocs2confluence/main/docs/architecture.png)
183
+
184
+ Pipeline stages: **loader → preprocess → IR → transforms → emitter → publisher**. The plan phase makes all API read calls; the execute phase makes all write calls in nav order so parent pages always exist before their children.
185
+
186
+ ---
187
+
188
+ ## Development
189
+
190
+ ```bash
191
+ uv run pytest -q
192
+ uv run ruff check src tests
193
+ uv run mypy src
194
+ uv run vulture src --min-confidence 80
195
+ ```
196
+
@@ -0,0 +1,155 @@
1
+ # mk2conf — MkDocs / Zensical to Confluence
2
+
3
+ [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
4
+ [![Python 3.12+](https://img.shields.io/badge/python-3.12+-blue.svg)](https://www.python.org/downloads/)
5
+ [![PyPI](https://img.shields.io/pypi/v/mkdocs2confluence)](https://pypi.org/project/mkdocs2confluence/)
6
+ [![Downloads](https://img.shields.io/pypi/dm/mkdocs2confluence)](https://pypi.org/project/mkdocs2confluence/)
7
+ [![Latest Release](https://img.shields.io/github/v/release/jeckyl2010/mkdocs2confluence)](https://github.com/jeckyl2010/mkdocs2confluence/releases/latest)
8
+ [![CI](https://github.com/jeckyl2010/mkdocs2confluence/actions/workflows/ci.yml/badge.svg)](https://github.com/jeckyl2010/mkdocs2confluence/actions/workflows/ci.yml)
9
+ [![Release](https://github.com/jeckyl2010/mkdocs2confluence/actions/workflows/release.yml/badge.svg)](https://github.com/jeckyl2010/mkdocs2confluence/actions/workflows/release.yml)
10
+ [![codecov](https://codecov.io/gh/jeckyl2010/mkdocs2confluence/graph/badge.svg)](https://codecov.io/gh/jeckyl2010/mkdocs2confluence)
11
+ [![Ruff](https://img.shields.io/badge/code%20style-ruff-000000.svg)](https://github.com/astral-sh/ruff)
12
+ [![mypy](https://img.shields.io/badge/type--checked-mypy-blue.svg)](https://mypy-lang.org/)
13
+ [![security: bandit](https://img.shields.io/badge/security-bandit-yellow.svg)](https://github.com/PyCQA/bandit)
14
+ [![SLSA Level 3](https://slsa.dev/images/gh-badge-level3.svg)](https://slsa.dev)
15
+ [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/jeckyl2010/mkdocs2confluence/badge)](https://securityscorecards.dev/viewer/?uri=github.com/jeckyl2010/mkdocs2confluence)
16
+
17
+ A Python CLI tool that compiles MkDocs-flavoured Markdown into **native Confluence storage XHTML** and publishes it directly to Confluence Cloud. It is a **compiler/transpiler**, not an HTML converter — every construct maps to its native Confluence equivalent, so pages look and behave like hand-authored Confluence content.
18
+
19
+ It also bridges the gap between Confluence reviewers and developers: the `sync-comments` command turns open Confluence page comments into GitHub pull request review threads, and auto-resolves them in Confluence when the PR is merged.
20
+
21
+ > **Zensical compatible** — [Zensical](https://zensical.org/) is the modern successor to MkDocs + Material for MkDocs. Since it uses the same `mkdocs.yml` format and Python Markdown extensions, your Zensical project works with mk2conf today with no changes required.
22
+
23
+ ---
24
+
25
+ ## Installation
26
+
27
+ Requires Python 3.12+. The PyPI package is `mkdocs2confluence`; the CLI command is `mk2conf`.
28
+
29
+ ```bash
30
+ pip install mkdocs2confluence
31
+ # or, for an isolated install:
32
+ pipx install mkdocs2confluence
33
+ ```
34
+
35
+ **From source** (see [Setup.md](Setup.md)):
36
+
37
+ ```bash
38
+ git clone https://github.com/jeckyl2010/mkdocs2confluence.git
39
+ cd mkdocs2confluence && uv sync
40
+ ```
41
+
42
+ ---
43
+
44
+ ## GitHub Actions
45
+
46
+ Publish docs automatically on every push — no local install needed:
47
+
48
+ ```yaml
49
+ - name: Publish docs to Confluence
50
+ uses: jeckyl2010/mkdocs2confluence@v1
51
+ with:
52
+ token: ${{ secrets.CONFLUENCE_API_TOKEN }}
53
+ ```
54
+
55
+ **Full workflow** — triggers on changes to `docs/` or `mkdocs.yml`:
56
+
57
+ ```yaml
58
+ name: Publish docs
59
+
60
+ on:
61
+ push:
62
+ branches: [main]
63
+ paths: ['docs/**', 'mkdocs.yml']
64
+
65
+ jobs:
66
+ publish:
67
+ runs-on: ubuntu-latest
68
+ steps:
69
+ - uses: actions/checkout@v4
70
+ - uses: jeckyl2010/mkdocs2confluence@v1
71
+ with:
72
+ token: ${{ secrets.CONFLUENCE_API_TOKEN }}
73
+ prune: 'true'
74
+ ```
75
+
76
+ Available inputs: `token` (required), `config`, `version`, `dry-run`, `section`, `page`, `prune`, `quiet`. See [docs/commands.md](docs/commands.md) for details.
77
+
78
+ ---
79
+
80
+ ## Quick start
81
+
82
+ ```bash
83
+ # Preview a page locally (no Confluence API calls)
84
+ mk2conf preview --page index.md --watch
85
+
86
+ # Dry-run: see what would be published
87
+ mk2conf publish --dry-run
88
+
89
+ # Publish all nav pages
90
+ mk2conf publish
91
+
92
+ # Export a section to PDF
93
+ mk2conf pdf --section Guide --out guide.pdf
94
+
95
+ # Sync Confluence comments to GitHub PR review threads
96
+ mk2conf sync-comments
97
+ ```
98
+
99
+ ---
100
+
101
+ ## Configuration
102
+
103
+ Add a `confluence:` block to your `mkdocs.yml`:
104
+
105
+ ```yaml
106
+ confluence:
107
+ base_url: https://yourorg.atlassian.net
108
+ space_key: TECH
109
+ email: user@example.com
110
+ token: !ENV CONFLUENCE_API_TOKEN # never hardcode the token
111
+ parent_page_id: "123456" # optional root page
112
+ mermaid_render: kroki # "kroki" (default) | "kroki:https://your-kroki" | "none"
113
+ full_width: true # default: true
114
+ ```
115
+
116
+ The `confluence:` block is also accepted under `extra:` for MkDocs strict-mode compatibility. The API token is read from `token:` in `mkdocs.yml`, then `CONFLUENCE_API_TOKEN`, then `MK2CONF_TOKEN`.
117
+
118
+ **Your first publish:**
119
+
120
+ ```bash
121
+ export CONFLUENCE_API_TOKEN=your_api_token_here
122
+ mk2conf preview --page docs/index.md --watch # verify output locally
123
+ mk2conf publish --dry-run # check the plan
124
+ mk2conf publish # go live
125
+ ```
126
+
127
+ ---
128
+
129
+ ## Documentation
130
+
131
+ | | |
132
+ |---|---|
133
+ | [docs/commands.md](docs/commands.md) | Full flag reference for all four commands |
134
+ | [docs/features.md](docs/features.md) | Supported Markdown / Material features and known limitations |
135
+ | [Setup.md](Setup.md) | Development environment setup |
136
+
137
+ ---
138
+
139
+ ## Architecture
140
+
141
+ ![Architecture](https://raw.githubusercontent.com/jeckyl2010/mkdocs2confluence/main/docs/architecture.png)
142
+
143
+ Pipeline stages: **loader → preprocess → IR → transforms → emitter → publisher**. The plan phase makes all API read calls; the execute phase makes all write calls in nav order so parent pages always exist before their children.
144
+
145
+ ---
146
+
147
+ ## Development
148
+
149
+ ```bash
150
+ uv run pytest -q
151
+ uv run ruff check src tests
152
+ uv run mypy src
153
+ uv run vulture src --min-confidence 80
154
+ ```
155
+
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "mkdocs2confluence"
3
- version = "0.11.0"
3
+ version = "0.12.0"
4
4
  description = "Publish MkDocs Material pages to Confluence Cloud — admonitions, Mermaid diagrams, tabs, page properties and more"
5
5
  readme = "README.md"
6
6
  license = { text = "GPL-3.0-or-later" }
@@ -0,0 +1,196 @@
1
+ Metadata-Version: 2.4
2
+ Name: mkdocs2confluence
3
+ Version: 0.12.0
4
+ Summary: Publish MkDocs Material pages to Confluence Cloud — admonitions, Mermaid diagrams, tabs, page properties and more
5
+ Author: Anders Hybertz
6
+ License: GPL-3.0-or-later
7
+ Project-URL: Homepage, https://github.com/jeckyl2010/mkdocs2confluence
8
+ Project-URL: Repository, https://github.com/jeckyl2010/mkdocs2confluence
9
+ Project-URL: Issues, https://github.com/jeckyl2010/mkdocs2confluence/issues
10
+ Project-URL: Changelog, https://github.com/jeckyl2010/mkdocs2confluence/releases
11
+ Keywords: mkdocs,confluence,atlassian,documentation,publishing,material-for-mkdocs,markdown,storage-format
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Documentation
20
+ Classifier: Topic :: Software Development :: Documentation
21
+ Classifier: Topic :: Text Processing :: Markup
22
+ Classifier: Topic :: Utilities
23
+ Requires-Python: >=3.12
24
+ Description-Content-Type: text/markdown
25
+ License-File: LICENSE
26
+ Requires-Dist: PyYAML>=6.0.3
27
+ Requires-Dist: httpx>=0.27
28
+ Requires-Dist: tinycss2>=1.5.1
29
+ Provides-Extra: pdf
30
+ Requires-Dist: weasyprint>=60.0; extra == "pdf"
31
+ Provides-Extra: dev
32
+ Requires-Dist: pytest; extra == "dev"
33
+ Requires-Dist: pytest-cov; extra == "dev"
34
+ Requires-Dist: ruff; extra == "dev"
35
+ Requires-Dist: mypy; extra == "dev"
36
+ Requires-Dist: types-PyYAML; extra == "dev"
37
+ Requires-Dist: bandit; extra == "dev"
38
+ Requires-Dist: build; extra == "dev"
39
+ Requires-Dist: pre-commit; extra == "dev"
40
+ Dynamic: license-file
41
+
42
+ # mk2conf — MkDocs / Zensical to Confluence
43
+
44
+ [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
45
+ [![Python 3.12+](https://img.shields.io/badge/python-3.12+-blue.svg)](https://www.python.org/downloads/)
46
+ [![PyPI](https://img.shields.io/pypi/v/mkdocs2confluence)](https://pypi.org/project/mkdocs2confluence/)
47
+ [![Downloads](https://img.shields.io/pypi/dm/mkdocs2confluence)](https://pypi.org/project/mkdocs2confluence/)
48
+ [![Latest Release](https://img.shields.io/github/v/release/jeckyl2010/mkdocs2confluence)](https://github.com/jeckyl2010/mkdocs2confluence/releases/latest)
49
+ [![CI](https://github.com/jeckyl2010/mkdocs2confluence/actions/workflows/ci.yml/badge.svg)](https://github.com/jeckyl2010/mkdocs2confluence/actions/workflows/ci.yml)
50
+ [![Release](https://github.com/jeckyl2010/mkdocs2confluence/actions/workflows/release.yml/badge.svg)](https://github.com/jeckyl2010/mkdocs2confluence/actions/workflows/release.yml)
51
+ [![codecov](https://codecov.io/gh/jeckyl2010/mkdocs2confluence/graph/badge.svg)](https://codecov.io/gh/jeckyl2010/mkdocs2confluence)
52
+ [![Ruff](https://img.shields.io/badge/code%20style-ruff-000000.svg)](https://github.com/astral-sh/ruff)
53
+ [![mypy](https://img.shields.io/badge/type--checked-mypy-blue.svg)](https://mypy-lang.org/)
54
+ [![security: bandit](https://img.shields.io/badge/security-bandit-yellow.svg)](https://github.com/PyCQA/bandit)
55
+ [![SLSA Level 3](https://slsa.dev/images/gh-badge-level3.svg)](https://slsa.dev)
56
+ [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/jeckyl2010/mkdocs2confluence/badge)](https://securityscorecards.dev/viewer/?uri=github.com/jeckyl2010/mkdocs2confluence)
57
+
58
+ A Python CLI tool that compiles MkDocs-flavoured Markdown into **native Confluence storage XHTML** and publishes it directly to Confluence Cloud. It is a **compiler/transpiler**, not an HTML converter — every construct maps to its native Confluence equivalent, so pages look and behave like hand-authored Confluence content.
59
+
60
+ It also bridges the gap between Confluence reviewers and developers: the `sync-comments` command turns open Confluence page comments into GitHub pull request review threads, and auto-resolves them in Confluence when the PR is merged.
61
+
62
+ > **Zensical compatible** — [Zensical](https://zensical.org/) is the modern successor to MkDocs + Material for MkDocs. Since it uses the same `mkdocs.yml` format and Python Markdown extensions, your Zensical project works with mk2conf today with no changes required.
63
+
64
+ ---
65
+
66
+ ## Installation
67
+
68
+ Requires Python 3.12+. The PyPI package is `mkdocs2confluence`; the CLI command is `mk2conf`.
69
+
70
+ ```bash
71
+ pip install mkdocs2confluence
72
+ # or, for an isolated install:
73
+ pipx install mkdocs2confluence
74
+ ```
75
+
76
+ **From source** (see [Setup.md](Setup.md)):
77
+
78
+ ```bash
79
+ git clone https://github.com/jeckyl2010/mkdocs2confluence.git
80
+ cd mkdocs2confluence && uv sync
81
+ ```
82
+
83
+ ---
84
+
85
+ ## GitHub Actions
86
+
87
+ Publish docs automatically on every push — no local install needed:
88
+
89
+ ```yaml
90
+ - name: Publish docs to Confluence
91
+ uses: jeckyl2010/mkdocs2confluence@v1
92
+ with:
93
+ token: ${{ secrets.CONFLUENCE_API_TOKEN }}
94
+ ```
95
+
96
+ **Full workflow** — triggers on changes to `docs/` or `mkdocs.yml`:
97
+
98
+ ```yaml
99
+ name: Publish docs
100
+
101
+ on:
102
+ push:
103
+ branches: [main]
104
+ paths: ['docs/**', 'mkdocs.yml']
105
+
106
+ jobs:
107
+ publish:
108
+ runs-on: ubuntu-latest
109
+ steps:
110
+ - uses: actions/checkout@v4
111
+ - uses: jeckyl2010/mkdocs2confluence@v1
112
+ with:
113
+ token: ${{ secrets.CONFLUENCE_API_TOKEN }}
114
+ prune: 'true'
115
+ ```
116
+
117
+ Available inputs: `token` (required), `config`, `version`, `dry-run`, `section`, `page`, `prune`, `quiet`. See [docs/commands.md](docs/commands.md) for details.
118
+
119
+ ---
120
+
121
+ ## Quick start
122
+
123
+ ```bash
124
+ # Preview a page locally (no Confluence API calls)
125
+ mk2conf preview --page index.md --watch
126
+
127
+ # Dry-run: see what would be published
128
+ mk2conf publish --dry-run
129
+
130
+ # Publish all nav pages
131
+ mk2conf publish
132
+
133
+ # Export a section to PDF
134
+ mk2conf pdf --section Guide --out guide.pdf
135
+
136
+ # Sync Confluence comments to GitHub PR review threads
137
+ mk2conf sync-comments
138
+ ```
139
+
140
+ ---
141
+
142
+ ## Configuration
143
+
144
+ Add a `confluence:` block to your `mkdocs.yml`:
145
+
146
+ ```yaml
147
+ confluence:
148
+ base_url: https://yourorg.atlassian.net
149
+ space_key: TECH
150
+ email: user@example.com
151
+ token: !ENV CONFLUENCE_API_TOKEN # never hardcode the token
152
+ parent_page_id: "123456" # optional root page
153
+ mermaid_render: kroki # "kroki" (default) | "kroki:https://your-kroki" | "none"
154
+ full_width: true # default: true
155
+ ```
156
+
157
+ The `confluence:` block is also accepted under `extra:` for MkDocs strict-mode compatibility. The API token is read from `token:` in `mkdocs.yml`, then `CONFLUENCE_API_TOKEN`, then `MK2CONF_TOKEN`.
158
+
159
+ **Your first publish:**
160
+
161
+ ```bash
162
+ export CONFLUENCE_API_TOKEN=your_api_token_here
163
+ mk2conf preview --page docs/index.md --watch # verify output locally
164
+ mk2conf publish --dry-run # check the plan
165
+ mk2conf publish # go live
166
+ ```
167
+
168
+ ---
169
+
170
+ ## Documentation
171
+
172
+ | | |
173
+ |---|---|
174
+ | [docs/commands.md](docs/commands.md) | Full flag reference for all four commands |
175
+ | [docs/features.md](docs/features.md) | Supported Markdown / Material features and known limitations |
176
+ | [Setup.md](Setup.md) | Development environment setup |
177
+
178
+ ---
179
+
180
+ ## Architecture
181
+
182
+ ![Architecture](https://raw.githubusercontent.com/jeckyl2010/mkdocs2confluence/main/docs/architecture.png)
183
+
184
+ Pipeline stages: **loader → preprocess → IR → transforms → emitter → publisher**. The plan phase makes all API read calls; the execute phase makes all write calls in nav order so parent pages always exist before their children.
185
+
186
+ ---
187
+
188
+ ## Development
189
+
190
+ ```bash
191
+ uv run pytest -q
192
+ uv run ruff check src tests
193
+ uv run mypy src
194
+ uv run vulture src --min-confidence 80
195
+ ```
196
+
@@ -37,6 +37,7 @@ src/mkdocs_to_confluence/preview/render.py
37
37
  src/mkdocs_to_confluence/preview/server.py
38
38
  src/mkdocs_to_confluence/publisher/__init__.py
39
39
  src/mkdocs_to_confluence/publisher/client.py
40
+ src/mkdocs_to_confluence/publisher/http_retry.py
40
41
  src/mkdocs_to_confluence/publisher/pipeline.py
41
42
  src/mkdocs_to_confluence/sync/__init__.py
42
43
  src/mkdocs_to_confluence/sync/anchoring.py
@@ -33,6 +33,7 @@ class ConfluenceConfig:
33
33
  github_repo: str | None = None # "owner/repo" — required for sync-comments
34
34
  github_token: str | None = None # GitHub PAT (falls back to GITHUB_TOKEN env var)
35
35
  github_base_branch: str = "main" # base branch for review PRs
36
+ allow_any_host: bool = False # set True to allow non-Atlassian Cloud base_url hosts
36
37
 
37
38
 
38
39
  @dataclass(frozen=True)
@@ -209,6 +210,29 @@ def load_config(mkdocs_yml: Path) -> MkDocsConfig:
209
210
  if not isinstance(base_url, str) or not base_url.strip():
210
211
  raise ConfigError("mkdocs.yml: 'confluence.base_url' is required and must be a non-empty string.")
211
212
 
213
+ # Security: require HTTPS so credentials are never sent in plaintext.
214
+ parsed_url = urlparse(base_url.strip())
215
+ if parsed_url.scheme != "https":
216
+ raise ConfigError(
217
+ "mkdocs.yml: 'confluence.base_url' must use HTTPS (got "
218
+ f"{parsed_url.scheme!r}). Plain HTTP would transmit credentials in "
219
+ "cleartext."
220
+ )
221
+
222
+ allow_any_host = bool(raw_conf.get("allow_any_host", False))
223
+
224
+ # Security: guard against a repo-controlled base_url redirecting credentials
225
+ # to an attacker host. Non-Atlassian Cloud hosts require an explicit opt-in.
226
+ host = parsed_url.hostname or ""
227
+ _is_atlassian = host == "atlassian.net" or host.endswith(".atlassian.net")
228
+ if not _is_atlassian and not allow_any_host:
229
+ raise ConfigError(
230
+ f"mkdocs.yml: 'confluence.base_url' host {host!r} is not an "
231
+ "Atlassian Cloud domain (*.atlassian.net). If you are using a "
232
+ "self-hosted Confluence instance, add 'allow_any_host: true' under "
233
+ "the 'confluence:' block to acknowledge this."
234
+ )
235
+
212
236
  space_key: str | None = raw_conf.get("space_key") or None
213
237
  if space_key:
214
238
  space_key = space_key.strip() or None
@@ -248,6 +272,7 @@ def load_config(mkdocs_yml: Path) -> MkDocsConfig:
248
272
  github_token=(str(raw_conf["github_token"]) if raw_conf.get("github_token")
249
273
  else os.environ.get("GITHUB_TOKEN") or None),
250
274
  github_base_branch=str(raw_conf.get("github_base_branch", "main")),
275
+ allow_any_host=allow_any_host,
251
276
  )
252
277
 
253
278
  # --- extra_css (optional) ---
@@ -220,7 +220,14 @@ def _traverse(nav: list[Any], docs_dir: Path, level: int, nav_file: str = ".page
220
220
  elif isinstance(value, str):
221
221
  # Could be a page file or a directory reference (awesome-pages style)
222
222
  target = (docs_dir / value).resolve()
223
- if target.is_dir():
223
+ docs_root = docs_dir.resolve()
224
+ if not target.is_relative_to(docs_root):
225
+ warnings.warn(
226
+ f"Nav page '{title}' resolves outside docs_dir ('{target}') — "
227
+ "it will be omitted from the resolved nav.",
228
+ stacklevel=4,
229
+ )
230
+ elif target.is_dir():
224
231
  children = _resolve_nav_dir(target, docs_dir, level + 1, nav_file)
225
232
  nodes.append(
226
233
  NavNode(