diff --git a/README.md b/README.md index 2c704af..7b525e5 100644 --- a/README.md +++ b/README.md @@ -8,11 +8,14 @@ Two-way Markdown ↔ Confluence sync from the command line, written in Python. Confluence MD allows you to create, edit and download Confluence Cloud pages as local Markdown files — all through the REST API, with a -single-file script and no server-side install. +single-file script and no server-side install. It works page by page or +on whole page trees, mirroring them to local folders and back. Round-tripping is the point: every supported element converts in both directions, so a page can be downloaded, edited locally in your editor, -and pushed back without losing structure. +and pushed back without losing structure. A version marker in each +downloaded file ensures nobody's concurrent edits are overwritten along +the way. --- diff --git a/docs/architecture.md b/docs/architecture.md index 71ba15e..7726357 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -1,7 +1,9 @@ # Architecture How the single module is organised and why the non-obvious parts — placeholder -substitution, version markers, tree state — work the way they do. +substitution, version markers, tree state — work the way they do. Read this +before changing either conversion pipeline, so the invariants the round-trip +tests rely on stay intact. - [Module layout](#module-layout) - [The two conversion pipelines](#the-two-conversion-pipelines) @@ -34,6 +36,8 @@ read top to bottom: Both pipelines are pure functions from string to string (plus optional collectors), which is what makes them unit-testable without any network. +Every API call stays in the CLI layer, which passes strings in and writes +the results out. **Upload** (`md_to_confluence_storage`): pre-process strikethrough (skipping code spans and fences), let python-markdown produce HTML, then walk the @@ -105,7 +109,8 @@ content. Both directions mirror the same layout: `.md` is a page, a sibling `/` folder holds its children, `_attachments/` holds its image -attachments. +attachments. Because the layouts match, whatever one direction writes, the +other can consume unchanged. **Download** (`download_page`): recursion threads a `_tree` dict through the calls, recording `title → written path` for every page. Page links are diff --git a/docs/configuration.md b/docs/configuration.md index 6966548..6e35b1a 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -1,7 +1,8 @@ # Configuration Everything needed to get from a fresh clone to a working setup: install the -dependencies, generate an API token, and store the credentials in a `.env` file. +dependencies, generate an API token, and store the credentials in a `.env` +file. Each step takes a minute or two and only needs doing once per machine. - [Prerequisites](#prerequisites) - [Installation](#installation) @@ -33,7 +34,8 @@ This installs the four dependencies: `atlassian-python-api`, `python-dotenv`, `markdown` and `beautifulsoup4`. Alternatively, install the project as a package to get a `confluence-md` -command on your PATH (usable anywhere instead of `python src/confluence_md.py`): +command on your PATH, which lets you run the tool from any directory instead +of invoking `python src/confluence_md.py` from a repository checkout: ```bash pip install . @@ -46,6 +48,8 @@ confluence-md --version The script authenticates with an API token rather than your password. Atlassian Cloud does **not** allow authentication with your regular password. +Tokens can be revoked individually at any time, so create one dedicated to +this tool. 1. Go to [https://id.atlassian.com/manage-profile/security/api-tokens](https://id.atlassian.com/manage-profile/security/api-tokens) 2. Log in with your Atlassian account @@ -70,8 +74,9 @@ You can find it in your browser address bar when you open Confluence. ## 3. Set up the `.env` file -The three credentials live in a `.env` file that the script loads at startup. -Copy the template from the project root and fill in your values: +The three credentials live in a `.env` file that the script loads at startup +from the directory it runs in. Copy the template from the project root and +fill in the three values collected in the previous steps: ```bash cp .env.example .env diff --git a/docs/conversion.md b/docs/conversion.md index 7cd3efc..9deab7f 100644 --- a/docs/conversion.md +++ b/docs/conversion.md @@ -82,7 +82,8 @@ break the Markdown table structure. ## Table of Contents — `[TOC]` **Upload:** A standalone `[TOC]` line in your Markdown becomes the Confluence -**Table of Contents macro**, which auto-generates a clickable TOC on the page. +**Table of Contents macro**, which auto-generates a clickable TOC on the page +and keeps itself up to date whenever the page's headings change. **Download:** The TOC macro becomes a list of anchor links to the page headings: @@ -100,7 +101,8 @@ Each link points to the corresponding `#heading-slug` within the Markdown file. ## Child Pages — `[CHILD_PAGES]` **Upload:** A standalone `[CHILD_PAGES]` line in your Markdown becomes the -Confluence **Children Display macro**, which auto-lists all child pages. +Confluence **Children Display macro**, which auto-lists all child pages of +the page and updates dynamically as children are added or removed. **Download:** The Children Display macro becomes a list of links to the child pages: @@ -127,7 +129,7 @@ by URL without uploading anything. **Download:** images backed by page attachments are saved into a `_attachments/` folder next to the output file, and the Markdown links -point there: +point there, so the images render correctly in any local Markdown preview: ```markdown ![diagram](My_Page_attachments/diagram.png) @@ -141,7 +143,8 @@ the same files. ## Task lists Markdown checkbox lists map to Confluence action-item task lists and back, -including the checked state and inline formatting in the item text: +including the checked state and inline formatting in the item text, so a +to-do list can be ticked off on either side and synced across: ```markdown - [ ] open task @@ -149,7 +152,8 @@ including the checked state and inline formatting in the item text: ``` A list converts as a task list only when **every** item starts with a -checkbox; lists mixing checkbox and plain items stay regular bullet lists. +checkbox; lists mixing checkbox and plain items stay regular bullet lists, +so no list is ever converted half-way into a mix of tasks and text. --- diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index bc1cbe1..a60e783 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -11,7 +11,8 @@ Symptom first: find the error message the script printed, then apply the fix. ## Configuration and authentication Errors in this group appear before any page content is transferred — the -script either refuses to start or Confluence refuses the credentials. +script either refuses to start or Confluence refuses the credentials. Fixing +them is always a matter of configuration, never of page content. | Error | Cause | Fix | |---|---|---| @@ -25,6 +26,8 @@ script either refuses to start or Confluence refuses the credentials. Errors in this group mean the page you pointed at could not be resolved — either the URL was not understood or the page is not visible to your account. +Check the URL in a browser first: if it does not open there, the tool cannot +reach it either. | Error | Cause | Fix | |---|---|---| diff --git a/docs/usage.md b/docs/usage.md index b26748a..7720d72 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -17,8 +17,9 @@ python src/confluence_md.py download [output.md] [--recur ## `upload` — create a new child page -Creates a new page as a child of the given parent. Aborts with an error if a -page with the same title already exists in the space — use `edit` in that case. +Creates a new page as a child of the given parent. Confluence requires titles +to be unique within a space, so the command aborts with an error if a page +with the same title already exists — use `edit` in that case. ```bash python src/confluence_md.py upload @@ -51,7 +52,8 @@ python src/confluence_md.py upload release_notes.md \ ``` The parent URL is the page in Confluence under which the new page will appear. -Open that page in your browser and copy the address bar URL. +Open that page in your browser and copy the address bar URL — both the pretty +`/spaces/.../pages/...` form and the `?pageId=...` form are accepted. --- @@ -120,6 +122,7 @@ python src/confluence_md.py download <page_url> [output.md] [--recursive] Images embedded from page attachments are saved into a `<name>_attachments/` folder next to the output file (created only when the page has such images). +External images referenced by URL are left as-is and never downloaded. The first line of the output file is a version marker comment (`<!-- confluence-md page_id=... version=... -->`). Leave it in place: `edit`