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
151 changes: 151 additions & 0 deletions .github/workflows/create_docs_version_pr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
name: Create Documentation Version PR

on:
push:
tags:
- 'v*.*.*'
workflow_dispatch:
inputs:
release:
description: 'Release tag or docs version to snapshot (for example v1.1.0, 1.1.2, 1.1.0, or 1.1). Prerelease values are skipped.'
required: true
type: string

permissions:
contents: write
pull-requests: write

concurrency:
group: docs-version-${{ github.event_name == 'workflow_dispatch' && inputs.release || github.ref_name }}
cancel-in-progress: false

jobs:
create-version-pr:
runs-on: ubuntu-latest
env:
DOCS_VERSION_PR_TOKEN: ${{ secrets.DOCS_VERSION_PR_TOKEN || github.token }}
GH_TOKEN: ${{ secrets.DOCS_VERSION_PR_TOKEN || github.token }}
steps:
- name: Resolve docs version
id: resolve
shell: bash
run: |
if [[ "${GITHUB_EVENT_NAME}" == "workflow_dispatch" ]]; then
RELEASE="${{ inputs.release }}"
else
RELEASE="${GITHUB_REF_NAME}"
fi

SHOULD_EVALUATE=false
SKIP_REASON=

if [[ "${RELEASE}" == *-* ]]; then
SKIP_REASON="Skipping docs version PR for prerelease '${RELEASE}'."
elif [[ "${RELEASE}" =~ ^v?([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then
DOC_VERSION="${BASH_REMATCH[1]}.${BASH_REMATCH[2]}"
SOURCE_REF="refs/tags/v${BASH_REMATCH[1]}.${BASH_REMATCH[2]}.${BASH_REMATCH[3]}"
SHOULD_EVALUATE=true
elif [[ "${RELEASE}" =~ ^([0-9]+)\.([0-9]+)$ ]]; then
DOC_VERSION="${BASH_REMATCH[1]}.${BASH_REMATCH[2]}"
SOURCE_REF="refs/tags/v${BASH_REMATCH[1]}.${BASH_REMATCH[2]}.0"
SHOULD_EVALUATE=true
else
SKIP_REASON="Skipping docs version PR for unsupported release input '${RELEASE}'. Use vX.Y.Z, X.Y.0, or X.Y."
fi

if [[ "${SHOULD_EVALUATE}" == "true" ]]; then
BRANCH_NAME="docs/version-${DOC_VERSION}"
fi

{
echo "should_evaluate=${SHOULD_EVALUATE}"
echo "doc_version=${DOC_VERSION}"
echo "branch_name=${BRANCH_NAME}"
echo "source_ref=${SOURCE_REF}"
echo "skip_reason=${SKIP_REASON}"
} >> "$GITHUB_OUTPUT"

- name: Report skipped docs version
if: steps.resolve.outputs.should_evaluate != 'true'
run: echo "${{ steps.resolve.outputs.skip_reason }}"

- name: Checkout release source
if: steps.resolve.outputs.should_evaluate == 'true'
uses: actions/checkout@v6
with:
ref: ${{ steps.resolve.outputs.source_ref }}
fetch-depth: 0
token: ${{ env.DOCS_VERSION_PR_TOKEN }}

- name: Setup Node.js
if: steps.resolve.outputs.should_evaluate == 'true'
uses: actions/setup-node@v6
with:
node-version: 20
cache: npm
cache-dependency-path: src/CrestApps.Core.Docs/package-lock.json

- name: Install dependencies
if: steps.resolve.outputs.should_evaluate == 'true'
working-directory: src/CrestApps.Core.Docs
run: npm ci

- name: Create versioned docs snapshot
if: steps.resolve.outputs.should_evaluate == 'true'
id: snapshot
working-directory: src/CrestApps.Core.Docs
shell: bash
run: |
DOC_VERSION="${{ steps.resolve.outputs.doc_version }}"

if [[ -f versions.json ]] && grep -q "\"${DOC_VERSION}\"" versions.json; then
echo "Docs version ${DOC_VERSION} already exists; no PR is needed."
echo "created=false" >> "$GITHUB_OUTPUT"
exit 0
fi

npx docusaurus docs:version "${DOC_VERSION}"
npm run build
echo "created=true" >> "$GITHUB_OUTPUT"

- name: Commit versioned docs
if: steps.snapshot.outputs.created == 'true'
shell: bash
run: |
DOC_VERSION="${{ steps.resolve.outputs.doc_version }}"
BRANCH_NAME="${{ steps.resolve.outputs.branch_name }}"

git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git checkout -B "${BRANCH_NAME}"
git add \
src/CrestApps.Core.Docs/versioned_docs \
src/CrestApps.Core.Docs/versioned_sidebars \
src/CrestApps.Core.Docs/versions.json

if git diff --cached --quiet; then
echo "No versioned docs changes to commit."
exit 0
fi

git commit -m "Add docs version ${DOC_VERSION}"
git push --force-with-lease origin "${BRANCH_NAME}"

- name: Open pull request
if: steps.snapshot.outputs.created == 'true'
shell: bash
run: |
DOC_VERSION="${{ steps.resolve.outputs.doc_version }}"
BRANCH_NAME="${{ steps.resolve.outputs.branch_name }}"
EXISTING_PR="$(gh pr list --base main --head "${BRANCH_NAME}" --state open --json number --jq '.[0].number // ""')"

if [[ -n "${EXISTING_PR}" ]]; then
echo "Pull request #${EXISTING_PR} already exists for ${BRANCH_NAME}."
exit 0
fi

gh pr create \
--base main \
--head "${BRANCH_NAME}" \
--title "Add docs version ${DOC_VERSION}" \
--body "Snapshots the current documentation as version ${DOC_VERSION}. Merging this PR publishes the versioned docs through the normal main-branch Pages deployment."
58 changes: 1 addition & 57 deletions .github/workflows/deploy_docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ on:
push:
branches:
- main
tags:
- 'v*.*.*'
workflow_dispatch:

permissions:
Expand All @@ -18,49 +16,7 @@ concurrency:
cancel-in-progress: false

jobs:
prepare:
runs-on: ubuntu-latest
outputs:
should_deploy: ${{ steps.evaluate.outputs.should_deploy }}
doc_version: ${{ steps.evaluate.outputs.doc_version }}
skip_reason: ${{ steps.evaluate.outputs.skip_reason }}
steps:
- name: Evaluate deployment target
id: evaluate
shell: bash
run: |
should_deploy=false
doc_version=
skip_reason=

if [[ "${GITHUB_EVENT_NAME}" == "workflow_dispatch" || "${GITHUB_REF}" == "refs/heads/main" ]]; then
should_deploy=true
elif [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then
if [[ "${GITHUB_REF_NAME}" == *-* ]]; then
skip_reason="Skipping documentation deployment for prerelease tag ${GITHUB_REF_NAME}."
elif [[ "${GITHUB_REF_NAME}" =~ ^v([0-9]+)\.([0-9]+)\.0$ ]]; then
should_deploy=true
doc_version="${BASH_REMATCH[1]}.${BASH_REMATCH[2]}"
else
skip_reason="Skipping documentation deployment for patch tag ${GITHUB_REF_NAME}."
fi
else
skip_reason="Skipping documentation deployment for ref ${GITHUB_REF}."
fi

{
echo "should_deploy=${should_deploy}"
echo "doc_version=${doc_version}"
echo "skip_reason=${skip_reason}"
} >> "$GITHUB_OUTPUT"

- name: Report skipped deployment
if: steps.evaluate.outputs.should_deploy != 'true'
run: echo "${{ steps.evaluate.outputs.skip_reason }}"

build:
needs: prepare
if: needs.prepare.outputs.should_deploy == 'true'
runs-on: ubuntu-latest
defaults:
run:
Expand All @@ -82,17 +38,6 @@ jobs:
- name: Install dependencies
run: npm ci

- name: Create versioned docs on qualifying tag push
if: needs.prepare.outputs.doc_version != ''
run: |
DOC_VERSION="${{ needs.prepare.outputs.doc_version }}"
if [[ -f versions.json ]] && grep -q "\"${DOC_VERSION}\"" versions.json; then
echo "Docs version ${DOC_VERSION} already exists; skipping snapshot creation."
else
echo "Creating docs version ${DOC_VERSION}"
npx docusaurus docs:version "${DOC_VERSION}"
fi

- name: Build site
run: npm run build

Expand All @@ -107,12 +52,11 @@ jobs:
path: src/CrestApps.Core.Docs/build

deploy:
if: needs.prepare.outputs.should_deploy == 'true'
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: [prepare, build]
needs: build
steps:
- name: Deploy to GitHub Pages
id: deployment
Expand Down
21 changes: 15 additions & 6 deletions src/CrestApps.Core.Docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,18 @@ continues to evolve. The unversioned `docs/` folder is the **Latest** version an
tracks `main`. Each released version is frozen under `versioned_docs/` and
`versioned_sidebars/`, with the list of published versions in `versions.json`.

Versions are created automatically on qualifying tag pushes (`vX.Y.0`) by the
`deploy_docs.yml` GitHub Actions workflow, which snapshots the current docs as
`X.Y` (for example, `v1.0.0` produces the `1.0` version, served under `/docs/1.0/`).
Versions are proposed automatically on stable `vX.Y.Z` tag pushes by the
`create_docs_version_pr.yml` GitHub Actions workflow, which opens a pull request
that snapshots the current docs as `X.Y` (for example, `v1.0.0` produces the `1.0`
version, served under `/docs/1.0/`). Patch tags create the `X.Y` docs version only
when that version does not already exist; otherwise they are logged and skipped
successfully. Prerelease tags are also skipped successfully. The workflow can be
run manually with a `vX.Y.Z`, `X.Y.0`, or `X.Y` input; two-part `X.Y` inputs
snapshot the matching `vX.Y.0` tag. If branch protection requires PR checks,
configure a `DOCS_VERSION_PR_TOKEN` repository secret backed by a GitHub App token
or fine-grained personal access token with contents and pull-request write access
so the generated branch and PR can trigger the normal validation workflows;
otherwise the workflow falls back to `GITHUB_TOKEN`.
To cut a version manually:

```bash
Expand All @@ -42,6 +51,6 @@ so the frozen version persists across future deployments.
## Deployment

The site is deployed automatically to GitHub Pages via the `deploy_docs.yml`
workflow on every push to `main`, on `vX.Y.0` release tag pushes, and on manual
`workflow_dispatch` runs. Prerelease tags (for example `v1.0.0-rc.1`) and patch
tags (for example `v1.0.1`) are intentionally skipped.
workflow on every push to `main` and on manual `workflow_dispatch` runs. Release
tags create documentation-version pull requests instead of deploying directly, so
branch and environment protection rules stay enforced.
8 changes: 7 additions & 1 deletion src/CrestApps.Core.Docs/docs/changelog/1.3.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,10 @@ and preview builds are published from `main` under the `1.3.0` version prefix.

## Change Logs

- None yet.
- changes release documentation versioning so stable `vX.Y.Z` tag pushes create a pull
request with the generated Docusaurus version files instead of generating
versioned docs inside the Pages deployment artifact; the workflow also supports
manual runs for `vX.Y.Z`, `X.Y.0`, or `X.Y` inputs, creates the `X.Y` docs version
from patch tags only when that major/minor docs version does not already exist,
and skips prerelease tags successfully after logging why no docs version PR was
needed
Loading
Loading