mkdocs2confluence 0.7.25__tar.gz → 0.7.27__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 (72) hide show
  1. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/PKG-INFO +1 -1
  2. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/pyproject.toml +1 -1
  3. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/src/mkdocs2confluence.egg-info/PKG-INFO +1 -1
  4. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/src/mkdocs_to_confluence/publisher/client.py +10 -1
  5. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/src/mkdocs_to_confluence/publisher/pipeline.py +10 -6
  6. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/tests/test_publish_pipeline.py +97 -0
  7. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/LICENSE +0 -0
  8. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/README.md +0 -0
  9. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/setup.cfg +0 -0
  10. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/src/mkdocs2confluence.egg-info/SOURCES.txt +0 -0
  11. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/src/mkdocs2confluence.egg-info/dependency_links.txt +0 -0
  12. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/src/mkdocs2confluence.egg-info/entry_points.txt +0 -0
  13. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/src/mkdocs2confluence.egg-info/requires.txt +0 -0
  14. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/src/mkdocs2confluence.egg-info/top_level.txt +0 -0
  15. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/src/mkdocs_to_confluence/__init__.py +0 -0
  16. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/src/mkdocs_to_confluence/cli.py +0 -0
  17. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/src/mkdocs_to_confluence/emitter/__init__.py +0 -0
  18. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/src/mkdocs_to_confluence/emitter/xhtml.py +0 -0
  19. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/src/mkdocs_to_confluence/ir/__init__.py +0 -0
  20. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/src/mkdocs_to_confluence/ir/document.py +0 -0
  21. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/src/mkdocs_to_confluence/ir/nodes.py +0 -0
  22. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/src/mkdocs_to_confluence/ir/treeutil.py +0 -0
  23. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/src/mkdocs_to_confluence/loader/__init__.py +0 -0
  24. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/src/mkdocs_to_confluence/loader/config.py +0 -0
  25. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/src/mkdocs_to_confluence/loader/extra_css.py +0 -0
  26. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/src/mkdocs_to_confluence/loader/nav.py +0 -0
  27. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/src/mkdocs_to_confluence/loader/page.py +0 -0
  28. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/src/mkdocs_to_confluence/parser/__init__.py +0 -0
  29. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/src/mkdocs_to_confluence/parser/markdown.py +0 -0
  30. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/src/mkdocs_to_confluence/pdf/__init__.py +0 -0
  31. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/src/mkdocs_to_confluence/pdf/generator.py +0 -0
  32. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/src/mkdocs_to_confluence/pdf/render.py +0 -0
  33. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/src/mkdocs_to_confluence/preprocess/__init__.py +0 -0
  34. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/src/mkdocs_to_confluence/preprocess/abbrevs.py +0 -0
  35. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/src/mkdocs_to_confluence/preprocess/fence.py +0 -0
  36. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/src/mkdocs_to_confluence/preprocess/frontmatter.py +0 -0
  37. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/src/mkdocs_to_confluence/preprocess/icons.py +0 -0
  38. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/src/mkdocs_to_confluence/preprocess/includes.py +0 -0
  39. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/src/mkdocs_to_confluence/preprocess/linkdefs.py +0 -0
  40. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/src/mkdocs_to_confluence/preview/__init__.py +0 -0
  41. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/src/mkdocs_to_confluence/preview/render.py +0 -0
  42. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/src/mkdocs_to_confluence/preview/server.py +0 -0
  43. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/src/mkdocs_to_confluence/publisher/__init__.py +0 -0
  44. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/src/mkdocs_to_confluence/transforms/__init__.py +0 -0
  45. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/src/mkdocs_to_confluence/transforms/abbrevs.py +0 -0
  46. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/src/mkdocs_to_confluence/transforms/assets.py +0 -0
  47. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/src/mkdocs_to_confluence/transforms/editlink.py +0 -0
  48. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/src/mkdocs_to_confluence/transforms/images.py +0 -0
  49. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/src/mkdocs_to_confluence/transforms/internallinks.py +0 -0
  50. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/src/mkdocs_to_confluence/transforms/mermaid.py +0 -0
  51. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/tests/test_abbrevs.py +0 -0
  52. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/tests/test_cli.py +0 -0
  53. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/tests/test_editlink.py +0 -0
  54. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/tests/test_emitter.py +0 -0
  55. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/tests/test_extra_css.py +0 -0
  56. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/tests/test_frontmatter.py +0 -0
  57. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/tests/test_icons.py +0 -0
  58. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/tests/test_images.py +0 -0
  59. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/tests/test_internallinks.py +0 -0
  60. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/tests/test_ir.py +0 -0
  61. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/tests/test_linkdefs.py +0 -0
  62. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/tests/test_loader.py +0 -0
  63. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/tests/test_mermaid.py +0 -0
  64. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/tests/test_page_loader.py +0 -0
  65. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/tests/test_parser.py +0 -0
  66. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/tests/test_pdf.py +0 -0
  67. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/tests/test_preprocess.py +0 -0
  68. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/tests/test_preview.py +0 -0
  69. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/tests/test_publish_client.py +0 -0
  70. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/tests/test_publish_config.py +0 -0
  71. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/tests/test_server.py +0 -0
  72. {mkdocs2confluence-0.7.25 → mkdocs2confluence-0.7.27}/tests/test_treeutil.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mkdocs2confluence
3
- Version: 0.7.25
3
+ Version: 0.7.27
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.7.25"
3
+ version = "0.7.27"
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.7.25
3
+ Version: 0.7.27
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
@@ -380,6 +380,9 @@ class ConfluenceClient:
380
380
  # Fetch space states once per run (keyed by space so one run = one API call)
381
381
  if cache_key not in self._space_states:
382
382
  self._space_states[cache_key] = self._fetch_available_states(page_id)
383
+ print(
384
+ f" [status] space states fetched: {[s.get('name') for s in self._space_states[cache_key]]}",
385
+ )
383
386
 
384
387
  matched: dict[str, Any] | None = None
385
388
  for state in self._space_states.get(cache_key, []):
@@ -393,6 +396,7 @@ class ConfluenceClient:
393
396
  "name": matched["name"],
394
397
  "color": matched["color"],
395
398
  }
399
+ print(f" [status] matched space state: {body}")
396
400
  else:
397
401
  # Fall back: name + color (required together when no id)
398
402
  _default_colors = {
@@ -404,9 +408,13 @@ class ConfluenceClient:
404
408
  "outdated": "#ff7452",
405
409
  }
406
410
  body = {"name": name, "color": _default_colors.get(_normalize(name), "#2684ff")}
411
+ print(f" [status] no space state match — using fallback: {body}")
407
412
 
408
413
  url = self._v1(f"/content/{page_id}/state")
409
414
  resp = self._http.put(url, json=body)
415
+ print(f" [status] PUT {url} → HTTP {resp.status_code}")
416
+ if not resp.is_success:
417
+ print(f" [status] response body: {resp.text[:300]}")
410
418
  self._raise_for_status(resp, f"set_page_status({page_id!r}, {status_key!r})")
411
419
 
412
420
  def _fetch_available_states(self, page_id: str) -> list[dict[str, Any]]:
@@ -419,7 +427,8 @@ class ConfluenceClient:
419
427
  resp = self._http.get(self._v1(f"/content/{page_id}/state/available"))
420
428
  if resp.is_success:
421
429
  data: dict[str, Any] = resp.json()
422
- return data.get("spaceContentStates") or []
430
+ return list(data.get("spaceContentStates") or [])
431
+ print(f" [warn] could not fetch available states (HTTP {resp.status_code}) — using fallback")
423
432
  return []
424
433
 
425
434
  def list_attachments(self, page_id: str) -> dict[str, dict[str, Any]]:
@@ -664,10 +664,12 @@ def _post_process_action(
664
664
  # Set Confluence page status (rough-draft / in-progress / etc.) — non-fatal.
665
665
  if action.page_id and action.confluence_status and not action.is_folder:
666
666
  try:
667
+ print(f" [status] setting '{action.confluence_status}' on page {action.page_id!r}...")
667
668
  client.set_page_status(action.page_id, action.confluence_status, space_key=space_key)
669
+ print(" [status] ok")
668
670
  except Exception as exc:
669
671
  # Always print status errors — user configured status explicitly
670
- print(f" [warn] could not set page status '{action.confluence_status}': {exc}", file=sys.stderr)
672
+ print(f" [warn] could not set page status '{action.confluence_status}': {exc}")
671
673
 
672
674
  # Upload assets — skip files whose mtime is not newer than Confluence.
673
675
  if action.page_id and action.attachments:
@@ -730,13 +732,15 @@ def execute_publish(
730
732
  # Still apply status even for unchanged pages.
731
733
  if action.page_id and action.confluence_status and not action.is_folder:
732
734
  try:
735
+ print(
736
+ f" [status] setting '{action.confluence_status}' on page {action.page_id!r}...",
737
+ )
733
738
  client.set_page_status(action.page_id, action.confluence_status, space_key=space_key)
739
+ print(" [status] ok")
734
740
  except Exception as exc:
735
- if not quiet:
736
- print(
737
- f" [warn] could not set page status '{action.confluence_status}': {exc}",
738
- file=sys.stderr,
739
- )
741
+ print(
742
+ f" [warn] could not set page status '{action.confluence_status}': {exc}",
743
+ )
740
744
  continue
741
745
 
742
746
  counter += 1
@@ -1945,3 +1945,100 @@ def test_execute_publish_quiet_suppresses_stdout(tmp_path: Path, capsys: pytest.
1945
1945
 
1946
1946
  out, _ = capsys.readouterr()
1947
1947
  assert out == ""
1948
+
1949
+
1950
+ # ── Status: end-to-end flow ───────────────────────────────────────────────────
1951
+
1952
+
1953
+ def test_compile_page_returns_confluence_status(tmp_path: Path) -> None:
1954
+ """compile_page must return the status: value from front matter."""
1955
+ docs = tmp_path / "docs"
1956
+ docs.mkdir()
1957
+ md = docs / "page.md"
1958
+ md.write_text("---\nstatus: in-progress\n---\n\n# My Page\n\nContent.\n", encoding="utf-8")
1959
+
1960
+ node = _page_node("My Page", md)
1961
+ config = _make_config(docs)
1962
+ _, _, _, confluence_status = compile_page(node, config)
1963
+
1964
+ assert confluence_status == "in-progress"
1965
+
1966
+
1967
+ def test_plan_publish_sets_confluence_status_on_create(tmp_path: Path) -> None:
1968
+ """plan_publish must carry confluence_status into a create PageAction."""
1969
+ docs = tmp_path / "docs"
1970
+ docs.mkdir()
1971
+ md = docs / "page.md"
1972
+ md.write_text("---\nstatus: in-progress\n---\n\n# My Page\n\nContent.\n", encoding="utf-8")
1973
+
1974
+ node = _page_node("My Page", md)
1975
+ config = _make_config(docs)
1976
+ conf_config = _make_conf_config()
1977
+
1978
+ client = MagicMock()
1979
+ client.find_page.return_value = None
1980
+
1981
+ plan = plan_publish([node], client, config, conf_config, space_id="42")
1982
+
1983
+ assert plan[0].action == "create"
1984
+ assert plan[0].confluence_status == "in-progress"
1985
+
1986
+
1987
+ def test_plan_publish_sets_confluence_status_on_skip(tmp_path: Path) -> None:
1988
+ """plan_publish must carry confluence_status into a skip (unchanged) PageAction."""
1989
+ from mkdocs_to_confluence.publisher.pipeline import _xhtml_hash
1990
+
1991
+ docs = tmp_path / "docs"
1992
+ docs.mkdir()
1993
+ md = docs / "page.md"
1994
+ md.write_text("---\nstatus: in-progress\n---\n\n# My Page\n\nContent.\n", encoding="utf-8")
1995
+
1996
+ node = _page_node("My Page", md)
1997
+ config = _make_config(docs)
1998
+ conf_config = _make_conf_config()
1999
+
2000
+ xhtml, _, _, _ = compile_page(node, config)
2001
+ stored_hash = _xhtml_hash(xhtml)
2002
+
2003
+ existing_page = {"id": "77", "version": {"number": 2}}
2004
+ client = MagicMock()
2005
+ client.find_page.return_value = existing_page
2006
+ client.get_content_hash.return_value = stored_hash
2007
+
2008
+ plan = plan_publish([node], client, config, conf_config, space_id="42")
2009
+
2010
+ assert plan[0].action == "skip"
2011
+ assert plan[0].confluence_status == "in-progress"
2012
+
2013
+
2014
+ def test_execute_publish_calls_set_page_status_on_create(tmp_path: Path) -> None:
2015
+ """execute_publish must call client.set_page_status for a created page with confluence_status."""
2016
+ from mkdocs_to_confluence.publisher.pipeline import execute_publish
2017
+
2018
+ node = _make_section_node("P", [])
2019
+ action = PageAction(
2020
+ node=node, title="P", action="create",
2021
+ parent_id=None, xhtml="<p/>", confluence_status="in-progress",
2022
+ )
2023
+ client = MagicMock()
2024
+ client.create_page.return_value = {"id": "99"}
2025
+
2026
+ execute_publish([action], client, space_id="42", docs_dir=tmp_path)
2027
+
2028
+ client.set_page_status.assert_called_once_with("99", "in-progress", space_key=None)
2029
+
2030
+
2031
+ def test_execute_publish_calls_set_page_status_on_skip(tmp_path: Path) -> None:
2032
+ """execute_publish must call client.set_page_status even for skipped (unchanged) pages."""
2033
+ from mkdocs_to_confluence.publisher.pipeline import execute_publish
2034
+
2035
+ node = _make_section_node("P", [])
2036
+ action = PageAction(
2037
+ node=node, title="P", action="skip",
2038
+ parent_id=None, page_id="88", confluence_status="in-progress",
2039
+ )
2040
+ client = MagicMock()
2041
+
2042
+ execute_publish([action], client, space_id="42", docs_dir=tmp_path)
2043
+
2044
+ client.set_page_status.assert_called_once_with("88", "in-progress", space_key=None)