From 0a1bce7d6c2d0be04a1bc07e16a4aa685a96d6bd Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Tue, 28 Oct 2025 16:49:34 +0300 Subject: [PATCH] CI: Add MkDocs setup. --- .github/workflows/deploy_mkdocs.yml | 18 +++ docs/css/custom.css | 12 ++ docs/img/ay-symbol-blackw-full.png | Bin 0 -> 1632 bytes docs/img/favicon.ico | Bin 0 -> 490 bytes docs/index.md | 1 + docs/license.md | 1 + mkdocs.yml | 71 ++++++++++ mkdocs_hooks.py | 194 ++++++++++++++++++++++++++++ mkdocs_requirements.txt | 9 ++ 9 files changed, 306 insertions(+) create mode 100644 .github/workflows/deploy_mkdocs.yml create mode 100644 docs/css/custom.css create mode 100644 docs/img/ay-symbol-blackw-full.png create mode 100644 docs/img/favicon.ico create mode 100644 docs/index.md create mode 100644 docs/license.md create mode 100644 mkdocs.yml create mode 100644 mkdocs_hooks.py create mode 100644 mkdocs_requirements.txt diff --git a/.github/workflows/deploy_mkdocs.yml b/.github/workflows/deploy_mkdocs.yml new file mode 100644 index 000000000..deafc7b85 --- /dev/null +++ b/.github/workflows/deploy_mkdocs.yml @@ -0,0 +1,18 @@ +name: Deploy MkDocs + +on: + push: + tags: + - "*" + workflow_dispatch: + +jobs: + build-mk-docs: + # FIXME: Update @develop to @main after `ops-repo-automation` release. + uses: ynput/ops-repo-automation/.github/workflows/deploy_mkdocs.yml@develop + with: + repo: ${{ github.repository }} + secrets: + YNPUT_BOT_TOKEN: ${{ secrets.YNPUT_BOT_TOKEN }} + CI_USER: ${{ secrets.CI_USER }} + CI_EMAIL: ${{ secrets.CI_EMAIL }} diff --git a/docs/css/custom.css b/docs/css/custom.css new file mode 100644 index 000000000..28461e6ec --- /dev/null +++ b/docs/css/custom.css @@ -0,0 +1,12 @@ +[data-md-color-scheme="slate"] { + /* simple slate overrides */ + --md-primary-fg-color: hsl(155, 49%, 50%); + --md-accent-fg-color: rgb(93, 200, 156); + --md-typeset-a-color: hsl(155, 49%, 45%) !important; +} +[data-md-color-scheme="default"] { + /* simple default overrides */ + --md-primary-fg-color: hsl(155, 49%, 50%); + --md-accent-fg-color: rgb(93, 200, 156); + --md-typeset-a-color: hsl(155, 49%, 45%) !important; +} diff --git a/docs/img/ay-symbol-blackw-full.png b/docs/img/ay-symbol-blackw-full.png new file mode 100644 index 0000000000000000000000000000000000000000..5edda784cc7a2512bc050aeb5779465cd04c2155 GIT binary patch literal 1632 zcmV-m2A}zfP)|OZpvMT@p z1?fpdK~#9!?VZ_j<2npP2TK@H|Np@^HmE0U%ie zwrho$g@vvQV82#~@&=G|0QSm38essrE`Y6a5b_{_ZveJIfb%f1-vrz!2L}SM1p+`L z4Isw}xJeE|9xN~f!14B_gUlen^`rmtz(@{K+wf~FAPWFI8GpG03nNh40^eR}`_(b* z8-J+-%jO_-@LyF0ur&Y|<1cjpw@$#fOYNM4)DJ)@0%R6|jS=Wiz|C_I=Nf>U7Qk%< zl-9scPo z3Cx5R%E5-s@I$Tu^jl%mX^2B`{K^P4o`yIC$FJK8TTeqAa^qLc!H&}qht%*@TVdC6 zm_umziU@R{2Rn`r7e4;k^z0a1r3ja`U?!+D8k+^NV@nR5yR0fu&YGJ75|)#BI*rkVftrp z6mf5x7MS!FxXP0O7!d_s{e`9_;HZ|^8!I@a1xi9IQ~aY_A&$RusYu0{2`JkVg_?~hiJ*b~gvXT_eUXnFz`lYEZ(}AMJP9^0sPLpoKur{sd`4_Z zO>9cgbt3kxX89CYOcKq(-XDldwJ^)ADT6)$KPJj&9W?#NEl@Q9AEF>tF(b0I#%e9_ z*|&NQ`Ol+Uq1bPvrZndN4n_bb9D5piqzbeXP+Pc20qBW+1JH?p0RZ|CAPWYN>jLO1 z0w5a(G*1bP0MLv8XES2I3D}W?h5%?n0LYR74O0Tlrc|ASkc|m^15k|sXLDk&EwHH- z8U&yU0U(P8RJ20OCWUTWU~Ma$0l@j7br6`6fO4DQ@;OL$4WM;eppF402uw;qB?Ag_ z5N#WPt2_g08E{(!WZeK-WD=lezzqUq-vC-;5};?mRSr&^1u7bF(F!Nd0yPc56_!CX z4S1P@!`=faeIzT?f-O;OXkv+;uQr1D@sJ=(^ko2Q?*wQY@Q{P# z%>Yu~3Q{-V7XswZ0MgwH)HmP<0_f3z?~NdPG=Nlh!xu2%TMeL315ook$O;CKVgxK< zK-N4Du!I4icp_*C12_x_1HynXAPk5$7!N}6DC~YRj4TOu-1xDtOi^ z34H@Fc7|eaFm{LId_WwLi9=FxOfF7}>Nucjz{MK_?BRU@UgEWBy;o)+-Wt1mZ_M(W zqebt|0+LMwsQmr;@f6HAfVk?1WB}2U0f;TXCrO-&VOBDW z7Or(873EIlIT6LwKxI2eo;o=1xOh(J^n}6w)#aY^{rCKb3;!u~VZ}*z0vS*W?WMRo z@~L)%?PUw?ZUL>QT|d}AYNP9!TivPy4YWJ<7X}bou&uG$CfJ;B#)Litao(Fnd9See}c`$7L48j z?CMlAO`U|4=H+hSCoCayPh<3}Ah-rupk8Q%tCxU%DVhvMPf_-612?Pd9uoEZ<3Rxa g4bPjr^y3ws0MrSDl)+%k9smFU07*qoM6N<$f>Hk4NdN!< literal 0 HcmV?d00001 diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 000000000..612c7a5e0 --- /dev/null +++ b/docs/index.md @@ -0,0 +1 @@ +--8<-- "README.md" diff --git a/docs/license.md b/docs/license.md new file mode 100644 index 000000000..f409d4523 --- /dev/null +++ b/docs/license.md @@ -0,0 +1 @@ +--8<-- "LICENSE" diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 000000000..df9fdff7d --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,71 @@ +site_name: ayon-python-api +repo_url: https://github.com/ynput/ayon-python-api + +nav: + - Home: index.md + - License: license.md + +theme: + name: material + palette: + - media: "(prefers-color-scheme: dark)" + scheme: slate + toggle: + icon: material/weather-sunny + name: Switch to light mode + - media: "(prefers-color-scheme: light)" + scheme: default + toggle: + icon: material/weather-night + name: Switch to dark mode + logo: img/ay-symbol-blackw-full.png + favicon: img/favicon.ico + features: + - navigation.sections + - navigation.path + - navigation.prune + +extra: + version: + provider: mike + +extra_css: [css/custom.css] + +markdown_extensions: + - mdx_gh_links + - pymdownx.snippets + +plugins: + - search + - offline + - mkdocs-autoapi: + autoapi_dir: ./ + autoapi_add_nav_entry: Reference + autoapi_ignore: + - .* + - docs/**/* + - tests/**/* + - tools/**/* + - stubs/**/* # mocha fix + - ./**/pythonrc.py # houdini fix + - .*/**/* + - ./*.py + - mkdocstrings: + handlers: + python: + paths: + - ./ + - client/* + - server/* + - services/* + - minify: + minify_html: true + minify_js: true + minify_css: true + htmlmin_opts: + remove_comments: true + cache_safe: true + - mike + +hooks: + - mkdocs_hooks.py diff --git a/mkdocs_hooks.py b/mkdocs_hooks.py new file mode 100644 index 000000000..ab5063a9b --- /dev/null +++ b/mkdocs_hooks.py @@ -0,0 +1,194 @@ +import os +from pathlib import Path +from shutil import rmtree +import json +import glob +import logging + +TMP_FILE = "./missing_init_files.json" +NFILES = [] + +# ----------------------------------------------------------------------------- + + +class ColorFormatter(logging.Formatter): + grey = "\x1b[38;20m" + green = "\x1b[32;20m" + yellow = "\x1b[33;20m" + red = "\x1b[31;20m" + bold_red = "\x1b[31;1m" + reset = "\x1b[0m" + fmt = ( + "%(asctime)s - %(name)s - %(levelname)s - %(message)s " # noqa + "(%(filename)s:%(lineno)d)" + ) + + FORMATS = { + logging.DEBUG: grey + fmt + reset, + logging.INFO: green + fmt + reset, + logging.WARNING: yellow + fmt + reset, + logging.ERROR: red + fmt + reset, + logging.CRITICAL: bold_red + fmt + reset, + } + + def format(self, record): + log_fmt = self.FORMATS.get(record.levelno) + formatter = logging.Formatter(log_fmt) + return formatter.format(record) + + +ch = logging.StreamHandler() +ch.setFormatter(ColorFormatter()) + +logging.basicConfig( + level=logging.INFO, + handlers=[ch], +) + + +# ----------------------------------------------------------------------------- + + +def create_init_file(dirpath, msg): + global NFILES + ini_file = f"{dirpath}/__init__.py" + Path(ini_file).touch() + NFILES.append(ini_file) + logging.info(f"{msg}: created '{ini_file}'") + + +def create_parent_init_files(dirpath: str, rootpath: str, msg: str): + parent_path = dirpath + while parent_path != rootpath: + parent_path = os.path.dirname(parent_path) + parent_init = os.path.join(parent_path, "__init__.py") + if not os.path.exists(parent_init): + create_init_file(parent_path, msg) + else: + break + + +def add_missing_init_files(*roots, msg=""): + """ + This function takes in one or more root directories as arguments and scans + them for Python files without an `__init__.py` file. It generates a JSON + file named `missing_init_files.json` containing the paths of these files. + + Args: + *roots: Variable number of root directories to scan. + + Returns: + None + """ + + for root in roots: + if not os.path.exists(root): + continue + rootpath = os.path.abspath(root) + for dirpath, dirs, files in os.walk(rootpath): + if "__init__.py" in files: + continue + + if "." in dirpath: + continue + + if ( + not glob.glob(os.path.join(dirpath, "*.py")) + and "vendor" not in dirpath + ): + continue + + create_init_file(dirpath, msg) + create_parent_init_files(dirpath, rootpath, msg) + + with open(TMP_FILE, "w") as f: + json.dump(NFILES, f) + + +def remove_missing_init_files(msg=""): + """ + This function removes temporary `__init__.py` files created in the + `add_missing_init_files()` function. It reads the paths of these files from + a JSON file named `missing_init_files.json`. + + Args: + None + + Returns: + None + """ + global NFILES + nfiles = [] + if os.path.exists(TMP_FILE): + with open(TMP_FILE, "r") as f: + nfiles = json.load(f) + else: + nfiles = NFILES + + for file in nfiles: + Path(file).unlink() + logging.info(f"{msg}: removed {file}") + + os.remove(TMP_FILE) + NFILES = [] + + +def remove_pychache_dirs(msg=""): + """ + This function walks the current directory and removes all existing + '__pycache__' directories. + + Args: + msg: An optional message to display during the removal process. + + Returns: + None + """ + nremoved = 0 + + for dirpath, dirs, files in os.walk("."): + if "__pycache__" in dirs: + pydir = Path(f"{dirpath}/__pycache__") + rmtree(pydir) + nremoved += 1 + logging.info(f"{msg}: removed '{pydir}'") + + if not nremoved: + logging.info(f"{msg}: no __pycache__ dirs found") + + +# mkdocs hooks ---------------------------------------------------------------- + + +def on_startup(command, dirty): + remove_pychache_dirs(msg="HOOK - on_startup") + + +def on_pre_build(config): + """ + This function is called before the MkDocs build process begins. It adds + temporary `__init__.py` files to directories that do not contain one, to + make sure mkdocs doesn't ignore them. + """ + try: + add_missing_init_files( + "client", + "server", + "services", + msg="HOOK - on_pre_build", + ) + except BaseException as e: + logging.error(e) + remove_missing_init_files( + msg="HOOK - on_post_build: cleaning up on error !" + ) + raise + + +def on_post_build(config): + """ + This function is called after the MkDocs build process ends. It removes + temporary `__init__.py` files that were added in the `on_pre_build()` + function. + """ + remove_missing_init_files(msg="HOOK - on_post_build") diff --git a/mkdocs_requirements.txt b/mkdocs_requirements.txt new file mode 100644 index 000000000..829d02951 --- /dev/null +++ b/mkdocs_requirements.txt @@ -0,0 +1,9 @@ +mkdocs-material >= 9.6.7 +mkdocs-autoapi >= 0.4.0 +mkdocstrings-python >= 1.16.2 +mkdocs-minify-plugin >= 0.8.0 +markdown-checklist >= 0.4.4 +mdx-gh-links >= 0.4 +pymdown-extensions >= 10.14.3 +mike >= 2.1.3 +mkdocstrings-shell >= 1.0.2