v2.0.0 #56
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Publish Docs | |
| # Publishes the versioned docs site to GitHub Pages. | |
| # | |
| # Discovers the versions to publish from the repository's GitHub releases (the | |
| # latest release, by date, for each major >= 1), builds each release tag into | |
| # its own sub-path (e.g. /v1/ and /v2/) with make generate-docs, injects a | |
| # version-picker widget into each page, adds a root redirect to the default | |
| # version, and deploys the combined site. A manual dispatch can also rebuild | |
| # the matching major-version path from a specified branch, tag, or commit. | |
| # Triggers on release publish and manual dispatch. | |
| on: | |
| release: | |
| types: [published] | |
| workflow_dispatch: | |
| inputs: | |
| docs_ref: | |
| description: Branch, tag, or commit whose docs should refresh its matching major version | |
| required: false | |
| type: string | |
| # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages | |
| permissions: | |
| contents: read | |
| pages: write | |
| id-token: write # Required for actions/deploy-pages | |
| # Allow only one concurrent deployment. Cancel any in-progress run when a newer one | |
| # starts: every run rediscovers the current releases and rebuilds the whole site from | |
| # scratch, so a newer run fully supersedes the work of the one it cancels. | |
| concurrency: | |
| group: "pages" | |
| cancel-in-progress: true | |
| jobs: | |
| publish-docs: | |
| # Only publish from the modelcontextprotocol/csharp-sdk repository | |
| if: ${{ github.repository == 'modelcontextprotocol/csharp-sdk' }} | |
| environment: | |
| name: github-pages | |
| url: ${{ steps.deployment.outputs.page_url }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout docs orchestration | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| # A release event otherwise checks out the released tag. Keep the | |
| # orchestration scripts and picker assets current with main. | |
| ref: main | |
| # Full history + tags so we can add a worktree for each version's release tag. | |
| fetch-depth: 0 | |
| - name: .NET Setup | |
| uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 | |
| with: | |
| dotnet-version: | | |
| 10.0.x | |
| 9.0.x | |
| - name: Discover versions from GitHub releases | |
| shell: bash | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| # For every major version >= 1, take the most recently published (by date) | |
| # non-draft release tagged v{major}.*. The vN prefix becomes the URL slug; | |
| # the site root redirects to the newest release, including prereleases. | |
| run: | | |
| set -euo pipefail | |
| gh release list --repo "${{ github.repository }}" --limit 200 \ | |
| --json tagName,isPrerelease,isDraft,publishedAt \ | |
| --jq ' | |
| [ .[] | |
| | select((.isDraft | not) and (.tagName | test("^v[1-9][0-9]*\\."))) | |
| | { slug: (.tagName | match("^v[0-9]+").string), | |
| ref: .tagName, label: .tagName, | |
| prerelease: .isPrerelease, published: .publishedAt } | |
| ] | |
| | group_by(.slug) | |
| | map(max_by(.published)) | |
| | sort_by(.published) | reverse | |
| | { default: .[0].slug, | |
| versions: map({ slug, ref, label, prerelease }) } | |
| ' | tee "$RUNNER_TEMP/docs-versions.json" | |
| - name: Build all versions | |
| shell: bash | |
| env: | |
| CONTENT_REF: ${{ inputs.docs_ref }} | |
| run: | | |
| set -euo pipefail | |
| ROOT="$PWD" | |
| COMBINED="$ROOT/combined" | |
| rm -rf "$COMBINED" | |
| mkdir -p "$COMBINED" | |
| # Orchestration (discovered docs-versions.json, scripts, picker assets) | |
| # always comes from THIS branch. Normally each version's HTML is produced | |
| # by its release tag. A manual docs_ref replaces the matching major's | |
| # HTML with content built from that ref, allowing content-only refreshes | |
| # without minting a product release. | |
| git fetch --tags --force origin | |
| CONTENT_REF="${CONTENT_REF:-}" | |
| CONTENT_WORKTREE="" | |
| CONTENT_SLUG="" | |
| if [[ -n "$CONTENT_REF" ]]; then | |
| CONTENT_WORKTREE="$ROOT/../work-content" | |
| git worktree add --force --detach "$CONTENT_WORKTREE" "$CONTENT_REF" | |
| CONTENT_SLUG="$(node "$ROOT/scripts/get-docs-version-slug.mjs" "$CONTENT_WORKTREE/src/Directory.Build.props")" | |
| if ! node "$ROOT/scripts/list-versions.mjs" | cut -f1 | grep -Fxq "$CONTENT_SLUG"; then | |
| echo "::error::The docs ref '$CONTENT_REF' has major '$CONTENT_SLUG', which has no published release." | |
| exit 1 | |
| fi | |
| echo "Refreshing $CONTENT_SLUG docs from $CONTENT_REF" | |
| fi | |
| while IFS=$'\t' read -r slug ref; do | |
| if [[ "$slug" == "$CONTENT_SLUG" ]]; then | |
| echo "::group::Build $slug (from ref $CONTENT_REF)" | |
| wt="$CONTENT_WORKTREE" | |
| else | |
| echo "::group::Build $slug (from tag $ref)" | |
| wt="$ROOT/../work-$slug" | |
| git worktree add --force --detach "$wt" "refs/tags/$ref" | |
| fi | |
| make -C "$wt" generate-docs | |
| mkdir -p "$COMBINED/$slug" | |
| cp -a "$wt/artifacts/_site/." "$COMBINED/$slug/" | |
| node "$ROOT/scripts/inject-version-picker.mjs" "$COMBINED/$slug" "$slug" --base / | |
| if [[ "$wt" != "$CONTENT_WORKTREE" ]]; then | |
| git worktree remove --force "$wt" | |
| fi | |
| echo "::endgroup::" | |
| done < <(node "$ROOT/scripts/list-versions.mjs") | |
| if [[ -n "$CONTENT_WORKTREE" ]]; then | |
| git worktree remove --force "$CONTENT_WORKTREE" | |
| fi | |
| node "$ROOT/scripts/finalize-docs-site.mjs" "$COMBINED" | |
| echo "Combined site contents:" | |
| ls -la "$COMBINED" | |
| - name: Upload Pages artifact | |
| uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0 | |
| with: | |
| path: 'combined' | |
| - name: Deploy to GitHub Pages | |
| id: deployment | |
| uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5.0.0 |