Skip to content
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
198 changes: 148 additions & 50 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
name: docs

# Every documentation version is a separate Hugo build, published under
# https://go-ndarray.github.io/docs/<version>/ on the gh-pages branch, where
# <version> is the minor version of ndarray the pages describe
# (params.ndarray.version in hugo.yaml: v0.9.1 -> 0.9). main is that
# version's source: each push to main replaces /docs/<version>/, and
# /docs/latest/ follows the newest. Pull requests build and check, and publish
# nothing.

on:
push:
branches: [main]
Expand All @@ -12,81 +20,171 @@ on:
permissions:
contents: read

env:
HUGO_VERSION: "0.167.0"
# sha256 of hugo_${HUGO_VERSION}_linux-amd64.tar.gz, from the release's checksums.txt.
HUGO_SHA256: "4d84519b9f619e6d4c3fb45a50157abeabeb724f859c60605f44c23def6e1169"
DOCS_URL: "https://go-ndarray.github.io/docs"

jobs:
# Build on every pull request as well as on main, so a change to the docs or to
# the toolchain in requirements.txt has to prove it still builds before it
# lands. Without this the workflow ran only on main, which meant a dependency
# bump had no signal at all and nothing could say whether it was safe to merge.
build:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.version }}
steps:
- name: Checkout
uses: actions/checkout@v7

- name: Set up Python
uses: actions/setup-python@v7
with:
python-version: "3.14"
cache: pip
cache-dependency-path: requirements.txt
# themes/hextra (the tannevaled/hextra fork, pinned to a release tag)
# and branding (go-ndarray/brand) are submodules.
submodules: recursive
# The whole history: each page's creation and modification come from git.
fetch-depth: 0

- name: Install MkDocs Material + mike
- name: Install Hugo ${{ env.HUGO_VERSION }}
run: |
pip install --upgrade pip
pip install -r requirements.txt
curl -fsSL -o /tmp/hugo.tar.gz \
"https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_${HUGO_VERSION}_linux-amd64.tar.gz"
echo "${HUGO_SHA256} /tmp/hugo.tar.gz" | sha256sum -c -
sudo tar -xzf /tmp/hugo.tar.gz -C /usr/local/bin hugo
hugo version

# The version label is ndarray's minor version, read from hugo.yaml,
# and it is the last segment of baseURL: the version selector reads it there.
- name: Version
id: version
run: |
ndarray=$(hugo config --format json | jq -r '.params.ndarray.version')
version=$(printf '%s\n' "${ndarray}" | sed -nE 's/^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/\1.\2/p')
if [ -z "${version}" ]; then
echo "::error::params.ndarray.version in hugo.yaml is \"${ndarray}\", not vMAJOR.MINOR.PATCH"
exit 1
fi
echo "version=${version}" >> "$GITHUB_OUTPUT"
echo "ndarray ${ndarray}: documentation version ${version}"

# Each page's creation (first commit, followed across renames) and its
# author, for the page history at its foot (params.page.history).
- name: Page history
run: |
mkdir -p data
sh themes/hextra/scripts/page-history.sh > data/pagehistory.json

# --panicOnWarning: a deprecated setting or a template warning fails the
# build rather than scrolling by. A broken {{< relref >}} is an error.
- name: Build
env:
HUGO_ENVIRONMENT: production
run: >-
hugo --gc --minify --panicOnWarning --printPathWarnings
--baseURL "${DOCS_URL}/${{ steps.version.outputs.version }}/"

# Internal links and anchors, offline, with the site laid out under
# /docs/<version>/ as it is served.
- name: Lay out the site for the link check
run: |
mkdir -p _check/docs
cp -R public "_check/docs/${{ steps.version.outputs.version }}"

- name: Check links
uses: lycheeverse/lychee-action@v2
with:
args: >-
--offline --no-progress --include-fragments
--index-files index.html
--root-dir ${{ github.workspace }}/_check
'_check/docs/**/*.html'
fail: true

# --strict turns a broken link or an unknown config key into a failure
# rather than a warning nobody reads.
- name: Build the site (strict)
run: mkdocs build --strict
- uses: actions/upload-artifact@v7
with:
name: site
path: public
retention-days: 7

# The offline check above proves the site's own links and anchors. An
# https:// URL is text to it: this job fetches each one the pages name.
links:
name: every external link resolves
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- name: Check
run: |
set -uo pipefail
# The character class matters: an extractor stopping only at ) and "
# carries a closing > or < into the request.
urls=$(grep -rhoE 'https?://[^)">< [:space:]]+' content/ README.md | sed -E 's/[.,`]+$//' | sort -u)
test -n "$urls" || { echo "::error::no links found; are the pages still there?"; exit 1; }
echo "checking $(printf '%s\n' "$urls" | wc -l) distinct URLs"
fail=0
while read -r u; do
case "$u" in
# Renders whatever it is asked for; proves nothing.
*img.shields.io*) continue ;;
# Documented placeholders, not hosts.
*example.com*|*example.org*|*example.net*|*localhost*|*127.0.0.1*|*.invalid*) continue ;;
esac
# Three attempts: one is a flake detector rather than a link
# checker, and a lane that fails at random gets ignored.
code=000
for _ in 1 2 3; do
code=$(curl -sS -o /dev/null -w '%{http_code}' -L --max-time 25 "$u" 2>/dev/null) || true
code=${code:-000}
case "$code" in 2*|3*) break ;; esac
sleep 3
done
case "$code" in
2*|3*) printf ' ok %s %s\n' "$code" "$u" ;;
*) printf ' FAIL %s %s\n' "$code" "$u"; fail=1 ;;
esac
done <<< "$urls"
test "$fail" -eq 0 || { echo "::error::at least one link does not resolve"; exit 1; }

deploy:
# Only main publishes. A pull request stops after build above: it has no
# business pushing to gh-pages, and `permissions: contents: write` is not
# granted to a fork's PR anyway.
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
# business pushing to gh-pages.
if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main'
needs: build
# Two deploys must never run at once: `mike deploy --push` pushes gh-pages,
# and a second job doing the same is rejected outright --
#
# ! [rejected] gh-pages -> gh-pages (fetch first)
#
# cancel-in-progress stays FALSE deliberately: killing a publish half way
# through is worse than making it wait, and the queued run then fetches the
# gh-pages the previous one just wrote.
# Never two deploys at once: both would push gh-pages and the second would
# be rejected. cancel-in-progress stays false -- killing a publish half way
# through is worse than making it wait.
concurrency:
group: gh-pages-deploy
cancel-in-progress: false
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout
uses: actions/checkout@v7
# The publishing script, from the commit being published.
- uses: actions/checkout@v7
with:
fetch-depth: 0
path: source

- name: Set up Python
uses: actions/setup-python@v7
# The published site. Only the version being built is replaced; every
# other version (the MkDocs-built 0.1 and 0.2) stays as it is.
- uses: actions/checkout@v7
with:
python-version: "3.14"
ref: gh-pages
path: gh-pages

- name: Install MkDocs Material + mike
run: |
pip install --upgrade pip
pip install -r requirements.txt
- uses: actions/download-artifact@v7
with:
name: site
path: site

- name: Configure git for mike
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
- name: Publish ${{ needs.build.outputs.version }}
run: source/scripts/publish-version.sh "${{ needs.build.outputs.version }}" site gh-pages

# mike publishes versioned docs to the gh-pages branch; GitHub Pages serves
# that branch at https://go-ndarray.github.io/docs/. The version label
# tracks main as "0.2" aliased "latest"; tag-driven versions can be added
# later. /docs/ redirects to the default ("latest").
- name: Deploy versioned docs
- name: Push gh-pages
working-directory: gh-pages
run: |
git fetch origin gh-pages --depth=1 || true
mike deploy --push --update-aliases 0.2 latest
mike set-default --push latest
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add -A
if git diff --cached --quiet; then
echo "nothing changed"
exit 0
fi
git commit -q -m "Deployed ${GITHUB_SHA::7} to ${{ needs.build.outputs.version }} with Hugo ${HUGO_VERSION}"
git push origin HEAD:gh-pages
95 changes: 0 additions & 95 deletions .github/workflows/redeploy-version.yml

This file was deleted.

11 changes: 8 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/site/
.venv/
__pycache__/
/public/
/resources/
/_check/
.hugo_build.lock
.DS_Store

# Written by themes/hextra/scripts/page-history.sh before each build (CI and local).
/data/pagehistory.json
6 changes: 6 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[submodule "themes/hextra"]
path = themes/hextra
url = https://github.com/tannevaled/hextra.git
[submodule "branding"]
path = branding
url = https://github.com/go-ndarray/brand.git
Loading
Loading