diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 70741c3..46883b0 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -1,9 +1,11 @@ name: Upload Documentation -on: - pull_request: - branches: - - main +# on: +# pull_request: +# branches: +# - main + +on: [push] jobs: hello_world_job: @@ -14,10 +16,13 @@ jobs: uses: actions/checkout@v3 - name: Conversion step env: - CONFLUENCE_URL: 'https://at-bachelor.atlassian.net/wiki' + CONFLUENCE_URL: 'https://at-bachelor.atlassian.net' CONFLUENCE_SPACE_KEY: '~955037829' - AUTH_TOKEN: ${{ secrets.AUTH_TOKEN }} + AUTH_USERNAME: ${{ secrets.AUTH_USERNAME }} + AUTH_API_TOKEN: ${{ secrets.AUTH_API_TOKEN }} uses: ./ # Uses an action in the root directory id: Convert with: fileslocation: './documentation' + + diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 19b9472..4e1848d 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -2,9 +2,6 @@ name: Run PyTest on: [push] -permissions: - contents: read - jobs: build: runs-on: ubuntu-latest @@ -19,16 +16,16 @@ jobs: apt-get update && apt-get install -y python3-venv python3 -m venv venv . venv/bin/activate - python -m pip install --upgrade pip if [ -f requirements.txt ]; then pip install -r requirements.txt; fi pip install -e . - name: Test with pytest env: CONFLUENCE_URL: 'https://at-bachelor.atlassian.net/wiki' CONFLUENCE_SPACE_KEY: '~955037829' - AUTH_TOKEN: ${{ secrets.AUTH_TOKEN }} + AUTH_USERNAME: ${{ secrets.AUTH_USERNAME }} + AUTH_API_TOKEN: ${{ secrets.AUTH_API_TOKEN }} INPUT_FILESLOCATION: './documentation' run: | . venv/bin/activate pip install -e . - pytest -v \ No newline at end of file + python3 -m pytest -v \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index d088cd7..72c4795 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,26 +1,29 @@ FROM ubuntu:latest -RUN apt-get update && apt-get install -y software-properties-common gcc && \ - add-apt-repository -y ppa:deadsnakes/ppa +RUN apt-get update + #&& apt-get install -y software-properties-common gcc && \ + # add-apt-repository -y ppa:deadsnakes/ppa -RUN apt-get install -y python3.6 python3-distutils python3-pip python3-apt python3-venv +#RUN apt-get install -y python3.6 python3-distutils python3-pip python3-apt python3-venv -RUN apt-get install -y pandoc +RUN apt-get install -y git jq + +# RUN apt-get install -y pandoc #ffmpeg libsm6 libxext6 -RUN python3 -m venv venv -RUN chmod +x /venv/* -RUN . /venv/bin/activate +# RUN python3 -m venv venv +# RUN chmod +x /venv/* +# RUN . /venv/bin/activate -COPY setup.py /setup.py -COPY requirements.txt requirements.txt -RUN pip install -r requirements.txt +# COPY setup.py /setup.py +# COPY requirements.txt requirements.txt +# RUN pip install -r requirements.txt COPY ./MarkdownToConfluence /MarkdownToConfluence -RUN pip install -e . +# RUN pip install -e . -RUN chmod +x /MarkdownToConfluence/convert_all.sh -RUN chmod +x /MarkdownToConfluence/convert.sh -#RUN chmod +x /MarkdownToConfluence/entrypoint.sh +# RUN chmod +x /MarkdownToConfluence/convert_all.sh +# RUN chmod +x /MarkdownToConfluence/convert.sh +RUN chmod +x /MarkdownToConfluence/entrypoint.sh -ENTRYPOINT [ "sh", "/MarkdownToConfluence/convert_all.sh" ] \ No newline at end of file +ENTRYPOINT [ "bash", "/MarkdownToConfluence/entrypoint.sh" ] \ No newline at end of file diff --git a/MarkdownToConfluence/__init__.py b/MarkdownToConfluence/__init__.py index e69de29..61dc199 100644 --- a/MarkdownToConfluence/__init__.py +++ b/MarkdownToConfluence/__init__.py @@ -0,0 +1 @@ +__all__ = ['utils', 'modules', 'confluence', 'globals'] \ No newline at end of file diff --git a/MarkdownToConfluence/confluence/check_if_page_exists.py b/MarkdownToConfluence/confluence/check_if_page_exists.py index af38b97..2421367 100644 --- a/MarkdownToConfluence/confluence/check_if_page_exists.py +++ b/MarkdownToConfluence/confluence/check_if_page_exists.py @@ -1,19 +1,22 @@ from urllib.parse import quote import requests, json import os +from requests.auth import HTTPBasicAuth + +from MarkdownToConfluence.confluence.PageNotFoundError import PageNotFoundError -AUTH_TOKEN = os.environ.get("AUTH_TOKEN") BASE_URL = os.environ.get("CONFLUENCE_URL") +AUTH_USERNAME = os.environ.get("AUTH_USERNAME") +AUTH_API_TOKEN = os.environ.get("AUTH_API_TOKEN") -authorization_string = f"Basic {AUTH_TOKEN}" +auth = HTTPBasicAuth(AUTH_USERNAME, AUTH_API_TOKEN) def page_exists_in_space(title: str, spaceKey: str) -> bool: - url = f"{BASE_URL}/rest/api/content?spaceKey={spaceKey}&title={quote(title)}" + url = f"{BASE_URL}/wiki/rest/api/content?spaceKey={spaceKey}&title={quote(title)}" headers = { - 'Authorization': authorization_string, 'User-Agent': 'python' } - response = requests.request('GET', url, headers=headers) + response = requests.request('GET', url, headers=headers, auth=auth) if(response.status_code == 200): results = json.loads(response.text)['results'] if(len(results) > 0): @@ -22,19 +25,20 @@ def page_exists_in_space(title: str, spaceKey: str) -> bool: return False else: print(response.text) + return False def get_page_id(title: str, spaceKey: str) -> str: - url = f"{BASE_URL}/rest/api/content?spaceKey={spaceKey}&title={quote(title)}" + url = f"{BASE_URL}/wiki/rest/api/content?spaceKey={spaceKey}&title={quote(title)}" headers = { - 'Authorization': authorization_string, 'User-Agent': 'python' } - response = requests.request('GET', url, headers=headers) + response = requests.request('GET', url, headers=headers, auth=auth) if(response.status_code == 200): results = json.loads(response.text)['results'] if(len(results) > 0): return results[0]['id'] else: - return 'Page does not exist' + raise PageNotFoundError(title, spaceKey) else: - print(response.text) \ No newline at end of file + print(response.text) + raise PageNotFoundError(title, spaceKey) \ No newline at end of file diff --git a/MarkdownToConfluence/confluence/create_content.py b/MarkdownToConfluence/confluence/create_content.py index 2eb66ec..24152bb 100644 --- a/MarkdownToConfluence/confluence/create_content.py +++ b/MarkdownToConfluence/confluence/create_content.py @@ -1,12 +1,14 @@ import json import codecs import requests -import sys, os +import sys, os, base64 +from requests.auth import HTTPBasicAuth -AUTH_TOKEN = os.environ.get("AUTH_TOKEN") BASE_URL = os.environ.get("CONFLUENCE_URL") +AUTH_USERNAME = os.environ.get("AUTH_USERNAME") +AUTH_API_TOKEN = os.environ.get("AUTH_API_TOKEN") -authorization_string = f"Basic {AUTH_TOKEN}" +auth = HTTPBasicAuth(AUTH_USERNAME, AUTH_API_TOKEN) def create_page(filename: str, title: str, space_obj, parent_id="none"): filename = filename.replace(".md", ".html") @@ -45,16 +47,15 @@ def create_page(filename: str, title: str, space_obj, parent_id="none"): f = codecs.open(f"{filename}", 'r', encoding='utf-8') template['body']['storage']['value'] = f.read() - url = f'{BASE_URL}/rest/api/content' + url = f'{BASE_URL}/wiki/rest/api/content' headers = { - 'Authorization': authorization_string, 'Content-Type': 'application/json; charset=utf-8', 'User-Agent': 'python' } # Upload html to confluence - response = requests.request("POST", url, headers=headers, data=json.dumps(template)) + response = requests.request("POST", url, headers=headers, data=json.dumps(template), auth=auth) return response diff --git a/MarkdownToConfluence/confluence/delete_content.py b/MarkdownToConfluence/confluence/delete_content.py index 2f7db20..224ecda 100644 --- a/MarkdownToConfluence/confluence/delete_content.py +++ b/MarkdownToConfluence/confluence/delete_content.py @@ -1,26 +1,25 @@ import requests, json -from MarkdownToConfluence.filetools import get_all_page_names_in_filesystem -import sys, os +from MarkdownToConfluence.utils import get_all_page_names_in_filesystem +import sys, os, base64 +from requests.auth import HTTPBasicAuth -#BASE_URL = os.environ.get("CONFLUENCE_URL") -BASE_URL = 'https://at-bachelor.atlassian.net/wiki' +BASE_URL = os.environ.get("CONFLUENCE_URL") FILES_PATH = os.environ.get("INPUT_FILESLOCATION") -#AUTH_TOKEN = os.environ.get("AUTH_TOKEN") -AUTH_TOKEN = "bGFyc2UxOUBzdHVkZW50LnNkdS5kazp6RzFrQk1ick9PUEtZblNSSFA0bTQxNUI=" SPACE_KEY = os.environ.get("CONFLUENCE_SPACE_KEY") +AUTH_USERNAME = os.environ.get("AUTH_USERNAME") +AUTH_API_TOKEN = os.environ.get("AUTH_API_TOKEN") -authorization_string = f"Basic {AUTH_TOKEN}" +auth = HTTPBasicAuth(AUTH_USERNAME, AUTH_API_TOKEN) def delete_page(page_id: str, page_name=""): - url = f"{BASE_URL}/rest/api/content/{page_id}" + url = f"{BASE_URL}/wiki/rest/api/content/{page_id}" headers = { - 'Authorization': authorization_string, 'User-Agent': 'python' } - response = requests.request('DELETE', url, headers=headers) + response = requests.request('DELETE', url, headers=headers, auth=auth) if(response.status_code == 204): print(f"Deleted {page_id} {page_name}") @@ -33,21 +32,20 @@ def delete_page(page_id: str, page_name=""): the exclude arg takes a list of page names, that are not to be deleted, even if they dont exist in the filesystem """ def delete_non_existing_pages(space_key: str, root: str, exclude=['Overview']): - url = f"{BASE_URL}/rest/api/content?spaceKey={space_key}" + url = f"{BASE_URL}/wiki/rest/api/content?spaceKey={space_key}" headers = { - 'Authorization': authorization_string, 'User-Agent': 'python' } results = [] - response = requests.request("GET", url, headers=headers) + response = requests.request("GET", url, headers=headers, auth=auth) response_json = json.loads(response.text) if(response.status_code == 200): results.extend(response_json['results']) while("next" in response_json['_links']): url = BASE_URL + response_json["_links"]["next"] - response = requests.request("GET", url, headers=headers) + response = requests.request("GET", url, headers=headers, auth=auth) response_json = json.loads(response.text) results.extend(response_json['results']) diff --git a/MarkdownToConfluence/confluence/update_content.py b/MarkdownToConfluence/confluence/update_content.py index 06c0fb3..41a4879 100644 --- a/MarkdownToConfluence/confluence/update_content.py +++ b/MarkdownToConfluence/confluence/update_content.py @@ -1,12 +1,14 @@ import json import codecs import requests -import os +import os, base64 +from requests.auth import HTTPBasicAuth -AUTH_TOKEN = os.environ.get("AUTH_TOKEN") BASE_URL = os.environ.get("CONFLUENCE_URL") +AUTH_USERNAME = os.environ.get("AUTH_USERNAME") +AUTH_API_TOKEN = os.environ.get("AUTH_API_TOKEN") -authorization_string = f"Basic {AUTH_TOKEN}" +auth = HTTPBasicAuth(AUTH_USERNAME, AUTH_API_TOKEN) def update_page_content(filename: str, title: str, page_id: str, space_obj,): filename = filename.replace(".md", ".html") @@ -37,21 +39,20 @@ def update_page_content(filename: str, title: str, page_id: str, space_obj,): f = codecs.open(f"{filename}", 'r', encoding='utf-8') template['body']['storage']['value'] = f.read() - url = f"{BASE_URL}/rest/api/content/{page_id}" + url = f"{BASE_URL}/wiki/rest/api/content/{page_id}" headers = { - 'Authorization': authorization_string, 'Content-Type': 'application/json; charset=utf-8', 'User-Agent': 'python' } # Get current version - get_response = requests.request("GET", f"{url}?expand=version", headers=headers) + get_response = requests.request("GET", f"{url}?expand=version", headers=headers, auth=auth) version_number = int(json.loads(get_response.text)['version']['number']) template['version']['number'] = version_number + 1 # Upload html to confluence - put_response = requests.request("PUT", url, headers=headers, data=json.dumps(template)) + put_response = requests.request("PUT", url, headers=headers, data=json.dumps(template), auth=auth) if(put_response.status_code != 200): print(template['body']) diff --git a/MarkdownToConfluence/confluence/upload_attachments.py b/MarkdownToConfluence/confluence/upload_attachments.py index 95909fe..2a79d11 100644 --- a/MarkdownToConfluence/confluence/upload_attachments.py +++ b/MarkdownToConfluence/confluence/upload_attachments.py @@ -1,37 +1,38 @@ -import requests, json, os +import requests, json, os, base64 from .check_if_page_exists import page_exists_in_space, get_page_id from .PageNotFoundError import PageNotFoundError +from requests.auth import HTTPBasicAuth BASE_URL = os.environ.get("CONFLUENCE_URL") -AUTH_TOKEN = os.environ.get("AUTH_TOKEN") SPACEKEY = os.environ.get("CONFLUENCE_SPACE_KEY") +AUTH_USERNAME = os.environ.get("AUTH_USERNAME") +AUTH_API_TOKEN = os.environ.get("AUTH_API_TOKEN") -authorization_string = f"Basic {AUTH_TOKEN}" +auth = HTTPBasicAuth(AUTH_USERNAME, AUTH_API_TOKEN) headers = { -'Authorization': authorization_string, 'User-Agent': 'python', 'X-Atlassian-Token': 'no-check' } def upload_attachment(page_title, attactchment_name, filepath): if(page_exists_in_space(page_title, SPACEKEY)): - url = f"{BASE_URL}/rest/api/content/{get_page_id(page_title, SPACEKEY)}/child/attachment" + url = f"{BASE_URL}/wiki/rest/api/content/{get_page_id(page_title, SPACEKEY)}/child/attachment" # Get attachment id id = "" - attachments = requests.get(url, headers=headers) + attachments = requests.get(url, headers=headers, auth=auth) for result in json.loads(attachments.text)['results']: if(result['title'] == attactchment_name): id = result['id'] if(id == ""): # Attachment doesnt exist, create it # Create attachment file = {'file': (attactchment_name, open(filepath, 'rb'))} - response = requests.post(url, headers=headers, files=file) + response = requests.post(url, headers=headers, files=file, auth=auth) else: # Attachment exists, update it # Update attachment files = {'file': (attactchment_name, open(os.path.abspath(filepath), 'rb'))} - response = requests.post(f'{url}/{id}/data', headers=headers, files=files) + response = requests.post(f'{url}/{id}/data', headers=headers, files=files, auth=auth) if(response.status_code == 200): print(f"Uploaded {attactchment_name} as attachment on page {page_title}") @@ -40,24 +41,3 @@ def upload_attachment(page_title, attactchment_name, filepath): return response else: raise PageNotFoundError(page_title, SPACEKEY) - -""" -def update_attachment_data(page_title, attactchment_name, filepath): - if(page_exists_in_space(page_title, SPACEKEY)): - url = f"{BASE_URL}/rest/api/content/{get_page_id(page_title, SPACEKEY)}/child/attachment" - - # Get attachment id - id = "" - attachments = requests.get(url, headers=headers) - for result in json.loads(attachments.text)['results']: - if(result['title'] == attactchment_name): - id = result['id'] - - # Update attachment - files = {'file': (f'{attactchment_name}', open(f'./{filepath}', 'rb'))} - response = requests.post(url + f'/{id}/data', headers=headers, files=files) - - return response - else: - raise PageNotFoundError(page_title, SPACEKEY) -""" \ No newline at end of file diff --git a/MarkdownToConfluence/entrypoint.sh b/MarkdownToConfluence/entrypoint.sh index 55fc5f5..e255cab 100644 --- a/MarkdownToConfluence/entrypoint.sh +++ b/MarkdownToConfluence/entrypoint.sh @@ -1,2 +1,14 @@ #!/bin/bash -ls \ No newline at end of file +git init +git config --global --add safe.directory /github/workspace +git config --global core.pager "less -FRSX" +git fetch -q +printenv +chmod -x ${GITHUB_EVENT_PATH} +before=$(jq .before ${GITHUB_EVENT_PATH} | tr -d '"') +after=${GITHUB_SHA} | tr -d '"' +git fetch origin ${before} --depth=1 +#git pull +git diff --name-status ${before}..${after} -- './documentation' +#echo ${GITHUB_EVENT_PATH} | python3 -c "import sys, json; print(json.load(sys.stdin)['before'])" +#cat ${GITHUB_EVENT_PATH} | python3 -c "import sys, json; print(json.load(sys.stdin)['after'])" \ No newline at end of file diff --git a/MarkdownToConfluence/file_parsing/__init__.py b/MarkdownToConfluence/file_parsing/__init__.py deleted file mode 100644 index 1e6e2ee..0000000 --- a/MarkdownToConfluence/file_parsing/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -__all__ = ["parse_markdown", "mermaid_parser", "image_parser"] -from .parse_markdown import parse_markdown \ No newline at end of file diff --git a/MarkdownToConfluence/file_parsing/attachments.py b/MarkdownToConfluence/file_parsing/attachments.py deleted file mode 100644 index 7deee65..0000000 --- a/MarkdownToConfluence/file_parsing/attachments.py +++ /dev/null @@ -1,26 +0,0 @@ -#TODO remove this file -from posixpath import dirname, basename -#from MarkdownToConfluence.modules.image.image_parser import convert_md_img_to_confluence_img -import re, os -from MarkdownToConfluence.filetools import get_abs_path_from_relative -""" -def parse_and_get_attachments(filename): - attachments = [] - with open(filename, 'r') as f: - lines = f.readlines() - with open(filename, 'w') as f: - for line in lines: - reg = re.match(r'!\[(?P[^\]]*)\]\((?P.*?)(?=\"|\))(\"(?P.*)\")?\)', line) - if (reg != None): - name = reg['title'] if reg['title'] != None else reg['alt'] - image = convert_md_img_to_confluence_img(line, filename) - if(image != None): - f.write(image) - else: - f.write(line) - path = get_abs_path_from_relative(reg['filename'], filename) - attachments.append((name, path)) - else: - f.write(line) - return attachments -""" \ No newline at end of file diff --git a/MarkdownToConfluence/file_parsing/parse_markdown.py b/MarkdownToConfluence/file_parsing/parse_markdown.py deleted file mode 100644 index 8b1a3b4..0000000 --- a/MarkdownToConfluence/file_parsing/parse_markdown.py +++ /dev/null @@ -1,12 +0,0 @@ -# TODO: remove this file -import sys -import MarkdownToConfluence.modules.mermaid as mermaid - -def parse_markdown(filename): - mermaid.convert(filename) - - -if __name__ == "__main__": - parse_markdown(f"{str(sys.argv[1])}") - -"""<ac:image><ri:attachment ri:filename="{diagram_name}" /></ac:image>""" \ No newline at end of file diff --git a/MarkdownToConfluence/file_parsing/tests/testdocs/images/markdown/image.md b/MarkdownToConfluence/file_parsing/tests/testdocs/images/markdown/image.md deleted file mode 100644 index ca1c3f5..0000000 --- a/MarkdownToConfluence/file_parsing/tests/testdocs/images/markdown/image.md +++ /dev/null @@ -1,6 +0,0 @@ -![alt](../attachments/image.png "title") -![alt](./image.png "title") -![alt](MarkdownToConfluence/file_parsing/tests/testdocs/images/attachments/image.png "title") -![alt](../attachments/image.png) -![alt](./image.png) -![alt](MarkdownToConfluence/file_parsing/tests/testdocs/images/attachments/image.png) \ No newline at end of file diff --git a/MarkdownToConfluence/file_parsing/tests/testdocs/index.md b/MarkdownToConfluence/file_parsing/tests/testdocs/index.md deleted file mode 100644 index 78c8c05..0000000 --- a/MarkdownToConfluence/file_parsing/tests/testdocs/index.md +++ /dev/null @@ -1,4 +0,0 @@ -```mermaid -graph -A[start] --> B[end] -``` \ No newline at end of file diff --git a/MarkdownToConfluence/filetools/__init__.py b/MarkdownToConfluence/filetools/__init__.py deleted file mode 100644 index 9f13802..0000000 --- a/MarkdownToConfluence/filetools/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -__all__ = ["page_file_info", "file_traversal"] -from .page_file_info import get_prefix -from .page_file_info import get_page_name_from_path -from .page_file_info import get_parent_name_from_path -from .page_file_info import get_all_md_paths -from .page_file_info import get_all_page_names_in_filesystem -from .paths import get_abs_path_from_relative \ No newline at end of file diff --git a/MarkdownToConfluence/main.py b/MarkdownToConfluence/main.py index d96e0b3..eccc725 100644 --- a/MarkdownToConfluence/main.py +++ b/MarkdownToConfluence/main.py @@ -1,11 +1,13 @@ from importlib.resources import path from posixpath import dirname, basename +from MarkdownToConfluence.confluence.PageNotFoundError import PageNotFoundError from confluence import page_exists_in_space, get_page_id from confluence import create_page from confluence import update_page_content from confluence import upload_attachment -import globals -from filetools.page_file_info import get_page_name_from_path, get_parent_name_from_path +from utils import convert_all_md_img_to_confluence_img +import MarkdownToConfluence.globals +from utils.page_file_info import get_page_name_from_path, get_parent_name_from_path import os import subprocess import markdown @@ -40,8 +42,7 @@ def upload_documentation(path_name:str, root:str): for line in lines: o.write(line) - # Get and parse attachments - #attachments = parse_and_get_attachments(path_name.replace('.md', '_final.md')) + # Load and run modules settings_path = f"{os.environ.get('INPUT_FILESLOCATION')}/settings.json" if(os.path.exists(settings_path)): modules = module_loader.get_modules(settings_path) @@ -51,6 +52,9 @@ def upload_documentation(path_name:str, root:str): for module in modules: module_loader.run_module(module, temp_file) + # Convert images + convert_all_md_img_to_confluence_img(temp_file) + # Convert to html with open(temp_file, 'r') as f: text = f.read() @@ -60,36 +64,43 @@ def upload_documentation(path_name:str, root:str): #print(f"Uploading {page_name} with {parent_name} as parent") #If the page already exists, just update it - if(page_exists_in_space(page_name, space_obj["key"])): - page_id = get_page_id(page_name, space_obj['key']) - response = update_page_content(path_name, page_name, page_id, space_obj) - if(response.status_code == 200): - print(f"Updated {page_name} with {parent_name} as parent") + if(page_exists_in_space(page_name, SPACE_KEY)): + try: + page_id = get_page_id(page_name, SPACE_KEY) + response = update_page_content(path_name, page_name, page_id, space_obj) + if(response.status_code == 200): + print(f"Updated {page_name} with {parent_name} as parent") + except PageNotFoundError as e: + print(e) #Else, create the page else: - if(parent_name != "none"): #Create page as a child page, if there is a parent - if(not page_exists_in_space(parent_name, space_obj['key'])): #If the parent page doesn't exists, create it - print(f"uploading parent: {parent_name}") - if(file_name != "index"): - subprocess.call(["bash", "/MarkdownToConfluence/convert.sh", f"{dirname(path_name)}/index.md"]) - else: - subprocess.call(["bash", "/MarkdownToConfluence/convert.sh", f"{dirname(dirname(path_name))}/index.md"]) - parent_id = get_page_id(parent_name, space_obj['key']) - response = create_page(path_name, page_name, space_obj, parent_id) + if(parent_name != ""): #Create page as a child page, if there is a parent + try: + if(not page_exists_in_space(parent_name, SPACE_KEY)): #If the parent page doesn't exists, create it + print(f"uploading parent: {parent_name}") + if(file_name != "index"): + subprocess.call(["bash", "/MarkdownToConfluence/convert.sh", f"{dirname(path_name)}/index.md"]) + else: + subprocess.call(["bash", "/MarkdownToConfluence/convert.sh", f"{dirname(dirname(path_name))}/index.md"]) + parent_id = get_page_id(parent_name, SPACE_KEY) + response = create_page(path_name, page_name, space_obj, parent_id) + except PageNotFoundError as e: + print(e) else: response = create_page(path_name, page_name, space_obj) #Create page as top page if(response.status_code == 200): print(f"Created {page_name} with {parent_name} as parent") if(response.status_code == 200): - for attachment in globals.attachments: + for attachment in MarkdownToConfluence.globals.attachments: upload_attachment(page_name, attachment[0], attachment[1]) else: print(f"Error uploading {page_name}. Status code {response.status_code}") print(response.text) + sys.exit(1) return response if __name__ == "__main__": import sys - globals.init() + MarkdownToConfluence.globals.init() upload_documentation(sys.argv[1], sys.argv[2]) \ No newline at end of file diff --git a/MarkdownToConfluence/module_loader.py b/MarkdownToConfluence/module_loader.py index d1788f7..a607497 100644 --- a/MarkdownToConfluence/module_loader.py +++ b/MarkdownToConfluence/module_loader.py @@ -1,5 +1,6 @@ import os, json from posixpath import basename +import pathlib def run_module(module_name: str, filename=None): name = "modules." + module_name @@ -11,7 +12,7 @@ def run_module(module_name: str, filename=None): def get_modules(settings_file=None): modules = [] - modules_location = './MarkdownToConfluence/modules' + modules_location = str(pathlib.Path(__file__).parent.resolve()) + '/modules' for filename in os.listdir(modules_location): f = os.path.join(modules_location, filename) # checking if it is a file diff --git a/MarkdownToConfluence/modules/__init__.py b/MarkdownToConfluence/modules/__init__.py index e69de29..56e2b91 100644 --- a/MarkdownToConfluence/modules/__init__.py +++ b/MarkdownToConfluence/modules/__init__.py @@ -0,0 +1 @@ +__all__ = ['mermaid', 'jira_tickets', 'attachment_link'] \ No newline at end of file diff --git a/MarkdownToConfluence/modules/attachment_link/__init__.py b/MarkdownToConfluence/modules/attachment_link/__init__.py new file mode 100644 index 0000000..ecdda3d --- /dev/null +++ b/MarkdownToConfluence/modules/attachment_link/__init__.py @@ -0,0 +1 @@ +from .parse_attachment_links import run, convert_all_md_attachment_links_to_confluence_attachment_links, convert_md_attachment_links_to_confluence_attachment_links \ No newline at end of file diff --git a/MarkdownToConfluence/modules/attachment_link/parse_attachment_links.py b/MarkdownToConfluence/modules/attachment_link/parse_attachment_links.py new file mode 100644 index 0000000..9fbb791 --- /dev/null +++ b/MarkdownToConfluence/modules/attachment_link/parse_attachment_links.py @@ -0,0 +1,29 @@ +from os import link +from posixpath import dirname, basename +import re +from MarkdownToConfluence.utils.paths import get_abs_path_from_relative +import MarkdownToConfluence.globals + +def convert_all_md_attachment_links_to_confluence_attachment_links(filename): + with open(filename, 'r') as f: + lines = f.readlines() + with open(filename, 'w') as f: + for line in lines: + res = convert_md_attachment_links_to_confluence_attachment_links(line, filename) + f.write(res) + +def convert_md_attachment_links_to_confluence_attachment_links(line: str, md_path: str): + links = re.findall(r'(!\[(?P<alt>[^\]]*)\]\((?P<filename>.*?)(?=\"|\))(\"(?P<title>.*)\")?\))', line) + new_line = line + for link in links: + if(not (link[2].strip().endswith('.png') or link[2].strip().endswith('.jpg'))): + path = get_abs_path_from_relative(link[2], md_path) + name = link[4] if link[4] != '' else basename(link[2]) + MarkdownToConfluence.globals.attachments.append((name, path)) + new_line = new_line.replace(link[0], f'<p class=\"media-group\"><ac:structured-macro ac:name=\"view-file\" ac:schema-version=\"1\" ac:macro-id=\"ce17b5c6-cfe6-4a77-92aa-7b810863f634\"><ac:parameter ac:name=\"name\"><ri:attachment ri:filename="{name}" ri:version-at-save=\"2\" /></ac:parameter></ac:structured-macro></p><p />') + return new_line + +def run(filename): + return convert_all_md_attachment_links_to_confluence_attachment_links(filename) + + diff --git a/MarkdownToConfluence/file_parsing/tests/__init__.py b/MarkdownToConfluence/modules/attachment_link/tests/__init__.py similarity index 100% rename from MarkdownToConfluence/file_parsing/tests/__init__.py rename to MarkdownToConfluence/modules/attachment_link/tests/__init__.py diff --git a/MarkdownToConfluence/modules/attachment_link/tests/test_parse_attachment_links.py b/MarkdownToConfluence/modules/attachment_link/tests/test_parse_attachment_links.py new file mode 100644 index 0000000..412f419 --- /dev/null +++ b/MarkdownToConfluence/modules/attachment_link/tests/test_parse_attachment_links.py @@ -0,0 +1,15 @@ +from MarkdownToConfluence.modules.attachment_link import convert_md_attachment_links_to_confluence_attachment_links +import MarkdownToConfluence.globals +import pytest, pathlib + +@pytest.fixture(autouse=True) +def run_before(): + MarkdownToConfluence.globals.init() + yield + MarkdownToConfluence.globals.init() + +def test_convert_md_attachment_links_to_confluence_attachment_links(): + root = str(pathlib.Path(__file__).parent.resolve()) + assert convert_md_attachment_links_to_confluence_attachment_links('![test](./zip_test.zip)', root) == '<p class=\"media-group\"><ac:structured-macro ac:name=\"view-file\" ac:schema-version=\"1\" ac:macro-id=\"ce17b5c6-cfe6-4a77-92aa-7b810863f634\"><ac:parameter ac:name=\"name\"><ri:attachment ri:filename="zip_test.zip" ri:version-at-save=\"2\" /></ac:parameter></ac:structured-macro></p><p />' + assert len(MarkdownToConfluence.globals.attachments) == 1 + assert MarkdownToConfluence.globals.attachments[0] == ('zip_test.zip', f'{root}/zip_test.zip') \ No newline at end of file diff --git a/MarkdownToConfluence/modules/attachment_link/tests/zip_test.zip b/MarkdownToConfluence/modules/attachment_link/tests/zip_test.zip new file mode 100644 index 0000000..a01abc1 Binary files /dev/null and b/MarkdownToConfluence/modules/attachment_link/tests/zip_test.zip differ diff --git a/MarkdownToConfluence/modules/image/__init__.py b/MarkdownToConfluence/modules/image/__init__.py deleted file mode 100644 index edfbc2e..0000000 --- a/MarkdownToConfluence/modules/image/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .image_parser import run \ No newline at end of file diff --git a/MarkdownToConfluence/modules/image/tests/test_image_parser.py b/MarkdownToConfluence/modules/image/tests/test_image_parser.py deleted file mode 100644 index 77f3ad8..0000000 --- a/MarkdownToConfluence/modules/image/tests/test_image_parser.py +++ /dev/null @@ -1,16 +0,0 @@ -from MarkdownToConfluence.modules.image.image_parser import run -import os, pathlib - -def test_convert_md_img_to_confluence_img(): - root=str(pathlib.Path(__file__).parent.resolve()) + '/testdocs' - filepath = f'{root}/images/markdown/image.md' - run(filepath) - with open("testfile.md", "r") as f: - assert f.readline().strip('\n') == '<ac:image ac:original-height="144" ac:original-width="70"><ri:attachment ri:filename="title"/></ac:image>' - assert f.readline().strip('\n') == '<ac:image ac:original-height="144" ac:original-width="70"><ri:attachment ri:filename="title"/></ac:image>' - assert f.readline().strip('\n') == '<ac:image ac:original-height="144" ac:original-width="70"><ri:attachment ri:filename="title"/></ac:image>' - assert f.readline().strip('\n') == '<ac:image ac:original-height="144" ac:original-width="70"><ri:attachment ri:filename="alt"/></ac:image>' - assert f.readline().strip('\n') == '<ac:image ac:original-height="144" ac:original-width="70"><ri:attachment ri:filename="alt"/></ac:image>' - assert f.readline().strip('\n') == '<ac:image ac:original-height="144" ac:original-width="70"><ri:attachment ri:filename="alt"/></ac:image>' - #os.remove("testfile.md") - \ No newline at end of file diff --git a/MarkdownToConfluence/modules/image/tests/testdocs/images/attachments/image.png b/MarkdownToConfluence/modules/image/tests/testdocs/images/attachments/image.png deleted file mode 100644 index 57d95e3..0000000 Binary files a/MarkdownToConfluence/modules/image/tests/testdocs/images/attachments/image.png and /dev/null differ diff --git a/MarkdownToConfluence/modules/image/tests/testdocs/images/markdown/image.md b/MarkdownToConfluence/modules/image/tests/testdocs/images/markdown/image.md deleted file mode 100644 index ca1c3f5..0000000 --- a/MarkdownToConfluence/modules/image/tests/testdocs/images/markdown/image.md +++ /dev/null @@ -1,6 +0,0 @@ -![alt](../attachments/image.png "title") -![alt](./image.png "title") -![alt](MarkdownToConfluence/file_parsing/tests/testdocs/images/attachments/image.png "title") -![alt](../attachments/image.png) -![alt](./image.png) -![alt](MarkdownToConfluence/file_parsing/tests/testdocs/images/attachments/image.png) \ No newline at end of file diff --git a/MarkdownToConfluence/modules/image/tests/testdocs/images/markdown/image.png b/MarkdownToConfluence/modules/image/tests/testdocs/images/markdown/image.png deleted file mode 100644 index 57d95e3..0000000 Binary files a/MarkdownToConfluence/modules/image/tests/testdocs/images/markdown/image.png and /dev/null differ diff --git a/MarkdownToConfluence/modules/jira_tickets/__init__.py b/MarkdownToConfluence/modules/jira_tickets/__init__.py new file mode 100644 index 0000000..206fe38 --- /dev/null +++ b/MarkdownToConfluence/modules/jira_tickets/__init__.py @@ -0,0 +1 @@ +from .jira_tickets_parser import run \ No newline at end of file diff --git a/MarkdownToConfluence/modules/jira_tickets/jira_tickets_parser.py b/MarkdownToConfluence/modules/jira_tickets/jira_tickets_parser.py new file mode 100644 index 0000000..3086a64 --- /dev/null +++ b/MarkdownToConfluence/modules/jira_tickets/jira_tickets_parser.py @@ -0,0 +1,48 @@ +import re +import requests, json, os +from requests.auth import HTTPBasicAuth + +def parse_tickets(filename: str): + with open(filename, 'r') as f: + lines = f.readlines() + with open(filename, 'w') as f: + for line in lines: + res = parse_ticket(line) + new_line = res if res.endswith('\n') else res + '\n' + f.write(new_line) + +def parse_ticket(line: str) -> str: + tickets = re.findall(r'\d+-[A-Z]+(?!-?[a-zA-Z]{1,10})', line[::-1]) #official atlassian regex magic + new_line = line + for ticket in tickets: + if(check_if_ticket_exists(ticket)): # TODO: Raise warning in pipeline + ticket = ticket[::-1] + ticket_tag = f"<ac:structured-macro ac:name='jira'><ac:parameter ac:name='columns'>key,summary,type,created,updated,due,assignee,reporter,priority,status,resolution</ac:parameter><ac:parameter ac:name='key'>{ticket}</ac:parameter> </ac:structured-macro>" + new_line = new_line.replace(ticket, ticket_tag) + return new_line + +def check_if_ticket_exists(ticket: str): + base_url = os.environ.get('CONFLUENCE_URL') + url = f'{base_url}/rest/api/3/issue/{ticket}' + username = os.environ.get('AUTH_USERNAME') + token = os.environ.get('AUTH_API_TOKEN') + auth = HTTPBasicAuth(username, token) + + headers = { + 'Content-Type': 'application/json; charset=utf-8', + 'User-Agent': 'python' + } + + response = requests.request( + "GET", + url, + headers=headers, + auth=auth + ) + + return response.status_code == 200 + +def run(filename): + return parse_tickets(filename) + +#print(check_if_ticket_exists('BAasdaC-74')) diff --git a/MarkdownToConfluence/modules/mermaid/mermaid_parser.py b/MarkdownToConfluence/modules/mermaid/mermaid_parser.py index 1df0114..11d420a 100644 --- a/MarkdownToConfluence/modules/mermaid/mermaid_parser.py +++ b/MarkdownToConfluence/modules/mermaid/mermaid_parser.py @@ -3,7 +3,7 @@ import requests import base64 -def parse_mermaid_macro(filename): +def parse_mermaid_macros(filename): if(os.path.isdir(filename)): filename += "/index_final.md" mermaid_diagram_num = 0 @@ -37,7 +37,7 @@ def parse_mermaid_macro(filename): file.write(line) def run(filename): - return parse_mermaid_macro(filename) + parse_mermaid_macros(filename) #parse_mermaid_macro('./documentation/page 3/index.md') \ No newline at end of file diff --git a/MarkdownToConfluence/modules/mermaid/tests/test_mermaid_parser.py b/MarkdownToConfluence/modules/mermaid/tests/test_mermaid_parser.py index c390e34..9962c99 100644 --- a/MarkdownToConfluence/modules/mermaid/tests/test_mermaid_parser.py +++ b/MarkdownToConfluence/modules/mermaid/tests/test_mermaid_parser.py @@ -4,11 +4,16 @@ def test_parse_mermaid_macro(): file = str(pathlib.Path(__file__).parent.resolve()) + '/testdocs/index.md' - run(file) - assert os.path.exists(str(pathlib.Path(__file__).parent.resolve()) + '/testdocs/index-1.png') - assert os.path.exists(str(pathlib.Path(__file__).parent.resolve()) + '/testdocs/index_final.md') - with open(str(pathlib.Path(__file__).parent.resolve()) + '/testdocs/index_final.md', 'r') as f: + test_file = file.replace('.md', '_test.md') + with open(file, 'r') as f: + lines = f.readlines() + with open(test_file, 'w') as f: + for line in lines: + f.write(line) + run(test_file) + assert os.path.exists(str(pathlib.Path(__file__).parent.resolve()) + '/testdocs/index_test-1.png') + with open(test_file, 'r') as f: line = f.readline() - assert line == f'![mermaid-1]({str(pathlib.Path(__file__).parent.resolve())}/testdocs/index-1.png)' - os.remove(str(pathlib.Path(__file__).parent.resolve()) + '/testdocs/index_final.md') - os.remove(str(pathlib.Path(__file__).parent.resolve()) + '/testdocs/index-1.png') \ No newline at end of file + assert line == f'![mermaid-1]({str(pathlib.Path(__file__).parent.resolve())}/testdocs/index_test-1.png)' + os.remove(test_file) + os.remove(str(pathlib.Path(__file__).parent.resolve()) + '/testdocs/index_test-1.png') \ No newline at end of file diff --git a/MarkdownToConfluence/modules/table_of_contents/__init__.py b/MarkdownToConfluence/modules/table_of_contents/__init__.py new file mode 100644 index 0000000..3afe1c6 --- /dev/null +++ b/MarkdownToConfluence/modules/table_of_contents/__init__.py @@ -0,0 +1 @@ +from .table_of_contents_parser import run \ No newline at end of file diff --git a/MarkdownToConfluence/modules/table_of_contents/table_of_contents_parser.py b/MarkdownToConfluence/modules/table_of_contents/table_of_contents_parser.py new file mode 100644 index 0000000..fac0506 --- /dev/null +++ b/MarkdownToConfluence/modules/table_of_contents/table_of_contents_parser.py @@ -0,0 +1,30 @@ +import os + +def parse_table_of_contents_macros(filename): + if(os.path.isdir(filename)): + filename += "/index_final.md" + reading_toc = False + root = '@self' + start_depth = 1 + with open(f"{filename}", "r") as file: + lines = file.readlines() + with open(f"{filename}", "w") as file: + for line in lines: + if line.strip("\n") == "```table-of-contents" or line.strip("\n") == "```TOC": + reading_toc = True + if reading_toc: + if(line.strip("\n") != "```mermaid" and line.strip("\n") != "```"): + if(line.find('root') != -1): + root = line.split('=')[-1].strip() + if(line.find('start-depth') != -1): + depth = line.split('=')[-1].strip() + if(depth.isnumeric()): + start_depth = int(depth) + if line.strip("\n") == "```": + file.write(f'<p><ac:structured-macro ac:name=\"pagetree\" ac:schema-version=\"1\" ac:macro-id=\"cace95ee428b28ba686848696668d8ca\"><ac:parameter ac:name=\"root\"><ac:link><ri:page ri:content-title="{root}" /></ac:link></ac:parameter><ac:parameter ac:name=\"startDepth\">{start_depth}</ac:parameter></ac:structured-macro></p><p />') + reading_toc = False + else: + file.write(line) + +def run(filename): + parse_table_of_contents_macros(filename) diff --git a/MarkdownToConfluence/modules/trello_boards/__init__.py b/MarkdownToConfluence/modules/trello_boards/__init__.py new file mode 100644 index 0000000..0075ddd --- /dev/null +++ b/MarkdownToConfluence/modules/trello_boards/__init__.py @@ -0,0 +1 @@ +from .trello_boards_parser import run \ No newline at end of file diff --git a/MarkdownToConfluence/modules/trello_boards/trello_boards_parser.py b/MarkdownToConfluence/modules/trello_boards/trello_boards_parser.py new file mode 100644 index 0000000..9add52a --- /dev/null +++ b/MarkdownToConfluence/modules/trello_boards/trello_boards_parser.py @@ -0,0 +1,22 @@ +import re, requests + +def parse_boards(filename: str): + with open(filename, 'r') as f: + lines = f.readlines() + with open(filename, 'w') as f: + for line in lines: + res = parse_board(line) + new_line = res if res.endswith('\n') else res + '\n' + f.write(new_line) + +def parse_board(line: str) -> str: + boards = re.findall(r'((https://)(trello.com/b/)[a-zA-Z\d]+([/][\w-]+)*)', line) #official atlassian regex magic + new_line = line + for board in boards: + board_url = board[0] + board_tag = f'<ac:structured-macro ac:name=\"trello-board\" ac:schema-version=\"1\" data-layout=\"default\" ac:macro-id=\"39a55cc39b49f1a520d43a1c87bf1f07\"><ac:parameter ac:name=\"url\">{board_url}</ac:parameter><ac:parameter ac:name=\"height\">760px</ac:parameter></ac:structured-macro>' + new_line = new_line.replace(board_url, board_tag) + return new_line + +def run(filename): + parse_boards(filename) \ No newline at end of file diff --git a/MarkdownToConfluence/utils/__init__.py b/MarkdownToConfluence/utils/__init__.py new file mode 100644 index 0000000..5137ec8 --- /dev/null +++ b/MarkdownToConfluence/utils/__init__.py @@ -0,0 +1,4 @@ +__all__ = ["page_file_info", "paths", "image_parser"] +from .paths import get_abs_path_from_relative +from .page_file_info import * +from .image_parser import convert_all_md_img_to_confluence_img diff --git a/MarkdownToConfluence/filetools/file_traversal.py b/MarkdownToConfluence/utils/file_traversal.py similarity index 85% rename from MarkdownToConfluence/filetools/file_traversal.py rename to MarkdownToConfluence/utils/file_traversal.py index 417b2f2..2b62c6b 100644 --- a/MarkdownToConfluence/filetools/file_traversal.py +++ b/MarkdownToConfluence/utils/file_traversal.py @@ -1,17 +1,14 @@ -import os -# assign directory -FILES_PATH = os.environ.get("INPUT_FILESLOCATION") - -# iterate over files in -# that directory -def traverse(directory): - for filename in os.listdir(directory): - f = os.path.join(directory, filename) - # checking if it is a file - if(os.path.isdir(f)): - traverse(f) - if(f.endswith('.md')): - print(f) - - -traverse(FILES_PATH) \ No newline at end of file +import os +# assign directory +FILES_PATH = os.environ.get("INPUT_FILESLOCATION") + +# iterate over files in +# that directory +def traverse(directory): + for filename in os.listdir(directory): + f = os.path.join(directory, filename) + # checking if it is a file + if(os.path.isdir(f)): + traverse(f) + if(f.endswith('.md')): + print(f) \ No newline at end of file diff --git a/MarkdownToConfluence/modules/image/image_parser.py b/MarkdownToConfluence/utils/image_parser.py similarity index 83% rename from MarkdownToConfluence/modules/image/image_parser.py rename to MarkdownToConfluence/utils/image_parser.py index 307b459..15105f9 100644 --- a/MarkdownToConfluence/modules/image/image_parser.py +++ b/MarkdownToConfluence/utils/image_parser.py @@ -1,7 +1,7 @@ from posixpath import dirname, basename import re, os -from MarkdownToConfluence.filetools import get_abs_path_from_relative -import globals +from MarkdownToConfluence.utils import get_abs_path_from_relative +from MarkdownToConfluence import globals from PIL import Image @@ -24,7 +24,7 @@ def convert_md_img_to_confluence_img(md_image_link: str, md_path: str): width, height = image.size name = img['title'] if img["title"] != None else basename(img['filename']) globals.attachments.append((name, path)) - return(f'<ac:image ac:original-height="{str(height)}" ac:original-width="{str(width)}"><ri:attachment ri:filename="{name}"/></ac:image>\n') + return(md_image_link.replace(img.string, f'<ac:image ac:original-height="{str(height)}" ac:original-width="{str(width)}" ac:width="{str(width)}"><ri:attachment ri:filename="{name}"/></ac:image>\n')) else: return None diff --git a/MarkdownToConfluence/filetools/page_file_info.py b/MarkdownToConfluence/utils/page_file_info.py similarity index 91% rename from MarkdownToConfluence/filetools/page_file_info.py rename to MarkdownToConfluence/utils/page_file_info.py index 58eb06b..f7786dd 100644 --- a/MarkdownToConfluence/filetools/page_file_info.py +++ b/MarkdownToConfluence/utils/page_file_info.py @@ -1,87 +1,89 @@ -import os, json -from posixpath import basename, dirname - -# Returns "" if path == root -def get_prefix(path: str, root: str) -> str: - if(not os.path.exists(path)): - raise FileNotFoundError(path) - if(not os.path.exists(root)): - raise FileNotFoundError(root) - if(path == root): - return "" - if(path.endswith("index.md") and "prefix.txt" in os.listdir(dirname(path))): # No prefix for index page in folder with prefix.txt (prefix is only for underpages) - return "" - if(os.path.isfile(path)): - path = os.path.dirname(path) - else: - if("prefix.txt" in os.listdir(path)): # assume index.md, No prefix for index page in folder with prefix.txt (prefix is only for underpages) - return "" - while("prefix.txt" not in os.listdir(path)): - path = os.path.dirname(path) - if(path == root or path == ""): - return "" - with open(f"{path}/prefix.txt") as f: - return f.readline() - -# Returns "" if path == root -def get_page_name_from_path(path: str, root: str): - if(path == root): - return "" - if(os.path.isdir(path)): # Assume index.md if path is dir - path += "/index.md" - path_arr = path.split('/') - page_name = get_prefix(path, root) - file_name = basename(path) - if(file_name == "index.md"): - page_name += path_arr[-2] - else: - page_name += file_name - return page_name.strip('.md') - -# Returns the page name of the parent of the file in path. Returns default value if no parent exists i system -# Returns "" if path == root -def get_parent_name_from_path(path: str, root: str, default="Overview"): - if(path == root): - return "" - if("settings.json" in os.listdir(root)): - settings = json.load(open(root + "/settings.json")) - if("parent_page" in settings.keys()): - default = settings["parent_page"] - if(os.path.isdir(path)): # Assume index.md if path is dir - path += "/index.md" - - path_arr = path.split('/') - file_name = basename(path) - parent_name = "" - - if(file_name == "index.md"): - parent_path = dirname(dirname(path)) - else: - parent_path = dirname(path) - if(parent_path != root): - parent_name = get_page_name_from_path(parent_path, root) - else: - parent_name = default - return parent_name - - -def get_all_md_paths(root: str): - paths = [] - def traverse(directory): - for filename in os.listdir(directory): - f = os.path.join(directory, filename) - # checking if it is a file - if(os.path.isdir(f)): - traverse(f) - if(f.endswith('.md')): - paths.append(f) - traverse(root) - return paths - -def get_all_page_names_in_filesystem(root: str): - page_names = [] - for path in get_all_md_paths(root): - name = (get_page_name_from_path(path, root)) - print(name) - page_names.append(name) - return page_names +import os, json +from posixpath import basename, dirname + +# Returns "" if path == root +def get_prefix(path: str, root: str) -> str: + if(not os.path.exists(path)): + raise FileNotFoundError(path) + if(not os.path.exists(root)): + raise FileNotFoundError(root) + if(path == root): + return "" + if(path.endswith("index.md") and "prefix.txt" in os.listdir(dirname(path))): # No prefix for index page in folder with prefix.txt (prefix is only for underpages) + return "" + if(path.endswith("index.md") and dirname(path) == root): + return "" + if(os.path.isfile(path)): + path = os.path.dirname(path) + else: + if("prefix.txt" in os.listdir(path)): # assume index.md, No prefix for index page in folder with prefix.txt (prefix is only for underpages) + return "" + while("prefix.txt" not in os.listdir(path)): + path = os.path.dirname(path) + if(path == root or path == "" or path == os.sep): + return "" + with open(f"{path}/prefix.txt", 'r') as f: + return f.readline() + +# Returns "" if path == root +def get_page_name_from_path(path: str, root: str): + if(path == root): + return "" + if(os.path.isdir(path)): # Assume index.md if path is dir + path += "/index.md" + path_arr = path.split('/') + page_name = get_prefix(path, root) + file_name = basename(path) + if(file_name == "index.md"): + page_name += path_arr[-2] + else: + page_name += file_name + return page_name.strip('.md') + +# Returns the page name of the parent of the file in path. Returns default value if no parent exists i system +# Returns "" if path == root +def get_parent_name_from_path(path: str, root: str, default=""): + if(path == root): + return "" + if("settings.json" in os.listdir(root)): + settings = json.load(open(root + "/settings.json")) + if("parent_page" in settings.keys()): + default = settings["parent_page"] + if(os.path.isdir(path)): # Assume index.md if path is dir + path += "/index.md" + + path_arr = path.split('/') + file_name = basename(path) + parent_name = "" + + if(file_name == "index.md"): + parent_path = dirname(dirname(path)) + else: + parent_path = dirname(path) + if(parent_path != root): + parent_name = get_page_name_from_path(parent_path, root) + else: + parent_name = default + return parent_name + + +def get_all_md_paths(root: str): + paths = [] + def traverse(directory): + for filename in os.listdir(directory): + f = os.path.join(directory, filename) + # checking if it is a file + if(os.path.isdir(f)): + traverse(f) + if(f.endswith('.md')): + paths.append(f) + traverse(root) + return paths + +def get_all_page_names_in_filesystem(root: str): + page_names = [] + for path in get_all_md_paths(root): + name = (get_page_name_from_path(path, root)) + page_names.append(name) + return page_names + diff --git a/MarkdownToConfluence/filetools/paths.py b/MarkdownToConfluence/utils/paths.py similarity index 74% rename from MarkdownToConfluence/filetools/paths.py rename to MarkdownToConfluence/utils/paths.py index a9cc0db..05829ae 100644 --- a/MarkdownToConfluence/filetools/paths.py +++ b/MarkdownToConfluence/utils/paths.py @@ -8,13 +8,13 @@ def get_abs_path_from_relative(relative_path: str, source_path: str, root=os.env relative_path = relative_path.strip() source_path = source_path.strip() abs_path = "" - if(os.path.isabs(relative_path)): + if(os.path.exists(str(os.path.realpath((os.path.join(source_path, relative_path))).strip()))): + abs_path = (os.path.join(source_path, relative_path)).strip() + elif(os.path.isabs(relative_path)): if(os.fspath(relative_path).startswith(os.getcwd())): abs_path = relative_path else: abs_path = os.path.join(_root, relative_path) - elif(os.path.exists(str(os.path.realpath((os.path.join(_root, source_path, relative_path))).strip()))): - abs_path = (os.path.join(_root, source_path, relative_path)).strip() else: abs_path = os.path.abspath(relative_path) #print(source_path, '\n', relative_path, '\n', os.path.realpath(abs_path), '\n') @@ -26,4 +26,6 @@ def get_abs_path_from_relative(relative_path: str, source_path: str, root=os.env # abs_path = os.path.realpath(os.path.join(dirname(source_path), relative_path)) # else: # abs_path = os.path.abspath(relative_path) - return os.path.realpath(abs_path) \ No newline at end of file + return os.path.realpath(abs_path) + +#print(get_abs_path_from_relative('./zip_test.zip', os.path.abspath('./documentation/page 3/index.md'), './documentation')) \ No newline at end of file diff --git a/MarkdownToConfluence/filetools/tests/__init__.py b/MarkdownToConfluence/utils/tests/__init__.py similarity index 100% rename from MarkdownToConfluence/filetools/tests/__init__.py rename to MarkdownToConfluence/utils/tests/__init__.py diff --git a/MarkdownToConfluence/filetools/tests/test_page_file_info.py b/MarkdownToConfluence/utils/tests/test_page_file_info.py similarity index 85% rename from MarkdownToConfluence/filetools/tests/test_page_file_info.py rename to MarkdownToConfluence/utils/tests/test_page_file_info.py index 6e214cd..03c2396 100644 --- a/MarkdownToConfluence/filetools/tests/test_page_file_info.py +++ b/MarkdownToConfluence/utils/tests/test_page_file_info.py @@ -1,90 +1,90 @@ -import pathlib -import pytest -import collections -import os -from MarkdownToConfluence.filetools.page_file_info import get_page_name_from_path, get_parent_name_from_path, get_prefix, get_all_md_paths, get_all_page_names_in_filesystem - -def test_get_prefix(): - root=str(pathlib.Path(__file__).parent.resolve()) + '/testdocs' - test_path=f'{root}/page 1/index.md' - assert type(get_prefix(test_path, root)) is str - assert get_prefix(test_path, root) == "" - test_path=f'{root}/page 1' - assert type(get_prefix(test_path, root)) is str - assert get_prefix(test_path, root) == "" - test_path=f'{root}/DAM Center 5/DC 5.0/5 Security/index.md' - assert type(get_prefix(test_path, root)) is str - assert get_prefix(test_path, root) == "DC5.0.0 " - test_path=f'{root}/DAM Center 5/DC 5.0/5 Security/Configuring CORS.md' - assert type(get_prefix(test_path, root)) is str - assert get_prefix(test_path, root) == "DC5.0.0 " - assert type(get_prefix(test_path, root)) is str - assert get_prefix(root, root) == "" - with pytest.raises(FileNotFoundError): - get_prefix("path/that/dont/exists.md", root) - with pytest.raises(FileNotFoundError): - get_prefix(f'{root}/page 1/index.md', 'path/that/dont/exist') - -def test_get_page_name_from_path(): - root=str(pathlib.Path(__file__).parent.resolve()) + '/testdocs' - test_path=f'{root}/page 1/index.md' - assert type(get_page_name_from_path(test_path, root)) is str - assert get_page_name_from_path(test_path, root) == 'page 1' - test_path=f'{root}/page 1' - assert type(get_page_name_from_path(test_path, root)) is str - assert get_page_name_from_path(test_path, root) == 'page 1' - test_path=f'{root}/DAM Center 5/DC 5.0/5 Security/index.md' - assert type(get_page_name_from_path(test_path, root)) is str - assert get_page_name_from_path(test_path, root) == 'DC5.0.0 5 Security' - test_path=f'{root}/DAM Center 5/DC 5.0/5 Security/Configuring CORS.md' - assert type(get_page_name_from_path(test_path, root)) is str - assert get_page_name_from_path(test_path, root) == 'DC5.0.0 Configuring CORS' - test_path=root - assert type(get_page_name_from_path(test_path, root)) is str - assert get_page_name_from_path(test_path, root) == '' - with pytest.raises(FileNotFoundError): - get_page_name_from_path("path/that/dont/exists.md", root) - with pytest.raises(FileNotFoundError): - get_page_name_from_path(f'{root}/page 1/index.md', 'path/that/dont/exist') - -def test_get_parent_name_from_path(): - root=str(pathlib.Path(__file__).parent.resolve()) + '/testdocs' - test_path=f'{root}/page 1/index.md' - assert type(get_parent_name_from_path(test_path, root)) is str - assert get_parent_name_from_path(test_path, root) == "parent page test name" - test_path=f'{root}/page 1' - assert type(get_parent_name_from_path(test_path, root)) is str - assert get_parent_name_from_path(test_path, root) == "parent page test name" - test_path=f'{root}/DAM Center 5/DC 5.0/5 Security/index.md' - assert type(get_parent_name_from_path(test_path, root)) is str - assert get_parent_name_from_path(test_path, root) == 'DC 5.0' - test_path=f'{root}/DAM Center 5/DC 5.0/5 Security/Configuring CORS.md' - assert type(get_parent_name_from_path(test_path, root)) is str - assert get_parent_name_from_path(test_path, root) == 'DC5.0.0 5 Security' - assert type(get_parent_name_from_path(root, root)) is str - assert get_parent_name_from_path(root, root) == '' - with pytest.raises(FileNotFoundError): - get_parent_name_from_path("path/that/dont/exists.md", root) - with pytest.raises(FileNotFoundError): - get_parent_name_from_path(f'{root}/page 1/index.md', 'path/that/dont/exist') - -def test_get_all_md_paths(): - root=str(pathlib.Path(__file__).parent.resolve()) + '/testdocs' - testpaths=[f'{root}/DAM Center 5/DC 5.0/5 Security/Configuring CORS.md', f'{root}/DAM Center 5/DC 5.0/5 Security/index.md', - f'{root}/DAM Center 5/DC 5.0/index.md', f'{root}/DAM Center 5/index.md', f'{root}/page 1/index.md', f'{root}/page 1/page 1.1/index.md', - f'{root}/page 1/page 1.1/abe.md'] - paths = get_all_md_paths(root) - assert type(paths) is list - abspaths = [os.path.abspath(path) for path in paths] - abstestpaths = [os.path.abspath(path) for path in testpaths] - assert collections.Counter(abspaths) == collections.Counter(abstestpaths) - for path in abspaths: - assert os.path.exists(path) - -def test_get_all_page_names_in_filesystem(): - root= str(pathlib.Path(__file__).parent.resolve()) + '/testdocs' - testnames = ['DC5.0.0 5 Security', 'DC5.0.0 Configuring CORS', 'DC 5.0', 'DAM Center 5', 'page 1', 'page 1.1', 'abe'] - names = get_all_page_names_in_filesystem(root) - assert type(names) is list - assert collections.Counter(names) == collections.Counter(testnames) +import pathlib +import pytest +import collections +import os +from MarkdownToConfluence.utils.page_file_info import get_page_name_from_path, get_parent_name_from_path, get_prefix, get_all_md_paths, get_all_page_names_in_filesystem + +def test_get_prefix(): + root=str(pathlib.Path(__file__).parent.resolve()) + '/testdocs' + test_path=f'{root}/page 1/index.md' + assert type(get_prefix(test_path, root)) is str + assert get_prefix(test_path, root) == "" + test_path=f'{root}/page 1' + assert type(get_prefix(test_path, root)) is str + assert get_prefix(test_path, root) == "" + test_path=f'{root}/DAM Center 5/DC 5.0/5 Security/index.md' + assert type(get_prefix(test_path, root)) is str + assert get_prefix(test_path, root) == "DC5.0.0 " + test_path=f'{root}/DAM Center 5/DC 5.0/5 Security/Configuring CORS.md' + assert type(get_prefix(test_path, root)) is str + assert get_prefix(test_path, root) == "DC5.0.0 " + assert type(get_prefix(test_path, root)) is str + assert get_prefix(root, root) == "" + with pytest.raises(FileNotFoundError): + get_prefix("path/that/dont/exists.md", root) + with pytest.raises(FileNotFoundError): + get_prefix(f'{root}/page 1/index.md', 'path/that/dont/exist') + +def test_get_page_name_from_path(): + root=str(pathlib.Path(__file__).parent.resolve()) + '/testdocs' + test_path=f'{root}/page 1/index.md' + assert type(get_page_name_from_path(test_path, root)) is str + assert get_page_name_from_path(test_path, root) == 'page 1' + test_path=f'{root}/page 1' + assert type(get_page_name_from_path(test_path, root)) is str + assert get_page_name_from_path(test_path, root) == 'page 1' + test_path=f'{root}/DAM Center 5/DC 5.0/5 Security/index.md' + assert type(get_page_name_from_path(test_path, root)) is str + assert get_page_name_from_path(test_path, root) == 'DC5.0.0 5 Security' + test_path=f'{root}/DAM Center 5/DC 5.0/5 Security/Configuring CORS.md' + assert type(get_page_name_from_path(test_path, root)) is str + assert get_page_name_from_path(test_path, root) == 'DC5.0.0 Configuring CORS' + test_path=root + assert type(get_page_name_from_path(test_path, root)) is str + assert get_page_name_from_path(test_path, root) == '' + with pytest.raises(FileNotFoundError): + get_page_name_from_path("path/that/dont/exists.md", root) + with pytest.raises(FileNotFoundError): + get_page_name_from_path(f'{root}/page 1/index.md', 'path/that/dont/exist') + +def test_get_parent_name_from_path(): + root=str(pathlib.Path(__file__).parent.resolve()) + '/testdocs' + test_path=f'{root}/page 1/index.md' + assert type(get_parent_name_from_path(test_path, root)) is str + assert get_parent_name_from_path(test_path, root) == "parent page test name" + test_path=f'{root}/page 1' + assert type(get_parent_name_from_path(test_path, root)) is str + assert get_parent_name_from_path(test_path, root) == "parent page test name" + test_path=f'{root}/DAM Center 5/DC 5.0/5 Security/index.md' + assert type(get_parent_name_from_path(test_path, root)) is str + assert get_parent_name_from_path(test_path, root) == 'DC 5.0' + test_path=f'{root}/DAM Center 5/DC 5.0/5 Security/Configuring CORS.md' + assert type(get_parent_name_from_path(test_path, root)) is str + assert get_parent_name_from_path(test_path, root) == 'DC5.0.0 5 Security' + assert type(get_parent_name_from_path(root, root)) is str + assert get_parent_name_from_path(root, root) == '' + with pytest.raises(FileNotFoundError): + get_parent_name_from_path("path/that/dont/exists.md", root) + with pytest.raises(FileNotFoundError): + get_parent_name_from_path(f'{root}/page 1/index.md', 'path/that/dont/exist') + +def test_get_all_md_paths(): + root=str(pathlib.Path(__file__).parent.resolve()) + '/testdocs/DAM Center 5' + testpaths=[f'{root}/DC 5.0/5 Security/Configuring CORS.md', f'{root}/DC 5.0/5 Security/index.md', + f'{root}/DC 5.0/index.md', f'{root}/index.md'] + paths = get_all_md_paths(root) + assert type(paths) is list + abspaths = [os.path.abspath(path) for path in paths] + abstestpaths = [os.path.abspath(path) for path in testpaths] + assert collections.Counter(abspaths) == collections.Counter(abstestpaths) + for path in abspaths: + assert os.path.exists(path) + +def test_get_all_page_names_in_filesystem(): + root=str(pathlib.Path(__file__).parent.resolve()) + '/testdocs/DAM Center 5' + print(root) + testnames = ['DC5.0.0 5 Security', 'DC5.0.0 Configuring CORS', 'DC 5.0', 'DAM Center 5'] + names = get_all_page_names_in_filesystem(root) + assert type(names) is list + assert collections.Counter(names) == collections.Counter(testnames) assert len(names) == len(set(names)) \ No newline at end of file diff --git a/MarkdownToConfluence/filetools/tests/test_paths.py b/MarkdownToConfluence/utils/tests/test_paths.py similarity index 73% rename from MarkdownToConfluence/filetools/tests/test_paths.py rename to MarkdownToConfluence/utils/tests/test_paths.py index 9b73fc6..8b6fa1b 100644 --- a/MarkdownToConfluence/filetools/tests/test_paths.py +++ b/MarkdownToConfluence/utils/tests/test_paths.py @@ -1,11 +1,11 @@ from posixpath import dirname -from MarkdownToConfluence.filetools.paths import get_abs_path_from_relative +from MarkdownToConfluence.utils.paths import get_abs_path_from_relative import pathlib, os def test_get_abs_path_from_relative(): source_path =str(pathlib.Path(__file__).resolve()) assert str(get_abs_path_from_relative('./testdocs/page 1/index-1.png', source_path, './MarkdownToConfluence')) == f'{dirname(source_path)}/testdocs/page 1/index-1.png' - assert str(get_abs_path_from_relative('MarkdownToConfluence/filetools/tests/testdocs/page 1/index.md', source_path, './MarkdownToConfluence')) == f'{(dirname(source_path))}/testdocs/page 1/index.md' + assert str(get_abs_path_from_relative('MarkdownToConfluence/utils/tests/testdocs/page 1/index.md', source_path, './MarkdownToConfluence')) == f'{(dirname(source_path))}/testdocs/page 1/index.md' assert str(get_abs_path_from_relative('../DAM Center 5/index.md', f'{dirname(source_path)}/testdocs/page 1/index.md', './MarkdownToConfluence')) == f'{dirname(source_path)}/testdocs/DAM Center 5/index.md' diff --git a/MarkdownToConfluence/filetools/tests/testdocs/DAM Center 5/DC 5.0/5 Security/Configuring CORS.md b/MarkdownToConfluence/utils/tests/testdocs/DAM Center 5/DC 5.0/5 Security/Configuring CORS.md similarity index 100% rename from MarkdownToConfluence/filetools/tests/testdocs/DAM Center 5/DC 5.0/5 Security/Configuring CORS.md rename to MarkdownToConfluence/utils/tests/testdocs/DAM Center 5/DC 5.0/5 Security/Configuring CORS.md diff --git a/MarkdownToConfluence/filetools/tests/testdocs/DAM Center 5/DC 5.0/5 Security/index.md b/MarkdownToConfluence/utils/tests/testdocs/DAM Center 5/DC 5.0/5 Security/index.md similarity index 100% rename from MarkdownToConfluence/filetools/tests/testdocs/DAM Center 5/DC 5.0/5 Security/index.md rename to MarkdownToConfluence/utils/tests/testdocs/DAM Center 5/DC 5.0/5 Security/index.md diff --git a/MarkdownToConfluence/filetools/tests/testdocs/DAM Center 5/DC 5.0/index.md b/MarkdownToConfluence/utils/tests/testdocs/DAM Center 5/DC 5.0/index.md similarity index 100% rename from MarkdownToConfluence/filetools/tests/testdocs/DAM Center 5/DC 5.0/index.md rename to MarkdownToConfluence/utils/tests/testdocs/DAM Center 5/DC 5.0/index.md diff --git a/MarkdownToConfluence/filetools/tests/testdocs/DAM Center 5/DC 5.0/prefix.txt b/MarkdownToConfluence/utils/tests/testdocs/DAM Center 5/DC 5.0/prefix.txt similarity index 100% rename from MarkdownToConfluence/filetools/tests/testdocs/DAM Center 5/DC 5.0/prefix.txt rename to MarkdownToConfluence/utils/tests/testdocs/DAM Center 5/DC 5.0/prefix.txt diff --git a/MarkdownToConfluence/filetools/tests/testdocs/DAM Center 5/index.md b/MarkdownToConfluence/utils/tests/testdocs/DAM Center 5/index.md similarity index 100% rename from MarkdownToConfluence/filetools/tests/testdocs/DAM Center 5/index.md rename to MarkdownToConfluence/utils/tests/testdocs/DAM Center 5/index.md diff --git a/MarkdownToConfluence/file_parsing/tests/testdocs/images/attachments/image.png b/MarkdownToConfluence/utils/tests/testdocs/attachments/image.png similarity index 100% rename from MarkdownToConfluence/file_parsing/tests/testdocs/images/attachments/image.png rename to MarkdownToConfluence/utils/tests/testdocs/attachments/image.png diff --git a/MarkdownToConfluence/utils/tests/testdocs/markdown/image.md b/MarkdownToConfluence/utils/tests/testdocs/markdown/image.md new file mode 100644 index 0000000..02a9dda --- /dev/null +++ b/MarkdownToConfluence/utils/tests/testdocs/markdown/image.md @@ -0,0 +1,6 @@ +![alt](../attachments/image.png "title") +![alt](./image.png "title") +![alt](MarkdownToConfluence/utils/tests/testdocs/attachments/image.png "title") +![alt](../attachments/image.png) +![alt](./image.png) +![alt](MarkdownToConfluence/utils/tests/testdocs/attachments/image.png) \ No newline at end of file diff --git a/MarkdownToConfluence/file_parsing/tests/testdocs/images/markdown/image.png b/MarkdownToConfluence/utils/tests/testdocs/markdown/image.png similarity index 100% rename from MarkdownToConfluence/file_parsing/tests/testdocs/images/markdown/image.png rename to MarkdownToConfluence/utils/tests/testdocs/markdown/image.png diff --git a/testfile.md b/MarkdownToConfluence/utils/tests/testdocs/markdown/image_test.md similarity index 100% rename from testfile.md rename to MarkdownToConfluence/utils/tests/testdocs/markdown/image_test.md diff --git a/MarkdownToConfluence/filetools/tests/testdocs/page 1/index-1.png b/MarkdownToConfluence/utils/tests/testdocs/page 1/index-1.png similarity index 100% rename from MarkdownToConfluence/filetools/tests/testdocs/page 1/index-1.png rename to MarkdownToConfluence/utils/tests/testdocs/page 1/index-1.png diff --git a/MarkdownToConfluence/filetools/tests/testdocs/page 1/index.md b/MarkdownToConfluence/utils/tests/testdocs/page 1/index.md similarity index 96% rename from MarkdownToConfluence/filetools/tests/testdocs/page 1/index.md rename to MarkdownToConfluence/utils/tests/testdocs/page 1/index.md index 4bd886a..407d7dd 100644 --- a/MarkdownToConfluence/filetools/tests/testdocs/page 1/index.md +++ b/MarkdownToConfluence/utils/tests/testdocs/page 1/index.md @@ -1,3 +1,3 @@ -# this is a page 1 - +# this is a page 1 + IF THIS WORK I GO BEAT MY MEAT \ No newline at end of file diff --git a/MarkdownToConfluence/filetools/tests/testdocs/page 1/page 1.1/abe.md b/MarkdownToConfluence/utils/tests/testdocs/page 1/page 1.1/abe.md similarity index 100% rename from MarkdownToConfluence/filetools/tests/testdocs/page 1/page 1.1/abe.md rename to MarkdownToConfluence/utils/tests/testdocs/page 1/page 1.1/abe.md diff --git a/MarkdownToConfluence/filetools/tests/testdocs/page 1/page 1.1/index.md b/MarkdownToConfluence/utils/tests/testdocs/page 1/page 1.1/index.md similarity index 100% rename from MarkdownToConfluence/filetools/tests/testdocs/page 1/page 1.1/index.md rename to MarkdownToConfluence/utils/tests/testdocs/page 1/page 1.1/index.md diff --git a/MarkdownToConfluence/filetools/tests/testdocs/settings.json b/MarkdownToConfluence/utils/tests/testdocs/settings.json similarity index 95% rename from MarkdownToConfluence/filetools/tests/testdocs/settings.json rename to MarkdownToConfluence/utils/tests/testdocs/settings.json index 35ce7dc..79b4214 100644 --- a/MarkdownToConfluence/filetools/tests/testdocs/settings.json +++ b/MarkdownToConfluence/utils/tests/testdocs/settings.json @@ -1,3 +1,3 @@ -{ - "parent_page": "parent page test name" +{ + "parent_page": "parent page test name" } \ No newline at end of file diff --git a/README.md b/README.md index 2b55926..d67591e 100644 --- a/README.md +++ b/README.md @@ -3,45 +3,101 @@ Bachelor 2022 - Anders Larsen & Theis Tengs This action converts your markdown files into the specified Atlassian Confluence space. +# Setup +## API User Token +First you need to create an API token for the user, you want to use for the action. We recommend that you create a new user, that is only used for this action, in order to get the full benefits from the action. This user should also have full permission to make changes on the space. See [here](https://support.atlassian.com/atlassian-account/docs/manage-api-tokens-for-your-atlassian-account/) for how to set up your API token. + ## Environment Variables The necessary environment variables are as follows: `CONFLUENCE_URL` -The URL for the, Atlassian network +The base URL for the Atlassian network. Follows the form: 'https://[your-network-name].atlassian.net' `CONFLUENCE_SPACE_KEY` -The key of the space that is being uploaded to. - -`AUTH_TOKEN` - -This is a base64 encoded string consisting of your Atlassian username (email) together with an API token from Atlassian aswell. +The key of the space that is being uploaded to. Can be found in the URL for your space. More info [here](https://confluence.atlassian.com/doc/space-keys-829076188.html) -An example could be: +`AUTH_USERNAME` + +The email used for the user connected to the API token. We recommend setting this as a GitHub secret. + +`AUTH_API_TOKEN` + +The API token generated for the user. We recommend setting this as a GitHub secret. -your@email.com:api_token - -This then needs to be base64 encoded and added as a github secret with the name of `AUTH_TOKEN`. ## Inputs ### `fileslocation` -**Required** The path to the folder containing the markdown documentation. Default `.\`. +**Required** The path from the root of your repository, to the folder containing the markdown documentation. Default `./`. ## Outputs ### Ikke lige nogle indtil nu + ## Example usage +Without github secrets: +```yaml +- name: Conversion step + env: + CONFLUENCE_URL: 'https://network.atlassian.net/wiki' + CONFLUENCE_SPACE_KEY: 'spaceKey' + AUTH_USERNAME: 'your@email.com' + AUTH_API_TOKEN: 'PeRsOnalApItOKen' + uses: TTengs/MarkdownToConfluence@latest + with: + fileslocation: './documentation' +``` + +With GitHub secrets ```yaml - name: Conversion step - env: - CONFLUENCE_URL: 'https://network.atlassian.net/wiki' - CONFLUENCE_SPACE_KEY: 'spaceKey' - AUTH_TOKEN: ${{ secrets.AUTH_TOKEN }} - uses: TTengs/MarkdownToConfluence@v1.1 - id: Convert - with: - fileslocation: './documentation' + env: + CONFLUENCE_URL: 'https://network.atlassian.net/wiki' + CONFLUENCE_SPACE_KEY: 'spaceKey' + AUTH_USERNAME: ${{ secrets.AUTH_USERNAME }} + AUTH_API_TOKEN: ${{ secrets.AUTH_API_TOKEN }} + uses: TTengs/MarkdownToConfluence@latest + with: + fileslocation: './documentation' ``` + +--- + +# Writing Documentation + +## Page structure +The structure of the markdown files in the filesystem, dictates the structure of the pages on confluence. + +All files should be located in a single folder, which is the one specified in [fileslocation](#fileslocation). This folder will not contain any markdown files (if so, they won't be recognized as pages), but only folders, a [prefix](./doc/prefix.md)- and [settings-file](./doc/settings.md). Every subfolder under this folder, will be considered a page, these are referenced later as a "folderpage". + +A folderpage can contain other folderpages, as well as markdown files. The file containing the content of the folderpage, __MUST__ be named "index.md". Any other markdown files inside the folderpage, will be considered as a child page. + +A child page can also be defined by another folderpage inside a folderpage. This is only recommended, if you need child pages for that folderpage as well. Otherwise, we recommend simply using multiple markdown files. + +### Page naming +The name of a folderpage dicates the name of the page in confluence. + +Folderpages with multiple markdown files, will contain child pages named after the name of the markdown file. + +Any folderpage can contain a [prefix.txt](./doc/prefix.md) file, dictating the prefix for all it's child pages. + +### Example +The following filestructure: + +![filesystem](./doc/images/filestructure.PNG) + +Will look like this, once uploaded to Confluence: + +![pagestructure](./doc/images/pagestructure.PNG) + +## Modules +This tool comes with a number of modules, which add extra markdown syntax, specialized for Confluence and other tools. + +- [Jira Tickets](./doc/modules/jira-tickets.md) +- [Attachments](./doc/modules/attachments.md) +- [Mermaid.js](./doc/modules/mermaid.md) +- [Table of Contents](./doc/modules/table-of-contents.md) +- [Trello Boards](./doc/modules/trello-boards.md) diff --git a/doc/images/attachment.PNG b/doc/images/attachment.PNG new file mode 100644 index 0000000..d041eff Binary files /dev/null and b/doc/images/attachment.PNG differ diff --git a/doc/images/filestructure.PNG b/doc/images/filestructure.PNG new file mode 100644 index 0000000..bdd4132 Binary files /dev/null and b/doc/images/filestructure.PNG differ diff --git a/doc/images/jira ticket.PNG b/doc/images/jira ticket.PNG new file mode 100644 index 0000000..57dbf3d Binary files /dev/null and b/doc/images/jira ticket.PNG differ diff --git a/doc/images/pagestructure.PNG b/doc/images/pagestructure.PNG new file mode 100644 index 0000000..d14e694 Binary files /dev/null and b/doc/images/pagestructure.PNG differ diff --git a/doc/images/prefix example.PNG b/doc/images/prefix example.PNG new file mode 100644 index 0000000..5899fed Binary files /dev/null and b/doc/images/prefix example.PNG differ diff --git a/doc/images/prefix result.PNG b/doc/images/prefix result.PNG new file mode 100644 index 0000000..f215b5d Binary files /dev/null and b/doc/images/prefix result.PNG differ diff --git a/doc/modules/attachments.md b/doc/modules/attachments.md new file mode 100644 index 0000000..f8b4bec --- /dev/null +++ b/doc/modules/attachments.md @@ -0,0 +1,34 @@ +# Attachments and Assets +It is possible to reference a multitude of different types of assets and attachments. + +## File location +The assets and attachments you wish to upload, can be stored anywhere inside of the documentation root folder. When referencing them, you simply specify either the relative path of the markdown file you wish the asset to be linked to, or the absoulute path from the root of the documentation folder (here you have to start the path with the name of the root folder). + +### Examples +With the given filestructure: + +![filestructure](../images/filestructure.PNG) + +If you want to incoorporate image.png into "page 3", you simple use the path `./image.png` + +But if you want to reference that same image from "page 1", you would write: `documentation/page 3/image.png`, given that "documentation" is the name of the root folder. + +You can therefore also create a dedicated attachment folder anywhere in the filesystem, and reference that when you need to attach a file or an image. + +## Images +You can insert an image by referencing it using regular markdown syntax: + +`![alt](filepath "optional title")` + +Only images of types .png and .jpg are supported. + +## Other attachments +If you want to attach a different filetype, it is also done with regular markdown syntax: + +`[alt](filepath "optional title")` + + | Note the missing "!" + +These attachments will then be uploaded to the page, and a reference link will be inserted into the page: + +![attachment](../images/attachment.PNG) \ No newline at end of file diff --git a/doc/modules/jira-tickets.md b/doc/modules/jira-tickets.md new file mode 100644 index 0000000..1aabc27 --- /dev/null +++ b/doc/modules/jira-tickets.md @@ -0,0 +1,16 @@ +# Jira Tickets +Jira tickets can be referenced and rendered by simply writing the unique key for the ticket/issue. + +The status of the issue wil automatically be updated, when it changes on Jira + +## Example +Markdown: + +```markdown +BAC-74 +this ticket, BAC-77, is within a line +``` + +This will be rendered like this: + +![jira-ticket](../images/jira%20ticket.PNG) \ No newline at end of file diff --git a/doc/modules/mermaid.md b/doc/modules/mermaid.md new file mode 100644 index 0000000..07311f6 --- /dev/null +++ b/doc/modules/mermaid.md @@ -0,0 +1,16 @@ +# Mermaid.js +Mermaid lets you create diagrams and visualizations using text and code. + +It is a Javascript based diagramming and charting tool that renders Markdown-inspired text definitions to create and modify diagrams dynamically. + +These diagrams will be rendered and uploaded to confluence as a PNG, and displayed on the page at the location of the macro. + +You can read more about how to write mermaid diagrams [here](https://mermaid-js.github.io/mermaid/#/) + +## Syntax +``` + ```mermaid + graph + ``` +``` + diff --git a/doc/modules/table-of-contents.md b/doc/modules/table-of-contents.md new file mode 100644 index 0000000..a5ec1fd --- /dev/null +++ b/doc/modules/table-of-contents.md @@ -0,0 +1,47 @@ +# Table of Contents +You can display a table of contents, showing a page tree of your confluence documentation. + +## Syntax +```markdown + ```TOC + [options] + ``` +``` +or +```markdown + ```table-of-contents + [options] + ``` +``` + +## Options +You can specify options for the page tree between the code blocks for the macro. + +`[option]=[value]` + +All options are optional, and can be left out. + +### `root` +This option specifies the root of the page tree. The root can either be the name of a page under the page containing the tree, or you can use '@self' or '@home' to reference the page containing the tree, or the home page, respectivly. + +Default = @self + +### `start-depth` +Any positive number representing the level to which child pages are shown when the page tree is first displayed. + +Default = 1 + +## Examples +```markdown + ```TOC + root=@home + start-depth=3 + ``` +``` + +You can also create a tree with no specified options like so: + +```markdown + ```TOC + ``` +``` \ No newline at end of file diff --git a/doc/modules/trello-boards.md b/doc/modules/trello-boards.md new file mode 100644 index 0000000..286cb18 --- /dev/null +++ b/doc/modules/trello-boards.md @@ -0,0 +1,2 @@ +# Trello Boards +You can display a trello board on your page, by simply pasting the URL for the board, anywhere in the markdown file. The Trello board will then be rendered directly into your page. \ No newline at end of file diff --git a/doc/prefix.md b/doc/prefix.md new file mode 100644 index 0000000..e589f94 --- /dev/null +++ b/doc/prefix.md @@ -0,0 +1,11 @@ +# Prefix file +Any folder or folderpage can contain a prefix.txt file. This can specify a prefix for the name of all it's child pages. The file must only contain __ONE__ line, which is the prefix for the pages. + +## Example +The following filestrcture, where prefix.txt contains the line: `DC5.0.0 ` + +![prefix example](./images/prefix%20example.PNG) + +Will result in the following pages: + +![prefix results](./images/prefix%20result.PNG) \ No newline at end of file diff --git a/doc/settings.md b/doc/settings.md new file mode 100644 index 0000000..713b6dd --- /dev/null +++ b/doc/settings.md @@ -0,0 +1,24 @@ +# Space settings +The root folder for your documentation can contain a settings.json file. This file can specify settings for how your documentation should be parsed and uploaded to confluence. + +--- +## Settings + +### `parent_page` +The name of the parent page for all of your documentation. This defaults to 'Overview', which is the standard root page for confluence spaces. + +Type: String +Required: No + +--- +### `modules` +This is a list of all the modules you want to be used in your system. Only modules listed here, will be used. If this option is not specified, all modules will be used. + +Available modules: + - mermaid + - jira-tickets + - attachment_link + - table_of_contents + +Type: List of Strings +Required: No \ No newline at end of file diff --git a/documentation/DAM Center 5/index.md b/documentation/DAM Center 5/index.md index e69de29..f645d9a 100644 --- a/documentation/DAM Center 5/index.md +++ b/documentation/DAM Center 5/index.md @@ -0,0 +1,5 @@ +# DAM Center 5 + +```TOC +start-depth=3 +``` \ No newline at end of file diff --git a/documentation/page 1/index.md b/documentation/page 1/index.md index 1cbe080..75a70a6 100644 --- a/documentation/page 1/index.md +++ b/documentation/page 1/index.md @@ -2,4 +2,5 @@ bare lige en hurtig test for at se om en page bliver bredere når man skriver en meget lang tekst, og om det så også går ud over størrelsen på et billede på siden -![graph](documentation/attachments/index-1.png) \ No newline at end of file +![graph](documentation/attachments/index-1.png) + diff --git a/documentation/page 1/page 1.1/abe.md b/documentation/page 1/page 1.1/abe.md index 1c48499..70b073c 100644 --- a/documentation/page 1/page 1.1/abe.md +++ b/documentation/page 1/page 1.1/abe.md @@ -1,3 +1,4 @@ # page abe -VIRKER DET HER!? \ No newline at end of file +VIRKER DET HER!? +abemand \ No newline at end of file diff --git a/documentation/page 1/page 1.1/index.md b/documentation/page 1/page 1.1/index.md index 9843dd4..4aaa599 100644 --- a/documentation/page 1/page 1.1/index.md +++ b/documentation/page 1/page 1.1/index.md @@ -1 +1,2 @@ -# page 1.1 \ No newline at end of file +# page 1.1 +dqwdqwd \ No newline at end of file diff --git a/documentation/page 2/index.md b/documentation/page 2/index.md index 2ea24c7..f057f27 100644 --- a/documentation/page 2/index.md +++ b/documentation/page 2/index.md @@ -1,2 +1,7 @@ # this is a page 2 -This change is only thing i push \ No newline at end of file +This change is only thing i push +BAC-74 +this ticket, BAC-77, is within a line + +Trello board: +https://trello.com/b/199TqwVE/project-guide \ No newline at end of file diff --git a/documentation/page 3/index.md b/documentation/page 3/index.md index 5f8483c..b0908d4 100644 --- a/documentation/page 3/index.md +++ b/documentation/page 3/index.md @@ -1,5 +1,3 @@ # this is page 3 -```mermaid - graph - A[start] --> B[end] -``` \ No newline at end of file + +![test](./zip_test.zip) \ No newline at end of file diff --git a/documentation/page 3/zip_test.zip b/documentation/page 3/zip_test.zip new file mode 100644 index 0000000..a01abc1 Binary files /dev/null and b/documentation/page 3/zip_test.zip differ diff --git a/documentation/settings.json b/documentation/settings.json index 94cad70..5e1f7df 100644 --- a/documentation/settings.json +++ b/documentation/settings.json @@ -2,6 +2,8 @@ "parent_page": "Overview", "modules": { "mermaid": true, - "image": true + "jira-tickets": true, + "attachment_link": true, + "table_of_contents": true } } \ No newline at end of file