Add docs source selector for manual publishes (#1828)
Copilot-Session: 155ceb73-c05f-4eb6-9968-f5bbf90ed6d0
This commit is contained in:
parent
20cdd493a4
commit
609499b298
3 changed files with 68 additions and 45 deletions
5
.github/release-process.md
vendored
5
.github/release-process.md
vendored
|
|
@ -49,4 +49,7 @@ monitor both and confirm their published outputs:
|
|||
published release tags and deploys it to
|
||||
[csharp.sdk.modelcontextprotocol.io](https://csharp.sdk.modelcontextprotocol.io). Verify the new
|
||||
version appears in the version picker and that its major-version path serves the updated content.
|
||||
A content-only docs refresh can be run later via manual dispatch with the `docs_ref` input.
|
||||
A content-only docs refresh can be run later via manual dispatch. Its `docs_source` input defaults
|
||||
to `release-tags` to mirror a release deployment; select `latest-branches` to refresh every
|
||||
published major from its current `release/{MAJOR}.x` branch, using `main` for its
|
||||
matching major.
|
||||
|
|
|
|||
29
.github/skills/verify-release/SKILL.md
vendored
29
.github/skills/verify-release/SKILL.md
vendored
|
|
@ -103,11 +103,14 @@ Report the run's conclusion, accounting for these docs-specific behaviors:
|
|||
- **Version discovery reads published releases.** For each major version >= 1, the workflow takes
|
||||
the most recently published non-draft release tagged `v{MAJOR}.*`. A draft release contributes
|
||||
nothing.
|
||||
- **Every major is rebuilt.** Each major's docs are built from that major's latest release tag into
|
||||
its own path (`/v1/`, `/v2/`). A new MAJOR adds a new path; the site root redirects to the newest
|
||||
release, prereleases included.
|
||||
- **Every major is rebuilt.** A release-triggered run builds each major from its latest release tag
|
||||
into its own path (`/v1/`, `/v2/`). A manual dispatch defaults to the same release-tag content,
|
||||
or can build every major from `release/{MAJOR}.x`, using `main` for its matching major,
|
||||
by selecting `docs_source=latest-branches`. A new MAJOR adds a new path; the site root redirects
|
||||
to the newest release, prereleases included.
|
||||
- **Orchestration comes from `main`.** The scripts and picker assets are always checked out from
|
||||
`main`, while each version's content comes from its release tag. A docs fix that lives only in a
|
||||
`main`. Release-triggered and default manual runs use release-tag content; a manual
|
||||
`docs_source=latest-branches` run uses source-branch content. A docs fix that lives only in a
|
||||
release branch will not affect orchestration.
|
||||
|
||||
If it failed, summarize the failing step. Common causes are a docs build failure in one version's
|
||||
|
|
@ -164,17 +167,21 @@ Both remediations require explicit user confirmation.
|
|||
gh run rerun {run-id} --failed
|
||||
```
|
||||
|
||||
**Refresh the docs without a new release** — when documentation content needs correcting after the
|
||||
release, the docs workflow accepts a manual dispatch that rebuilds one major version's content from
|
||||
an arbitrary ref, without minting a product release:
|
||||
**Rebuild the released docs** — use the default `release-tags` source to retry a failed Pages
|
||||
deployment after a release, without minting a product release:
|
||||
|
||||
```
|
||||
gh workflow run docs.yml --field docs_ref={branch-tag-or-commit}
|
||||
gh workflow run docs.yml --field docs_source=release-tags
|
||||
```
|
||||
|
||||
The ref's major version, read from `src/Directory.Build.props`, must have a published release; the
|
||||
workflow fails fast if it does not. This replaces only the matching major's HTML — orchestration
|
||||
and all other versions are unaffected.
|
||||
**Refresh docs without a new release** — select `latest-branches` to rebuild every published major
|
||||
from its current source branch (`release/{MAJOR}.x`, using `main` for its matching major):
|
||||
|
||||
```
|
||||
gh workflow run docs.yml --field docs_source=latest-branches
|
||||
```
|
||||
|
||||
The workflow fails instead of silently using a release tag when any major has no matching branch.
|
||||
|
||||
## Edge Cases
|
||||
|
||||
|
|
|
|||
79
.github/workflows/docs.yml
vendored
79
.github/workflows/docs.yml
vendored
|
|
@ -6,8 +6,8 @@ name: Publish Docs
|
|||
# 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.
|
||||
# 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:
|
||||
|
|
@ -15,10 +15,14 @@ on:
|
|||
types: [published]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
docs_ref:
|
||||
description: Branch, tag, or commit whose docs should refresh its matching major version
|
||||
required: false
|
||||
type: string
|
||||
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:
|
||||
|
|
@ -86,7 +90,7 @@ jobs:
|
|||
- name: Build all versions
|
||||
shell: bash
|
||||
env:
|
||||
CONTENT_REF: ${{ inputs.docs_ref }}
|
||||
USE_SOURCE_BRANCHES: ${{ inputs.docs_source == 'latest-branches' }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
ROOT="$PWD"
|
||||
|
|
@ -96,28 +100,43 @@ jobs:
|
|||
|
||||
# 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"
|
||||
# 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 [[ "$slug" == "$CONTENT_SLUG" ]]; then
|
||||
echo "::group::Build $slug (from ref $CONTENT_REF)"
|
||||
wt="$CONTENT_WORKTREE"
|
||||
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"
|
||||
|
|
@ -130,16 +149,10 @@ jobs:
|
|||
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
|
||||
git worktree remove --force "$wt"
|
||||
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:"
|
||||
|
|
|
|||
Loading…
Reference in a new issue