Skip to content
Open
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
159 changes: 143 additions & 16 deletions .github/workflows/publish_docs_to_pages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ on:
push:
branches:
- main
tags:
- v*

permissions:
contents: write

jobs:
build:
build-and-deploy:
if: github.repository_owner == 'numpy'
runs-on: ubuntu-latest
steps:
Expand All @@ -24,32 +26,157 @@ jobs:
run: |
python -m pip install --upgrade pip
pip install .[doc]
- name: Determine docs version
id: version
run: |
if [[ "${{ github.ref }}" == refs/tags/v* ]]; then
# Extract version from tag (e.g., v1.2.0 -> 1.2.0)
VERSION="${GITHUB_REF#refs/tags/v}"
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "is_release=true" >> $GITHUB_OUTPUT
echo "docs_path=version/$VERSION" >> $GITHUB_OUTPUT
else
echo "version=dev" >> $GITHUB_OUTPUT
echo "is_release=false" >> $GITHUB_OUTPUT
echo "docs_path=dev" >> $GITHUB_OUTPUT
fi
- name: Build documentation with Sphinx
env:
DOCS_VERSION: ${{ steps.version.outputs.version }}
run: |
cd doc
make html
mv build/html /tmp
mv build/html /tmp/html
cd ..
- name: Deploy to gh-pages branch
env:
DOCS_PATH: ${{ steps.version.outputs.docs_path }}
IS_RELEASE: ${{ steps.version.outputs.is_release }}
VERSION: ${{ steps.version.outputs.version }}
run: |
git config user.name "${GITHUB_ACTOR}"
git config user.email "${GITHUB_ACTOR}@users.noreply.github.com"
echo "Checking out gh-pages branch"
git fetch origin gh-pages
git checkout gh-pages
echo "Removing old dev documentation"
git clean -xdf .
cd dev
git rm -r '*'
cd ..
echo "Committing emptied dev directory"
git commit -m "Remove old dev documentation"
mkdir -p dev
cd dev
echo "Copying /tmp/html here"
cp -v -r /tmp/html/* .
echo "Adding new dev documentation"

echo "Deploying docs to $DOCS_PATH"

if [ "$IS_RELEASE" = "true" ]; then
# For releases, create new version directory
mkdir -p "$DOCS_PATH"
rm -rf "${DOCS_PATH:?}"/*
else
# For dev builds, clean and recreate dev directory
git clean -xdf .
if [ -d "dev" ]; then
cd dev
git rm -r '*' || true
cd ..
git commit -m "Remove old dev documentation" || true
fi
mkdir -p dev
fi

# Copy the built docs
cp -r /tmp/html/* "$DOCS_PATH/"

# For releases, update versions.json at the root of gh-pages
if [ "$IS_RELEASE" = "true" ]; then
echo "Updating versions.json for release $VERSION"
python3 << 'EOF'
import json
import os

version = os.environ['VERSION']
versions_file = '_static/versions.json'

# Read existing versions.json or start fresh
if os.path.exists(versions_file):
with open(versions_file, 'r') as f:
versions = json.load(f)
else:
versions = []

# Create entry for new version
new_entry = {
"name": version,
"version": version,
"url": f"https://numpy.org/numpy-financial/version/{version}/"
}

# Check if this version already exists (update it) or add new
version_exists = False
for v in versions:
if v.get('version') == version:
v.update(new_entry)
version_exists = True
break

if not version_exists:
# Insert after dev (index 1) or at the beginning if no dev
dev_index = next((i for i, v in enumerate(versions) if v.get('version') == 'dev'), -1)
insert_index = dev_index + 1 if dev_index >= 0 else 0
versions.insert(insert_index, new_entry)

# Update "preferred" flag - newest release should be preferred
# First, remove preferred from all non-dev entries
for v in versions:
if v.get('version') != 'dev' and 'preferred' in v:
del v['preferred']

# Find the highest version (excluding dev) and mark it as preferred
from packaging.version import Version, InvalidVersion
release_versions = []
for v in versions:
ver = v.get('version', '')
if ver != 'dev':
try:
release_versions.append((Version(ver), v))
except InvalidVersion:
pass

if release_versions:
release_versions.sort(key=lambda x: x[0], reverse=True)
highest = release_versions[0][1]
highest['preferred'] = True
# Update the name to indicate stable
highest['name'] = f"{highest['version']} (stable)"

# Ensure dev is always first
versions.sort(key=lambda v: (0 if v.get('version') == 'dev' else 1, v.get('version', '')), reverse=False)
# Re-sort releases by version descending (dev stays first)
dev_entry = [v for v in versions if v.get('version') == 'dev']
release_entries = [v for v in versions if v.get('version') != 'dev']
try:
release_entries.sort(key=lambda v: Version(v.get('version', '0')), reverse=True)
except:
pass
versions = dev_entry + release_entries

# Write updated versions.json
os.makedirs('_static', exist_ok=True)
with open(versions_file, 'w') as f:
json.dump(versions, f, indent=4)
EOF

# Also copy versions.json to the new version's _static directory
# so it's available when viewing that version's docs
cp _static/versions.json "$DOCS_PATH/_static/versions.json"

# Update 'latest' symlink to point to the new version
rm -f latest
ln -s "version/$VERSION" latest
git add latest
fi

# Stage and commit changes
git add -A .
git commit -m "Add new dev documentation"
echo "Pushing new documentation to origin"
if [ "$IS_RELEASE" = "true" ]; then
git commit -m "Add documentation for version $VERSION"
else
git commit -m "Update dev documentation"
fi

echo "Pushing documentation to origin"
git push -v origin gh-pages
32 changes: 13 additions & 19 deletions RELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,25 +77,19 @@ PyPI trusted publishing. Do not build or upload artifacts by hand.
- paste the contents of ${CHANGES} in the `Describe this release section`
- if pre-release check the box labelled `Set as a pre-release`

- Publish the documentation for the release. A GH workflow builds
`dev/` from `main`; the released versions have to be published by
hand. Skip this step for a pre-release.

- wait for the workflow to rebuild `dev/` from the release
commit, and check that https://numpy.org/numpy-financial/dev/
shows ${VERSION}. Do this before the version bump below, which
returns `dev/` to a development version.

- in a clone of the `gh-pages` branch, copy those docs to their
permanent location and point `latest` at them:

cp -r dev version/${VERSION}
git add version/${VERSION}
git rm -rf latest
ln -s version/${VERSION} latest
git add latest

- commit and push `gh-pages`
- Publish the documentation for the release. The `Publish docs to gh-pages`
workflow automatically builds and deploys versioned documentation when
a `v*` tag is pushed:

- Dev docs are deployed to `/dev/` from `main` branch pushes
- Release docs are deployed to `/version/${VERSION}/` from `v*` tags
- The workflow automatically updates `_static/versions.json` with the
new version and marks the highest version as stable

Verify the deployment:
- Check https://numpy.org/numpy-financial/version/${VERSION}/ shows
the new version's documentation
- Check the version switcher dropdown includes the new version

- Update https://github.com/numpy/numpy-financial/milestones:

Expand Down
13 changes: 13 additions & 0 deletions doc/source/_static/versions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[
{
"name": "dev",
"version": "dev",
"url": "https://numpy.org/numpy-financial/dev/"
},
{
"name": "1.1.0 (stable)",
"version": "1.1.0",
"url": "https://numpy.org/numpy-financial/version/1.1.0/",
"preferred": true
}
]
42 changes: 41 additions & 1 deletion doc/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
# list see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html

import os
from datetime import datetime

import numpy_financial

# -- Path setup --------------------------------------------------------------
Expand All @@ -20,7 +23,7 @@
# -- Project information -----------------------------------------------------

project = 'numpy-financial'
copyright = '2023, numpy-financial developers'
copyright = f'2005-{datetime.now().year}, NumPy Developers'
author = 'numpy-financial developers'


Expand Down Expand Up @@ -61,3 +64,40 @@

html_logo = "_static/numpy_financial_logov.svg"
html_favicon = "_static/numpy_financial_favicon.png"

# -- Version switcher configuration ------------------------------------------

# Determine the version string for the switcher.
# Must match a "version" field in versions.json for the dropdown to show it selected.
#
# In production (CI), DOCS_VERSION is set explicitly:
# - "dev" for main branch builds (deployed to /dev/)
# - "X.Y.Z" for release tag builds (deployed to /version/X.Y.Z/)
#
# For local development, default to showing stable version to test the typical UX.
if os.environ.get("DOCS_VERSION"):
# CI sets this explicitly based on branch/tag
switcher_version = os.environ["DOCS_VERSION"]
else:
# Local development: show stable version (1.1.0) as default for UX testing
# This matches what users see when visiting the main docs site
switcher_version = "1.1.0"

# For local development, use relative path to test version switcher UI.
# In CI/production, use the absolute URL.
if os.environ.get("READTHEDOCS") or os.environ.get("CI"):
json_url = "https://numpy.org/numpy-financial/_static/versions.json"
else:
# Local development: use relative path (requires serving with http server)
json_url = "_static/versions.json"

html_theme_options = {
"github_url": "https://github.com/numpy/numpy-financial",
# Navbar layout: theme switcher, version switcher, then GitHub icon
"navbar_end": ["theme-switcher", "version-switcher", "navbar-icon-links"],
"switcher": {
"json_url": json_url,
"version_match": switcher_version,
},
"show_version_warning_banner": True,
}
Loading