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 build every # major-version path from release tags or current source branches. # Triggers on release publish and manual dispatch. on: release: types: [published] workflow_dispatch: inputs: docs_source: description: Source for every published major-version path required: true default: release-tags type: choice options: - release-tags - latest-branches # 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: USE_SOURCE_BRANCHES: ${{ inputs.docs_source == 'latest-branches' }} 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 dispatch can instead build every major from # its current source branch. git fetch --tags --force --prune origin "+refs/heads/*:refs/remotes/origin/*" USE_SOURCE_BRANCHES="${USE_SOURCE_BRANCHES:-false}" MAIN_SLUG="" if [[ "$USE_SOURCE_BRANCHES" == "true" ]]; then MAIN_PROPS="$(mktemp)" git show refs/remotes/origin/main:src/Directory.Build.props > "$MAIN_PROPS" MAIN_SLUG="$(node "$ROOT/scripts/get-docs-version-slug.mjs" "$MAIN_PROPS")" rm -f "$MAIN_PROPS" echo "Refreshing all published docs from source branches (main serves $MAIN_SLUG)" else echo "Refreshing all published docs from release tags" fi while IFS=$'\t' read -r slug ref; do if [[ "$USE_SOURCE_BRANCHES" == "true" ]]; then source_branch="release/${slug#v}.x" if ! git show-ref --verify --quiet "refs/remotes/origin/$source_branch"; then if [[ "$slug" == "$MAIN_SLUG" ]]; then source_branch="main" else echo "::error::No source branch found for $slug. Expected release/${slug#v}.x, or main with VersionPrefix for $slug." exit 1 fi fi echo "::group::Build $slug (from branch $source_branch)" wt="$ROOT/../work-$slug" git worktree add --force --detach "$wt" "refs/remotes/origin/$source_branch" source_slug="$(node "$ROOT/scripts/get-docs-version-slug.mjs" "$wt/src/Directory.Build.props")" if [[ "$source_slug" != "$slug" ]]; then git worktree remove --force "$wt" echo "::error::Source branch '$source_branch' has major '$source_slug', not '$slug'." exit 1 fi 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 / git worktree remove --force "$wt" echo "::endgroup::" done < <(node "$ROOT/scripts/list-versions.mjs") 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