diff --git a/.github/actions/sphinx/build/action.yml b/.github/actions/sphinx/build/action.yml index 74af5c68c..ee5d9ff05 100644 --- a/.github/actions/sphinx/build/action.yml +++ b/.github/actions/sphinx/build/action.yml @@ -1,4 +1,11 @@ name: Build sphinx documentation + +inputs: + SPHINX_VERSION: + required: true + SPHINX_RELEASE: + required: true + runs: using: composite steps: @@ -9,4 +16,7 @@ runs: python -m pip install '.[sphinx]' - working-directory: sphinx shell: bash - run: make html + run: > + SPHINX_VERSION=${{ inputs.SPHINX_VERSION }} + SPHINX_RELEASE=${{ inputs.SPHINX_RELEASE }} + make html diff --git a/.github/actions/sphinx/deploy/action.yml b/.github/actions/sphinx/deploy/action.yml index ecb5b8c37..e6118ee0f 100644 --- a/.github/actions/sphinx/deploy/action.yml +++ b/.github/actions/sphinx/deploy/action.yml @@ -1,19 +1,38 @@ name: Deploy sphinx documentation -permissions: - contents: write + +inputs: + CONFIGURATION: + required: true + ACTION: + required: false + default: sync + type: choice + options: + - copy + - sync + PROVIDER: + required: false + default: scaleway + BUCKET: + required: false + default: prod-probabl-skore + SOURCE: + required: true + DESTINATION: + required: true + runs: using: composite steps: - shell: bash run: | - rm -rf docs/latest - mv sphinx/build/html docs/latest + sudo apt-get update + sudo apt-get install -y rclone + - shell: bash + run: echo "${{ inputs.CONFIGURATION }}" > rclone.configuration - shell: bash run: | - git config user.name 'github-actions[bot]' - git config user.email 'github-actions[bot]@users.noreply.github.com' - git config commit.cleanup 'verbatim' - - git add docs/latest - git commit -m $'docs: Build documentation triggered by ${{ github.sha }}\n\n\nskip-checks:true' - git push + rclone --config rclone.configuration \ + ${{ inputs.ACTION }} \ + ${{ inputs.SOURCE }} \ + ${{ inputs.PROVIDER }}:${{ inputs.BUCKET }}/${{ inputs.DESTINATION }} diff --git a/.github/workflows/sphinx.yml b/.github/workflows/sphinx.yml index b602fc874..73b1a5e2f 100644 --- a/.github/workflows/sphinx.yml +++ b/.github/workflows/sphinx.yml @@ -1,5 +1,51 @@ name: Sphinx + +# **How it works** +# ================ +# +# After each __commit__ on the `main` branch, the documentation is built and deployed on the `S3:dev/` directory. +# After each __release__, the documentation is built and deployed to the `S3:version/` directory, the version being +# a subpart of the tag `MAJOR.MINOR.BUGFIX`: `MAJOR.MINOR`. +# +# For instance, with the following timeline: +# +# dev/ dev/ dev/ dev/ dev/ +# 0.1/ 0.2/ +# main -- x -- x -- x -- x -- x -- > +# | | +# tag 0.1 0.2 +# +# The S3 bucket looks like: +# . +# ├── 0.1/ +# ├── 0.2/ +# ├── dev/ +# ├── index.html +# └── versions.json +# +# **Q&A** +# ======= +# +# ### `dev/`, why? +# It contains the most up-to-date documentation, i.e. the documentation of code that is not released but committed on the main branch. +# +# ### Version the documentation on `MAJOR.MINOR, why not on `MAJOR`? +# Currently, we add new features at a minor level. This way, we can separate documentation between two features. +# +# ### Only on release (not on release-candidate), why? +# The release-candidates are documented in the `dev/` directory. We don't want to create noise with explicit directory for such tags. +# +# ### How to change an old version of the documentation? +# You can create tags wherever you want, i.e. on separate branches. +# For example, you can create a branch from an old tag (`0.1.5`), modify the documentation and create a new tag (`0.1.6`). +# The corresponding documentation will be automatically updated (`0.1`). +# +# **Side-notes** +# ============== +# +# Only the 10 latest versions are listed in sphinx version-switcher to avoid overloading, but the bucket remains unchanged. + on: pull_request: paths: @@ -17,22 +63,131 @@ on: - 'examples/**' - 'sphinx/**' - 'skore/**' + release: + types: [released] concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: - sphinx: + sphinx-version: runs-on: ubuntu-latest + outputs: + SPHINX_VERSION: ${{ steps.sphinx-version.outputs.SPHINX_VERSION }} + SPHINX_RELEASE: ${{ steps.sphinx-version.outputs.SPHINX_RELEASE }} + steps: + - shell: bash + id: sphinx-version + run: | + set -u + + if [[ "${GITHUB_EVENT_NAME}" != "release" ]]; then + echo "SPHINX_VERSION=dev" >> "${GITHUB_OUTPUT}" + echo "SPHINX_RELEASE=0.0.0+dev" >> "${GITHUB_OUTPUT}" + exit 0 + fi + + set -e + + if [[ "${GITHUB_REF_NAME}" =~ ^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)?$ ]]; then + echo "SPHINX_VERSION=${BASH_REMATCH[1]}.${BASH_REMATCH[2]}" >> "${GITHUB_OUTPUT}" + echo "SPHINX_RELEASE=${GITHUB_REF_NAME}" >> "${GITHUB_OUTPUT}" + fi + + sphinx-build: + runs-on: ubuntu-latest + needs: sphinx-version steps: - uses: actions/checkout@v4 - with: - ssh-key: ${{ secrets.DEPLOY_KEY }} - uses: actions/setup-python@v5 with: python-version: '3.12' cache: 'pip' - uses: ./.github/actions/sphinx/build - - if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} - uses: ./.github/actions/sphinx/deploy + with: + SPHINX_VERSION: ${{ needs.sphinx-version.outputs.SPHINX_VERSION }} + SPHINX_RELEASE: ${{ needs.sphinx-version.outputs.SPHINX_RELEASE }} + - uses: actions/upload-artifact@v4 + with: + name: sphinx-html-artifact + path: sphinx/build/html/ + + sphinx-deploy-html: + runs-on: ubuntu-latest + if: ${{ (github.event_name == 'release') || (github.event_name == 'push' && github.ref == 'refs/heads/main') }} + needs: [sphinx-version, sphinx-build] + steps: + - uses: actions/checkout@v4 + - uses: actions/download-artifact@v4 + with: + name: sphinx-html-artifact + path: html/ + - uses: ./.github/actions/sphinx/deploy + with: + CONFIGURATION: ${{ secrets.RCLONE_CONFIG_DOCS }} + SOURCE: html/ + DESTINATION: ${{ needs.sphinx-version.outputs.SPHINX_VERSION }}/ + + sphinx-deploy-root-files: + runs-on: ubuntu-latest + if: ${{ github.event_name == 'release' }} + needs: [sphinx-version, sphinx-build, sphinx-deploy-html] + steps: + - uses: actions/checkout@v4 + - shell: python + run: | + import os + import requests + import operator + import json + + url = "https://skore.probabl.ai" + current = os.environ["CURRENT"] + + response = requests.get(f"{url}/versions.json") + response.raise_for_status() + + history = set(map(operator.itemgetter("version"), response.json())) - {"dev"} | {current} + history = sorted(history, key=lambda x: float(x), reverse=True)[:10] + + new = [ + { + "name": version, + "version": version, + "url": f"{url}/{version}/", + "preferred": i == 1, + } + for i, version in enumerate(["dev"] + history) + ] + + os.mkdir("artifacts") + + with open("artifacts/versions.json", "w", encoding="utf-8") as file: + json.dump(new, file, ensure_ascii=False, indent=4) + + with open("artifacts/index.html", "w", encoding="utf-8") as file: + file.write( + f""" + + + + """ + ) + env: + CURRENT: ${{ needs.sphinx-version.outputs.SPHINX_VERSION }} + - uses: ./.github/actions/sphinx/deploy + with: + CONFIGURATION: ${{ secrets.RCLONE_CONFIG_DOCS }} + ACTION: copy + SOURCE: artifacts/ + DESTINATION: + + sphinx-clean: + runs-on: ubuntu-latest + if: always() + needs: [sphinx-version, sphinx-build, sphinx-deploy-html, sphinx-deploy-root-files] + steps: + - uses: geekyeggo/delete-artifact@v5 + with: + name: sphinx-html-artifact diff --git a/sphinx/Makefile b/sphinx/Makefile index ed8809902..eb0083a35 100644 --- a/sphinx/Makefile +++ b/sphinx/Makefile @@ -1,12 +1,15 @@ # Minimal makefile for Sphinx documentation # +export SPHINX_VERSION ?= dev +export SPHINX_RELEASE ?= 0.0.0+dev + # You can set these variables from the command line, and also # from the environment for the first two. -SPHINXOPTS ?= -SPHINXBUILD ?= sphinx-build -SOURCEDIR = . -BUILDDIR = build +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = . +BUILDDIR = build # Put it first so that "make" without argument is like "make help". help: diff --git a/sphinx/conf.py b/sphinx/conf.py index cac73427c..e4091e13d 100644 --- a/sphinx/conf.py +++ b/sphinx/conf.py @@ -6,11 +6,13 @@ # -- Project information ----------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information +import os + project = "skore" copyright = "2024, Probabl" author = "Probabl" -# version = "0" -# release = "0" +version = os.environ["SPHINX_VERSION"] +release = os.environ["SPHINX_RELEASE"] # -- General configuration --------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration @@ -50,10 +52,10 @@ "within_subsection_order": "FileNameSortKey", # See https://sphinx-gallery.github.io/stable/configuration.html#sorting-gallery-examples for alternatives "show_memory": False, "write_computation_times": False, - 'reference_url': { + "reference_url": { # The module you locally document uses None - 'skore': None, - } + "skore": None, + }, } # intersphinx configuration @@ -105,7 +107,15 @@ "icon": "fa-brands fa-discord", }, ], - # "announcement": "This code is still in development. The API is subject to change.", + "switcher": { + "json_url": "https://skore.probabl.ai/versions.json", + "version_match": version, + }, + "check_switcher": True, + "show_version_warning_banner": True, + "navbar_start": ["navbar-logo", "version-switcher"], + "navbar_center": ["navbar-nav"], + "navbar_end": ["theme-switcher", "navbar-icon-links"], } # Plausible Analytics @@ -118,10 +128,10 @@ # Sphinx remove the sidebar from some pages html_sidebars = { - "install": [], - "getting_started": [], - "user_guide": [], - "contributor_guide": [], + "install": [], + "getting_started": [], + "user_guide": [], + "contributor_guide": [], } # Sphinx-Copybutton configuration