name: Build & publish on: push: tags: - "draft*" - "rc*" - "v*" workflow_dispatch: inputs: release_tag: description: "Existing tag to publish, for example draft2026, rc2026, or v2026" required: true type: string permissions: contents: write env: MKDOCS_CONFIG: mkdocs/mkdocs.yml MKDOCS_STRICT: ${{ vars.MKDOCS_STRICT || 'true' }} RELEASE_TAG: ${{ inputs.release_tag || github.ref_name }} jobs: publish: runs-on: ubuntu-latest steps: - name: Checkout (tag) uses: actions/checkout@v4 with: fetch-depth: 0 ref: ${{ inputs.release_tag || github.ref }} - name: Validate release tag run: | set -euo pipefail case "${RELEASE_TAG}" in draft*|rc*|v*) ;; *) echo "::error::Release tag must start with draft, rc, or v. Got '${RELEASE_TAG}'." exit 1 ;; esac if ! git rev-parse --verify --quiet "refs/tags/${RELEASE_TAG}" >/dev/null; then echo "::error::Tag '${RELEASE_TAG}' was not found. Create and push the tag before running this workflow." exit 1 fi echo "RELEASE_COMMIT=$(git rev-list -n 1 "${RELEASE_TAG}")" >> "${GITHUB_ENV}" - name: Setup Python uses: actions/setup-python@v5 with: python-version: "3.11" - name: Install deps run: | set -euo pipefail pip install -r mkdocs/requirements.txt if ! command -v pandoc >/dev/null 2>&1; then sudo apt-get update sudo apt-get install -y pandoc fi - name: Build docs (normal + offline, strict gate) run: | set -euo pipefail REPO_SLUG="${GITHUB_REPOSITORY#*/}" BASE_SITE_URL="https://${GITHUB_REPOSITORY_OWNER}.github.io/${REPO_SLUG}/" MKDOCS_REPO_URL="https://github.com/${GITHUB_REPOSITORY}/tree/${RELEASE_TAG}" MKDOCS_REPO_NAME="${GITHUB_REPOSITORY}" if [[ "${RELEASE_TAG}" == draft* ]]; then MKDOCS_SITE_URL="${BASE_SITE_URL}draft/" elif [[ "${RELEASE_TAG}" == rc* ]]; then MKDOCS_SITE_URL="${BASE_SITE_URL}rc/" else MKDOCS_SITE_URL="${BASE_SITE_URL}" fi export MKDOCS_SITE_URL MKDOCS_REPO_URL MKDOCS_REPO_NAME FLAGS=() if [ "${MKDOCS_STRICT}" = "true" ]; then FLAGS+=(--strict) fi OUT_BASE="${RUNNER_TEMP}/mkdocs_out" SITE="${OUT_BASE}/site" SITE_OFFLINE="${OUT_BASE}/site_offline/${RELEASE_TAG}" rm -rf "${OUT_BASE}" mkdir -p "${SITE}" "${SITE_OFFLINE}" mkdocs build "${FLAGS[@]}" -f "${MKDOCS_CONFIG}" -d "${SITE}" OFFLINE=true mkdocs build "${FLAGS[@]}" -f "${MKDOCS_CONFIG}" -d "${SITE_OFFLINE}" - name: Export docx run: | set -euo pipefail SHORT_SHA="${GITHUB_SHA::7}" OUT_DIR="${RUNNER_TEMP}/pandoc" OUT_FILE="${RELEASE_TAG}-${SHORT_SHA}.docx" echo "SHORT_SHA=`echo ${SHORT_SHA}`" >> $GITHUB_ENV mkdir -p "${OUT_DIR}" # Collect markdown files, excluding README.md and docs/index.md mapfile -t MD_FILES < <( find docs -name '*.md' \ ! -name 'index.md' \ ! -name 'README.md' \ | sort ) echo "Generating ${OUT_FILE}" # Adjust input paths as needed pandoc \ "${MD_FILES[@]}" \ --number-sections \ -o "${OUT_DIR}/${OUT_FILE}" echo "Pandoc output written to ${OUT_DIR}/${OUT_FILE}" - name: Zip offline site run: | set -euo pipefail cd "${RUNNER_TEMP}/mkdocs_out/site_offline/" zip -r "${RELEASE_TAG}.zip" ./${RELEASE_TAG} - name: Prepare release notes run: | set -euo pipefail RELEASE_NOTES="${RUNNER_TEMP}/release-notes.md" if [[ "${RELEASE_TAG}" == draft* || "${RELEASE_TAG}" == rc* ]]; then printf 'Prerelease.\n\n' > "${RELEASE_NOTES}" else : > "${RELEASE_NOTES}" fi cat docs/summary-of-changes.md >> "${RELEASE_NOTES}" - name: Publish prerelease if: startsWith(env.RELEASE_TAG, 'rc') || startsWith(env.RELEASE_TAG, 'draft') uses: ncipollo/release-action@v1 with: allowUpdates: true artifacts: ${{ runner.temp }}/mkdocs_out/site_offline/${{ env.RELEASE_TAG }}.zip,${{ runner.temp }}/pandoc/${{ env.RELEASE_TAG }}-${{ env.SHORT_SHA }}.docx bodyFile: ${{ runner.temp }}/release-notes.md commit: ${{ env.RELEASE_COMMIT }} name: ${{ env.RELEASE_TAG }} prerelease: true replacesArtifacts: true tag: ${{ env.RELEASE_TAG }} token: ${{ secrets.GITHUB_TOKEN }} - name: Publish release if: startsWith(env.RELEASE_TAG, 'v') uses: ncipollo/release-action@v1 with: allowUpdates: true artifacts: ${{ runner.temp }}/mkdocs_out/site_offline/${{ env.RELEASE_TAG }}.zip,${{ runner.temp }}/pandoc/${{ env.RELEASE_TAG }}-${{ env.SHORT_SHA }}.docx bodyFile: ${{ runner.temp }}/release-notes.md commit: ${{ env.RELEASE_COMMIT }} name: ${{ env.RELEASE_TAG }} replacesArtifacts: true tag: ${{ env.RELEASE_TAG }} token: ${{ secrets.GITHUB_TOKEN }} - name: Checkout gh-pages branch uses: actions/checkout@v4 with: ref: gh-pages fetch-depth: 0 - name: Deploy release to gh-pages root if: startsWith(env.RELEASE_TAG, 'v') run: | set -euo pipefail rm -rf ./* cp -a ${RUNNER_TEMP}/mkdocs_out/site/. . git add -A git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" git commit -m "Deploy release ${RELEASE_TAG}" || echo "No changes to commit" git push origin gh-pages - name: Deploy RC preview to /rc/ if: startsWith(env.RELEASE_TAG, 'rc') run: | set -euo pipefail rm -rf rc draft mkdir -p rc cp -a ${RUNNER_TEMP}/mkdocs_out/site/. rc/ printf '{"tag":"%s"}\n' "${RELEASE_TAG}" > rc/rc.json git add -A git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" git commit -m "Deploy RC preview ${RELEASE_TAG}" || echo "No changes to commit" git push origin gh-pages - name: Deploy draft preview to /draft/ if: startsWith(env.RELEASE_TAG, 'draft') run: | set -euo pipefail rm -rf rc draft mkdir -p draft cp -a ${RUNNER_TEMP}/mkdocs_out/site/. draft/ printf '{"tag":"%s"}\n' "${RELEASE_TAG}" > draft/draft.json git add -A git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" git commit -m "Deploy draft preview ${RELEASE_TAG}" || echo "No changes to commit" git push origin gh-pages