From 237cccfdf996a60a9afeddac3351f65fdb499ea4 Mon Sep 17 00:00:00 2001 From: cupcakearmy Date: Wed, 16 Dec 2020 10:41:24 +0100 Subject: [PATCH] moving over from old repo --- .gitignore | 8 +++ Dockerfile | 13 ++++ LICENSE | 21 +++++++ Pipfile | 16 +++++ Pipfile.lock | 169 +++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 77 ++++++++++++++++++++++- action.yml | 25 ++++++++ src/main.py | 44 ++++++++++++++ 8 files changed, 371 insertions(+), 2 deletions(-) create mode 100755 .gitignore create mode 100755 Dockerfile create mode 100755 LICENSE create mode 100755 Pipfile create mode 100755 Pipfile.lock mode change 100644 => 100755 README.md create mode 100755 action.yml create mode 100755 src/main.py diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000..c6a8391 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +.mypy_cache +.venv + +# Dev +.vscode +Test.md +.github/workflows +*.secrets \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100755 index 0000000..1391b76 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,13 @@ +FROM python:3.9-alpine + +WORKDIR /tmp +RUN pip install pipenv +COPY ./Pipfile* ./ +RUN pipenv install --system --deploy + + +WORKDIR /action +COPY ./src . + +ENTRYPOINT [ "python" ] +CMD [ "/action/main.py" ] \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100755 index 0000000..4b1eaeb --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Niccolo Borgioli + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Pipfile b/Pipfile new file mode 100755 index 0000000..11e6c7d --- /dev/null +++ b/Pipfile @@ -0,0 +1,16 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +requests = "*" +markdown = "*" +py-gfm = "*" + +[dev-packages] +autopep8 = "*" +mypy = "*" + +[requires] +python_version = "3.9" diff --git a/Pipfile.lock b/Pipfile.lock new file mode 100755 index 0000000..1f7c236 --- /dev/null +++ b/Pipfile.lock @@ -0,0 +1,169 @@ +{ + "_meta": { + "hash": { + "sha256": "88ca19a4a790aab7be54f3279f465695c5ab1d77b1bd3e9e6e0ae1b55952445e" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.9" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "certifi": { + "hashes": [ + "sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c", + "sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830" + ], + "version": "==2020.12.5" + }, + "chardet": { + "hashes": [ + "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", + "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" + ], + "version": "==3.0.4" + }, + "idna": { + "hashes": [ + "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6", + "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==2.10" + }, + "markdown": { + "hashes": [ + "sha256:5d9f2b5ca24bc4c7a390d22323ca4bad200368612b5aaa7796babf971d2b2f18", + "sha256:c109c15b7dc20a9ac454c9e6025927d44460b85bd039da028d85e2b6d0bcc328" + ], + "index": "pypi", + "version": "==3.3.3" + }, + "py-gfm": { + "hashes": [ + "sha256:c4e873f310a84137acae5884a15e81a18eac17da9c00b20d5d9b82d37fd2d077", + "sha256:ef3a3e6e54817c21e97cc16c85789b0681e62958823a0ba3e3d29f8509d9dc49" + ], + "index": "pypi", + "version": "==1.0.2" + }, + "requests": { + "hashes": [ + "sha256:7f1a0b932f4a60a1a65caa4263921bb7d9ee911957e0ae4a23a6dd08185ad5f8", + "sha256:e786fa28d8c9154e6a4de5d46a1d921b8749f8b74e28bde23768e5e16eece998" + ], + "index": "pypi", + "version": "==2.25.0" + }, + "urllib3": { + "hashes": [ + "sha256:19188f96923873c92ccb987120ec4acaa12f0461fa9ce5d3d0772bc965a39e08", + "sha256:d8ff90d979214d7b4f8ce956e80f4028fc6860e4431f731ea4a8c08f23f99473" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", + "version": "==1.26.2" + } + }, + "develop": { + "autopep8": { + "hashes": [ + "sha256:d21d3901cb0da6ebd1e83fc9b0dfbde8b46afc2ede4fe32fbda0c7c6118ca094" + ], + "index": "pypi", + "version": "==1.5.4" + }, + "mypy": { + "hashes": [ + "sha256:0a0d102247c16ce93c97066443d11e2d36e6cc2a32d8ccc1f705268970479324", + "sha256:0d34d6b122597d48a36d6c59e35341f410d4abfa771d96d04ae2c468dd201abc", + "sha256:2170492030f6faa537647d29945786d297e4862765f0b4ac5930ff62e300d802", + "sha256:2842d4fbd1b12ab422346376aad03ff5d0805b706102e475e962370f874a5122", + "sha256:2b21ba45ad9ef2e2eb88ce4aeadd0112d0f5026418324176fd494a6824b74975", + "sha256:72060bf64f290fb629bd4a67c707a66fd88ca26e413a91384b18db3876e57ed7", + "sha256:af4e9ff1834e565f1baa74ccf7ae2564ae38c8df2a85b057af1dbbc958eb6666", + "sha256:bd03b3cf666bff8d710d633d1c56ab7facbdc204d567715cb3b9f85c6e94f669", + "sha256:c614194e01c85bb2e551c421397e49afb2872c88b5830e3554f0519f9fb1c178", + "sha256:cf4e7bf7f1214826cf7333627cb2547c0db7e3078723227820d0a2490f117a01", + "sha256:da56dedcd7cd502ccd3c5dddc656cb36113dd793ad466e894574125945653cea", + "sha256:e86bdace26c5fe9cf8cb735e7cedfe7850ad92b327ac5d797c656717d2ca66de", + "sha256:e97e9c13d67fbe524be17e4d8025d51a7dca38f90de2e462243ab8ed8a9178d1", + "sha256:eea260feb1830a627fb526d22fbb426b750d9f5a47b624e8d5e7e004359b219c" + ], + "index": "pypi", + "version": "==0.790" + }, + "mypy-extensions": { + "hashes": [ + "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d", + "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8" + ], + "version": "==0.4.3" + }, + "pycodestyle": { + "hashes": [ + "sha256:2295e7b2f6b5bd100585ebcb1f616591b652db8a741695b3d8f5d28bdc934367", + "sha256:c58a7d2815e0e8d7972bf1803331fb0152f867bd89adf8a01dfd55085434192e" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==2.6.0" + }, + "toml": { + "hashes": [ + "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", + "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f" + ], + "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==0.10.2" + }, + "typed-ast": { + "hashes": [ + "sha256:0666aa36131496aed8f7be0410ff974562ab7eeac11ef351def9ea6fa28f6355", + "sha256:0c2c07682d61a629b68433afb159376e24e5b2fd4641d35424e462169c0a7919", + "sha256:0d8110d78a5736e16e26213114a38ca35cb15b6515d535413b090bd50951556d", + "sha256:249862707802d40f7f29f6e1aad8d84b5aa9e44552d2cc17384b209f091276aa", + "sha256:24995c843eb0ad11a4527b026b4dde3da70e1f2d8806c99b7b4a7cf491612652", + "sha256:269151951236b0f9a6f04015a9004084a5ab0d5f19b57de779f908621e7d8b75", + "sha256:3742b32cf1c6ef124d57f95be609c473d7ec4c14d0090e5a5e05a15269fb4d0c", + "sha256:4083861b0aa07990b619bd7ddc365eb7fa4b817e99cf5f8d9cf21a42780f6e01", + "sha256:498b0f36cc7054c1fead3d7fc59d2150f4d5c6c56ba7fb150c013fbc683a8d2d", + "sha256:4e3e5da80ccbebfff202a67bf900d081906c358ccc3d5e3c8aea42fdfdfd51c1", + "sha256:6daac9731f172c2a22ade6ed0c00197ee7cc1221aa84cfdf9c31defeb059a907", + "sha256:715ff2f2df46121071622063fc7543d9b1fd19ebfc4f5c8895af64a77a8c852c", + "sha256:73d785a950fc82dd2a25897d525d003f6378d1cb23ab305578394694202a58c3", + "sha256:7e4c9d7658aaa1fc80018593abdf8598bf91325af6af5cce4ce7c73bc45ea53d", + "sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b", + "sha256:8ce678dbaf790dbdb3eba24056d5364fb45944f33553dd5869b7580cdbb83614", + "sha256:92c325624e304ebf0e025d1224b77dd4e6393f18aab8d829b5b7e04afe9b7a2c", + "sha256:aaee9905aee35ba5905cfb3c62f3e83b3bec7b39413f0a7f19be4e547ea01ebb", + "sha256:b52ccf7cfe4ce2a1064b18594381bccf4179c2ecf7f513134ec2f993dd4ab395", + "sha256:bcd3b13b56ea479b3650b82cabd6b5343a625b0ced5429e4ccad28a8973f301b", + "sha256:c9e348e02e4d2b4a8b2eedb48210430658df6951fa484e59de33ff773fbd4b41", + "sha256:d205b1b46085271b4e15f670058ce182bd1199e56b317bf2ec004b6a44f911f6", + "sha256:d43943ef777f9a1c42bf4e552ba23ac77a6351de620aa9acf64ad54933ad4d34", + "sha256:d5d33e9e7af3b34a40dc05f498939f0ebf187f07c385fd58d591c533ad8562fe", + "sha256:d648b8e3bf2fe648745c8ffcee3db3ff903d0817a01a12dd6a6ea7a8f4889072", + "sha256:f208eb7aff048f6bea9586e61af041ddf7f9ade7caed625742af423f6bae3298", + "sha256:fac11badff8313e23717f3dada86a15389d0708275bddf766cca67a84ead3e91", + "sha256:fc0fea399acb12edbf8a628ba8d2312f583bdbdb3335635db062fa98cf71fca4", + "sha256:fcf135e17cc74dbfbc05894ebca928ffeb23d9790b3167a674921db19082401f", + "sha256:fe460b922ec15dd205595c9b5b99e2f056fd98ae8f9f56b888e7a17dc2b757e7" + ], + "version": "==1.4.1" + }, + "typing-extensions": { + "hashes": [ + "sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918", + "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c", + "sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f" + ], + "version": "==3.7.4.3" + } + } +} diff --git a/README.md b/README.md old mode 100644 new mode 100755 index b7030a9..40f74f5 --- a/README.md +++ b/README.md @@ -1,2 +1,75 @@ -# Github-action-confluence-sync -Github action for syncing files with confluence pages. +# Confluence Markdown Sync Action + +This Github Action serves the purpose of copying the contents of a Markdown `.md` file to a Confluence Cloud Page. + +## Getting Started + +```yml +# .github/workflows/my-workflow.yml +on: [push] + +jobs: + dev: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - uses: confluence-markdown-sync + with: + from: './README.md' + to: '123456' # The confluence page id where to write the output + cloud: + user: + token: +``` + +## Authentication + +Uses basic auth for the rest api. + +- `cloud`: The ID can be found by looking at yout confluence domain: `https://xxx.atlassian.net/...` +- `user`: The user that generated the access token +- `token`: You can generate the token [here](https://id.atlassian.com/manage-profile/security/api-tokens). Link to [Docs](https://confluence.atlassian.com/cloud/api-tokens-938839638.html) + +- `to`: The page ID can be found by simply navigating to the page where you want the content to be postet to and looke at the url. It will look something like this: `https://.atlassian.net/wiki/spaces//pages//` + +### Using secrets + +It's **higly reccomended** that you use secrets! + +To use them you need them to specify them before in your repo. [Docs](https://docs.github.com/en/free-pro-team@latest/actions/reference/encrypted-secrets) + +The you can use them in any input field. + +```yml +# .github/workflows/my-workflow.yml +# ... +token: ${{ secrets.token }} +``` + +## Development + +1. Clone the repo +2. Install [act](https://github.com/nektos/act) +3. Create the same config in the repo folder as in the getting started section above. +4. Change `uses: confluence-markdown-sync` -> `uses: ./` +5. Create an example markdown file `Some.md` and set it in the config `from: './Some.md'` +6. Run locally `act -b` + +### With secrets + +You can simply create a `.secrets` file and specify it to `act` + +``` +token=abc123 +``` + +```yml +# .github/workflows/dev.yml +# ... +token: ${{ secrets.token }} +``` + +```bash +act -b --secret-file .secrets +``` diff --git a/action.yml b/action.yml new file mode 100755 index 0000000..e2ca264 --- /dev/null +++ b/action.yml @@ -0,0 +1,25 @@ +# action.yml +name: 'confluence-markdown-sync' +description: 'Copy content of a markdown file to a confluence site' +branding: + icon: 'upload-cloud' + color: 'blue' +inputs: + from: + description: 'Path to the markdown file. Relative to root of repository' + required: true + to: + description: 'The page ID in confluence' + required: true + cloud: + description: 'Atlassian Cloud ID' + required: true + user: + description: 'Username of the token user' + required: true + token: + description: 'Token for the user' + required: true +runs: + using: 'docker' + image: 'Dockerfile' diff --git a/src/main.py b/src/main.py new file mode 100755 index 0000000..d0edf70 --- /dev/null +++ b/src/main.py @@ -0,0 +1,44 @@ +from typing import Dict, List +from os import listdir, environ +from os.path import join + +import requests +from markdown import markdown +from mdx_gfm import GithubFlavoredMarkdownExtension + +workspace = environ.get('GITHUB_WORKSPACE') +if not workspace: + raise Exception('No workspace is set') + +envs: Dict[str, str] = {} +for key in ['from', 'to', 'cloud', 'user', 'token']: + value = environ.get(f'INPUT_{key.upper()}') + if not value: + raise Exception(f'Missing value for {key}') + envs[key] = value + +with open(join(workspace, envs['from'])) as f: + md = f.read() + +url = f"https://{envs['cloud']}.atlassian.net/wiki/rest/api/content/{envs['to']}" + +current = requests.get(url, auth=(envs['user'], envs['token'])).json() + +html = markdown(md, extensions=[GithubFlavoredMarkdownExtension()]) +content = { + 'id': current['id'], + 'type': current['type'], + 'title': current['title'], + 'version': {'number': current['version']['number'] + 1}, + 'body': { + 'editor': { + 'value': html, + 'representation': 'editor' + } + } +} + +updated = requests.put(url, json=content, auth=( + envs['user'], envs['token'])).json() +link = updated['_links']['base'] + updated['_links']['webui'] +print(f'Uploaded content successfully to page {link}')