diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000..3dec733 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,52 @@ +# API reference: one DocC archive per module (the .docc catalogs under Sources/), merged into one static site and +# published to GitHub Pages at https://mac4dstem.github.io/CuboKit/documentation/ on every tag. +# On a pull request the site is built and uploaded as an artifact only, so a broken catalog fails before the tag. +# +# No swift-docc-plugin: the kit takes no package dependencies (CLAUDE.md). `xcodebuild docbuild` builds the archives +# from the package's own schemes; `docc merge` (Xcode 16+) joins them. Needs Pages enabled with source "GitHub Actions" +# (repository Settings > Pages). Pattern first proposed for CuboKit; the other kits copy it with their module list. +name: Docs + +on: + push: + tags: ['*'] + pull_request: + paths: ['Sources/**/*.docc/**', '.github/workflows/docs.yml', 'tools/build-docs.sh'] + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: docs-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + runs-on: macos-latest + timeout-minutes: 60 + steps: + - uses: actions/checkout@v4 + - name: Select the newest Xcode + run: | + xcode=$(ls -d /Applications/Xcode*.app | sort -V | tail -1) + sudo xcode-select -s "$xcode" + xcodebuild -version + - name: Build the site + run: tools/build-docs.sh .docs-site /CuboKit + - uses: actions/upload-pages-artifact@v3 + with: + path: .docs-site + + deploy: + needs: build + if: startsWith(github.ref, 'refs/tags/') + runs-on: ubuntu-latest + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - id: deployment + uses: actions/deploy-pages@v4 diff --git a/.gitignore b/.gitignore index d90c01e..0c14fcc 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ .swiftpm/ *.xcresult __pycache__/ +.docs-site/ diff --git a/README.md b/README.md index f9412dc..c4dc984 100644 --- a/README.md +++ b/README.md @@ -158,6 +158,7 @@ swift build # no setup, no dependency; the Metal kernels swift test -c release # the gate (tools/test.sh does the same and reports skipped real-data tests) tools/consumer-check/run.sh # a separate package using the public API only tools/readme-consumer/run.sh # the README's own code, compiled and run +tools/build-docs.sh .docs-site # the DocC site for every module (Xcode 16+); CI publishes it on a tag ``` The tests need nothing outside the package: the synthetic pins are committed. To regenerate pins, install the reference diff --git a/tools/build-docs.sh b/tools/build-docs.sh new file mode 100755 index 0000000..72d2d99 --- /dev/null +++ b/tools/build-docs.sh @@ -0,0 +1,26 @@ +#!/bin/bash +# Builds the DocC site for every module with a .docc catalog and merges it into one static site. +# tools/build-docs.sh [] e.g. tools/build-docs.sh .docs-site /CuboKit +# macOS with Xcode 16 or later. Output is gitignored (.docs-site). +set -euo pipefail +cd "$(dirname "$0")/.." +out="${1:?output dir}" +base="${2:-}" +derived="$(mktemp -d)" +trap 'rm -rf "$derived"' EXIT + +modules=$(find Sources -maxdepth 2 -name '*.docc' -exec basename {} .docc \; | sort) +archives=() +for m in $modules; do + xcodebuild docbuild -scheme "$m" -destination 'generic/platform=macOS' -derivedDataPath "$derived" >"$derived/$m.log" 2>&1 \ + || { tail -30 "$derived/$m.log"; echo "docbuild failed for $m"; exit 1; } + archives+=("$(find "$derived/Build/Products" -name "$m.doccarchive" -maxdepth 3 | head -1)") +done + +merged="$derived/CuboKit.doccarchive" +xcrun docc merge "${archives[@]}" --output-path "$merged" +rm -rf "$out" +xcrun docc process-archive transform-for-static-hosting "$merged" --output-path "$out" ${base:+--hosting-base-path "$base"} +# the site root has no page of its own: send it to the merged documentation landing page +printf '' "${base}" > "$out/index.html" +echo "built $out ($(echo "$modules" | wc -l | tr -d ' ') modules)"