Markdown to Confluence Publisher
markdown-to-confluence is a Python library and command-line tool (md-to-conf) designed to publish Markdown files to Confluence wikis. It parses Markdown, converts its content into Confluence Storage Format (XHTML), and invokes Confluence API endpoints to upload pages and attachments (like images). It supports single-page and directory synchronization modes, handling relative links and page hierarchies. The current version is 0.5.8 and it appears to be actively maintained with a focus on ease of use for documentation synchronization.
Warnings
- gotcha Confluence authentication requires your organization domain, username (email), and an API key. These can be supplied via command-line arguments (`--orgname`, `--username`, `--apikey`) or environment variables (`ATLASSIAN_ORGNAME`, `ATLASSIAN_USERNAME`, `ATLASSIAN_API_KEY`). Incorrect credentials or insufficient permissions will result in a 401 Unauthorized error or other access-related failures.
- gotcha When publishing to a directory or specifying an `--ancestor` page, if the target Confluence space key or the ancestor page title is not found, the tool will exit with an error. Space keys and page titles are case-sensitive.
- gotcha Confluence has known issues rendering SVG images (e.g., wrong size, text truncation). `markdown-to-confluence` attempts to mitigate this by checking for a corresponding PNG image in the same directory and publishing it instead if found.
- gotcha Relative links in Markdown documents are fully supported only when publishing a *directory* of files (directory mode). All relative links must point to other Markdown files within the synchronized directory hierarchy. In single-page mode, relative links to other local Markdown files are not supported.
- gotcha Confluence's Markdown flavor and storage format can differ from standard GitHub Flavored Markdown (GFM). Certain features like `<details>` (spoilers), local anchors within list items, and specific header ID generation might not convert as expected.
- gotcha The tool uses implicit association (matching titles) or explicit association (`<!-- confluence-page-id: ID -->` comment) to link Markdown files to Confluence pages. If a Confluence page created implicitly lacks a 'trusted ancestor' (i.e., its parent doesn't exist or isn't trusted), subsequent synchronizations can fail.
Install
-
pip install markdown-to-confluence
Imports
- ConfluenceClient
from md_to_conf.client import ConfluenceClient
- ConfluenceConverter
from md_to_conf.converter import ConfluenceConverter
Quickstart
# Create a markdown file named 'my_doc.md'
# Example content:
# # My Awesome Documentation
# This is a paragraph with **bold** text.
#
# ## Section 1
# - Item 1
# - Item 2
import os
# Set environment variables for Confluence authentication
# Replace with your actual values or ensure they are set in your environment
os.environ['ATLASSIAN_ORGNAME'] = os.environ.get('ATLASSIAN_ORGNAME', 'your_organization') # e.g., 'yourcompany' for yourcompany.atlassian.net
os.environ['ATLASSIAN_USERNAME'] = os.environ.get('ATLASSIAN_USERNAME', 'your_confluence_email')
os.environ['ATLASSIAN_API_KEY'] = os.environ.get('ATLASSIAN_API_KEY', 'your_atlassian_api_key')
# To publish 'my_doc.md' to the 'DOC' space in Confluence, using the CLI:
# Ensure 'md-to-conf' is available in your PATH after installation
# Example using subprocess (or run directly in your shell):
import subprocess
markdown_file = "my_doc.md"
confluence_space_key = "DOC"
# Create a dummy markdown file for the example
with open(markdown_file, "w") as f:
f.write("# My Awesome Documentation\n")
f.write("This is a paragraph with **bold** text.\n\n")
f.write("## Section 1\n")
f.write("- Item 1\n")
f.write("- Item 2\n")
print(f"Attempting to publish {markdown_file} to Confluence space {confluence_space_key}...")
try:
# Using the command-line interface directly
command = [
"md-to-conf",
markdown_file,
confluence_space_key,
"--orgname", os.environ['ATLASSIAN_ORGNAME'],
"--username", os.environ['ATLASSIAN_USERNAME'],
"--apikey", os.environ['ATLASSIAN_API_KEY'],
"--verbose" # Add for detailed output during publishing
]
# For security, avoid passing sensitive data directly in `shell=True`
process = subprocess.run(command, capture_output=True, text=True, check=True)
print("Publishing successful (or simulated if --simulate was used).")
print("STDOUT:", process.stdout)
print("STDERR:", process.stderr)
except subprocess.CalledProcessError as e:
print(f"Error publishing: {e}")
print("STDOUT:", e.stdout)
print("STDERR:", e.stderr)
print("Hint: Check your Confluence credentials, organization name, and space key.")
print("Also ensure the Confluence API key has sufficient permissions.")
except FileNotFoundError:
print("Error: 'md-to-conf' command not found. Is markdown-to-confluence installed and in your PATH?")
# Clean up dummy file
os.remove(markdown_file)