Skip to content

feat(skore)!: Refactor hub authentication (#2340) #6112

feat(skore)!: Refactor hub authentication (#2340)

feat(skore)!: Refactor hub authentication (#2340) #6112

Workflow file for this run

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:
push:
branches: [main]
tags: ['skore/[0-9]+.[0-9]+.[0-9]+']
merge_group:
types: [checks_requested]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions: {}
defaults:
run:
shell: bash
env:
PYTHON: '3.13'
SCIKIT_LEARN: '1.8'
LOCKFILE: 'ci/requirements/skore/python-3.13/scikit-learn-1.8/sphinx-requirements.txt'
jobs:
sphinx-changes:
runs-on: ubuntu-latest
outputs:
changes: ${{ steps.filter.outputs.sphinx }}
permissions:
pull-requests: read
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Define if at least one file has changed
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
id: filter
with:
filters: |
sphinx:
- '.github/actions/sphinx/**'
- '.github/workflows/sphinx.yml'
- 'ci/requirements/skore/**/sphinx-requirements.txt'
- 'examples/**'
- 'sphinx/**'
- 'skore/**'
sphinx-lockfiles:
runs-on: ubuntu-latest
needs: [sphinx-changes]
if: ${{ (contains(fromJSON('["pull_request", "merge_group"]'), github.event_name)) && (needs.sphinx-changes.outputs.changes == 'true') }}
permissions:
contents: read
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 2
- name: Check lockfiles are not obsolete
run: |
set -eu
# Check if `pyproject.toml` has changed in this pull-request
# ├── False
# │ └── Exit 0
# └── True
# └── Check if lockfiles have changed in this pull-request
# ├── True
# │ └── Exit 0
# └── False
# └── Recompile lockfiles and check if they have to change
# ├── False
# │ └── Exit 0
# └── True
# └── Exit 1
changes=$(git diff --name-only HEAD^1 HEAD)
if
(echo "${changes}" | grep -qE "skore/pyproject.toml") &&
(echo "${changes}" | (! grep -qE "${LOCKFILE}"))
then
curl -LsSf https://astral.sh/uv/0.6.16/install.sh | sh
bash ci/pip-compile.sh --sphinx-requirements
if (git diff --name-only | grep -qE "${LOCKFILE}"); then
echo '::error title=skore-sphinx-lockfiles::Lockfiles obsolete, please execute `$ bash ci/pip-compile.sh --sphinx-requirements`'
exit 1
fi
fi
sphinx-version:
runs-on: ubuntu-latest
needs: [sphinx-changes]
if: ${{ (github.event_name == 'push') || (needs.sphinx-changes.outputs.changes == 'true') }}
outputs:
SPHINX_VERSION: ${{ steps.sphinx-version.outputs.SPHINX_VERSION }}
SPHINX_RELEASE: ${{ steps.sphinx-version.outputs.SPHINX_RELEASE }}
steps:
- id: sphinx-version
run: |
set -u
if [[ "${GITHUB_EVENT_NAME}" != "push" ]] || [[ "${GITHUB_REF_TYPE}" != "tag" ]]; 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}" =~ ^skore/((0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*))$ ]]; then
echo "SPHINX_VERSION=${BASH_REMATCH[2]}.${BASH_REMATCH[3]}" >> "${GITHUB_OUTPUT}"
echo "SPHINX_RELEASE=${BASH_REMATCH[1]}" >> "${GITHUB_OUTPUT}"
fi
sphinx-build:
runs-on: ubuntu-latest
needs: [sphinx-version]
if: ${{ (github.event_name == 'push') || (needs.sphinx-changes.outputs.changes == 'true') }}
permissions:
contents: read
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
lfs: 'true'
- name: Setup Python
uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
id: setup-python
with:
python-version: ${{ env.PYTHON }}
check-latest: True
cache: pip
- name: Restore python-venv
uses: actions/cache/restore@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
id: cache-python-venv
with:
path: skore/venv
key: >-
python-venv
-ubuntu-latest
-${{ steps.setup-python.outputs.python-version }}
-${{ hashFiles(env.LOCKFILE) }}
- name: Setup python-venv
working-directory: skore
run: |
set -eu
# Ensure venv is created
python -m venv venv
# Activate venv for each step
echo "${GITHUB_WORKSPACE}/skore/venv/bin" >> ${GITHUB_PATH}
echo "VIRTUAL_ENV=${GITHUB_WORKSPACE}/skore/venv" >> ${GITHUB_ENV}
- name: Install dependencies in python-venv
if: steps.cache-python-venv.outputs.cache-hit != 'true'
run: |
set -eu
python -m pip install --upgrade pip build
python -m pip install --requirement "${LOCKFILE}"
- name: Save python-venv
uses: actions/cache/save@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
if: steps.cache-python-venv.outputs.cache-hit != 'true'
with:
path: skore/venv
key: ${{ steps.cache-python-venv.outputs.cache-primary-key }}
- name: Install
working-directory: skore
run: python -m pip install --force-reinstall --no-deps .
- name: Build documentation
working-directory: sphinx
timeout-minutes: 60
run: make html
env:
SPHINX_VERSION: ${{ needs.sphinx-version.outputs.SPHINX_VERSION }}
SPHINX_RELEASE: ${{ needs.sphinx-version.outputs.SPHINX_RELEASE }}
SPHINX_DOMAIN: ${{ vars.DOCUMENTATION_DOMAIN }}
- name: Upload documentation
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: sphinx-html-artifact
path: sphinx/build/html/
sphinx-deploy-html:
if: ${{ github.event_name == 'push' }}
runs-on: ubuntu-latest
needs: [sphinx-version, sphinx-build]
permissions:
contents: read
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
sparse-checkout: .github
- name: Download HTML artifacts
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
with:
name: sphinx-html-artifact
path: html/
- name: Deploy HTML artifacts
uses: ./.github/actions/sphinx/deploy
with:
CONFIGURATION: ${{ secrets.RCLONE_CONFIG_DOCS }}
BUCKET: ${{ vars.DOCUMENTATION_BUCKET }}
SOURCE: html/
DESTINATION: ${{ needs.sphinx-version.outputs.SPHINX_VERSION }}/
sphinx-deploy-root-files:
if: ${{ (github.event_name == 'push') && (github.ref_type == 'tag') }}
runs-on: ubuntu-latest
needs: [sphinx-version, sphinx-build, sphinx-deploy-html]
permissions:
contents: read
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
sparse-checkout: .github
- shell: python
run: |
import os
import requests
import operator
import json
version = os.environ["SPHINX_VERSION"]
release = os.environ["SPHINX_RELEASE"]
url = os.environ["SPHINX_URL"]
# Retrieve history
response = requests.get(f"{url}/versions.json")
response.raise_for_status()
history = {version["name"]: version["version"] for version in response.json()}
# Add new version to history
history[version] = release
# Sort history, and always keep "dev" at the beginning
history = sorted(
history.items(),
key=lambda item: tuple(map(float, item[0].split("."))) if item[0] != "dev" else (float('inf'), 0),
reverse=True
)
# Rewrite the history with "dev" and the 10 latest versions
new = [
{
"name": version,
"version": release,
"url": f"{url}/{version}/",
"preferred": i == 1,
}
for i, (version, release) in enumerate(history[:11])
]
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"""
<head>
<meta http-equiv=\"refresh\" content=\"0; url={new[1]["url"]}\"/>
</head>
"""
)
env:
SPHINX_VERSION: ${{ needs.sphinx-version.outputs.SPHINX_VERSION }}
SPHINX_RELEASE: ${{ needs.sphinx-version.outputs.SPHINX_RELEASE }}
SPHINX_URL: https://${{ vars.DOCUMENTATION_DOMAIN }}
- uses: ./.github/actions/sphinx/deploy
with:
CONFIGURATION: ${{ secrets.RCLONE_CONFIG_DOCS }}
BUCKET: ${{ vars.DOCUMENTATION_BUCKET }}
ACTION: copy
SOURCE: artifacts/
DESTINATION:
sphinx-purge-cdn-cache:
runs-on: ubuntu-latest
#
# Using `if: ${{ (! cancelled()) && contains(needs.*.result, 'success') }}` at
# __job level__ doesn't work as expected. It always returns true if one of the needs
# , or unfortunately one of their **transitive** needs, satisfies the condition.
#
# https://github.com/actions/runner/issues/1540
#
if: ${{ (! cancelled()) && ((needs.sphinx-deploy-html.result == 'success') || (needs.sphinx-deploy-root-files == 'success')) }}
needs:
- sphinx-deploy-html
- sphinx-deploy-root-files
steps:
- run: |
curl --fail-with-body \
-X POST \
--url "https://api.bunny.net/pullzone/${PULLZONE}/purgeCache" \
--header "AccessKey: ${ACCESS_KEY}"
env:
PULLZONE: ${{ vars.BUNNY_PULLZONE }}
ACCESS_KEY: ${{ secrets.BUNNY_API_KEY }}
sphinx-clean-artifacts:
runs-on: ubuntu-latest
if: ${{ always() && (github.event_name != 'pull_request') }}
needs: [sphinx-version, sphinx-build, sphinx-deploy-html, sphinx-deploy-root-files]
steps:
- uses: geekyeggo/delete-artifact@f275313e70c08f6120db482d7a6b98377786765b # v5.1.0
with:
name: sphinx-html-artifact
sphinx:
needs:
- sphinx-changes
- sphinx-lockfiles
- sphinx-version
- sphinx-build
- sphinx-deploy-html
- sphinx-deploy-root-files
- sphinx-clean-artifacts
if: ${{ always() }}
runs-on: Ubuntu-latest
steps:
- run: |
[[ ${{ contains(needs.*.result, 'failure') }} = false ]]