diff --git a/.github/workflows/web_update.yml b/.github/workflows/web_update.yml new file mode 100644 index 0000000..fc952e4 --- /dev/null +++ b/.github/workflows/web_update.yml @@ -0,0 +1,53 @@ +name: API Auto Update # The name of the workflow indicates its purpose to automatically update the API documentation. + +on: # Defines the events that trigger the workflow. + push: + branches: ["main"] + workflow_dispatch: # This allows the workflow to be manually triggered. + +permissions: + contents: write + pages: write + id-token: write + +concurrency: + group: "pages" + +jobs: + deploy: # Defines a job called 'deploy'. + runs-on: ubuntu-latest # Specifies the virtual environment where the job will run. + + steps: + - name: Checkout # Step to checkout the repository's code. + uses: actions/checkout@v4 # Uses the actions/checkout action to access the repository code. + + - name: Configure GitHub Pages + uses: actions/configure-pages@v5 + + - name: Cache pip # Step to cache pip packages. + uses: actions/cache@v4 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} + restore-keys: | + ${{ runner.os }}-pip- + + - name: Install dependencies # Step to install dependencies. + run: | + pip install quairkit sphinx_immaterial nbsphinx + + - name: Generate Sphinx Documentation for API Documentation # Step to generate Sphinx documentation. + run: bash ./version.sh + + - name: Upload artifact # Step to upload the built site as an artifact. + uses: actions/upload-pages-artifact@v3 + with: + path: docs/api + + - name: Deploy to GitHub Pages # Step to deploy to GitHub Pages. + id: deployment + uses: peaceiris/actions-gh-pages@v4 + with: + publish_branch: gh-pages # Specifies the branch to deploy to. + github_token: ${{ secrets.GITHUB_TOKEN }} # Authenticates using a GitHub Token. + publish_dir: ./docs/api # Specifies the directory to deploy. \ No newline at end of file diff --git a/api.sh b/api.sh index de342fc..0041b90 100644 --- a/api.sh +++ b/api.sh @@ -1,14 +1,16 @@ #!/bin/bash # Step 0: 删除 html 和 sphinx_src 文件夹 -rm -rf docs/api/html -rm -rf docs/api/sphinx_src +rm -rf docs/api +rm -rf docs/sphinx_src -# Step 1: 安装 Sphinx 和 sphinx_material(如果尚未安装) -pip install sphinx_material +# Step 1: 安装必要包 +pip show sphinx_immaterial || pip install sphinx_immaterial +pip show nbsphinx || pip install nbsphinx # Step 2: 生成所有必要的 rst 和 conf.py 文件 python docs/update_quairkit_rst.py +cp -r tutorials docs/sphinx_src/ # Step 3: 使用 Sphinx 构建 HTML 文档 sphinx-build -b html docs/sphinx_src docs/api diff --git a/docs/update_quairkit_rst.py b/docs/update_quairkit_rst.py index 9789860..f7332b2 100644 --- a/docs/update_quairkit_rst.py +++ b/docs/update_quairkit_rst.py @@ -9,6 +9,9 @@ _platform_name = "QuAIRKit" +# set the module names you want to include in API documentation in _module_names +_module_names = ["quairkit", "tutorials"] + # set the file name you want to ignore in API documentation in _ignore_file_names _ignore_file_names = ["quairkit.core.utils", "quairkit.core.intrinsic"] @@ -22,7 +25,7 @@ def is_correct_directory(): return os.path.exists(required_file) def _list_quairkit_files( - path: str = os.path.join(".", "quairkit"), + path: str = os.path.join("."), base_path: str = "", file_name_attr_list: List[Tuple[str, str]] = None, ) -> List[Tuple[str, str]]: @@ -47,15 +50,26 @@ def _list_quairkit_files( relative_path = os.path.join(base_path, child).replace(os.path.sep, ".") if os.path.isdir(child_path): - sub_list = _list_quairkit_files(child_path, relative_path, []) - if sub_list: # 仅当子目录非空时才添加 - file_name_attr_list.append((f"quairkit.{relative_path}", "folder")) + if sub_list := _list_quairkit_files(child_path, relative_path, []): + file_name_attr_list.append((f"{relative_path}", "folder")) file_name_attr_list.extend(sub_list) elif child.endswith(".py"): file_name_attr_list.append( - (f"quairkit.{relative_path.replace('.py', '')}", "python") + (f"{relative_path.rstrip('.py')}", "python") ) - + # elif child.endswith(".ipynb"): + # file_name_attr_list.append( + # (f"{relative_path.rstrip('.ipynb')}", "notebook") + # ) + + file_name_attr_list = [ + sub_array + for sub_array in file_name_attr_list + if any( + sub_array[0].startswith(module_name) for module_name in _module_names + ) + ] + file_name_attr_list = [ sub_array for sub_array in file_name_attr_list @@ -63,6 +77,7 @@ def _list_quairkit_files( sub_array[0].startswith(ignore_item) for ignore_item in _ignore_file_names ) ] + file_name_attr_list.sort() return file_name_attr_list @@ -106,6 +121,23 @@ def _update_function_rst( with open(file_path, "w") as file: file.write(rst_content) + + rst_content = \ +"""\ +tutorials +========= + +.. toctree:: + :maxdepth: 4 + :glob: + + tutorials/* +""" + + file_path = os.path.join(source_directory, "tutorials.rst") + + with open(file_path, "w") as file: + file.write(rst_content) return @@ -113,10 +145,9 @@ def _update_function_rst( def _update_index_rst( file_list: List[Tuple[str, str]], source_directory: str = _sphinx_source_dir ) -> None: - """_summary_ - + """ Args: - source_directory (str, optional): _description_. Defaults to source_dir. + source_directory (str, optional): Defaults to source_dir. The directory where .rst files will be created. """ rst_content = "" if len(sys.argv) == 1: @@ -126,7 +157,7 @@ def _update_index_rst( Welcome to {_platform_name}'s documentation! ==================================== -|quairkit| `Go to {_platform_name} Home `_ +|quairkit| `Go to QuAIR-Platform Home `_ """ @@ -134,24 +165,13 @@ def _update_index_rst( .. toctree:: :maxdepth: 1 """ - rst_content += _get_modules_rst(file_list) + rst_content += "".join(f"\n {item}" for item in _module_names) file_path = os.path.join(source_directory, "index.rst") with open(file_path, "w") as file: file.write(rst_content) -def _get_modules_rst( - file_list: List[Tuple[str, str]], source_directory: str = _sphinx_source_dir -): - file_list_copy = file_list.copy() - rst_content = "" - for item in file_list_copy: - if item[0].count(".") == 1: - rst_content += f"\n {item[0]}" - return rst_content - - def _update_conf_py(source_directory: str = _sphinx_source_dir): """_summary_ @@ -173,13 +193,12 @@ def _update_conf_py(source_directory: str = _sphinx_source_dir): import os import sys -sys.path.insert(0, os.path.join('..', '..', '')) +sys.path.insert(0, os.path.join('..', '..')) # -- Project information ----------------------------------------------------- project = "{_platform_name}" -copyright = "2023, QuAIR" +copyright = "2024, QuAIR" author = "QuAIR" -html_baseurl = "https://quair.github.io/" # The full version, including alpha/beta/rc tags release = "0.1.0" @@ -197,6 +216,7 @@ def _update_conf_py(source_directory: str = _sphinx_source_dir): "sphinx.ext.mathjax", "sphinx.ext.todo", "sphinx_immaterial", + "nbsphinx", """ if len(sys.argv) == 2 and sys.argv[1] == "wiki": rst_content += """\ @@ -228,22 +248,11 @@ def _update_conf_py(source_directory: str = _sphinx_source_dir): html_title = "QuAIRKit" html_short_title = "QuAIRKit" build_dir = "api" -# html_theme_options = { -# 'navigation_depth': 1, -# } html_theme_options = { - 'base_url': 'https://quair.github.io/quairkit/', - 'repo_url': 'https://github.com/QuAIR/QuAIRKit', - 'repo_name': 'QuAIRKit', - # 'google_analytics_account': 'UA-XXXXX', - 'html_minify': True, - 'css_minify': True, - 'nav_title': 'QuAIRKit API Documentation', - # 'logo_icon': '', - # 'globaltoc_depth': 2, - 'color_primary': "green", - 'color_accent': 'indigo', - "palette": { "primary": "green" } + "repo_url": 'https://github.com/QuAIR/QuAIRKit', + "repo_name": 'QuAIRKit', + "palette": { "primary": "green" }, + "version_dropdown": True, } html_favicon = '../favicon.svg' # Add any paths that contain custom static files (such as style sheets) here, @@ -262,6 +271,8 @@ def _update_conf_py(source_directory: str = _sphinx_source_dir): autodoc_docstring_signature = False autodoc_typehints_description_target = "documented" autodoc_typehints_format = "short" + + """ file_path = os.path.join(source_directory, "conf.py") @@ -269,16 +280,38 @@ def _update_conf_py(source_directory: str = _sphinx_source_dir): file.write(rst_content) +def _create_redirect_html(): + html_content = """ + + + + + + + + +

If this page does not refresh automatically, then please direct your browser to + our latest docs. +

+ + +""" + file_dir = os.path.join(".", "docs", "api") + os.makedirs(file_dir, exist_ok=True) + with open(os.path.join(file_dir, "index.html"), 'w', encoding='utf-8') as file: + file.write(html_content) + + if __name__ == "__main__": _current_script_path = os.path.abspath(__file__) _platform_dir_path = os.path.dirname(os.path.dirname(_current_script_path)) _current_working_dir = os.getcwd() - if _current_working_dir == _platform_dir_path: - result = _list_quairkit_files() - os.makedirs(_sphinx_source_dir, exist_ok=True) - _update_index_rst(result) - _update_function_rst(result) - _update_conf_py() - else: + if _current_working_dir != _platform_dir_path: raise SystemExit(f"The current working directory is not {_platform_dir_path}.") + result = _list_quairkit_files() + os.makedirs(_sphinx_source_dir, exist_ok=True) + _update_index_rst(result) + _update_function_rst(result) + _update_conf_py() + _create_redirect_html() diff --git a/version.sh b/version.sh new file mode 100644 index 0000000..02e9442 --- /dev/null +++ b/version.sh @@ -0,0 +1,75 @@ +#!/bin/bash + +# Update system repositories and install Pandoc +sudo apt-get update +sudo apt-get install -y pandoc + +# Check and install the Sphinx Material theme and nbsphinx if not already installed +pip show sphinx_immaterial || pip install sphinx_immaterial +pip show nbsphinx || pip install nbsphinx + +# Clean up the existing API documentation directories +rm -rf docs/api +rm -rf docs/sphinx_src +rm -rf docs/source + +# Retrieve all Git tags and store them in an array +tags=($(git tag)) + +# Retrieve the name of the current branch +current_branch=$(git rev-parse --abbrev-ref HEAD) + +# Initialize the version_info list for Python configuration +version_info_content="html_theme_options['version_info'] = [" + +# Populate the version_info list with tag data +for i in "${!tags[@]}"; do + tag="${tags[$i]}" + if [ $i -eq 0 ]; then + version_info_content+="{'version': '$tag', 'title': '$tag', 'aliases': ['$tag']}" + else + version_info_content+=", {'version': '$tag', 'title': '$tag', 'aliases': ['$tag']}" + fi +done + +# Close the version_info list +version_info_content+="]" + +# Fetch all tags from the repository +git fetch --all --tags + +# Loop through all tags and generate Sphinx documentation for each with specific conditions +for tag in "${tags[@]}"; do + case $tag in + v0.0.1) + git checkout $tag + python docs/update_avocado_rst.py + sphinx-build docs/source docs/api/$tag + rm -rf docs/source + ;; + v0.0.2-alpha) + git checkout $tag + python docs/avocado/update_avocado_rst.py + sphinx-build docs/avocado/sphinx_src docs/api/$tag + rm -rf docs/avocado/sphinx_src + ;; + *) + git checkout $tag + python docs/update_quairkit_rst.py + sphinx-build docs/sphinx_src docs/api/$tag + rm -rf docs/sphinx_src + ;; + esac +done + +# Revert to the current branch +git checkout $current_branch + +# Build the final Sphinx documentation for the current branch +python docs/update_quairkit_rst.py +cp -r tutorials docs/sphinx_src/tutorials +echo "$version_info_content" >> docs/sphinx_src/conf.py +sphinx-build docs/sphinx_src docs/api/latest + +# Notify the user where to find the built documentation +echo "The documentation is built. You can open it by navigating to 'docs/api/index.html' in your browser."