mkdocs2confluence 0.20.3__tar.gz → 0.20.4__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 (110) hide show
  1. {mkdocs2confluence-0.20.3/src/mkdocs2confluence.egg-info → mkdocs2confluence-0.20.4}/PKG-INFO +1 -1
  2. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/pyproject.toml +1 -1
  3. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4/src/mkdocs2confluence.egg-info}/PKG-INFO +1 -1
  4. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/compiler/page.py +5 -4
  5. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/publisher/planner.py +27 -10
  6. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/tests/test_publish_pipeline.py +46 -9
  7. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/LICENSE +0 -0
  8. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/README.md +0 -0
  9. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/setup.cfg +0 -0
  10. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs2confluence.egg-info/SOURCES.txt +0 -0
  11. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs2confluence.egg-info/dependency_links.txt +0 -0
  12. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs2confluence.egg-info/entry_points.txt +0 -0
  13. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs2confluence.egg-info/requires.txt +0 -0
  14. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs2confluence.egg-info/top_level.txt +0 -0
  15. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/__init__.py +0 -0
  16. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/cli.py +0 -0
  17. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/compiler/__init__.py +0 -0
  18. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/compiler/models.py +0 -0
  19. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/emitter/__init__.py +0 -0
  20. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/emitter/xhtml.py +0 -0
  21. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/ir/__init__.py +0 -0
  22. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/ir/nodes.py +0 -0
  23. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/ir/treeutil.py +0 -0
  24. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/loader/__init__.py +0 -0
  25. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/loader/config.py +0 -0
  26. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/loader/extra_css.py +0 -0
  27. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/loader/nav.py +0 -0
  28. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/loader/page.py +0 -0
  29. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/parser/__init__.py +0 -0
  30. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/parser/markdown.py +0 -0
  31. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/pdf/__init__.py +0 -0
  32. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/pdf/generator.py +0 -0
  33. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/pdf/render.py +0 -0
  34. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/preprocess/__init__.py +0 -0
  35. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/preprocess/abbrevs.py +0 -0
  36. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/preprocess/captions.py +0 -0
  37. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/preprocess/fence.py +0 -0
  38. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/preprocess/frontmatter.py +0 -0
  39. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/preprocess/icons.py +0 -0
  40. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/preprocess/includes.py +0 -0
  41. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/preprocess/linkdefs.py +0 -0
  42. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/preview/__init__.py +0 -0
  43. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/preview/render.py +0 -0
  44. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/preview/server.py +0 -0
  45. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/publisher/__init__.py +0 -0
  46. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/publisher/changelog.py +0 -0
  47. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/publisher/client.py +0 -0
  48. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/publisher/executor.py +0 -0
  49. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/publisher/http_retry.py +0 -0
  50. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/publisher/models.py +0 -0
  51. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/skill_installer.py +0 -0
  52. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/skills/mkdocs-changelog/SKILL.md +0 -0
  53. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/skills/mkdocs-changelog/scripts/changelog_data.py +0 -0
  54. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/sync/__init__.py +0 -0
  55. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/sync/anchoring.py +0 -0
  56. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/sync/command.py +0 -0
  57. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/sync/comments.py +0 -0
  58. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/sync/github.py +0 -0
  59. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/sync/platform.py +0 -0
  60. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/sync/state.py +0 -0
  61. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/transforms/__init__.py +0 -0
  62. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/transforms/_kroki.py +0 -0
  63. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/transforms/abbrevs.py +0 -0
  64. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/transforms/admonition_titles.py +0 -0
  65. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/transforms/assets.py +0 -0
  66. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/transforms/attachment_previews.py +0 -0
  67. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/transforms/captions.py +0 -0
  68. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/transforms/editlink.py +0 -0
  69. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/transforms/footer.py +0 -0
  70. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/transforms/images.py +0 -0
  71. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/transforms/internallinks.py +0 -0
  72. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/transforms/mermaid.py +0 -0
  73. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/src/mkdocs_to_confluence/transforms/plantuml.py +0 -0
  74. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/tests/test_abbrevs.py +0 -0
  75. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/tests/test_admonition_titles.py +0 -0
  76. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/tests/test_attachment_previews.py +0 -0
  77. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/tests/test_captions.py +0 -0
  78. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/tests/test_changelog_config.py +0 -0
  79. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/tests/test_changelog_publish.py +0 -0
  80. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/tests/test_children_macro.py +0 -0
  81. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/tests/test_cli.py +0 -0
  82. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/tests/test_editlink.py +0 -0
  83. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/tests/test_emitter.py +0 -0
  84. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/tests/test_exclude_properties_config.py +0 -0
  85. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/tests/test_extra_css.py +0 -0
  86. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/tests/test_footer.py +0 -0
  87. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/tests/test_frontmatter.py +0 -0
  88. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/tests/test_icons.py +0 -0
  89. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/tests/test_images.py +0 -0
  90. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/tests/test_internallinks.py +0 -0
  91. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/tests/test_ir.py +0 -0
  92. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/tests/test_linkdefs.py +0 -0
  93. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/tests/test_loader.py +0 -0
  94. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/tests/test_mermaid.py +0 -0
  95. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/tests/test_page_loader.py +0 -0
  96. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/tests/test_parser.py +0 -0
  97. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/tests/test_pdf.py +0 -0
  98. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/tests/test_plantuml.py +0 -0
  99. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/tests/test_preprocess.py +0 -0
  100. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/tests/test_preview.py +0 -0
  101. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/tests/test_publish_client.py +0 -0
  102. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/tests/test_publish_config.py +0 -0
  103. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/tests/test_server.py +0 -0
  104. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/tests/test_skill_installer.py +0 -0
  105. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/tests/test_sync_anchoring.py +0 -0
  106. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/tests/test_sync_command.py +0 -0
  107. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/tests/test_sync_comments.py +0 -0
  108. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/tests/test_sync_github.py +0 -0
  109. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/tests/test_sync_state.py +0 -0
  110. {mkdocs2confluence-0.20.3 → mkdocs2confluence-0.20.4}/tests/test_treeutil.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mkdocs2confluence
3
- Version: 0.20.3
3
+ Version: 0.20.4
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
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "mkdocs2confluence"
3
- version = "0.20.3"
3
+ version = "0.20.4"
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.20.3
3
+ Version: 0.20.4
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
@@ -7,7 +7,7 @@ from mkdocs_to_confluence.emitter.xhtml import emit
7
7
  from mkdocs_to_confluence.ir.nodes import ChildrenMacro, FrontMatter, SourceFooter
8
8
  from mkdocs_to_confluence.loader.config import MkDocsConfig
9
9
  from mkdocs_to_confluence.loader.nav import NavNode
10
- from mkdocs_to_confluence.loader.page import load_page
10
+ from mkdocs_to_confluence.loader.page import PageLoadError, load_page
11
11
  from mkdocs_to_confluence.parser.markdown import parse, parse_inline
12
12
  from mkdocs_to_confluence.preprocess.abbrevs import (
13
13
  extract_abbreviations,
@@ -52,10 +52,11 @@ def compile_page(
52
52
  quiet: bool = False,
53
53
  ) -> CompileResult:
54
54
  """Run the full compile pipeline for one page and return a typed result."""
55
- if node.source_path is None:
56
- return CompileResult(xhtml="")
57
-
55
+ # load_page raises PageLoadError for a nav entry whose file is missing;
56
+ # never compile it to an empty body, which would blank the published page.
58
57
  raw = load_page(node)
58
+ if node.source_path is None: # unreachable after load_page; narrows the type
59
+ raise PageLoadError(f"Cannot load page '{node.title}': no source file.")
59
60
 
60
61
  preprocessed = preprocess_includes(
61
62
  raw,
@@ -47,6 +47,29 @@ def _find_section_index(node: NavNode) -> NavNode | None:
47
47
  return None
48
48
 
49
49
 
50
+ def _plan_skipped_page_action(
51
+ node: NavNode,
52
+ client: ConfluenceClient,
53
+ *,
54
+ space_id: str,
55
+ title: str,
56
+ parent_id: str | None,
57
+ ) -> PageAction:
58
+ """Build a skip action for a nav page that is not being published this run.
59
+
60
+ Carries the existing page's ID so ``--prune`` keeps it: the page is still
61
+ in ``nav:``, only skipped (``ready: false`` or a load error).
62
+ """
63
+ existing = client.find_page(space_id, title)
64
+ return PageAction(
65
+ node=node,
66
+ title=title,
67
+ action="skip",
68
+ parent_id=parent_id,
69
+ page_id=str(existing["id"]) if existing is not None else None,
70
+ )
71
+
72
+
50
73
  def _plan_compiled_page_action(
51
74
  node: NavNode,
52
75
  client: ConfluenceClient,
@@ -231,11 +254,8 @@ def _plan_nodes(
231
254
  if not quiet:
232
255
  print(f" skipping '{clean_title}' (ready: false)")
233
256
  actions.append(
234
- PageAction(
235
- node=node,
236
- title=clean_title,
237
- action="skip",
238
- parent_id=parent_id,
257
+ _plan_skipped_page_action(
258
+ node, client, space_id=space_id, title=clean_title, parent_id=parent_id
239
259
  )
240
260
  )
241
261
  continue
@@ -248,11 +268,8 @@ def _plan_nodes(
248
268
  if not quiet:
249
269
  print(f" skipping '{clean_title}' (error: {exc})")
250
270
  actions.append(
251
- PageAction(
252
- node=node,
253
- title=clean_title,
254
- action="skip",
255
- parent_id=parent_id,
271
+ _plan_skipped_page_action(
272
+ node, client, space_id=space_id, title=clean_title, parent_id=parent_id
256
273
  )
257
274
  )
258
275
  continue
@@ -78,16 +78,13 @@ def test_compile_page_with_ready_false_still_compiles(tmp_path: Path) -> None:
78
78
  assert isinstance(xhtml, str)
79
79
 
80
80
 
81
- def test_compile_page_with_source_path_none_returns_empty(tmp_path: Path) -> None:
82
- docs = tmp_path / "docs"
83
- docs.mkdir()
81
+ def test_compile_page_raises_for_missing_source(tmp_path: Path) -> None:
82
+ # An empty result would be published over the existing page, blanking it.
83
+ from mkdocs_to_confluence.loader.page import PageLoadError
84
+
84
85
  node = NavNode(title="Missing", docs_path="missing.md", source_path=None, level=0)
85
- config = _make_config(docs)
86
- result = compile_page(node, config)
87
- xhtml, attachments, labels = result.xhtml, result.attachments, result.labels
88
- assert xhtml == ""
89
- assert attachments == []
90
- assert labels == ()
86
+ with pytest.raises(PageLoadError, match="Missing"):
87
+ compile_page(node, _make_config(tmp_path))
91
88
 
92
89
 
93
90
  def test_compile_page_excludes_configured_properties(tmp_path: Path) -> None:
@@ -2211,3 +2208,43 @@ def test_execute_publish_calls_set_page_status_on_skip(tmp_path: Path) -> None:
2211
2208
  execute_publish([action], client, space_id="42", docs_dir=tmp_path)
2212
2209
 
2213
2210
  client.set_page_status.assert_called_once_with("88", "in-progress", space_key=None)
2211
+
2212
+
2213
+ class TestSkippedPagesSurvivePrune:
2214
+ """A page still in nav: but skipped this run must keep its Confluence page."""
2215
+
2216
+ @staticmethod
2217
+ def _publish_with_prune(node: NavNode, docs: Path) -> tuple[list[PageAction], MagicMock]:
2218
+ from mkdocs_to_confluence.publisher.executor import execute_publish
2219
+
2220
+ client = MagicMock()
2221
+ client.find_page.return_value = {"id": "555", "version": {"number": 3}}
2222
+ client.get_descendant_ids.return_value = ["555"]
2223
+ client.is_managed.return_value = True
2224
+ plan, _ = plan_publish([node], client, _make_config(docs), _make_conf_config(), space_id="42", quiet=True)
2225
+ execute_publish(plan, client, space_id="42", docs_dir=docs, root_page_id="ROOT", prune=True, quiet=True)
2226
+ return plan, client
2227
+
2228
+ def test_ready_false_page_is_kept(self, tmp_path: Path) -> None:
2229
+ docs = tmp_path / "docs"
2230
+ docs.mkdir()
2231
+ md = docs / "guide.md"
2232
+ md.write_text("---\nready: false\n---\n\n# Guide\n", encoding="utf-8")
2233
+
2234
+ plan, client = self._publish_with_prune(_page_node("Guide", md), docs)
2235
+
2236
+ assert [(a.action, a.page_id) for a in plan] == [("skip", "555")]
2237
+ client.delete_page.assert_not_called()
2238
+
2239
+ def test_missing_file_is_skipped_not_blanked(self, tmp_path: Path) -> None:
2240
+ # A nav entry whose file is gone (e.g. renamed) must not publish an
2241
+ # empty body over the existing page, nor let prune delete it.
2242
+ docs = tmp_path / "docs"
2243
+ docs.mkdir()
2244
+ node = NavNode(title="Guide", docs_path="guide.md", source_path=None, level=0)
2245
+
2246
+ plan, client = self._publish_with_prune(node, docs)
2247
+
2248
+ assert [(a.action, a.page_id) for a in plan] == [("skip", "555")]
2249
+ client.update_page.assert_not_called()
2250
+ client.delete_page.assert_not_called()