mkdocs2confluence 0.8.1__tar.gz → 0.8.3__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 (84) hide show
  1. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/PKG-INFO +3 -3
  2. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/README.md +2 -2
  3. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/pyproject.toml +1 -1
  4. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/src/mkdocs2confluence.egg-info/PKG-INFO +3 -3
  5. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/src/mkdocs_to_confluence/cli.py +25 -17
  6. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/tests/test_cli.py +57 -1
  7. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/LICENSE +0 -0
  8. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/setup.cfg +0 -0
  9. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/src/mkdocs2confluence.egg-info/SOURCES.txt +0 -0
  10. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/src/mkdocs2confluence.egg-info/dependency_links.txt +0 -0
  11. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/src/mkdocs2confluence.egg-info/entry_points.txt +0 -0
  12. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/src/mkdocs2confluence.egg-info/requires.txt +0 -0
  13. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/src/mkdocs2confluence.egg-info/top_level.txt +0 -0
  14. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/src/mkdocs_to_confluence/__init__.py +0 -0
  15. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/src/mkdocs_to_confluence/emitter/__init__.py +0 -0
  16. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/src/mkdocs_to_confluence/emitter/xhtml.py +0 -0
  17. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/src/mkdocs_to_confluence/ir/__init__.py +0 -0
  18. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/src/mkdocs_to_confluence/ir/document.py +0 -0
  19. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/src/mkdocs_to_confluence/ir/nodes.py +0 -0
  20. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/src/mkdocs_to_confluence/ir/treeutil.py +0 -0
  21. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/src/mkdocs_to_confluence/loader/__init__.py +0 -0
  22. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/src/mkdocs_to_confluence/loader/config.py +0 -0
  23. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/src/mkdocs_to_confluence/loader/extra_css.py +0 -0
  24. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/src/mkdocs_to_confluence/loader/nav.py +0 -0
  25. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/src/mkdocs_to_confluence/loader/page.py +0 -0
  26. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/src/mkdocs_to_confluence/parser/__init__.py +0 -0
  27. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/src/mkdocs_to_confluence/parser/markdown.py +0 -0
  28. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/src/mkdocs_to_confluence/pdf/__init__.py +0 -0
  29. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/src/mkdocs_to_confluence/pdf/generator.py +0 -0
  30. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/src/mkdocs_to_confluence/pdf/render.py +0 -0
  31. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/src/mkdocs_to_confluence/preprocess/__init__.py +0 -0
  32. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/src/mkdocs_to_confluence/preprocess/abbrevs.py +0 -0
  33. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/src/mkdocs_to_confluence/preprocess/fence.py +0 -0
  34. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/src/mkdocs_to_confluence/preprocess/frontmatter.py +0 -0
  35. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/src/mkdocs_to_confluence/preprocess/icons.py +0 -0
  36. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/src/mkdocs_to_confluence/preprocess/includes.py +0 -0
  37. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/src/mkdocs_to_confluence/preprocess/linkdefs.py +0 -0
  38. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/src/mkdocs_to_confluence/preview/__init__.py +0 -0
  39. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/src/mkdocs_to_confluence/preview/render.py +0 -0
  40. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/src/mkdocs_to_confluence/preview/server.py +0 -0
  41. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/src/mkdocs_to_confluence/publisher/__init__.py +0 -0
  42. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/src/mkdocs_to_confluence/publisher/client.py +0 -0
  43. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/src/mkdocs_to_confluence/publisher/pipeline.py +0 -0
  44. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/src/mkdocs_to_confluence/sync/__init__.py +0 -0
  45. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/src/mkdocs_to_confluence/sync/anchoring.py +0 -0
  46. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/src/mkdocs_to_confluence/sync/command.py +0 -0
  47. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/src/mkdocs_to_confluence/sync/comments.py +0 -0
  48. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/src/mkdocs_to_confluence/sync/github.py +0 -0
  49. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/src/mkdocs_to_confluence/sync/platform.py +0 -0
  50. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/src/mkdocs_to_confluence/sync/state.py +0 -0
  51. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/src/mkdocs_to_confluence/transforms/__init__.py +0 -0
  52. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/src/mkdocs_to_confluence/transforms/abbrevs.py +0 -0
  53. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/src/mkdocs_to_confluence/transforms/assets.py +0 -0
  54. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/src/mkdocs_to_confluence/transforms/editlink.py +0 -0
  55. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/src/mkdocs_to_confluence/transforms/images.py +0 -0
  56. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/src/mkdocs_to_confluence/transforms/internallinks.py +0 -0
  57. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/src/mkdocs_to_confluence/transforms/mermaid.py +0 -0
  58. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/tests/test_abbrevs.py +0 -0
  59. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/tests/test_editlink.py +0 -0
  60. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/tests/test_emitter.py +0 -0
  61. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/tests/test_extra_css.py +0 -0
  62. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/tests/test_frontmatter.py +0 -0
  63. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/tests/test_icons.py +0 -0
  64. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/tests/test_images.py +0 -0
  65. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/tests/test_internallinks.py +0 -0
  66. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/tests/test_ir.py +0 -0
  67. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/tests/test_linkdefs.py +0 -0
  68. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/tests/test_loader.py +0 -0
  69. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/tests/test_mermaid.py +0 -0
  70. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/tests/test_page_loader.py +0 -0
  71. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/tests/test_parser.py +0 -0
  72. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/tests/test_pdf.py +0 -0
  73. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/tests/test_preprocess.py +0 -0
  74. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/tests/test_preview.py +0 -0
  75. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/tests/test_publish_client.py +0 -0
  76. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/tests/test_publish_config.py +0 -0
  77. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/tests/test_publish_pipeline.py +0 -0
  78. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/tests/test_server.py +0 -0
  79. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/tests/test_sync_anchoring.py +0 -0
  80. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/tests/test_sync_command.py +0 -0
  81. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/tests/test_sync_comments.py +0 -0
  82. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/tests/test_sync_github.py +0 -0
  83. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/tests/test_sync_state.py +0 -0
  84. {mkdocs2confluence-0.8.1 → mkdocs2confluence-0.8.3}/tests/test_treeutil.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mkdocs2confluence
3
- Version: 0.8.1
3
+ Version: 0.8.3
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
@@ -326,7 +326,7 @@ confluence:
326
326
 
327
327
  **Workflow:**
328
328
 
329
- 1. Run `mk2conf publish` firstgenerates `.mk2conf-pages.json` mapping source files to Confluence page IDs.
329
+ 1. Run `mk2conf publish` (full or partial) writes/merges `.mk2conf-pages.json` mapping source files to Confluence page IDs. Every publish run merges into this file, so partial `--page` / `--section` runs and multiple configs in the same repo all accumulate correctly.
330
330
  2. Run `mk2conf sync-comments` — for each page with open Confluence comments, creates a `mk2conf/review/{slug}` branch and PR, then posts each comment as a GitHub review thread. Inline comments with a text selection are anchored to the matching source line; page-level comments fall back to file-level review threads. Every thread body includes a **View in Confluence** deep-link that opens Confluence focused on the exact comment.
331
331
  3. Developer addresses feedback on the branch, pushes changes, and merges the PR.
332
332
  4. Run `mk2conf sync-comments --check-merges` — detects merged PRs, adds a resolution reply to each Confluence comment with the commit info, and marks the comments as resolved.
@@ -335,7 +335,7 @@ confluence:
335
335
 
336
336
  | File | Purpose |
337
337
  |---|---|
338
- | `.mk2conf-pages.json` | Source path → Confluence page ID map, written after each `publish` |
338
+ | `.mk2conf-pages.json` | Source path → Confluence page ID map, merged after each `publish` run |
339
339
  | `.mk2conf-sync-state.json` | Tracks open/merged review PRs and their associated comment IDs |
340
340
 
341
341
  ---
@@ -286,7 +286,7 @@ confluence:
286
286
 
287
287
  **Workflow:**
288
288
 
289
- 1. Run `mk2conf publish` firstgenerates `.mk2conf-pages.json` mapping source files to Confluence page IDs.
289
+ 1. Run `mk2conf publish` (full or partial) writes/merges `.mk2conf-pages.json` mapping source files to Confluence page IDs. Every publish run merges into this file, so partial `--page` / `--section` runs and multiple configs in the same repo all accumulate correctly.
290
290
  2. Run `mk2conf sync-comments` — for each page with open Confluence comments, creates a `mk2conf/review/{slug}` branch and PR, then posts each comment as a GitHub review thread. Inline comments with a text selection are anchored to the matching source line; page-level comments fall back to file-level review threads. Every thread body includes a **View in Confluence** deep-link that opens Confluence focused on the exact comment.
291
291
  3. Developer addresses feedback on the branch, pushes changes, and merges the PR.
292
292
  4. Run `mk2conf sync-comments --check-merges` — detects merged PRs, adds a resolution reply to each Confluence comment with the commit info, and marks the comments as resolved.
@@ -295,7 +295,7 @@ confluence:
295
295
 
296
296
  | File | Purpose |
297
297
  |---|---|
298
- | `.mk2conf-pages.json` | Source path → Confluence page ID map, written after each `publish` |
298
+ | `.mk2conf-pages.json` | Source path → Confluence page ID map, merged after each `publish` run |
299
299
  | `.mk2conf-sync-state.json` | Tracks open/merged review PRs and their associated comment IDs |
300
300
 
301
301
  ---
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "mkdocs2confluence"
3
- version = "0.8.1"
3
+ version = "0.8.3"
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" }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mkdocs2confluence
3
- Version: 0.8.1
3
+ Version: 0.8.3
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
@@ -326,7 +326,7 @@ confluence:
326
326
 
327
327
  **Workflow:**
328
328
 
329
- 1. Run `mk2conf publish` firstgenerates `.mk2conf-pages.json` mapping source files to Confluence page IDs.
329
+ 1. Run `mk2conf publish` (full or partial) writes/merges `.mk2conf-pages.json` mapping source files to Confluence page IDs. Every publish run merges into this file, so partial `--page` / `--section` runs and multiple configs in the same repo all accumulate correctly.
330
330
  2. Run `mk2conf sync-comments` — for each page with open Confluence comments, creates a `mk2conf/review/{slug}` branch and PR, then posts each comment as a GitHub review thread. Inline comments with a text selection are anchored to the matching source line; page-level comments fall back to file-level review threads. Every thread body includes a **View in Confluence** deep-link that opens Confluence focused on the exact comment.
331
331
  3. Developer addresses feedback on the branch, pushes changes, and merges the PR.
332
332
  4. Run `mk2conf sync-comments --check-merges` — detects merged PRs, adds a resolution reply to each Confluence comment with the commit info, and marks the comments as resolved.
@@ -335,7 +335,7 @@ confluence:
335
335
 
336
336
  | File | Purpose |
337
337
  |---|---|
338
- | `.mk2conf-pages.json` | Source path → Confluence page ID map, written after each `publish` |
338
+ | `.mk2conf-pages.json` | Source path → Confluence page ID map, merged after each `publish` run |
339
339
  | `.mk2conf-sync-state.json` | Tracks open/merged review PRs and their associated comment IDs |
340
340
 
341
341
  ---
@@ -548,25 +548,33 @@ def _cmd_publish(args: argparse.Namespace) -> None:
548
548
  print(str(report))
549
549
 
550
550
  # Write page map so sync-comments can match source files to Confluence pages.
551
- if not (getattr(args, "page", None) or getattr(args, "section", None)):
552
- import json as _json_pm
551
+ # Always merge into the existing map so partial runs (--page/--section) and
552
+ # multiple configs pointing to the same repo root all accumulate correctly.
553
+ import json as _json_pm
554
+ try:
555
+ repo_root = config_path.parent
553
556
  try:
554
- repo_root = config_path.parent
557
+ docs_rel = config.docs_dir.relative_to(repo_root)
558
+ except ValueError:
559
+ docs_rel = Path("docs")
560
+ new_entries = {
561
+ str(docs_rel / action.node.docs_path): action.page_id
562
+ for action in plan
563
+ if action.node.docs_path and action.page_id and not action.is_folder
564
+ }
565
+ pm_path = repo_root / ".mk2conf-pages.json"
566
+ existing: dict[str, str] = {}
567
+ if pm_path.exists():
555
568
  try:
556
- docs_rel = config.docs_dir.relative_to(repo_root)
557
- except ValueError:
558
- docs_rel = Path("docs")
559
- page_map = {
560
- str(docs_rel / action.node.docs_path): action.page_id
561
- for action in plan
562
- if action.node.docs_path and action.page_id and not action.is_folder
563
- }
564
- pm_path = repo_root / ".mk2conf-pages.json"
565
- pm_path.write_text(_json_pm.dumps(page_map, indent=2), encoding="utf-8")
566
- if not getattr(args, "quiet", False):
567
- print(f"Page map: {len(page_map)} page(s) → {pm_path.name}")
568
- except Exception as exc:
569
- print(f" [warn] could not write page map: {exc}", file=sys.stderr)
569
+ existing = _json_pm.loads(pm_path.read_text(encoding="utf-8"))
570
+ except Exception:
571
+ pass
572
+ existing.update(new_entries)
573
+ pm_path.write_text(_json_pm.dumps(existing, indent=2), encoding="utf-8")
574
+ if not getattr(args, "quiet", False):
575
+ print(f"Page map: {len(existing)} page(s) {pm_path.name}")
576
+ except Exception as exc:
577
+ print(f" [warn] could not write page map: {exc}", file=sys.stderr)
570
578
 
571
579
  if getattr(args, "report", None):
572
580
  import json as _json
@@ -27,7 +27,7 @@ def _minimal_config(tmp_path: Path, *, extra: str = "") -> Path:
27
27
  """),
28
28
  encoding="utf-8",
29
29
  )
30
- (tmp_path / "docs").mkdir()
30
+ (tmp_path / "docs").mkdir(exist_ok=True)
31
31
  return yml
32
32
 
33
33
 
@@ -237,3 +237,59 @@ class TestWatchFlag:
237
237
  main(["preview", "--config", str(yml), "--page", "index.md", "--watch"])
238
238
 
239
239
  mock_render.assert_called_once()
240
+
241
+
242
+ class TestPageMap:
243
+ """The page map (.mk2conf-pages.json) should merge on every publish run."""
244
+
245
+ def _run_publish(self, tmp_path: Path, plan_actions: list) -> None:
246
+ yml = _minimal_config(tmp_path)
247
+ (tmp_path / "docs").mkdir(exist_ok=True)
248
+ (tmp_path / "docs" / "index.md").write_text("# Home\n", encoding="utf-8")
249
+ mock_client = MagicMock()
250
+ mock_client.__enter__ = MagicMock(return_value=mock_client)
251
+ mock_client.__exit__ = MagicMock(return_value=False)
252
+ mock_client.get_space_id.return_value = "~SPACE"
253
+ with patch("mkdocs_to_confluence.publisher.client.ConfluenceClient", return_value=mock_client), \
254
+ patch("mkdocs_to_confluence.publisher.pipeline.plan_publish", return_value=plan_actions), \
255
+ patch("mkdocs_to_confluence.publisher.pipeline.execute_publish", return_value=MagicMock(
256
+ __str__=lambda s: "0 created",
257
+ errors=[],
258
+ )), \
259
+ patch("sys.stdout.isatty", return_value=False):
260
+ main(["publish", "--config", str(yml), "--quiet"])
261
+
262
+ def _make_action(self, docs_path: str, page_id: str) -> MagicMock:
263
+ action = MagicMock()
264
+ action.node.docs_path = docs_path
265
+ action.page_id = page_id
266
+ action.is_folder = False
267
+ return action
268
+
269
+ def test_page_map_written_on_full_publish(self, tmp_path: Path) -> None:
270
+ action = self._make_action("index.md", "111")
271
+ self._run_publish(tmp_path, [action])
272
+ import json
273
+ pm = json.loads((tmp_path / ".mk2conf-pages.json").read_text())
274
+ assert "docs/index.md" in pm
275
+ assert pm["docs/index.md"] == "111"
276
+
277
+ def test_page_map_merges_on_second_publish(self, tmp_path: Path) -> None:
278
+ import json
279
+ # First publish: index.md
280
+ self._run_publish(tmp_path, [self._make_action("index.md", "111")])
281
+ # Second publish: overview.md only
282
+ self._run_publish(tmp_path, [self._make_action("overview.md", "222")])
283
+ pm = json.loads((tmp_path / ".mk2conf-pages.json").read_text())
284
+ # Both entries should be present
285
+ assert pm.get("docs/index.md") == "111"
286
+ assert pm.get("docs/overview.md") == "222"
287
+
288
+ def test_page_map_merge_updates_existing_entry(self, tmp_path: Path) -> None:
289
+ import json
290
+ # First publish: index.md with page_id 111
291
+ self._run_publish(tmp_path, [self._make_action("index.md", "111")])
292
+ # Second publish: same file, new page_id (e.g. recreated)
293
+ self._run_publish(tmp_path, [self._make_action("index.md", "999")])
294
+ pm = json.loads((tmp_path / ".mk2conf-pages.json").read_text())
295
+ assert pm["docs/index.md"] == "999"