mkdocs2confluence 0.5.28__tar.gz → 0.6.1__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.
- {mkdocs2confluence-0.5.28/src/mkdocs2confluence.egg-info → mkdocs2confluence-0.6.1}/PKG-INFO +18 -3
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/README.md +17 -2
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/pyproject.toml +9 -2
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1/src/mkdocs2confluence.egg-info}/PKG-INFO +18 -3
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/src/mkdocs_to_confluence/cli.py +13 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/src/mkdocs_to_confluence/loader/config.py +1 -1
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/src/mkdocs_to_confluence/loader/nav.py +1 -3
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/src/mkdocs_to_confluence/preprocess/includes.py +1 -1
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/src/mkdocs_to_confluence/publisher/client.py +64 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/src/mkdocs_to_confluence/publisher/pipeline.py +225 -131
- mkdocs2confluence-0.6.1/tests/test_images.py +320 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/tests/test_preprocess.py +11 -1
- mkdocs2confluence-0.6.1/tests/test_preview.py +326 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/tests/test_publish_client.py +237 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/tests/test_publish_config.py +152 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/tests/test_publish_pipeline.py +887 -0
- mkdocs2confluence-0.5.28/tests/test_images.py +0 -160
- mkdocs2confluence-0.5.28/tests/test_preview.py +0 -133
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/LICENSE +0 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/setup.cfg +0 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/src/mkdocs2confluence.egg-info/SOURCES.txt +0 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/src/mkdocs2confluence.egg-info/dependency_links.txt +0 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/src/mkdocs2confluence.egg-info/entry_points.txt +0 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/src/mkdocs2confluence.egg-info/requires.txt +0 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/src/mkdocs2confluence.egg-info/top_level.txt +0 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/src/mkdocs_to_confluence/__init__.py +0 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/src/mkdocs_to_confluence/emitter/__init__.py +0 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/src/mkdocs_to_confluence/emitter/xhtml.py +0 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/src/mkdocs_to_confluence/ir/__init__.py +0 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/src/mkdocs_to_confluence/ir/document.py +0 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/src/mkdocs_to_confluence/ir/nodes.py +0 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/src/mkdocs_to_confluence/ir/treeutil.py +0 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/src/mkdocs_to_confluence/loader/__init__.py +0 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/src/mkdocs_to_confluence/loader/extra_css.py +0 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/src/mkdocs_to_confluence/loader/page.py +0 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/src/mkdocs_to_confluence/parser/__init__.py +0 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/src/mkdocs_to_confluence/parser/markdown.py +0 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/src/mkdocs_to_confluence/preprocess/__init__.py +0 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/src/mkdocs_to_confluence/preprocess/abbrevs.py +0 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/src/mkdocs_to_confluence/preprocess/fence.py +0 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/src/mkdocs_to_confluence/preprocess/frontmatter.py +0 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/src/mkdocs_to_confluence/preprocess/icons.py +0 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/src/mkdocs_to_confluence/preprocess/linkdefs.py +0 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/src/mkdocs_to_confluence/preview/__init__.py +0 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/src/mkdocs_to_confluence/preview/render.py +0 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/src/mkdocs_to_confluence/publisher/__init__.py +0 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/src/mkdocs_to_confluence/transforms/__init__.py +0 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/src/mkdocs_to_confluence/transforms/abbrevs.py +0 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/src/mkdocs_to_confluence/transforms/assets.py +0 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/src/mkdocs_to_confluence/transforms/editlink.py +0 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/src/mkdocs_to_confluence/transforms/images.py +0 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/src/mkdocs_to_confluence/transforms/internallinks.py +0 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/src/mkdocs_to_confluence/transforms/mermaid.py +0 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/tests/test_abbrevs.py +0 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/tests/test_editlink.py +0 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/tests/test_emitter.py +0 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/tests/test_extra_css.py +0 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/tests/test_frontmatter.py +0 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/tests/test_icons.py +0 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/tests/test_internallinks.py +0 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/tests/test_ir.py +0 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/tests/test_linkdefs.py +0 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/tests/test_loader.py +0 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/tests/test_mermaid.py +0 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/tests/test_page_loader.py +0 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/tests/test_parser.py +0 -0
- {mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/tests/test_treeutil.py +0 -0
{mkdocs2confluence-0.5.28/src/mkdocs2confluence.egg-info → mkdocs2confluence-0.6.1}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mkdocs2confluence
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.1
|
|
4
4
|
Summary: Publish MkDocs Material pages to Confluence Cloud — admonitions, Mermaid diagrams, tabs, page properties and more
|
|
5
5
|
Author: Anders Hybertz
|
|
6
6
|
License: GPL-3.0-or-later
|
|
@@ -41,6 +41,7 @@ Dynamic: license-file
|
|
|
41
41
|
[](https://www.gnu.org/licenses/gpl-3.0)
|
|
42
42
|
[](https://www.python.org/downloads/)
|
|
43
43
|
[](https://pypi.org/project/mkdocs2confluence/)
|
|
44
|
+
[](https://pypi.org/project/mkdocs2confluence/)
|
|
44
45
|
[](https://github.com/jeckyl2010/mkdocs2confluence/releases/latest)
|
|
45
46
|
[](https://github.com/jeckyl2010/mkdocs2confluence/actions/workflows/ci.yml)
|
|
46
47
|
[](https://github.com/jeckyl2010/mkdocs2confluence/actions/workflows/release.yml)
|
|
@@ -133,7 +134,7 @@ The `--html` flag renders Confluence macros as visual HTML panels so you can rev
|
|
|
133
134
|
Compile all pages listed in `nav:` and publish them to Confluence Cloud.
|
|
134
135
|
|
|
135
136
|
```
|
|
136
|
-
mk2conf publish [--config PATH] [--page PATH] [--section PATH] [--dry-run] [--report FILE]
|
|
137
|
+
mk2conf publish [--config PATH] [--page PATH] [--section PATH] [--dry-run] [--report FILE] [--prune]
|
|
137
138
|
```
|
|
138
139
|
|
|
139
140
|
| Flag | Default | Description |
|
|
@@ -143,6 +144,7 @@ mk2conf publish [--config PATH] [--page PATH] [--section PATH] [--dry-run] [--re
|
|
|
143
144
|
| `--section PATH` | *(whole nav)* | Publish only a nav subtree (e.g. `Guide` or `Guide/Setup`) |
|
|
144
145
|
| `--dry-run` | off | Print the publish plan without making any API calls |
|
|
145
146
|
| `--report FILE` | *(none)* | Write a JSON publish report to `FILE` |
|
|
147
|
+
| `--prune` | off | Delete managed Confluence pages no longer in `nav:` (see [Orphan pruning](#orphan-pruning)) |
|
|
146
148
|
|
|
147
149
|
#### Configuration
|
|
148
150
|
|
|
@@ -171,6 +173,19 @@ The API token is read from (in priority order):
|
|
|
171
173
|
- Section nodes (nav groups without a page) become empty parent pages in Confluence, mirroring the nav hierarchy.
|
|
172
174
|
- All locally linked assets are uploaded as Confluence page attachments automatically.
|
|
173
175
|
- **Smart update detection** — before calling the Confluence update API, mk2conf compares a `sha256` hash of the compiled output against the hash stored from the previous run (kept as a hidden Confluence page property `mk2conf-content-hash`). Pages whose content has not changed are skipped entirely — no version bump, no watcher notification.
|
|
176
|
+
- **Orphan pruning** — every page created by mk2conf is stamped with a hidden `mk2conf-managed` property. Pass `--prune` to automatically delete managed pages that have been removed from `nav:`. Manually-created Confluence pages are never deleted.
|
|
177
|
+
|
|
178
|
+
#### Orphan pruning
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
mk2conf publish --prune
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
After each publish run, `--prune` fetches all descendants of the configured `parent_page_id`, diffs them against the pages just published, and deletes any managed orphans — i.e. pages that carry the `mk2conf-managed` stamp but are no longer in the MkDocs nav.
|
|
185
|
+
|
|
186
|
+
> **Safety:** Only pages stamped by mk2conf are eligible for deletion. Any page created directly in Confluence will never be touched, even if it sits inside the managed hierarchy.
|
|
187
|
+
>
|
|
188
|
+
> **Partial runs:** `--prune` is silently ignored when `--page` or `--section` is used, because a partial publish would only cover a subset of the nav and would incorrectly identify out-of-scope pages as orphans.
|
|
174
189
|
|
|
175
190
|
#### Mermaid rendering
|
|
176
191
|
|
|
@@ -321,7 +336,7 @@ Any unrecognised block is preserved as a visible `warning` macro — no content
|
|
|
321
336
|
|
|
322
337
|
## Roadmap
|
|
323
338
|
|
|
324
|
-
- [
|
|
339
|
+
- [x] **Delete orphaned pages** — `--prune` detects and removes managed Confluence pages that have been removed from `nav:`. Manually-created pages are never deleted.
|
|
325
340
|
|
|
326
341
|
---
|
|
327
342
|
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
[](https://www.gnu.org/licenses/gpl-3.0)
|
|
4
4
|
[](https://www.python.org/downloads/)
|
|
5
5
|
[](https://pypi.org/project/mkdocs2confluence/)
|
|
6
|
+
[](https://pypi.org/project/mkdocs2confluence/)
|
|
6
7
|
[](https://github.com/jeckyl2010/mkdocs2confluence/releases/latest)
|
|
7
8
|
[](https://github.com/jeckyl2010/mkdocs2confluence/actions/workflows/ci.yml)
|
|
8
9
|
[](https://github.com/jeckyl2010/mkdocs2confluence/actions/workflows/release.yml)
|
|
@@ -95,7 +96,7 @@ The `--html` flag renders Confluence macros as visual HTML panels so you can rev
|
|
|
95
96
|
Compile all pages listed in `nav:` and publish them to Confluence Cloud.
|
|
96
97
|
|
|
97
98
|
```
|
|
98
|
-
mk2conf publish [--config PATH] [--page PATH] [--section PATH] [--dry-run] [--report FILE]
|
|
99
|
+
mk2conf publish [--config PATH] [--page PATH] [--section PATH] [--dry-run] [--report FILE] [--prune]
|
|
99
100
|
```
|
|
100
101
|
|
|
101
102
|
| Flag | Default | Description |
|
|
@@ -105,6 +106,7 @@ mk2conf publish [--config PATH] [--page PATH] [--section PATH] [--dry-run] [--re
|
|
|
105
106
|
| `--section PATH` | *(whole nav)* | Publish only a nav subtree (e.g. `Guide` or `Guide/Setup`) |
|
|
106
107
|
| `--dry-run` | off | Print the publish plan without making any API calls |
|
|
107
108
|
| `--report FILE` | *(none)* | Write a JSON publish report to `FILE` |
|
|
109
|
+
| `--prune` | off | Delete managed Confluence pages no longer in `nav:` (see [Orphan pruning](#orphan-pruning)) |
|
|
108
110
|
|
|
109
111
|
#### Configuration
|
|
110
112
|
|
|
@@ -133,6 +135,19 @@ The API token is read from (in priority order):
|
|
|
133
135
|
- Section nodes (nav groups without a page) become empty parent pages in Confluence, mirroring the nav hierarchy.
|
|
134
136
|
- All locally linked assets are uploaded as Confluence page attachments automatically.
|
|
135
137
|
- **Smart update detection** — before calling the Confluence update API, mk2conf compares a `sha256` hash of the compiled output against the hash stored from the previous run (kept as a hidden Confluence page property `mk2conf-content-hash`). Pages whose content has not changed are skipped entirely — no version bump, no watcher notification.
|
|
138
|
+
- **Orphan pruning** — every page created by mk2conf is stamped with a hidden `mk2conf-managed` property. Pass `--prune` to automatically delete managed pages that have been removed from `nav:`. Manually-created Confluence pages are never deleted.
|
|
139
|
+
|
|
140
|
+
#### Orphan pruning
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
mk2conf publish --prune
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
After each publish run, `--prune` fetches all descendants of the configured `parent_page_id`, diffs them against the pages just published, and deletes any managed orphans — i.e. pages that carry the `mk2conf-managed` stamp but are no longer in the MkDocs nav.
|
|
147
|
+
|
|
148
|
+
> **Safety:** Only pages stamped by mk2conf are eligible for deletion. Any page created directly in Confluence will never be touched, even if it sits inside the managed hierarchy.
|
|
149
|
+
>
|
|
150
|
+
> **Partial runs:** `--prune` is silently ignored when `--page` or `--section` is used, because a partial publish would only cover a subset of the nav and would incorrectly identify out-of-scope pages as orphans.
|
|
136
151
|
|
|
137
152
|
#### Mermaid rendering
|
|
138
153
|
|
|
@@ -283,7 +298,7 @@ Any unrecognised block is preserved as a visible `warning` macro — no content
|
|
|
283
298
|
|
|
284
299
|
## Roadmap
|
|
285
300
|
|
|
286
|
-
- [
|
|
301
|
+
- [x] **Delete orphaned pages** — `--prune` detects and removes managed Confluence pages that have been removed from `nav:`. Manually-created pages are never deleted.
|
|
287
302
|
|
|
288
303
|
---
|
|
289
304
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "mkdocs2confluence"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.6.1"
|
|
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" }
|
|
@@ -88,4 +88,11 @@ exclude_lines = [
|
|
|
88
88
|
"pragma: no cover",
|
|
89
89
|
"if TYPE_CHECKING:",
|
|
90
90
|
"raise NotImplementedError",
|
|
91
|
-
]
|
|
91
|
+
]
|
|
92
|
+
|
|
93
|
+
[dependency-groups]
|
|
94
|
+
dev = [
|
|
95
|
+
"pip-audit>=2.10.0",
|
|
96
|
+
"radon>=6.0.1",
|
|
97
|
+
"vulture>=2.16",
|
|
98
|
+
]
|
{mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1/src/mkdocs2confluence.egg-info}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mkdocs2confluence
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.1
|
|
4
4
|
Summary: Publish MkDocs Material pages to Confluence Cloud — admonitions, Mermaid diagrams, tabs, page properties and more
|
|
5
5
|
Author: Anders Hybertz
|
|
6
6
|
License: GPL-3.0-or-later
|
|
@@ -41,6 +41,7 @@ Dynamic: license-file
|
|
|
41
41
|
[](https://www.gnu.org/licenses/gpl-3.0)
|
|
42
42
|
[](https://www.python.org/downloads/)
|
|
43
43
|
[](https://pypi.org/project/mkdocs2confluence/)
|
|
44
|
+
[](https://pypi.org/project/mkdocs2confluence/)
|
|
44
45
|
[](https://github.com/jeckyl2010/mkdocs2confluence/releases/latest)
|
|
45
46
|
[](https://github.com/jeckyl2010/mkdocs2confluence/actions/workflows/ci.yml)
|
|
46
47
|
[](https://github.com/jeckyl2010/mkdocs2confluence/actions/workflows/release.yml)
|
|
@@ -133,7 +134,7 @@ The `--html` flag renders Confluence macros as visual HTML panels so you can rev
|
|
|
133
134
|
Compile all pages listed in `nav:` and publish them to Confluence Cloud.
|
|
134
135
|
|
|
135
136
|
```
|
|
136
|
-
mk2conf publish [--config PATH] [--page PATH] [--section PATH] [--dry-run] [--report FILE]
|
|
137
|
+
mk2conf publish [--config PATH] [--page PATH] [--section PATH] [--dry-run] [--report FILE] [--prune]
|
|
137
138
|
```
|
|
138
139
|
|
|
139
140
|
| Flag | Default | Description |
|
|
@@ -143,6 +144,7 @@ mk2conf publish [--config PATH] [--page PATH] [--section PATH] [--dry-run] [--re
|
|
|
143
144
|
| `--section PATH` | *(whole nav)* | Publish only a nav subtree (e.g. `Guide` or `Guide/Setup`) |
|
|
144
145
|
| `--dry-run` | off | Print the publish plan without making any API calls |
|
|
145
146
|
| `--report FILE` | *(none)* | Write a JSON publish report to `FILE` |
|
|
147
|
+
| `--prune` | off | Delete managed Confluence pages no longer in `nav:` (see [Orphan pruning](#orphan-pruning)) |
|
|
146
148
|
|
|
147
149
|
#### Configuration
|
|
148
150
|
|
|
@@ -171,6 +173,19 @@ The API token is read from (in priority order):
|
|
|
171
173
|
- Section nodes (nav groups without a page) become empty parent pages in Confluence, mirroring the nav hierarchy.
|
|
172
174
|
- All locally linked assets are uploaded as Confluence page attachments automatically.
|
|
173
175
|
- **Smart update detection** — before calling the Confluence update API, mk2conf compares a `sha256` hash of the compiled output against the hash stored from the previous run (kept as a hidden Confluence page property `mk2conf-content-hash`). Pages whose content has not changed are skipped entirely — no version bump, no watcher notification.
|
|
176
|
+
- **Orphan pruning** — every page created by mk2conf is stamped with a hidden `mk2conf-managed` property. Pass `--prune` to automatically delete managed pages that have been removed from `nav:`. Manually-created Confluence pages are never deleted.
|
|
177
|
+
|
|
178
|
+
#### Orphan pruning
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
mk2conf publish --prune
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
After each publish run, `--prune` fetches all descendants of the configured `parent_page_id`, diffs them against the pages just published, and deletes any managed orphans — i.e. pages that carry the `mk2conf-managed` stamp but are no longer in the MkDocs nav.
|
|
185
|
+
|
|
186
|
+
> **Safety:** Only pages stamped by mk2conf are eligible for deletion. Any page created directly in Confluence will never be touched, even if it sits inside the managed hierarchy.
|
|
187
|
+
>
|
|
188
|
+
> **Partial runs:** `--prune` is silently ignored when `--page` or `--section` is used, because a partial publish would only cover a subset of the nav and would incorrectly identify out-of-scope pages as orphans.
|
|
174
189
|
|
|
175
190
|
#### Mermaid rendering
|
|
176
191
|
|
|
@@ -321,7 +336,7 @@ Any unrecognised block is preserved as a visible `warning` macro — no content
|
|
|
321
336
|
|
|
322
337
|
## Roadmap
|
|
323
338
|
|
|
324
|
-
- [
|
|
339
|
+
- [x] **Delete orphaned pages** — `--prune` detects and removes managed Confluence pages that have been removed from `nav:`. Manually-created pages are never deleted.
|
|
325
340
|
|
|
326
341
|
---
|
|
327
342
|
|
|
@@ -115,6 +115,15 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
115
115
|
default=None,
|
|
116
116
|
help="Write a JSON publish report to FILE after the run.",
|
|
117
117
|
)
|
|
118
|
+
publish.add_argument(
|
|
119
|
+
"--prune",
|
|
120
|
+
action="store_true",
|
|
121
|
+
help=(
|
|
122
|
+
"Delete managed Confluence pages that are no longer in the MkDocs nav. "
|
|
123
|
+
"Only pages stamped by mk2conf are eligible — manually-created pages are never deleted. "
|
|
124
|
+
"Ignored when --page or --section is used."
|
|
125
|
+
),
|
|
126
|
+
)
|
|
118
127
|
|
|
119
128
|
return parser
|
|
120
129
|
|
|
@@ -308,10 +317,14 @@ def _cmd_publish(args: argparse.Namespace) -> None:
|
|
|
308
317
|
)
|
|
309
318
|
sys.exit(1)
|
|
310
319
|
plan = plan_publish(nav_nodes, client, config, conf_config, space_id=space_id)
|
|
320
|
+
# --prune is silently disabled for partial publishes (--page / --section)
|
|
321
|
+
# because published_ids would only cover the subset, not the full nav.
|
|
322
|
+
partial = bool(getattr(args, "page", None) or getattr(args, "section", None))
|
|
311
323
|
report = execute_publish(
|
|
312
324
|
plan, client, dry_run=False, space_id=space_id,
|
|
313
325
|
docs_dir=config.docs_dir, full_width=conf_config.full_width,
|
|
314
326
|
root_page_id=conf_config.parent_page_id,
|
|
327
|
+
prune=getattr(args, "prune", False) and not partial,
|
|
315
328
|
)
|
|
316
329
|
except ConfluenceError as exc:
|
|
317
330
|
print(f"error: {exc}", file=sys.stderr)
|
{mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/src/mkdocs_to_confluence/loader/config.py
RENAMED
|
@@ -107,7 +107,7 @@ def _make_env_loader() -> type[yaml.SafeLoader]:
|
|
|
107
107
|
|
|
108
108
|
# Catch-all: any other unknown tag (e.g. !!python/name:... used by
|
|
109
109
|
# MkDocs Material) is silently ignored — we only care about nav/site_name.
|
|
110
|
-
def _ignore(loader: yaml.SafeLoader,
|
|
110
|
+
def _ignore(loader: yaml.SafeLoader, _tag_suffix: str, node: yaml.Node) -> None:
|
|
111
111
|
return None
|
|
112
112
|
|
|
113
113
|
_Loader.add_multi_constructor("", _ignore) # type: ignore[no-untyped-call]
|
|
@@ -39,7 +39,7 @@ class NavNode:
|
|
|
39
39
|
return self.docs_path is not None
|
|
40
40
|
|
|
41
41
|
|
|
42
|
-
def resolve_nav(config: MkDocsConfig
|
|
42
|
+
def resolve_nav(config: MkDocsConfig) -> list[NavNode]:
|
|
43
43
|
"""Resolve *config.nav* into a list of top-level :class:`NavNode` objects.
|
|
44
44
|
|
|
45
45
|
When ``config.nav`` is ``None`` (e.g. projects using ``awesome-pages`` or
|
|
@@ -48,8 +48,6 @@ def resolve_nav(config: MkDocsConfig, mkdocs_root: Path | None = None) -> list[N
|
|
|
48
48
|
|
|
49
49
|
Args:
|
|
50
50
|
config: Parsed :class:`~mkdocs_to_confluence.loader.config.MkDocsConfig`.
|
|
51
|
-
mkdocs_root: Directory containing ``mkdocs.yml``. Used only to compute
|
|
52
|
-
``docs_dir`` when it is not already absolute; defaults to CWD.
|
|
53
51
|
|
|
54
52
|
Returns:
|
|
55
53
|
List of top-level :class:`NavNode` instances.
|
{mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/src/mkdocs_to_confluence/preprocess/includes.py
RENAMED
|
@@ -290,7 +290,7 @@ def _resolve_include_path(rel_path: str, source_path: Path, docs_dir: Path) -> P
|
|
|
290
290
|
"""
|
|
291
291
|
for base in (docs_dir, source_path.parent):
|
|
292
292
|
candidate = (base / rel_path).resolve()
|
|
293
|
-
if candidate.is_file():
|
|
293
|
+
if candidate.is_file() and candidate.is_relative_to(base.resolve()):
|
|
294
294
|
return candidate
|
|
295
295
|
return None
|
|
296
296
|
|
{mkdocs2confluence-0.5.28 → mkdocs2confluence-0.6.1}/src/mkdocs_to_confluence/publisher/client.py
RENAMED
|
@@ -9,12 +9,20 @@ from __future__ import annotations
|
|
|
9
9
|
import base64
|
|
10
10
|
from pathlib import Path
|
|
11
11
|
from typing import Any, cast
|
|
12
|
+
from urllib.parse import parse_qs, urlparse
|
|
12
13
|
|
|
13
14
|
import httpx
|
|
14
15
|
|
|
15
16
|
from mkdocs_to_confluence.loader.config import ConfluenceConfig
|
|
16
17
|
|
|
17
18
|
|
|
19
|
+
def _extract_cursor(next_url: str) -> str:
|
|
20
|
+
"""Extract the ``cursor`` query parameter from a pagination ``next`` URL."""
|
|
21
|
+
qs = parse_qs(urlparse(next_url).query)
|
|
22
|
+
cursors = qs.get("cursor", [])
|
|
23
|
+
return cursors[0] if cursors else ""
|
|
24
|
+
|
|
25
|
+
|
|
18
26
|
class ConfluenceError(RuntimeError):
|
|
19
27
|
"""Raised when the Confluence API returns an unexpected response."""
|
|
20
28
|
|
|
@@ -409,3 +417,59 @@ class ConfluenceClient:
|
|
|
409
417
|
headers={"X-Atlassian-Token": "no-check"},
|
|
410
418
|
)
|
|
411
419
|
self._raise_for_status(resp, f"upload_attachment({filename!r})")
|
|
420
|
+
|
|
421
|
+
# ── Orphan detection ───────────────────────────────────────────────────────
|
|
422
|
+
|
|
423
|
+
def stamp_managed(self, page_id: str) -> None:
|
|
424
|
+
"""Mark *page_id* as managed by mk2conf via a v2 content property.
|
|
425
|
+
|
|
426
|
+
The property ``mk2conf-managed`` is set to ``true`` on first publish and
|
|
427
|
+
never updated. It is used by :meth:`is_managed` to distinguish pages
|
|
428
|
+
created by mk2conf from manually-created Confluence pages.
|
|
429
|
+
|
|
430
|
+
Errors are swallowed — this is a best-effort stamp and must never block
|
|
431
|
+
a publish.
|
|
432
|
+
"""
|
|
433
|
+
url = self._v2(f"/pages/{page_id}/properties/mk2conf-managed")
|
|
434
|
+
get_resp = self._http.get(url)
|
|
435
|
+
if get_resp.status_code == 200:
|
|
436
|
+
return # already stamped
|
|
437
|
+
self._http.post(
|
|
438
|
+
self._v2(f"/pages/{page_id}/properties"),
|
|
439
|
+
json={"key": "mk2conf-managed", "value": True},
|
|
440
|
+
)
|
|
441
|
+
|
|
442
|
+
def get_descendant_ids(self, page_id: str) -> list[str]:
|
|
443
|
+
"""Return all descendant page IDs under *page_id* at all depths.
|
|
444
|
+
|
|
445
|
+
Uses ``GET /wiki/api/v2/pages/{id}/descendants?depth=all``.
|
|
446
|
+
Paginates automatically via cursor. Returns page IDs only — callers
|
|
447
|
+
that need to filter by managed status use :meth:`is_managed`.
|
|
448
|
+
"""
|
|
449
|
+
ids: list[str] = []
|
|
450
|
+
url = self._v2(f"/pages/{page_id}/descendants")
|
|
451
|
+
params: dict[str, str | int] = {"depth": "all", "limit": 250}
|
|
452
|
+
while True:
|
|
453
|
+
resp = self._http.get(url, params=params)
|
|
454
|
+
self._raise_for_status(resp, f"get_descendant_ids({page_id!r})")
|
|
455
|
+
data = resp.json()
|
|
456
|
+
for item in data.get("results", []):
|
|
457
|
+
if item.get("type") == "page":
|
|
458
|
+
ids.append(str(item["id"]))
|
|
459
|
+
next_url = data.get("_links", {}).get("next")
|
|
460
|
+
if not next_url:
|
|
461
|
+
break
|
|
462
|
+
# next_url is an absolute path — extract cursor and re-request
|
|
463
|
+
url = self._v2(f"/pages/{page_id}/descendants")
|
|
464
|
+
params = {"depth": "all", "limit": 250, "cursor": _extract_cursor(next_url)}
|
|
465
|
+
return ids
|
|
466
|
+
|
|
467
|
+
def is_managed(self, page_id: str) -> bool:
|
|
468
|
+
"""Return ``True`` if *page_id* has the ``mk2conf-managed`` property."""
|
|
469
|
+
resp = self._http.get(self._v2(f"/pages/{page_id}/properties/mk2conf-managed"))
|
|
470
|
+
return resp.status_code == 200
|
|
471
|
+
|
|
472
|
+
def delete_page(self, page_id: str) -> None:
|
|
473
|
+
"""Permanently delete *page_id* from Confluence."""
|
|
474
|
+
resp = self._http.delete(self._v2(f"/pages/{page_id}"))
|
|
475
|
+
self._raise_for_status(resp, f"delete_page({page_id!r})")
|