Skip to content

Commit 9fedf2f

Browse files
author
hannahwestra25
committed
Merge branch 'main' of https://github.com/microsoft/PyRIT into hawestra/text_adaptive_scenario
2 parents 8e96798 + a6c3fb0 commit 9fedf2f

120 files changed

Lines changed: 5840 additions & 1259 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/docs-versions.yml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Versions exposed on the PyRIT documentation site.
2+
#
3+
# This file is the single source of truth consumed by:
4+
# * .github/workflows/docs.yml - builds each version listed below
5+
# * the version picker injected into every doc page
6+
# * doc/contributing/10_release_process.md - tells the releaser to edit this file
7+
#
8+
# To add a new release version: append an entry under `versions:`, and update
9+
# `default:` / `stable:` if the new release should become the landing page.
10+
11+
default: "0.13.0" # served at the site root (microsoft.github.io/PyRIT/)
12+
stable: "0.13.0" # served at /stable/ and shown as "(stable)" in the picker
13+
14+
versions:
15+
- slug: latest
16+
name: "latest (dev, main)"
17+
ref: main
18+
- slug: "0.13.0"
19+
name: "0.13.0"
20+
ref: releases/v0.13.0
21+
- slug: "0.12.1"
22+
name: "0.12.1"
23+
ref: releases/v0.12.1

.github/workflows/docs.yml

Lines changed: 235 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -3,82 +3,255 @@ name: build-book
33
on:
44
push:
55
branches:
6-
- "main"
6+
- main
7+
- "releases/v*"
8+
paths-ignore:
9+
- "**/*.md"
10+
- ".github/ISSUE_TEMPLATE/**"
711
pull_request:
812
branches:
9-
- "main"
10-
- "release/**"
13+
- main
14+
- "releases/**"
15+
paths:
16+
- ".github/workflows/docs.yml"
17+
- ".github/docs-versions.yml"
18+
- "build_scripts/inject_version_picker.py"
19+
- "build_scripts/version_picker_assets/**"
20+
- "doc/**"
21+
- "build_scripts/pydoc2json.py"
22+
- "build_scripts/gen_api_md.py"
23+
- "pyrit/**"
1124
workflow_dispatch:
1225

13-
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
26+
# Permissions for the GH Pages deployment.
1427
permissions:
1528
contents: read
1629
pages: write
1730
id-token: write
1831

19-
# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
20-
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
32+
# One deploy at a time. Don't cancel in-progress production deploys.
2133
concurrency:
22-
group: "pages"
34+
group: pages
2335
cancel-in-progress: false
2436

2537
env:
26-
# BASE_URL determines the website path prefix, including CSS & JS assets
27-
BASE_URL: /${{ github.event.repository.name }}
38+
# All versioned URLs live under /<repo-name>/<slug>/, e.g. /PyRIT/0.13.0/.
39+
DOCS_BASE: /${{ github.event.repository.name }}
40+
# Manual cache-bust knob. Bump this when the build pipeline changes in a
41+
# way that affects the rendered HTML output but isn't captured by the
42+
# source-ref SHA -- e.g. bumping python-version, uv version, or changing
43+
# build flags in the steps below. Forgetting to bump is harmless (you
44+
# just serve a stale cached build for one push); bumping unnecessarily
45+
# is also harmless (one extra rebuild).
46+
CACHE_VERSION: "v1"
2847

29-
# This job installs dependencies, builds the book, and pushes it to `gh-pages`
3048
jobs:
31-
deploy-book:
49+
# ------------------------------------------------------------------
50+
# 1. Read .github/docs-versions.yml and turn it into a build matrix.
51+
# ------------------------------------------------------------------
52+
versions:
53+
name: Resolve version matrix
3254
runs-on: ubuntu-latest
33-
permissions:
34-
pages: write
35-
id-token: write
55+
outputs:
56+
matrix: ${{ steps.matrix.outputs.matrix }}
57+
default: ${{ steps.matrix.outputs.default }}
58+
stable: ${{ steps.matrix.outputs.stable }}
59+
versions_json: ${{ steps.matrix.outputs.versions_json }}
3660
steps:
37-
- uses: actions/checkout@v6
38-
39-
# Install dependencies
40-
- name: Set up Python 3.11
41-
uses: actions/setup-python@v6
42-
with:
43-
python-version: 3.11
44-
45-
- name: Install uv
46-
uses: astral-sh/setup-uv@v7
47-
with:
48-
# Install a specific version of uv.
49-
version: "0.9.17"
50-
enable-cache: true
51-
cache-dependency-glob: |
52-
**/pyproject.toml
53-
**/uv.lock
54-
55-
- name: Install PyRIT with uv
56-
run: uv sync --extra all
57-
58-
# LaTeX toolchain needed for the PDF export (jupyter-book --pdf via xelatex).
59-
# Mirrors the ReadTheDocs build so CI catches PDF-only issues (e.g. broken
60-
# image paths) instead of letting them silently break the RTD build.
61-
- name: Install LaTeX (for PDF export)
62-
run: |
63-
sudo apt-get update
64-
sudo apt-get install -y --no-install-recommends \
65-
texlive-xetex \
66-
texlive-fonts-recommended \
67-
texlive-fonts-extra \
68-
texlive-plain-generic \
69-
texlive-latex-extra \
70-
latexmk
71-
72-
# Build the book (HTML site + PDF export)
73-
- name: Build the book
74-
run: |
75-
make docs-build-all
76-
# Upload the book's HTML as an artifact
77-
- name: Upload artifact
78-
uses: actions/upload-pages-artifact@v5
79-
with:
80-
path: "doc/_build/html"
81-
- name: Deploy to GitHub Pages
82-
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
83-
id: deployment
84-
uses: actions/deploy-pages@v5
61+
- uses: actions/checkout@v6
62+
with:
63+
sparse-checkout: |
64+
.github/docs-versions.yml
65+
build_scripts/resolve_docs_matrix.py
66+
sparse-checkout-cone-mode: false
67+
68+
- name: Set up Python 3.13
69+
uses: actions/setup-python@v6
70+
with:
71+
python-version: "3.13"
72+
73+
- name: Install PyYAML
74+
run: pip install --quiet "pyyaml>=6.0"
75+
76+
- name: Compute matrix
77+
id: matrix
78+
run: |
79+
python build_scripts/resolve_docs_matrix.py \
80+
--config .github/docs-versions.yml \
81+
--github-output "$GITHUB_OUTPUT"
82+
83+
# ------------------------------------------------------------------
84+
# 2. Build each version in parallel.
85+
# ------------------------------------------------------------------
86+
build:
87+
name: Build ${{ matrix.slug }}
88+
needs: versions
89+
runs-on: ubuntu-latest
90+
strategy:
91+
fail-fast: false
92+
matrix: ${{ fromJson(needs.versions.outputs.matrix) }}
93+
env:
94+
BASE_URL: ${{ format('/{0}/{1}', github.event.repository.name, matrix.slug) }}
95+
steps:
96+
- name: Checkout ${{ matrix.ref }}
97+
uses: actions/checkout@v6
98+
with:
99+
ref: ${{ matrix.ref }}
100+
101+
- name: Resolve commit SHA
102+
# matrix.ref is a branch name (e.g. "releases/v0.13.0") that can move,
103+
# so resolve to the actual commit SHA we just checked out. This is the
104+
# primary cache key component: frozen release branches that don't move
105+
# produce identical SHAs and hit the cache forever; main produces a
106+
# new SHA on every push so it always rebuilds.
107+
id: sha
108+
run: echo "sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
109+
110+
- name: Restore built site from cache
111+
# Cache hit -> we skip the entire install + build pipeline and just
112+
# upload the restored doc/_build/html as the matrix artifact. Cache
113+
# miss -> we do a fresh build and actions/cache saves the result on
114+
# job success, so the next run with the same SHA hits.
115+
id: cache
116+
uses: actions/cache@v4
117+
with:
118+
path: doc/_build/html
119+
key: docs-${{ env.CACHE_VERSION }}-${{ matrix.slug }}-${{ steps.sha.outputs.sha }}
120+
121+
- name: Set up Python 3.13
122+
if: steps.cache.outputs.cache-hit != 'true'
123+
uses: actions/setup-python@v6
124+
with:
125+
python-version: "3.13"
126+
127+
- name: Install uv
128+
if: steps.cache.outputs.cache-hit != 'true'
129+
uses: astral-sh/setup-uv@v7
130+
with:
131+
version: "0.9.17"
132+
enable-cache: true
133+
cache-dependency-glob: |
134+
**/pyproject.toml
135+
**/uv.lock
136+
137+
- name: Install PyRIT with dev dependencies
138+
if: steps.cache.outputs.cache-hit != 'true'
139+
# Use `uv sync --frozen` so each release branch installs the exact
140+
# versions pinned in its own uv.lock. Frozen branch = frozen deps =
141+
# bit-for-bit reproducible rebuild forever.
142+
#
143+
# Newer release branches (incl. main) use PEP 735 [dependency-groups];
144+
# older releases use legacy [project.optional-dependencies]. We pick
145+
# the right flag up front by reading pyproject.toml (via stdlib
146+
# tomllib) so any uv sync failure surfaces normally instead of being
147+
# swallowed by `|| fallback` with stderr redirected to /dev/null.
148+
run: |
149+
set -euo pipefail
150+
choice=$(python -c "
151+
import sys, tomllib
152+
d = tomllib.loads(open('pyproject.toml').read())
153+
if 'dev' in (d.get('dependency-groups') or {}):
154+
print('--group dev')
155+
elif 'dev' in (d.get('project', {}).get('optional-dependencies') or {}):
156+
print('--extra dev')
157+
else:
158+
print('error: no dev group/extra in pyproject.toml', file=sys.stderr); sys.exit(1)
159+
")
160+
echo "Installing with: uv sync --frozen $choice"
161+
uv sync --frozen $choice
162+
163+
- name: Generate API reference (pydoc2json + gen_api_md)
164+
if: steps.cache.outputs.cache-hit != 'true'
165+
run: |
166+
source .venv/bin/activate
167+
python build_scripts/pydoc2json.py pyrit --submodules -o doc/_api/pyrit_all.json
168+
python build_scripts/gen_api_md.py
169+
170+
- name: Build the static HTML site
171+
if: steps.cache.outputs.cache-hit != 'true'
172+
# --all builds frontmatter exports (PDF, per doc/myst.yml).
173+
# --html is required to produce the static HTML site we deploy.
174+
# NOT using --strict because older release branches have known
175+
# warnings (e.g. unresolved cross-refs) that aren't worth fixing
176+
# retroactively just to satisfy strict mode.
177+
working-directory: doc
178+
run: |
179+
source ../.venv/bin/activate
180+
jupyter-book build --all --html
181+
182+
- name: Upload built site
183+
uses: actions/upload-artifact@v4
184+
with:
185+
name: site-${{ matrix.slug }}
186+
path: doc/_build/html
187+
retention-days: 7
188+
if-no-files-found: error
189+
190+
# ------------------------------------------------------------------
191+
# 3. Compose dist/, inject picker, deploy to GH Pages.
192+
# ------------------------------------------------------------------
193+
deploy:
194+
name: Deploy
195+
needs: [versions, build]
196+
runs-on: ubuntu-latest
197+
# Deploy on push to main, or when triggered manually from main. Skipped
198+
# for pushes to release branches (those builds are validation-only) and
199+
# for pull requests.
200+
if: >-
201+
${{ github.ref == 'refs/heads/main' &&
202+
(github.event_name == 'push' || github.event_name == 'workflow_dispatch') }}
203+
environment:
204+
name: github-pages
205+
url: ${{ steps.deployment.outputs.page_url }}
206+
steps:
207+
- uses: actions/checkout@v6
208+
with:
209+
sparse-checkout: |
210+
.github/docs-versions.yml
211+
build_scripts/inject_version_picker.py
212+
build_scripts/version_picker_assets
213+
build_scripts/generate_pages_manifest.py
214+
build_scripts/compose_docs_dist.py
215+
sparse-checkout-cone-mode: false
216+
217+
- name: Set up Python 3.13
218+
uses: actions/setup-python@v6
219+
with:
220+
python-version: "3.13"
221+
222+
- name: Install PyYAML
223+
run: pip install --quiet "pyyaml>=6.0"
224+
225+
- name: Download all version artifacts
226+
uses: actions/download-artifact@v4
227+
with:
228+
path: artifacts
229+
pattern: site-*
230+
231+
- name: Compose dist/
232+
# Compose script does everything: stage artifacts into dist/<slug>/,
233+
# write per-version pages.json manifests, write top-level versions.json,
234+
# write the root + /stable/ redirects, and write 404.html (with the
235+
# auto-redirect script that uses the manifest to find the closest
236+
# sibling page in the same version).
237+
run: |
238+
python build_scripts/compose_docs_dist.py \
239+
--artifacts-dir artifacts \
240+
--dist-dir dist \
241+
--config .github/docs-versions.yml \
242+
--base "${DOCS_BASE}"
243+
244+
- name: Inject version picker
245+
run: |
246+
python build_scripts/inject_version_picker.py \
247+
--site-dir dist \
248+
--base "${DOCS_BASE}"
249+
250+
- name: Upload Pages artifact
251+
uses: actions/upload-pages-artifact@v5
252+
with:
253+
path: dist
254+
255+
- name: Deploy to GitHub Pages
256+
id: deployment
257+
uses: actions/deploy-pages@v5

.readthedocs.yaml

Lines changed: 0 additions & 26 deletions
This file was deleted.

0 commit comments

Comments
 (0)