Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: sphinx documentation configs, build script, CI job #117

Merged
merged 1 commit into from
Aug 4, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions .github/workflows/docs.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
name: Docs

on:
push:
branches: [main]
release:
types: [released]
pull_request:
types: [opened, synchronize]

jobs:
docs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2

- name: Setup Python
uses: actions/setup-python@v2
with:
python-version: 3.8

- name: Install Dependencies
run: pip install .[doc]

- name: Build HTML artifact
run: python build_docs.py

- name: Upload HTML artifact
uses: actions/upload-artifact@v1
with:
name: DocumentationHTML
path: docs/_build/

- name: Commit and publish documentation changes to gh-pages branch
run: |
git clone https://github.com/${GITHUB_REPOSITORY} --branch gh-pages --single-branch gh-pages
cp -r docs/_build/* gh-pages/
cd gh-pages
touch .nojekyll
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
git add .
if [[ "${GITHUB_EVENT_NAME}" =~ "pull_request" ]]; then
echo "skipping 'git commit' step for PR"
else
git commit -m "Update documentation" -a || true
fi
# The above command will fail if no changes were present, so we use "|| true" to ignore that
- name: Push changes
uses: ad-m/github-push-action@master
if: ${{ github.event_name != 'pull_request' }}
with:
branch: gh-pages
directory: gh-pages
github_token: ${{ secrets.GITHUB_TOKEN }}
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,15 @@ This project is in early development and should be considered an alpha.
Things might not work, breaking changes are likely.
Comments, questions, criticisms and pull requests are welcomed.

## Documentation

To build docs:

```bash
python build_docs.py # build docs in docs/_build
python build_docs.py --rsync=/tmp/ape # for serving up docs in development
```

## License

This project is licensed under the [Apache 2.0](LICENSE).
110 changes: 110 additions & 0 deletions build_docs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
"""
Used with the `docs` Github action to make versioned docs directories in the
gh-pages branch.
"""


import argparse
import os
import re
import shutil
import subprocess
from distutils.version import LooseVersion
from pathlib import Path

REDIRECT_HTML = """
<!DOCTYPE html>
<meta charset="utf-8">
<title>Redirecting...</title>
<meta http-equiv="refresh" content="0; URL=./stable/">
"""

DOCS_BUILD_PATH = Path("docs/_build")


def log(*args, **kwargs):
print(*args, **kwargs) # noqa: T001


def run(args):
log("Running:", args)
subprocess.check_call(args)


def main():
# clean out the contents of the build directory, but leave the directory in
# place so that serving up files continues to work when you're developing
# docs locally
DOCS_BUILD_PATH.mkdir(exist_ok=True)
for path in DOCS_BUILD_PATH.iterdir():
shutil.rmtree(path) if path.is_dir() else path.unlink()

if "pull_request" in os.environ.get("GITHUB_EVENT_NAME", ""):
# build only the current working dir's docs for a PR because PR builds
# don't have all the refs needed for multiversion
run(["sphinx-build", "docs", "docs/_build"])
return # none of the steps below need to run if we're building for a PR
else:
# build docs for each version
run(["sphinx-multiversion", "docs", "docs/_build"])

# move the current branch to "latest"
branch = subprocess.check_output(["git", "branch", "--show-current"]).decode("ascii").strip()
branch = branch or "main"
if (DOCS_BUILD_PATH / branch).is_dir():
Path(DOCS_BUILD_PATH / branch).rename(DOCS_BUILD_PATH / "latest")

# clean up static files so we don't need to host the same 10+ MB of web
# fonts for each version of the docs
for d in Path("docs/_build").glob("**/fonts"):
if "latest" in str(d):
continue # leave only the copy of the static files from the latest version
shutil.rmtree(d)

# copy the highest released version to "stable"
all_releases = [
LooseVersion(d.name) for d in DOCS_BUILD_PATH.iterdir() if re.match(r"v\d+\.", d.name)
]
no_pre_releases = [v for v in all_releases if "-" not in str(v)]
stable = None
if no_pre_releases:
stable = max(no_pre_releases)
elif all_releases:
stable = max(all_releases)
else:
log("WARNING: Couldn't find any released versions. Going to use 'latest' for 'stable'.")
stable = "latest"
log(f"Copying latest stable release {stable} to 'stable'.")
shutil.copytree(DOCS_BUILD_PATH / str(stable), DOCS_BUILD_PATH / "stable")

# set up the redirect at /index.html
with open(DOCS_BUILD_PATH / "index.html", "w") as f:
f.write(REDIRECT_HTML)


if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument(
"--rsync",
help="Where to put the fully built docs subdir for serving in development. "
"/tmp/projectname is recommended.",
)
args = parser.parse_args()

main()

if args.rsync:
run(["rsync", "-pthrvz", "--delete", "./docs/_build/", args.rsync])
log("\n")
log(
(
"NOTE: To serve these files in development, run `python3 -m http.server` inside "
"`{}`, then go to http://127.0.0.1:8000/projectname in the browser."
).format(Path(args.rsync).parent)
)
log(
"NOTE: If you're making changes to docs locally, go to the 'latest' branch to see "
"your changes. Also, due to the way sphinx-multiversion integrates with git, you need "
"to commit your changes each time before building."
)
log()
32 changes: 32 additions & 0 deletions docs/_autoapi_templates/python/data.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{% if obj.display %}
.. {{ obj.type }}:: {{ obj.name }}
{%+ if obj.value is not none or obj.annotation is not none -%}
:annotation:
{%- if obj.annotation %} :{{ obj.annotation }}
{%- endif %}
{%- if obj.value is not none %} = {%
if obj.value is string and obj.value.splitlines()|count > 1 -%}
Multiline-String

.. raw:: html

<details><summary>Show Value</summary>

.. code-block:: text
:linenos:

{{ obj.value|indent(width=8) }}

.. raw:: html

</details>

{%- else -%}
{{ obj.value|string|truncate(100) }}
{%- endif %}
{%- endif %}
{% endif %}


{{ obj.docstring|prepare_docstring|indent(3) }}
{% endif %}
125 changes: 125 additions & 0 deletions docs/_autoapi_templates/python/module.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
{% if not obj.display %}
:orphan:

{% endif %}
:mod:`{{ obj.name }}`
======={{ "=" * obj.name|length }}

.. py:module:: {{ obj.name }}

{% if obj.docstring %}
.. autoapi-nested-parse::

{{ obj.docstring|prepare_docstring|indent(3) }}

{% endif %}

{% block subpackages %}
{% set visible_subpackages = obj.subpackages|selectattr("display")|list %}
{% if visible_subpackages %}

.. raw:: html

<h3>Subpackages</h3>

.. toctree::
:titlesonly:
:maxdepth: 3

{% for subpackage in visible_subpackages %}
{{ subpackage.short_name }}/index.rst
{% endfor %}


{% endif %}
{% endblock %}
{% block submodules %}
{% set visible_submodules = obj.submodules|selectattr("display")|list %}
{% if visible_submodules %}

.. raw:: html

<h3>Submodules</h3>

.. toctree::
:titlesonly:
:maxdepth: 1

{% for submodule in visible_submodules %}
{{ submodule.short_name }}/index.rst
{% endfor %}


{% endif %}
{% endblock %}
{% block content %}
{% if obj.all is not none %}
{% set visible_children = obj.children|selectattr("short_name", "in", obj.all)|list %}
{% elif obj.type is equalto("package") %}
{% set visible_children = obj.children|selectattr("display")|list %}
{% else %}
{% set visible_children = obj.children|selectattr("display")|rejectattr("imported")|list %}
{% endif %}
{% if visible_children %}


.. raw:: html

<h3>{{ obj.type|title }} Contents</h3>

{% set visible_classes = visible_children|selectattr("type", "equalto", "class")|list %}
{% set visible_functions = visible_children|selectattr("type", "equalto", "function")|list %}
{% set visible_attributes = visible_children|selectattr("type", "equalto", "data")|list %}
{% if "show-module-summary" in autoapi_options and (visible_classes or visible_functions) %}
{% block classes scoped %}
{% if visible_classes %}
**Classes**:

.. autoapisummary::

{% for klass in visible_classes %}
{{ klass.id }}
{% endfor %}


{% endif %}
{% endblock %}

{% block functions scoped %}
{% if visible_functions %}
**Functions**:

.. autoapisummary::

{% for function in visible_functions %}
{{ function.id }}
{% endfor %}


{% endif %}
{% endblock %}

{% block attributes scoped %}
{% if visible_attributes %}
**Attributes**:

.. autoapisummary::

{% for attribute in visible_attributes %}
{{ attribute.id }}
{% endfor %}


{% endif %}
{% endblock %}
{% endif %}

-----------

{% for obj_item in visible_children %}

{{ obj_item.render()|indent(0) }}

{% endfor %}
{% endif %}
{% endblock %}
1 change: 1 addition & 0 deletions docs/_static/custom.css
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#version-picker-label { color: white; display: inline; }
16 changes: 16 additions & 0 deletions docs/_static/custom.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
$(document).ready(function() {
// version picker logic
let currentDocsVersion = 'stable';
let path = document.location.pathname.split("/");
if(path.length >= 3) {
currentDocsVersion = path[2];
}
$("option[value='" + currentDocsVersion + "']").attr("selected", "selected");
$("select").change(function() {
if(this.value === "") {
return false;
}
let newUrl = document.URL.replace(PROJECT + "/" + currentDocsVersion, PROJECT + "/" + $(this).val());
window.location = newUrl;
});
});
Loading