* Only upload images that have changed by recording a file hash as the image comment * Add image to attachments based markdown formatted image links Allow dash in attachment filename (#13) Co-authored-by: Simon Stamm <simon.stamm@tui.com> Signed-off-by: Pawel Sikora <sikor6@gmail.com>
This commit is contained in:
parent
70844b3532
commit
c022db9f5f
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
mkdocs_with_confluence/__pycache__/*
|
||||||
|
mkdocs_with_confluence.egg-info/*
|
@ -1,5 +1,6 @@
|
|||||||
import time
|
import time
|
||||||
import os
|
import os
|
||||||
|
import hashlib
|
||||||
import sys
|
import sys
|
||||||
import re
|
import re
|
||||||
import tempfile
|
import tempfile
|
||||||
@ -211,16 +212,19 @@ class MkdocsWithConfluence(BasePlugin):
|
|||||||
tf = tempfile.NamedTemporaryFile(delete=False)
|
tf = tempfile.NamedTemporaryFile(delete=False)
|
||||||
f = open(tf.name, "w")
|
f = open(tf.name, "w")
|
||||||
|
|
||||||
files = []
|
attachments = []
|
||||||
try:
|
try:
|
||||||
for match in re.finditer(r'img src="file://(.*)" s', markdown):
|
for match in re.finditer(r'img src="file://(.*)" s', markdown):
|
||||||
if self.config["debug"]:
|
if self.config["debug"]:
|
||||||
print(f"DEBUG - FOUND IMAGE: {match.group(1)}")
|
print(f"DEBUG - FOUND IMAGE: {match.group(1)}")
|
||||||
files.append(match.group(1))
|
attachments.append(match.group(1))
|
||||||
|
for match in re.finditer(r"!\[[\w\. -]*\]\((?!http|file)(.*)\)", markdown):
|
||||||
|
if self.config["debug"]:
|
||||||
|
print(f"DEBUG - FOUND IMAGE: {match.group(1)}")
|
||||||
|
attachments.append("docs/" + match.group(1))
|
||||||
except AttributeError as e:
|
except AttributeError as e:
|
||||||
if self.config["debug"]:
|
if self.config["debug"]:
|
||||||
print(f"DEBUG - WARN(({e}): No images found in markdown. Proceed..")
|
print(f"DEBUG - WARN(({e}): No images found in markdown. Proceed..")
|
||||||
|
|
||||||
new_markdown = re.sub(
|
new_markdown = re.sub(
|
||||||
r'<img src="file:///tmp/', '<p><ac:image ac:height="350"><ri:attachment ri:filename="', markdown
|
r'<img src="file:///tmp/', '<p><ac:image ac:height="350"><ri:attachment ri:filename="', markdown
|
||||||
)
|
)
|
||||||
@ -334,14 +338,14 @@ class MkdocsWithConfluence(BasePlugin):
|
|||||||
n_kol = len(i + "INFO - Mkdocs With Confluence:" + " *NEW PAGE*")
|
n_kol = len(i + "INFO - Mkdocs With Confluence:" + " *NEW PAGE*")
|
||||||
print(f"INFO - Mkdocs With Confluence: {i} *NEW PAGE*")
|
print(f"INFO - Mkdocs With Confluence: {i} *NEW PAGE*")
|
||||||
|
|
||||||
if files:
|
if attachments:
|
||||||
if self.config["debug"]:
|
if self.config["debug"]:
|
||||||
print(f"\nDEBUG - UPLOADING ATTACHMENTS TO CONFLUENCE, DETAILS:\n" f"FILES: {files}\n")
|
print(f"\nDEBUG - UPLOADING ATTACHMENTS TO CONFLUENCE, DETAILS:\n" f"FILES: {attachments}\n")
|
||||||
|
|
||||||
n_kol = len(" *NEW ATTACHMENTS({len(files)})*")
|
n_kol = len(" *NEW ATTACHMENTS({len(attachments)})*")
|
||||||
print(f"\033[A\033[F\033[{n_kol}G *NEW ATTACHMENTS({len(files)})*")
|
print(f"\033[A\033[F\033[{n_kol}G *NEW ATTACHMENTS({len(attachments)})*")
|
||||||
for f in files:
|
for f in attachments:
|
||||||
self.add_attachment(page.title, f)
|
self.add_or_update_attachment(page.title, f)
|
||||||
|
|
||||||
except IndexError as e:
|
except IndexError as e:
|
||||||
if self.config["debug"]:
|
if self.config["debug"]:
|
||||||
@ -384,13 +388,60 @@ class MkdocsWithConfluence(BasePlugin):
|
|||||||
print(f"WRN - Page '{name}' doesn't exist in the mkdocs.yml nav section!")
|
print(f"WRN - Page '{name}' doesn't exist in the mkdocs.yml nav section!")
|
||||||
return name
|
return name
|
||||||
|
|
||||||
def add_attachment(self, page_name, filepath):
|
# Adapted from https://stackoverflow.com/a/3431838
|
||||||
print(f"INFO - Mkdocs With Confluence * {page_name} *NEW ATTACHMENT* {filepath}")
|
def get_file_sha1(self, file_path):
|
||||||
|
hash_sha1 = hashlib.sha1()
|
||||||
|
with open(file_path, "rb") as f:
|
||||||
|
for chunk in iter(lambda: f.read(4096), b""):
|
||||||
|
hash_sha1.update(chunk)
|
||||||
|
return hash_sha1.hexdigest()
|
||||||
|
|
||||||
|
def add_or_update_attachment(self, page_name, filepath):
|
||||||
|
print(f"INFO - Mkdocs With Confluence * {page_name} *ADD/Update ATTACHMENT if required* {filepath}")
|
||||||
if self.config["debug"]:
|
if self.config["debug"]:
|
||||||
print(f" * Mkdocs With Confluence: Add Attachment: PAGE NAME: {page_name}, FILE: {filepath}")
|
print(f" * Mkdocs With Confluence: Add Attachment: PAGE NAME: {page_name}, FILE: {filepath}")
|
||||||
page_id = self.find_page_id(page_name)
|
page_id = self.find_page_id(page_name)
|
||||||
if page_id:
|
if page_id:
|
||||||
url = self.config["host_url"] + "/" + page_id + "/child/attachment/"
|
file_hash = self.get_file_sha1(filepath)
|
||||||
|
attachment_message = f"MKDocsWithConfluence [v{file_hash}]"
|
||||||
|
existing_attachment = self.get_attachment(page_id, filepath)
|
||||||
|
if existing_attachment:
|
||||||
|
file_hash_regex = re.compile(r"\[v([a-f0-9]{40})]$")
|
||||||
|
existing_match = file_hash_regex.search(existing_attachment["version"]["message"])
|
||||||
|
if existing_match is not None and existing_match.group(1) == file_hash:
|
||||||
|
if self.config["debug"]:
|
||||||
|
print(f" * Mkdocs With Confluence * {page_name} * Existing attachment skipping * {filepath}")
|
||||||
|
else:
|
||||||
|
self.update_attachment(page_id, filepath, existing_attachment, attachment_message)
|
||||||
|
else:
|
||||||
|
self.create_attachment(page_id, filepath, attachment_message)
|
||||||
|
else:
|
||||||
|
if self.config["debug"]:
|
||||||
|
print("PAGE DOES NOT EXISTS")
|
||||||
|
|
||||||
|
def get_attachment(self, page_id, filepath):
|
||||||
|
name = os.path.basename(filepath)
|
||||||
|
if self.config["debug"]:
|
||||||
|
print(f" * Mkdocs With Confluence: Get Attachment: PAGE ID: {page_id}, FILE: {filepath}")
|
||||||
|
|
||||||
|
url = self.config["host_url"] + "/" + page_id + "/child/attachment"
|
||||||
|
headers = {"X-Atlassian-Token": "no-check"} # no content-type here!
|
||||||
|
if self.config["debug"]:
|
||||||
|
print(f"URL: {url}")
|
||||||
|
auth = (self.user, self.pw)
|
||||||
|
|
||||||
|
r = requests.get(url, headers=headers, params={"filename": name, "expand": "version"}, auth=auth)
|
||||||
|
r.raise_for_status()
|
||||||
|
with nostdout():
|
||||||
|
response_json = r.json()
|
||||||
|
if response_json["size"]:
|
||||||
|
return response_json["results"][0]
|
||||||
|
|
||||||
|
def update_attachment(self, page_id, filepath, existing_attachment, message):
|
||||||
|
if self.config["debug"]:
|
||||||
|
print(f" * Mkdocs With Confluence: Update Attachment: PAGE ID: {page_id}, FILE: {filepath}")
|
||||||
|
|
||||||
|
url = self.config["host_url"] + "/" + page_id + "/child/attachment/" + existing_attachment["id"] + "/data"
|
||||||
headers = {"X-Atlassian-Token": "no-check"} # no content-type here!
|
headers = {"X-Atlassian-Token": "no-check"} # no content-type here!
|
||||||
if self.config["debug"]:
|
if self.config["debug"]:
|
||||||
print(f"URL: {url}")
|
print(f"URL: {url}")
|
||||||
@ -401,18 +452,42 @@ class MkdocsWithConfluence(BasePlugin):
|
|||||||
content_type, encoding = mimetypes.guess_type(filename)
|
content_type, encoding = mimetypes.guess_type(filename)
|
||||||
if content_type is None:
|
if content_type is None:
|
||||||
content_type = "multipart/form-data"
|
content_type = "multipart/form-data"
|
||||||
files = {"file": (filename, open(filename, "rb"), content_type)}
|
files = {"file": (filename, open(filename, "rb"), content_type), "comment": message}
|
||||||
|
|
||||||
if not self.dryrun:
|
if not self.dryrun:
|
||||||
r = requests.post(url, headers=headers, files=files, auth=auth)
|
r = requests.post(url, headers=headers, files=files, auth=auth)
|
||||||
r.raise_for_status()
|
r.raise_for_status()
|
||||||
|
print(r.json())
|
||||||
|
if r.status_code == 200:
|
||||||
|
print("OK!")
|
||||||
|
else:
|
||||||
|
print("ERR!")
|
||||||
|
|
||||||
|
def create_attachment(self, page_id, filepath, message):
|
||||||
|
if self.config["debug"]:
|
||||||
|
print(f" * Mkdocs With Confluence: Create Attachment: PAGE ID: {page_id}, FILE: {filepath}")
|
||||||
|
|
||||||
|
url = self.config["host_url"] + "/" + page_id + "/child/attachment"
|
||||||
|
headers = {"X-Atlassian-Token": "no-check"} # no content-type here!
|
||||||
|
if self.config["debug"]:
|
||||||
|
print(f"URL: {url}")
|
||||||
|
filename = filepath
|
||||||
|
auth = (self.user, self.pw)
|
||||||
|
|
||||||
|
# determine content-type
|
||||||
|
content_type, encoding = mimetypes.guess_type(filename)
|
||||||
|
if content_type is None:
|
||||||
|
content_type = "multipart/form-data"
|
||||||
|
files = {"file": (filename, open(filename, "rb"), content_type), "comment": message}
|
||||||
|
|
||||||
|
if not self.dryrun:
|
||||||
|
r = requests.post(url, headers=headers, files=files, auth=auth)
|
||||||
|
print(r.json())
|
||||||
|
r.raise_for_status()
|
||||||
if r.status_code == 200:
|
if r.status_code == 200:
|
||||||
print("OK!")
|
print("OK!")
|
||||||
else:
|
else:
|
||||||
print("ERR!")
|
print("ERR!")
|
||||||
else:
|
|
||||||
if self.config["debug"]:
|
|
||||||
print("PAGE DOES NOT EXISTS")
|
|
||||||
|
|
||||||
def find_page_id(self, page_name):
|
def find_page_id(self, page_name):
|
||||||
if self.config["debug"]:
|
if self.config["debug"]:
|
||||||
|
2
setup.py
2
setup.py
@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name="mkdocs-with-confluence",
|
name="mkdocs-with-confluence",
|
||||||
version="0.2.5",
|
version="0.2.6",
|
||||||
description="MkDocs plugin for uploading markdown documentation to Confluence via Confluence REST API",
|
description="MkDocs plugin for uploading markdown documentation to Confluence via Confluence REST API",
|
||||||
keywords="mkdocs markdown confluence documentation rest python",
|
keywords="mkdocs markdown confluence documentation rest python",
|
||||||
url="https://github.com/pawelsikora/mkdocs-with-confluence/",
|
url="https://github.com/pawelsikora/mkdocs-with-confluence/",
|
||||||
|
Loading…
Reference in New Issue
Block a user