Skip to content

Validate DefaultWorkingDirectory during ProcessKitOptions binding #31

Validate DefaultWorkingDirectory during ProcessKitOptions binding

Validate DefaultWorkingDirectory during ProcessKitOptions binding #31

Workflow file for this run

name: Docs
# Publishes the whole documentation site for this repository to GitHub Pages, as
# a SINGLE combined site made of two halves that live at non-overlapping paths:
#
# /ProcessKit-fSharp/ -> the mdBook GUIDES book (docs/**, theme/**, book.toml)
# /ProcessKit-fSharp/api/ -> the fsdocs API REFERENCE (generated from XML docs)
#
# WHY ONE WORKFLOW (not two): GitHub Pages serves one site per repository, and
# `actions/deploy-pages` publishes a single artifact that REPLACES the entire
# site. Two independent workflows each deploying only their own half would clobber
# the other half on every run. So every run of this one workflow builds BOTH
# halves and deploys their union — neither trigger can wipe the other's output.
#
# TRIGGERS:
# * release: published -> a new release ships; refresh the API reference (and
# rebuild the book from the tag).
# * push to docs/**, theme/**, book.toml -> a guides edit; rebuild the book.
# * workflow_dispatch -> manual rebuild (e.g. after editing this workflow).
#
# API-REFERENCE SOURCE = LATEST PUBLISHED RELEASE (not the pushed commit). The
# reference is generated from the XML doc comments of the two SHIPPING packages
# (ProcessKit, ProcessKit.Extensions.DependencyInjection) and is meant to track
# what a consumer actually installed from NuGet. Building it from the latest
# release tag — even when this run was triggered by an ordinary docs push to main
# — keeps that invariant: the published reference never shows an API surface that
# has not shipped yet. The book, by contrast, is built from the triggering ref so
# guide edits go live immediately on push. (Rebuilding the reference on a docs
# push is deliberately un-optimised: it is cheap insurance against clobbering, and
# docs pushes are infrequent.)
#
# GENERATOR CHOICE: fsdocs (FSharp.Formatting), not docfx. This repository's public
# surface is F#-authored (curried module functions, discriminated unions, `'T`
# generics) and fsdocs renders those natively and readably (e.g.
# `Command.arg value command`, `Result<int, ProcessError>`); docfx's metadata-based
# renderer is built around C# conventions and reads F#-specific shapes awkwardly. A
# C# reader still gets a correct, idiomatic call from the guides in `docs/`
# (linked from `apidocs/index.md`) for the handful of members (the `CommandVerbs`
# extension methods) where the F#-native rendering looks like a static call instead
# of C#'s dot-syntax — documented on the generated front page.
#
# This workflow does not modify ci.yml/release.yml — it is the single, independent
# publishing pipeline scoped to the doc site.
on:
release:
types: [published]
push:
branches: [main]
paths:
- 'docs/**'
- 'theme/**'
- 'book.toml'
- '.github/workflows/docs.yml'
workflow_dispatch:
# Only one Pages deployment may be in flight at a time; never cancel one that is
# already uploading/activating (unlike CI, a half-applied Pages deploy is not a
# safe thing to abandon mid-flight).
concurrency:
group: pages
cancel-in-progress: false
permissions:
contents: read
pages: write
id-token: write
jobs:
build:
runs-on: ubuntu-latest
steps:
# Actions are pinned to a full commit SHA (supply-chain hardening); the
# trailing comment records the human-readable version. Dependabot bumps the
# SHA and updates the comment on its weekly run.
#
# First checkout = the triggering ref (main HEAD on a push, the tag on a
# release). This is what the mdBook GUIDES are built from, so a docs edit
# goes live as soon as it lands.
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
# ── Guides book (mdBook) → site root ────────────────────────────────────
# Pinned to the same mdBook version used by the sibling ProcessKit-rs docs
# workflow so both repositories render their books identically.
- name: Install mdBook
run: |
curl -sSL https://github.com/rust-lang/mdBook/releases/download/v0.4.40/mdbook-v0.4.40-x86_64-unknown-linux-gnu.tar.gz \
| tar -xz -C /usr/local/bin
- name: Build guides (mdBook)
run: mdbook build
# Regression check for theme/custom.css's pinned-title sidebar selector: it
# parses the just-built, CI-pinned-mdBook DOM and asserts the selector
# matches exactly the "Overview" entry (see the K-005 pitfall and
# scripts/check-sidebar-nav.py's own docstring for the underlying mdBook
# v0.4.40 DOM quirk). python3 is preinstalled on this runner image; no
# extra setup step needed.
- name: Check sidebar pinned-title selector
run: python3 scripts/check-sidebar-nav.py book/index.html
# docs/internals/** and docs/planning/** are internal, non-public project
# notes. They are absent from docs/SUMMARY.md so they never appear in the
# book's navigation, but mdBook copies any non-chapter source file to the
# output verbatim — so drop them from the built site to guarantee they are
# not reachable at a guessed URL either.
- name: Prune internal docs from the built book
run: rm -rf book/internals book/planning
# ── API reference (fsdocs) → /api/ subpath, built from the latest release ─
# Resolve which release the reference should reflect: the just-published tag
# on a release event, otherwise the latest published release (so an ordinary
# docs push never surfaces an unreleased API surface).
- name: Resolve the API-reference source (latest published release)
id: apiref
env:
GH_TOKEN: ${{ github.token }}
run: |
if [ "${{ github.event_name }}" = "release" ]; then
tag="${{ github.event.release.tag_name }}"
else
tag="$(gh release view --repo "${{ github.repository }}" --json tagName --jq .tagName)"
fi
echo "Building the API reference from release: $tag"
echo "tag=$tag" >> "$GITHUB_OUTPUT"
# Second checkout, into ./_released, pinned to that release tag. The fsdocs
# build below runs entirely inside this tree so the reference reflects the
# released source, independent of what is on main.
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ steps.apiref.outputs.tag }}
path: _released
- uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0
with:
# Only the SDK band matters here (pinned by global.json) — this workflow
# builds Release assemblies for fsdocs to read, it does not run tests, so
# the net8.0 runtime is not needed the way it is in ci.yml's test job.
dotnet-version: '10.0.x'
- name: Cache NuGet packages
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ~/.nuget/packages
key: ${{ runner.os }}-nuget-${{ hashFiles('_released/Directory.Packages.props', '_released/nuget.config', '_released/global.json') }}
restore-keys: ${{ runner.os }}-nuget-
# Restores fsdocs-tool alongside Fantomas (.config/dotnet-tools.json).
- name: Restore local tools
working-directory: _released
run: dotnet tool restore
- name: Restore
working-directory: _released
run: dotnet restore
# fsdocs reads each project's built DLL + XML doc file. ProcessKit.Extensions.DependencyInjection
# resolves ProcessKit via Reference + AssemblySearchPaths (not ProjectReference,
# per this repo's convention), so ProcessKit must already be built at the same
# Configuration for that path to exist — building the whole solution up front
# (build order comes from ProcessKit.slnx's BuildDependency entries) guarantees it.
- name: Build
working-directory: _released
run: dotnet build ProcessKit.slnx --no-restore --configuration Release
# Resolves the real Pages base URL (e.g. https://zelanton.github.io/ProcessKit-fSharp)
# so generated absolute links/assets are correct without hardcoding it here —
# also works unchanged if a custom domain is ever configured for Pages.
- name: Configure Pages
id: pages
uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0
# --projects scopes the reference to the two shipping packages named in the
# task (ProcessKit, ProcessKit.Extensions.DependencyInjection) — ProcessKit.Testing
# (test doubles, not part of the runtime surface a consumer builds against) and
# the benchmarks project are intentionally excluded.
#
# `root` is the API reference's own base URL — the /api/ SUBPATH of the Pages
# site, since the mdBook guides occupy the root. fsdocs uses it to emit correct
# absolute links/asset URLs for the reference.
#
# --sourcerepo / fsdocs-license-link / fsdocs-release-notes-link override
# fsdocs' own defaults, which point at a `master` branch and a RELEASE_NOTES.md
# file this repo does not have (it uses `main` and CHANGELOG.md instead).
- name: Build API reference (fsdocs)
working-directory: _released
run: >-
dotnet fsdocs build
--input apidocs
--output apidocs/output
--projects src/ProcessKit/ProcessKit.fsproj src/ProcessKit.Extensions.DependencyInjection/ProcessKit.Extensions.DependencyInjection.fsproj
--properties Configuration=Release
--sourcerepo https://github.com/${{ github.repository }}/tree/main
--parameters
root "${{ steps.pages.outputs.base_url }}/api/"
fsdocs-collection-name "ProcessKit API Reference"
fsdocs-license-link "https://github.com/${{ github.repository }}/blob/main/LICENSE"
fsdocs-release-notes-link "https://github.com/${{ github.repository }}/blob/main/CHANGELOG.md"
--clean
# ── Assemble the combined site: book at the root, API reference under /api/ ─
- name: Assemble the combined Pages site
run: |
mkdir -p _site
cp -r book/. _site/
mkdir -p _site/api
cp -r _released/apidocs/output/. _site/api/
- uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0
with:
path: _site
deploy:
needs: build
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- id: deployment
uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5.0.0