From 67603f790fc5757775a81323a215015bd250dc10 Mon Sep 17 00:00:00 2001 From: August L-R Date: Mon, 29 Jun 2026 12:30:39 +0000 Subject: [PATCH 01/16] fix (reference): add favicon --- reference/assets/img/signalwire-favicon.png | Bin 89743 -> 4187 bytes reference/mkdocs.yml | 1 + 2 files changed, 1 insertion(+) diff --git a/reference/assets/img/signalwire-favicon.png b/reference/assets/img/signalwire-favicon.png index 4b8ff9921f2b0d6f6a360f28b038d1fb4cdba6dd..ac64199f042d034bda48fe971fb4195536a9f29b 100644 GIT binary patch literal 4187 zcmV-h5Tx&kP)fP6mrcvmw+x?bX=OE{Bqs@&{pwdGlv0YMRc({WBS-{DS|UKw5&@Ey2#~ZyfTSe?BrOpjX^8+ytBz(@;+F~) zsQfP>^e-tA*cC585Ej9123#pEhL!YrJ2X)#xqu*Sg8RW|AsaqX)Hf))cNTo_JAwoE zkp&Szi;}bo=mC@hg@*rMZwAbH#N(B>0~#6>gnE`!+evU#AIa3y9LAqy7ye!%L7Dde z(Ks(9{M+wcZdmGq0;@(~=X(PM1OWs&1sT&&(hIA$OWCBw=7V!N1`49P^*_sM$*phWc%9ZnVnJ z5j-Didka>+=yT^Y9#U#qk{+Op;V*jHBhy3R?~esA-mN(nFE{t*hYFMfrwz1{A)wme+ZMQW zijxP}4C-$YhSi-QlGOxXN^o81(nWChlvFYSC^Z41#7WHY3BRV`Ez0RfYdl?4|)bR`?3exiQOQe>4j}@Il4} zKdK^aUS%5nxfB&8gYmk6_JD6Gczi|-iJhR??vSj9YRDl{HgwMH_$4c(-rP1l=8OFE z85<+~CuU|iZJ=TJ`Py-{X&b>)YYAW3fcof5RD+9fEX01jkV6i`9yeIa5LCuiB4a&3 z)I$P{o0H`a&zXmBD|lj7hT#KD!`C}Qf``}O-Leez*%pLjL(0}~x>Dc;sH}(VyD!eo z6OjY@fFDw*LalZIq8H-w1uk=!xYX=r5WWYtfG1~WICVe_Z@v`xcdf$v%@c@jwUBn2 zju|PgCb1;cWg%sgns*`cU;0z-n+uEx5W#=-e*=#HWh3cYK@ggO?|YCE@YKI&74bNsi#BB|LMj zhHpI1mje6%@78A#X{Tud^G(t?dg|m}G@tOrw>5k}s7?V?{@k7VM#bv4Lqw+SZ+`^8 z#)4(nX86}5V~F$f2MUFM`2e;4Bj}W7w?B9oY7+&x7yXX#g}3yF^TR3>ApiT8df3*W z+Whug5_~rge^!bi-;Z|>U%2`mRBP6yL!~9K1n$N2^AgCilc3E4M7+}uIJQ8w5x(a_ ztpm%i%W%?>PJHn5A3XeU6QZ?y!$YM%Twa3U`SoQdfi(3Xdvp=()m5itMJwUEE_6=8 zirE=XJi;RP^k1ydH@3sYFffHCBf7Mc?n8? zVrWDF%hKO}mz1zE4{@oOZ3W#LU-Nbsk1B|jWUlc`fn!u`KU)2q9nv0h8iQqDvQ z9ZF~G6?=DqRkKqJ>~E93eI?xbjD{bDWPX6?9fJfyKoBCj)nZ?E8fsgknYI0b1XA|| z&;7lmB`_v{lsY`_x4-1M8*Avdzoc=q!gZS_dC~KAU1;2_`2InH7v^L*y01g_uIJ#E zr=e#T{ey~IToPCkf)H!WAneH}qrTW`Cgdm{4t~C{q$Mz(4vvlzhzJmvErFM9lA zqr%VXf5u8d-+f`yDGry8O;ZEpZd-wxyBxaLHtiwX#h9TsZNnZj2xso39pC1*%wLqw z2Y6RJi2u+lh~8bzOyH!@(ER}C?hCMfbVSK58^>}^U~$>CAHX{s;gik!S?~8P=)VtG z0PlT9cFr75=4vJJt_Xf5Fc-f{SIX~Y<`1g(ER;_~< z)+6c~p<69`w0>N!5|m(15bsH$p+X5k@Xkiui{_)YY)6D4Vp{_U5S=sHkk%v*%2|SY zCu5y*cu7bQ|535|e0#X|ecYei176UScnL$=w00b~1k)GeFI{6^f*`=T_d={8hjsXV zg8225I^2>2`;c0431l4Dp4%~#)Y=wDbRa|_E$rMn3484Es7>3i(%(f~;pI?v7i6+hUTywwmP*f(kDV&Bwv==!3KbX*-d??)aXdePGlKO!cQU|=6DLCV%C*=m-+vhb!X=#W%$$HX8zNH9g`l56@ExmB*8KNL~7yGCJAH}N+5(D4lRj$(L91xZ|aw!9d5Gd_$y=biy`4_@8O<* zubvI39W!r0-0K9FFUEhk4eJE?WR$AU>P53IHK=q7q#%9I1z5-QL8y4k&`RUZph$xM zc^CJB`{I=#I;^0hC9ouHZ9vtg;lxA93_AjGxkswRA3xYDt2W zvvX>=EfSnF2xsnjX08uytpw4(xwQdKIfBepBcR`Yq1mgzd+%mE0v?@XSNg(odhTC(9=_5%`8%jNJ+makh{^arA7YaQ6 zfkYY({4`Ykk26!@yF>0^ z3I5X6ElUu+`E`wm>&KIxFqk*r_nB}*jI+oEoBj-D@wQ2!>lo6CZEKg-}V?j!{w_wMNMZx z5bQkZmqPEiY}^jDDOhzwh94Yi866Hvv!XEy5eN4rwcuj?_ISRTZykh)uC@5TU4h!# zpy8X?Ul@gmH&4W#@PnohF@nFj9_pR`w{j61RZCq>;Xkg*%|7Unc)q(_{ZiZi#GWF-ah#Kz&uWV}YYd2>|ED@yJImCo}aFUU<`I z#0;11-k!rROfziw@N>oHI&;H7d7Ns{Tmor80;Tks046r3>>}3pl_Wjn5T5^=&&U}$ z8Uk=qt?#~t0M}P!J*x2X=wb=xUmQJ+R!g8lg*b5U_yU>yPOm?{?lE#^j>Z7&HZE=| z1vM!_r%aXJ9==mgU`cRWkwsJ>QZ{mMU-Lsi5&V^Z4Hz}cB^PS=ZHZzeF!z>=^%i#X!D$fFKyx}?xhi|!;^@t1(pXJqkI+u;}PId&B% z9BSz(AgIP3pt%IceUH?_J&+)Oc=HOt0-`w(yXV!{m@5g8}H3MVuHFF<(#V!xg^ zSB}Cu^H`%NeMaz~c`e|qYqNyX9DK*tg|y>`J3RQSv@Wxd=B6#>FF};WdQM zuS0#hMTd&DX~Y4&ktg)S8Z`jXv$N5&exq{>pL*5j?CWx1fi#!4AiG5|ZkWSESEh|@ zWvEO6XyE|ohMa!uYf?=~^_C8VHUR(0SAE9B1b_Ug4i8=t5B$m!;OmZbkB)scc+`6Y z|FP9RV`t|O4oJ%^{0YM~{OAPsICce9mH;hXS3(;%eRL4~iNhV1#0aEqGw%8vGNw1bJ>Zvj7}xWMIrx)CI4qvt{_qn4c5{XAp%;C|UmqX* z2d1Y9!}f_BEZ+=^OwHlbMB4t z!2ju}qHe!~@1aZtXlb_p-#!y!n(&?fV~0hTl?MDofEH%^kG||P{`y>O@E88Fbl@if zG#m3DTdi04tSHW}aQINk$sqP@E5Wiq2aKMXjU};j!RZbQeo=bxt6qQz$UC2e47{|F zM$gP1zGC>3Pj{GKqVSU;AiwZ(*#ejPI)#%m41ctSACxHksumzBv3}!&kX35~oX*0? zVVx2D3r9Q5zf{AQB?`Z~1;`J4D_;*#S!HCGSOov#GaPCK&S17FV2|;+TV_UfY+(i;fZjI!uD58)N}^_tTJfH!2#kie6m>{r8vb(^HtP zFHHoX1k=O2>eiz~k*uJZQz8Jn&J`%tG(431Sf2=xv?L5nS|UKw5&@Ey2#~ZyfTSe? lBrOpjX^8-d07}6jMQ!#}om5`+**=664 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 Mv@btXeR}@Ne^~DM&;S4c diff --git a/reference/mkdocs.yml b/reference/mkdocs.yml index e8d754a9..24fa9864 100644 --- a/reference/mkdocs.yml +++ b/reference/mkdocs.yml @@ -13,6 +13,7 @@ use_directory_urls: false theme: name: material custom_dir: overrides + favicon: assets/img/signalwire-favicon.png features: - navigation.sections - navigation.indexes From 01c3e8e90b6e63452aa16d302bada190a66102ea Mon Sep 17 00:00:00 2001 From: August L-R Date: Wed, 1 Jul 2026 22:07:29 +0000 Subject: [PATCH 02/16] ci(reference): trigger docs on v* release tags instead of the pilot branch --- .github/workflows/reference-docs.yml | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/.github/workflows/reference-docs.yml b/.github/workflows/reference-docs.yml index c8ce2c4b..58c0dd3d 100644 --- a/.github/workflows/reference-docs.yml +++ b/.github/workflows/reference-docs.yml @@ -4,10 +4,8 @@ # and publishes it to this repo's OWN GitHub Pages via mike (versioned): # https://signalwire.github.io/signalwire-python/ # -# PILOT triggers: workflow_dispatch + push to the pilot branch. This is NOT -# gated on releases yet. -# PRODUCTION (later): switch the trigger to `v*` tags so each release version -# is deployed and `latest` is re-aliased. See the commented block below. +# Triggers on `v*` release tags — each release deploys its versioned doc set via +# mike and re-aliases `latest` — plus workflow_dispatch for manual/fork-preview runs. # # MANUAL REPO SETTING REQUIRED to go live (one-time, in the GitHub UI): # Settings -> Pages -> Build and deployment -> Source = "Deploy from a branch" @@ -15,15 +13,10 @@ name: reference-docs on: - workflow_dispatch: + workflow_dispatch: # manual runs (and fork-preview builds) push: - branches: - - docs/api-reference-pilot - - # --- PRODUCTION trigger (enable when promoting out of the pilot) ------------ - # push: - # tags: - # - "v*" + tags: + - "v*" # each release deploys its versioned doc set via mike, alongside publish-release.yml permissions: contents: write # mike pushes the built site to the gh-pages branch From ca84ed59ee18b16dbef741f870a1efc21323ece5 Mon Sep 17 00:00:00 2001 From: August L-R Date: Wed, 1 Jul 2026 22:18:42 +0000 Subject: [PATCH 03/16] =?UTF-8?q?chore(reference):=20address=20review=20ni?= =?UTF-8?q?ts=20=E2=80=94=20accurate=20docs=5Fdir=20comment,=20drop=20dead?= =?UTF-8?q?=20navbar.js=20code?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- reference/assets/js/navbar.js | 3 --- reference/mkdocs.yml | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/reference/assets/js/navbar.js b/reference/assets/js/navbar.js index 4c345717..a435eb16 100644 --- a/reference/assets/js/navbar.js +++ b/reference/assets/js/navbar.js @@ -102,7 +102,6 @@ /* --- Init ----------------------------------------------------------------- */ function init() { registerDropdown("product-trigger", "product-panel", { align: "start" }); - registerDropdown("lang-trigger", "lang-panel", { align: "center" }); registerDropdown("support-trigger", "support-panel", { align: "end" }); registerDropdown("theme-trigger", "theme-panel", { align: "end" }); @@ -119,8 +118,6 @@ setTimeout(syncThemeUI, 0); }); } - // Header sun/moon button = quick toggle. - var themeTrigger = document.getElementById("theme-trigger"); syncThemeUI(); // Material re-applies the scheme asynchronously; observe to keep icons in sync. var obs = new MutationObserver(syncThemeUI); diff --git a/reference/mkdocs.yml b/reference/mkdocs.yml index 24fa9864..333f77b4 100644 --- a/reference/mkdocs.yml +++ b/reference/mkdocs.yml @@ -3,7 +3,7 @@ site_description: API reference for the SignalWire Python SDK, generated from do site_url: https://signalwire.github.io/signalwire-python/ # Generated per-run by gen.sh (one API page per importable subpackage of -# `signalwire`, plus the SDK README as the landing page). This is NOT the repo's +# `signalwire`, plus a generated landing page). This is NOT the repo's # existing top-level docs/ dir (owned by doc-audit.yml) — keep them separate. docs_dir: _docs site_dir: _site From b98608f2ee649ef967140a331160e7ad283a10e9 Mon Sep 17 00:00:00 2001 From: August L-R Date: Thu, 2 Jul 2026 17:35:24 +0000 Subject: [PATCH 04/16] refactor(reference): publish a single unversioned site via mkdocs gh-deploy (remove `mike`) --- .github/workflows/reference-docs.yml | 41 ++++++++++++-------------- reference/README.md | 43 +++++++++------------------- reference/gen.sh | 2 +- reference/mkdocs.yml | 7 +---- reference/requirements.txt | 1 - 5 files changed, 34 insertions(+), 60 deletions(-) diff --git a/.github/workflows/reference-docs.yml b/.github/workflows/reference-docs.yml index 58c0dd3d..0e1a5710 100644 --- a/.github/workflows/reference-docs.yml +++ b/.github/workflows/reference-docs.yml @@ -1,35 +1,41 @@ # API reference docs (pilot). # # Builds the SignalWire Python SDK API reference (MkDocs Material + mkdocstrings) -# and publishes it to this repo's OWN GitHub Pages via mike (versioned): +# and publishes a single, unversioned "latest" site to this repo's OWN GitHub Pages: # https://signalwire.github.io/signalwire-python/ # -# Triggers on `v*` release tags — each release deploys its versioned doc set via -# mike and re-aliases `latest` — plus workflow_dispatch for manual/fork-preview runs. +# Triggers on `v*` release tags — each release rebuilds + republishes the site — +# plus workflow_dispatch for manual/fork-preview runs. (Versioning via mike was +# intentionally left out of the pilot; it can be added back later.) # # MANUAL REPO SETTING REQUIRED to go live (one-time, in the GitHub UI): # Settings -> Pages -> Build and deployment -> Source = "Deploy from a branch" -# -> Branch = `gh-pages` / `(root)`. mike pushes the built site there. +# -> Branch = `gh-pages` / `(root)`. `mkdocs gh-deploy` pushes the built site there. name: reference-docs +env: + # Match the repo's other workflows (redundant here since this workflow's + # actions are pinned to v6, which is already Node 24-native). + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" + on: workflow_dispatch: # manual runs (and fork-preview builds) push: tags: - - "v*" # each release deploys its versioned doc set via mike, alongside publish-release.yml + - "v*" # each release rebuilds + republishes the site, alongside publish-release.yml permissions: - contents: write # mike pushes the built site to the gh-pages branch + contents: write # gh-deploy pushes the built site to the gh-pages branch jobs: build-deploy: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: - fetch-depth: 0 # mike needs full history + the gh-pages branch + fetch-depth: 0 # gh-deploy needs the gh-pages branch history - - uses: actions/setup-python@v5 + - uses: actions/setup-python@v6 with: python-version: "3.11" @@ -39,7 +45,7 @@ jobs: pip install -r reference/requirements.txt pip install -e . - - name: Configure git for mike + - name: Configure git run: | git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" @@ -47,16 +53,5 @@ jobs: - name: Generate API pages run: bash reference/gen.sh --no-build - - name: Resolve version - id: ver - run: | - # Pilot: use the package version. Production: derive from the v* tag, - # e.g. VERSION="${GITHUB_REF_NAME#v}". - VERSION=$(python -c "import tomllib;print(tomllib.load(open('pyproject.toml','rb'))['project']['version'])") - echo "version=$VERSION" >> "$GITHUB_OUTPUT" - - - name: Deploy with mike (versioned) to gh-pages - run: | - mike deploy --config-file reference/mkdocs.yml --push --update-aliases \ - "${{ steps.ver.outputs.version }}" latest - mike set-default --config-file reference/mkdocs.yml --push latest + - name: Build + deploy to gh-pages + run: python3 -m mkdocs gh-deploy --config-file reference/mkdocs.yml --force diff --git a/reference/README.md b/reference/README.md index e39a0b2f..6ebc7c92 100644 --- a/reference/README.md +++ b/reference/README.md @@ -2,7 +2,7 @@ Language-native API reference for the SignalWire Python SDK, generated from docstrings with **MkDocs Material + mkdocstrings**, wrapped in the SignalWire -**Fern navbar**, and versioned with **mike**. Published to this repo's own +**Fern navbar**, and published as a single unversioned site to this repo's own GitHub Pages: > https://signalwire.github.io/signalwire-python/ @@ -32,8 +32,8 @@ first — keep that. From the repo root, in a virtualenv: ```bash +pip install -r reference/requirements.txt pip install -e . -pip install mkdocs-material "mkdocstrings[python]" mike # Generate API pages + build the static site into reference/_site bash reference/gen.sh @@ -46,35 +46,21 @@ mkdocs serve --config-file reference/mkdocs.yml `use_directory_urls: false`, so every page is a real `.html` file and the site works under the `/signalwire-python/` base path. -## Versioning (mike) +## Deploy -`extra.version.provider: mike` in `mkdocs.yml` turns on Material's version -selector; it reads `versions.json` from the site root at runtime. mike commits -each deployed version to a local `gh-pages` branch. - -```bash -bash reference/gen.sh --no-build # generate pages first - -# Deploy a version and (re)point the `latest` alias at it; set it as default. -mike deploy --config-file reference/mkdocs.yml --update-aliases 3.0.2 latest -mike set-default --config-file reference/mkdocs.yml latest -mike list --config-file reference/mkdocs.yml # -> 3.0.2 [latest], 3.0.1 - -mike serve --config-file reference/mkdocs.yml # preview all versions + selector -``` - -Add `--push` to push the `gh-pages` branch to the remote (CI does this; do not -locally). +A single, unversioned "latest" site is published to the `gh-pages` branch via +`mkdocs gh-deploy` (CI does this — see below). Versioning (a per-release version +selector via `mike`) was intentionally left out of the pilot and can be added +later without touching the markup. ## CI `.github/workflows/reference-docs.yml` (plain `actions/setup-python`, no Docker): -- **Pilot triggers:** `workflow_dispatch` + push to `docs/api-reference-pilot`. -- Installs the SDK editable + `mkdocs-material`, `mkdocstrings[python]`, `mike`, - runs `gen.sh --no-build`, then `mike deploy --push --update-aliases latest`. -- **Production trigger (later):** `v*` tags (commented in the workflow), so each - release deploys its version and re-aliases `latest`. +- **Triggers:** `v*` release tags (each release rebuilds + republishes) plus + `workflow_dispatch` for manual / fork-preview runs. +- Installs from `reference/requirements.txt` + the SDK editable, runs + `gen.sh --no-build`, then `mkdocs gh-deploy --force` to the `gh-pages` branch. ## Manual repo setting required to go live @@ -83,14 +69,13 @@ One-time, in the GitHub UI: > **Settings → Pages → Build and deployment → Source = "Deploy from a branch" → > Branch = `gh-pages` / `(root)`.** -mike pushes the built site to `gh-pages`; Pages then serves it at +`mkdocs gh-deploy` pushes the built site to `gh-pages`; Pages then serves it at `https://signalwire.github.io/signalwire-python/`. ## Pilot simplifications -- **Language switcher:** cross-site links with Python marked active; other - languages point at the POC demo (no per-language hosted site exists yet). - **Theme toggle:** drives Material's own light/dark color scheme. No cross-origin `localStorage` theme sync with signalwire.com/docs (different origin — out of scope). -- Out of scope: llms.txt/markdown emission, Docker, other languages, custom domain. +- Out of scope: versioning (mike), llms.txt/markdown emission, Docker, other + languages, custom domain. diff --git a/reference/gen.sh b/reference/gen.sh index 1b393129..6d13eb49 100755 --- a/reference/gen.sh +++ b/reference/gen.sh @@ -11,7 +11,7 @@ # editable install to resolve imports — that is preserved here. # # Usage: reference/gen.sh # generate pages + `mkdocs build` -# reference/gen.sh --no-build # generate pages only (mike runs the build) +# reference/gen.sh --no-build # generate pages only (CI builds + deploys) set -euo pipefail HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # .../reference diff --git a/reference/mkdocs.yml b/reference/mkdocs.yml index 333f77b4..48d2b1d3 100644 --- a/reference/mkdocs.yml +++ b/reference/mkdocs.yml @@ -9,7 +9,7 @@ docs_dir: _docs site_dir: _site use_directory_urls: false -# Mike serves each version under //, so links must be relative. +# Served under the project-pages subpath (/signalwire-python/); links stay relative. theme: name: material custom_dir: overrides @@ -34,11 +34,6 @@ theme: icon: material/weather-sunny name: Switch to light mode -extra: - version: - provider: mike - default: latest - extra_css: - assets/fern/tokens.css - assets/fern/fern.css diff --git a/reference/requirements.txt b/reference/requirements.txt index 6b9325ba..137a880e 100644 --- a/reference/requirements.txt +++ b/reference/requirements.txt @@ -4,5 +4,4 @@ mkdocs==1.6.1 mkdocs-material==9.7.6 mkdocstrings==1.0.4 mkdocstrings-python==2.0.4 -mike==2.2.0 pymdown-extensions==10.21.3 From d55e2178f644e0729f99d8847e4bdf7f07609242 Mon Sep 17 00:00:00 2001 From: August L-R Date: Mon, 17 Aug 2026 15:59:20 +0000 Subject: [PATCH 05/16] chore(reference): drop stale "(pilot)" from workflow header comment --- .github/workflows/reference-docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/reference-docs.yml b/.github/workflows/reference-docs.yml index ec58a0ef..4e78e958 100644 --- a/.github/workflows/reference-docs.yml +++ b/.github/workflows/reference-docs.yml @@ -1,4 +1,4 @@ -# API reference docs (pilot). +# API reference docs. # # Builds the SignalWire Python SDK API reference (MkDocs Material + mkdocstrings) # and publishes a single, unversioned "latest" site to this repo's OWN GitHub Pages: From 73cd62d5fc42b8df7f25ad1d21cd72d331a57b90 Mon Sep 17 00:00:00 2001 From: August L-R Date: Tue, 18 Aug 2026 14:03:40 +0000 Subject: [PATCH 06/16] docs: escape bracketed docstring text that renders as broken links --- signalwire/signalwire/pom/pom_tool.py | 18 ++++++++++++------ signalwire/signalwire/relay/client.py | 2 +- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/signalwire/signalwire/pom/pom_tool.py b/signalwire/signalwire/pom/pom_tool.py index 4dbc30da..6c970c7d 100644 --- a/signalwire/signalwire/pom/pom_tool.py +++ b/signalwire/signalwire/pom/pom_tool.py @@ -3,14 +3,20 @@ POM Tool - Command line utility for working with Prompt Object Model files Usage: - pom_tool [--output=] [--outfile=] [--merge_pom="
:"] - pom_tool (-h | --help) + +```text +pom_tool [--output=] [--outfile=] [--merge_pom="
:"] +pom_tool (-h | --help) +``` Options: - -h --help Show this help message - --output= Output format: md, xml, json, yaml [default: md] - --outfile= Output file (if not specified, prints to stdout) - --merge_pom= Merge another POM into a section: "
:" + +```text +-h --help Show this help message +--output= Output format: md, xml, json, yaml [default: md] +--outfile= Output file (if not specified, prints to stdout) +--merge_pom= Merge another POM into a section: "
:" +``` """ import argparse diff --git a/signalwire/signalwire/relay/client.py b/signalwire/signalwire/relay/client.py index 6dc4252e..dc77e77d 100644 --- a/signalwire/signalwire/relay/client.py +++ b/signalwire/signalwire/relay/client.py @@ -10,7 +10,7 @@ - Each Action registers with a ``control_id`` and listens for its own event_type (e.g. ``calling.call.play``). Actions filter events by ``control_id`` so multiple concurrent actions on the same call work. -- Result code checking accepts any 2xx (matching the JS SDK regex /^2[0-9][0-9]$/). +- Result code checking accepts any 2xx (matching the JS SDK regex ``/^2[0-9][0-9]$/``). ``signalwire.connect`` responses skip code checking entirely. - Execute has a configurable timeout (default 10s) to detect half-open connections. - Requests made while disconnected are queued and flushed after re-auth. From f1fe4cceb64b6d8ee06791dd75cef2f9fb4e5023 Mon Sep 17 00:00:00 2001 From: August L-R Date: Tue, 18 Aug 2026 14:03:58 +0000 Subject: [PATCH 07/16] build(reference): harden gen.sh flags, strict build, empty-page guard --- reference/gen.sh | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/reference/gen.sh b/reference/gen.sh index 6d13eb49..f39285e8 100755 --- a/reference/gen.sh +++ b/reference/gen.sh @@ -10,10 +10,22 @@ # The package is nested (signalwire/signalwire/) and mkdocstrings needs the # editable install to resolve imports — that is preserved here. # -# Usage: reference/gen.sh # generate pages + `mkdocs build` -# reference/gen.sh --no-build # generate pages only (CI builds + deploys) +# Usage: reference/gen.sh # generate pages + strict `mkdocs build` +# reference/gen.sh --no-build # generate pages only (the caller builds/deploys) +# reference/gen.sh --no-install # skip the pip installs (the caller installed already) +# Both flags are accepted together, in either order. set -euo pipefail +NO_BUILD=0 +NO_INSTALL=0 +for arg in "$@"; do + case "$arg" in + --no-build) NO_BUILD=1 ;; + --no-install) NO_INSTALL=1 ;; + *) echo "gen.sh: unknown option: $arg" >&2; exit 2 ;; + esac +done + HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # .../reference REPO="$(cd "$HERE/.." && pwd)" # repo root DOCS="$HERE/_docs" @@ -21,8 +33,12 @@ CFG="$HERE/mkdocs.yml" # Install the doc toolchain + the SDK (editable, so mkdocstrings can import it). # Use `python3 -m pip` so this works whether or not a bare `pip` is on PATH. -python3 -m pip install -q -r "$HERE/requirements.txt" -python3 -m pip install -q -e "$REPO" +# CI installs both itself and passes --no-install, so the pinned environment is +# not re-resolved underneath the build. +if [ "$NO_INSTALL" -eq 0 ]; then + python3 -m pip install -q -r "$HERE/requirements.txt" + python3 -m pip install -q -e "$REPO" +fi # Build the docs tree: generated landing page + one API page per subpackage. rm -rf "$DOCS" @@ -47,6 +63,11 @@ for name in names: fh.write(f"# signalwire.{name}\n\n::: signalwire.{name}\n") written.append(name) +# An unresolvable install yields zero modules, and every command below still +# succeeds, so `set -e` would let a gutted site sail through to deploy. Fail loud. +if not written: + sys.exit("gen.sh: no API pages generated (is the signalwire package importable?)") + # API-section landing entry. with open(os.path.join(api_out, "index.md"), "w") as fh: fh.write("# API reference\n\n") @@ -77,10 +98,11 @@ with open(os.path.join(docs_root, "index.md"), "w") as fh: print("api pages:", ", ".join(written)) PY -if [ "${1:-}" = "--no-build" ]; then +if [ "$NO_BUILD" -eq 1 ]; then echo "pages generated under $DOCS (skipping mkdocs build)" exit 0 fi -python3 -m mkdocs build --config-file "$CFG" +# --strict so a local run fails on the same warnings CI fails on. +python3 -m mkdocs build --strict --config-file "$CFG" echo "python -> $HERE/_site ($(find "$HERE/_site" -name '*.html' | wc -l) pages)" From d7ac075c47694060db7610ce4663f13ca5fe120d Mon Sep 17 00:00:00 2001 From: August L-R Date: Tue, 18 Aug 2026 14:04:11 +0000 Subject: [PATCH 08/16] ci(reference): publish docs only from stable, newer releases --- .github/workflows/reference-docs.yml | 111 ++++++++++++++++++++++----- 1 file changed, 90 insertions(+), 21 deletions(-) diff --git a/.github/workflows/reference-docs.yml b/.github/workflows/reference-docs.yml index 4e78e958..4ea703ad 100644 --- a/.github/workflows/reference-docs.yml +++ b/.github/workflows/reference-docs.yml @@ -1,39 +1,48 @@ # API reference docs. # # Builds the SignalWire Python SDK API reference (MkDocs Material + mkdocstrings) -# and publishes a single, unversioned "latest" site to this repo's OWN GitHub Pages: +# and publishes a single, unversioned site to this repo's OWN GitHub Pages: # https://signalwire.github.io/signalwire-python/ # -# Triggers on `v*` release tags — each release rebuilds + republishes the site — -# plus workflow_dispatch for manual/fork-preview runs. (Versioning via mike was -# intentionally left out of the pilot; it can be added back later.) +# Publishing is deliberately narrow, because `gh-deploy --force` overwrites the +# live site with no prior version left to roll back to: +# * `release: published` only, downstream of publish-release.yml's validation, +# so a rejected tag can never become the public site. +# * stable, non-prerelease semver tags only, and only when the tag is newer +# than the version the last publish recorded at the site root. +# * workflow_dispatch builds a preview by default; it publishes only when the +# `deploy` input is ticked, and never from a fork. # # MANUAL REPO SETTING REQUIRED to go live (one-time, in the GitHub UI): -# Settings -> Pages -> Build and deployment -> Source = "Deploy from a branch" -# -> Branch = `gh-pages` / `(root)`. `mkdocs gh-deploy` pushes the built site there. +# Settings > Pages > Build and deployment > Source = "Deploy from a branch", +# Branch = `gh-pages` / `(root)`. `mkdocs gh-deploy` pushes the built site there. name: reference-docs -env: - # Match the repo's other workflows (redundant here since this workflow's - # actions, checkout v7 and setup-python v6, are already Node 24-native). - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" - on: - workflow_dispatch: # manual runs (and fork-preview builds) - push: - tags: - - "v*" # each release rebuilds + republishes the site, alongside publish-release.yml + workflow_dispatch: + inputs: + deploy: + description: "Publish to gh-pages (leave false for a build-only preview)" + type: boolean + default: false + release: + types: [published] permissions: contents: write # gh-deploy pushes the built site to the gh-pages branch +concurrency: + group: reference-docs-production + cancel-in-progress: false # never interrupt a push mid-flight + jobs: build-deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 with: - fetch-depth: 0 # gh-deploy needs the gh-pages branch history + fetch-depth: 0 # gh-deploy needs gh-pages history + ref: ${{ github.event.release.tag_name || github.ref }} - uses: actions/setup-python@v6 with: @@ -45,13 +54,73 @@ jobs: pip install -r reference/requirements.txt pip install -e . + # Single decision point for whether this run may force-push the public site. + # Do NOT hoist this into a job-level `env:`; job env is evaluated before any + # step runs, so it cannot read `steps.*` outputs. One step, all reasons logged. + - name: Decide whether to publish + id: gate + env: + EVENT: ${{ github.event_name }} + TAG: ${{ github.event.release.tag_name }} + PRERELEASE: ${{ github.event.release.prerelease }} + DISPATCH_DEPLOY: ${{ inputs.deploy }} + IS_UPSTREAM: ${{ github.repository == 'signalwire/signalwire-python' }} + run: | + publish=false + if [ "$IS_UPSTREAM" != "true" ]; then + echo "::notice::fork build; not publishing" + elif [ "$EVENT" = "workflow_dispatch" ]; then + publish="$DISPATCH_DEPLOY" + elif [ "$EVENT" = "release" ]; then + if [ "$PRERELEASE" = "true" ]; then + echo "::warning::$TAG is flagged pre-release; not republishing" + # Stable semver only. Actions expressions have no regex, which is why this + # check lives in a step. The prerelease flag is only as good as whoever + # published remembering to tick it, and nothing infers it from the tag name. + elif [[ ! "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "::warning::$TAG is not stable semver; not republishing" + else + # Monotonicity: never replace the live site with an older version. + # A release can be cut from any ref, so a backport tag or a release + # built against an old commit would otherwise force-push older docs + # over newer with nothing left on gh-pages to roll back to. Compare + # against the marker the last successful publish left at the site root. + # Fetch the branch explicitly rather than trusting checkout's refspec. + git fetch --no-tags origin +refs/heads/gh-pages:refs/remotes/origin/gh-pages 2>/dev/null || true + prev="$(git show refs/remotes/origin/gh-pages:version.txt 2>/dev/null | tr -d '[:space:]')" + if [ -z "$prev" ]; then + echo "::notice::no deployed version marker; treating $TAG as the first publish" + publish=true + elif [ "$(printf '%s\n%s\n' "${prev#v}" "${TAG#v}" | sort -V | tail -1)" = "${TAG#v}" ]; then + # Equal versions pass, so re-running a release can republish it. + publish=true + else + echo "::warning::live site is $prev, which is newer than $TAG; not republishing" + fi + fi + fi + echo "publish=$publish" >> "$GITHUB_OUTPUT" + echo "publish=$publish" + + - name: Generate API pages + run: bash reference/gen.sh --no-build --no-install + + # Leaves the marker the monotonicity check reads on the NEXT run. Must run + # after gen.sh, which does `rm -rf _docs`. Release runs only: a dispatch has + # no tag, and writing a non-version value would corrupt the comparison. + - name: Stamp the version marker + if: github.event_name == 'release' + run: echo "${{ github.event.release.tag_name }}" > reference/_docs/version.txt + + - name: Build (strict), the gate before any push + run: python3 -m mkdocs build --strict --config-file reference/mkdocs.yml + - name: Configure git + if: steps.gate.outputs.publish == 'true' run: | git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" - - name: Generate API pages - run: bash reference/gen.sh --no-build - - - name: Build + deploy to gh-pages - run: python3 -m mkdocs gh-deploy --config-file reference/mkdocs.yml --force + - name: Deploy to gh-pages + if: steps.gate.outputs.publish == 'true' + run: python3 -m mkdocs gh-deploy --strict --config-file reference/mkdocs.yml --force From b81222683d89de531e15ca8b3a8e15091133b941 Mon Sep 17 00:00:00 2001 From: August L-R Date: Tue, 18 Aug 2026 14:04:19 +0000 Subject: [PATCH 09/16] ci(reference): add non-deploying PR build check --- .github/workflows/reference-check.yml | 38 +++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 .github/workflows/reference-check.yml diff --git a/.github/workflows/reference-check.yml b/.github/workflows/reference-check.yml new file mode 100644 index 00000000..647b9813 --- /dev/null +++ b/.github/workflows/reference-check.yml @@ -0,0 +1,38 @@ +# API reference docs, PR check. +# +# Build-only counterpart to reference-docs.yml: no deploy, no write permission. +# Without this, a broken generator, an unimportable module, or a new unresolved +# cross-reference is first exercised on release day against the live site. +name: reference-check + +on: + pull_request: + paths: + - "signalwire/**" + - "reference/**" + - "pyproject.toml" + - ".github/workflows/reference-check.yml" + +permissions: + contents: read # never deploys + +concurrency: + group: reference-check-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + - uses: actions/setup-python@v6 + with: + python-version: "3.11" + - name: Install SDK (editable) + doc toolchain + run: | + python -m pip install --upgrade pip + pip install -r reference/requirements.txt + pip install -e . + # gen.sh without --no-build runs the strict `mkdocs build`. + - name: Generate + build (strict) + run: bash reference/gen.sh --no-install From 320f1f6a4c2c34e1a0359519d4ab78f4f7f1eb3a Mon Sep 17 00:00:00 2001 From: August L-R Date: Tue, 18 Aug 2026 14:04:34 +0000 Subject: [PATCH 10/16] docs(reference): drop pilot framing, document the gated pipeline --- reference/README.md | 65 +++++++++++++++++++++++++---------- reference/assets/js/navbar.js | 8 ++--- reference/overrides/main.html | 6 ++-- 3 files changed, 53 insertions(+), 26 deletions(-) diff --git a/reference/README.md b/reference/README.md index 6ebc7c92..4634b108 100644 --- a/reference/README.md +++ b/reference/README.md @@ -1,4 +1,4 @@ -# API reference (pilot) +# API reference Language-native API reference for the SignalWire Python SDK, generated from docstrings with **MkDocs Material + mkdocstrings**, wrapped in the SignalWire @@ -15,7 +15,9 @@ existing top-level `docs/` directory (owned by `doc-audit.yml`). ``` reference/ mkdocs.yml MkDocs Material + mkdocstrings config (docs_dir = _docs) + requirements.txt pinned doc toolchain (MkDocs Material, mkdocstrings) gen.sh installs the SDK editable, generates the API pages, builds + dev-server.sh generates the pages, then serves them with live reload overrides/main.html extends Material's base.html; injects the Fern navbar assets/ Fern tokens/CSS/JS + logo/favicon (committed; no shared host yet) _docs/ GENERATED docs tree (one page per signalwire.) [gitignored] @@ -38,44 +40,69 @@ pip install -e . # Generate API pages + build the static site into reference/_site bash reference/gen.sh -# Live preview (regenerates pages first, then serves with autoreload) -bash reference/gen.sh --no-build -mkdocs serve --config-file reference/mkdocs.yml +# Live preview: regenerates the pages, then serves with autoreload, bound to +# 0.0.0.0 so a forwarded port reaches it. PORT defaults to 3001. +bash reference/dev-server.sh [PORT] ``` +`gen.sh` also takes `--no-build` (generate the pages only) and `--no-install` +(skip the pip installs). Both CI workflows pass `--no-install`, since they install +the pinned toolchain themselves; the publishing one adds `--no-build`, since it +builds in a separate step. + `use_directory_urls: false`, so every page is a real `.html` file and the site works under the `/signalwire-python/` base path. ## Deploy -A single, unversioned "latest" site is published to the `gh-pages` branch via -`mkdocs gh-deploy` (CI does this — see below). Versioning (a per-release version -selector via `mike`) was intentionally left out of the pilot and can be added -later without touching the markup. +The site is unversioned: `mkdocs gh-deploy` publishes it to the `gh-pages` branch, +where the current release's docs sit at the site root. There is no per-version +path and no `latest` alias to navigate to. A version selector (via `mike`) can be +added later without touching the markup. CI does the publishing, see below. ## CI -`.github/workflows/reference-docs.yml` (plain `actions/setup-python`, no Docker): +Two workflows, both plain `actions/setup-python`, no Docker. + +`.github/workflows/reference-check.yml` builds on every PR touching `signalwire/`, +`reference/`, or `pyproject.toml`. It runs `gen.sh --no-install`, whose strict +`mkdocs build` fails the check on a generator error, an unimportable module, or a +new unresolved cross-reference. Build only: `contents: read`, never deploys. -- **Triggers:** `v*` release tags (each release rebuilds + republishes) plus - `workflow_dispatch` for manual / fork-preview runs. -- Installs from `reference/requirements.txt` + the SDK editable, runs - `gen.sh --no-build`, then `mkdocs gh-deploy --force` to the `gh-pages` branch. +`.github/workflows/reference-docs.yml` builds and publishes. It installs from +`reference/requirements.txt` plus the SDK editable, runs `gen.sh --no-build +--no-install`, builds with `--strict`, and only then runs `mkdocs gh-deploy --force`. + +- **Triggers:** published releases, plus `workflow_dispatch` for manual and + fork-preview runs. +- **Publishes only when** the run is on `signalwire/signalwire-python` (not a + fork), the release is not flagged pre-release, the tag is stable semver + (`vX.Y.Z`), and the tag is greater than or equal to the version recorded in + `version.txt` at the root of the live site. That last check exists because + `gh-deploy --force` leaves no prior version on `gh-pages` to roll back to, so + republishing older docs over newer would be unrecoverable. +- A `workflow_dispatch` run builds a preview and publishes only if you tick the + `deploy` input. ## Manual repo setting required to go live One-time, in the GitHub UI: -> **Settings → Pages → Build and deployment → Source = "Deploy from a branch" → +> **Settings > Pages > Build and deployment > Source = "Deploy from a branch", > Branch = `gh-pages` / `(root)`.** `mkdocs gh-deploy` pushes the built site to `gh-pages`; Pages then serves it at `https://signalwire.github.io/signalwire-python/`. -## Pilot simplifications +To create the `gh-pages` branch the first time, run `reference-docs` manually with +the `deploy` input ticked. A dispatch publish writes no `version.txt`, so the next +release finds an empty marker and publishes unconditionally; the monotonicity +check takes effect from the release after that. + +## Scope -- **Theme toggle:** drives Material's own light/dark color scheme. No - cross-origin `localStorage` theme sync with signalwire.com/docs (different - origin — out of scope). -- Out of scope: versioning (mike), llms.txt/markdown emission, Docker, other +- **Theme toggle:** drives Material's own light/dark color scheme. There is no + cross-origin `localStorage` theme sync with signalwire.com/docs, which is a + different origin. +- **Not included:** versioning (mike), llms.txt/markdown emission, Docker, other languages, custom domain. diff --git a/reference/assets/js/navbar.js b/reference/assets/js/navbar.js index a435eb16..38b55c25 100644 --- a/reference/assets/js/navbar.js +++ b/reference/assets/js/navbar.js @@ -1,9 +1,9 @@ /* ============================================================================= Fern navbar behaviour for the injected header (no iframe). Ported and trimmed from the SDK-docs POC (assets/js/app.js): - - dropdown open/close + anchored positioning (product / language / support / theme) - - theme toggle drives Material's own color scheme (default <-> slate) - Out of scope for the pilot (different origin from signalwire.com): + - dropdown open/close + anchored positioning (product / support / theme) + - theme toggle drives Material's own color scheme (default and slate) + Not implemented (different origin from signalwire.com): - cross-origin localStorage["theme"] sync with the Fern docs site - iframe theme bridging to other generators ============================================================================= */ @@ -110,7 +110,7 @@ themeItems[i].addEventListener("click", function () { closeAll(); var pref = this.getAttribute("data-theme-pref"); - // System resolves to the OS preference; pilot maps it to light/dark now. + // System resolves to the OS preference, mapped onto light/dark here. if (pref === "system") { pref = window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light"; } diff --git a/reference/overrides/main.html b/reference/overrides/main.html index 6e92558c..fe0cc2bf 100644 --- a/reference/overrides/main.html +++ b/reference/overrides/main.html @@ -7,9 +7,9 @@ mkdocs.yml (extra_css / extra_javascript); navbar.css pushes Material's layout down by --header-height so this fixed bar doesn't overlap content. - Pilot simplifications (see reference/README.md): - - Language switcher = cross-site links, Python marked active; the other - languages point at the POC demo (no per-language hosted site exists yet). + Scope (see reference/README.md): + - No language switcher. The header center is an empty spacer until the other + SDK languages have hosted reference sites of their own. - Theme toggle drives Material's own light/dark scheme. No cross-origin localStorage theme sync with signalwire.com/docs (different origin). --> From 288b738fca70071501a301b30edb9c962d437bfc Mon Sep 17 00:00:00 2001 From: August L-R Date: Tue, 18 Aug 2026 14:04:42 +0000 Subject: [PATCH 11/16] refactor(reference): remove dead language-switcher CSS --- reference/assets/css/navbar.css | 32 +------------------------------- 1 file changed, 1 insertion(+), 31 deletions(-) diff --git a/reference/assets/css/navbar.css b/reference/assets/css/navbar.css index cf008327..9551cf90 100644 --- a/reference/assets/css/navbar.css +++ b/reference/assets/css/navbar.css @@ -111,30 +111,8 @@ html { scroll-padding-top: calc(var(--fern-header-height) + var(--md-header-heig #fern-header [data-fern-logo] img { height: 28px; width: auto; display: block; } #fern-header .fern-logo-text { font-weight: 600; font-size: var(--text-sm); white-space: nowrap; } +/* The center slot is an empty spacer; the language switcher it once held is gone. */ #fern-header .fern-header-center { flex: 1; display: flex; justify-content: center; min-width: 0; } -#fern-header .fern-header-center .lang-trigger { max-width: 360px; } - -/* --- Language switcher trigger (search-bar slot) --- */ -.lang-trigger { - appearance: none; background: transparent; border: 0; font: inherit; - flex: 1; display: inline-flex; align-items: center; - gap: calc(var(--spacing) * 2); - height: calc(var(--spacing) * 9); - padding: calc(var(--spacing) * 2); - border-radius: calc(var(--radius) * 2); - box-shadow: inset 0 0 0 1px var(--grayscale-a5); - color: var(--grayscale-a11); font-size: var(--text-sm); font-weight: 500; - cursor: pointer; overflow: hidden; - transition: background-color 0.15s, box-shadow 0.15s; -} -.lang-trigger:hover, .lang-trigger[data-state="open"] { background-color: var(--grayscale-a3); } -.lang-trigger:focus-visible { outline: none; box-shadow: inset 0 0 0 1px var(--accent); } -.lang-trigger svg { width: calc(var(--spacing) * 4); height: calc(var(--spacing) * 4); flex-shrink: 0; } -.lang-trigger .lang-trigger-label { color: var(--grayscale-12); white-space: nowrap; } -.lang-trigger .lang-trigger-meta { - margin-left: auto; color: var(--grayscale-a9); font-weight: 400; - white-space: nowrap; overflow: hidden; text-overflow: ellipsis; -} /* --- Right-side button group --- */ .fern-button-group { display: inline-flex; align-items: center; gap: calc(var(--spacing) * 2); } @@ -213,18 +191,10 @@ html { scroll-padding-top: calc(var(--fern-header-height) + var(--md-header-heig #product-panel .fern-product-selector-radio-group > a[href*="server-sdks"]::before, #product-panel .fern-product-selector-radio-group > a[href$="/docs/apis"]::before { top: -28px; font-size: 11px; } -/* --- Language dropdown items --- */ -#lang-panel { min-width: 320px; } -#lang-panel .fern-dropdown-item { gap: calc(var(--spacing) * 2); } -#lang-panel .item-meta { margin-left: auto; padding-left: calc(var(--spacing) * 4); font-size: var(--text-xs); color: var(--grayscale-a9); } -.lang-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--lang-color, var(--grayscale-8)); display: inline-block; flex-shrink: 0; } -#lang-panel .fern-dropdown-item[aria-current="true"] { background: var(--accent-a3); } - /* --- Responsive: collapse like the Fern header --- */ @media (max-width: 1023px) { #fern-header .fern-header-navbar-links .fern-button-text { display: none; } #fern-header .fern-logo-text { display: none; } - .lang-trigger .lang-trigger-meta { display: none; } } @media (max-width: 600px) { #product-panel { width: 96vw; } From 0f0e8f86e4c79788f4eb8e999dc9add345c05702 Mon Sep 17 00:00:00 2001 From: August L-R Date: Tue, 18 Aug 2026 20:59:44 +0000 Subject: [PATCH 12/16] ci(reference): publish via workflow_call, fail closed, restrict dispatch --- .github/workflows/publish-release.yml | 16 ++ .github/workflows/reference-docs.yml | 224 +++++++++++++++++++------- 2 files changed, 178 insertions(+), 62 deletions(-) diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index 59439aa5..f3624322 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -159,3 +159,19 @@ jobs: echo "\`\`\`" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "**PyPI:** https://pypi.org/project/signalwire-sdk/${{ steps.tag_version.outputs.tag_version }}/" >> $GITHUB_STEP_SUMMARY + + # Republish the API reference for the version that just shipped. + # + # Called here rather than triggered by `release: published` inside + # reference-docs.yml: the Create GitHub Release step above uses + # secrets.GITHUB_TOKEN, and GitHub deliberately does not raise + # workflow-triggering events for that token, so a release trigger would never + # fire on this path. `needs: publish-release` also gives the ordering we + # actually want, with the docs going out only after the PyPI upload succeeded. + reference-docs: + needs: publish-release + permissions: + contents: write # the called workflow force-pushes the built site to gh-pages + uses: ./.github/workflows/reference-docs.yml + with: + tag: ${{ github.ref_name }} # the `v*` tag that triggered this run diff --git a/.github/workflows/reference-docs.yml b/.github/workflows/reference-docs.yml index 4ea703ad..66acfb0e 100644 --- a/.github/workflows/reference-docs.yml +++ b/.github/workflows/reference-docs.yml @@ -4,14 +4,28 @@ # and publishes a single, unversioned site to this repo's OWN GitHub Pages: # https://signalwire.github.io/signalwire-python/ # -# Publishing is deliberately narrow, because `gh-deploy --force` overwrites the -# live site with no prior version left to roll back to: -# * `release: published` only, downstream of publish-release.yml's validation, -# so a rejected tag can never become the public site. -# * stable, non-prerelease semver tags only, and only when the tag is newer -# than the version the last publish recorded at the site root. -# * workflow_dispatch builds a preview by default; it publishes only when the -# `deploy` input is ticked, and never from a fork. +# Publishing is deliberately narrow. `gh-deploy` force-pushes, but it does NOT +# discard history: mkdocs passes no_history=False, so ghp-import parents each +# deploy onto origin/gh-pages and --force forces only the push. A bad publish is +# therefore recoverable, by hand, with: +# git push --force origin gh-pages~1:gh-pages +# That recovery depends on somebody noticing, so the gate below exists to keep an +# older or invalid version from becoming the public site in the first place: +# * called by publish-release.yml only after the full CI gate set and the PyPI +# upload have succeeded, so a rejected tag can never become the public site. +# * stable semver tags only, and only when the tag is at least as new as the +# version the last publish recorded at the site root. +# * workflow_dispatch builds a preview by default. It publishes only when the +# `deploy` input is ticked, only from the default branch, and never from a +# fork. +# * anything the gate cannot positively determine fails CLOSED. +# +# There is deliberately NO `release: published` trigger. publish-release.yml +# creates the GitHub Release with `secrets.GITHUB_TOKEN`, and GitHub does not +# raise workflow-triggering events for actions taken with that token +# (workflow_dispatch and repository_dispatch excepted). A `release` trigger would +# therefore sit here looking correct and silently never fire on the normal tag +# path. The reusable `workflow_call` below is the wire that actually connects. # # MANUAL REPO SETTING REQUIRED to go live (one-time, in the GitHub UI): # Settings > Pages > Build and deployment > Source = "Deploy from a branch", @@ -19,99 +33,185 @@ name: reference-docs on: + workflow_call: + inputs: + tag: + description: "Release tag being published (vX.Y.Z). Its presence is what marks a run as a release publish." + type: string + required: true workflow_dispatch: inputs: deploy: description: "Publish to gh-pages (leave false for a build-only preview)" type: boolean default: false - release: - types: [published] + version_marker: + description: "Recovery only: overwrite the site's version.txt with this (vX.Y.Z). Leave blank to preserve the current marker." + type: string + required: false + default: "" +# Applies to the workflow_dispatch path. On the workflow_call path the caller's +# job grants the token permissions, so publish-release.yml sets contents: write +# on the job that calls this workflow. permissions: contents: write # gh-deploy pushes the built site to the gh-pages branch -concurrency: - group: reference-docs-production - cancel-in-progress: false # never interrupt a push mid-flight - jobs: build-deploy: runs-on: ubuntu-latest + # Job level, NOT workflow level. A called workflow's jobs run inside the + # CALLER's run, so a top-level `concurrency:` here would be ignored on the + # publish-release.yml path and two releases could race the force-push. + # + # Publishing runs share one serialized group; previews get a per-ref group of + # their own, so a newly queued preview can never displace a pending release + # publish (which would drop it as "cancelled" rather than failing red). + concurrency: + group: ${{ (inputs.tag != '' || inputs.deploy) && 'reference-docs-production' || format('reference-docs-preview-{0}', github.ref) }} + cancel-in-progress: false # never interrupt a push mid-flight steps: - uses: actions/checkout@v7 with: - fetch-depth: 0 # gh-deploy needs gh-pages history - ref: ${{ github.event.release.tag_name || github.ref }} - - - uses: actions/setup-python@v6 - with: - python-version: "3.11" - - - name: Install SDK (editable) + doc toolchain - run: | - python -m pip install --upgrade pip - pip install -r reference/requirements.txt - pip install -e . + # Required, and do NOT "optimize" it away: this is what fetches + # origin/gh-pages. Without that ref present, the force-push lands a + # parentless orphan commit and the deploy history really is destroyed. + fetch-depth: 0 + ref: ${{ inputs.tag || github.ref }} - # Single decision point for whether this run may force-push the public site. - # Do NOT hoist this into a job-level `env:`; job env is evaluated before any - # step runs, so it cannot read `steps.*` outputs. One step, all reasons logged. + # Runs BEFORE the toolchain install, so a run that cannot publish does not + # first pay several minutes of pip. It needs nothing but git. + # + # Single decision point for whether this run may force-push the public + # site, and the single place that decides what the version marker becomes. + # `inputs.tag` is only defined for workflow_call and `inputs.deploy` only + # for workflow_dispatch; the one belonging to the other trigger evaluates + # to an empty string, which is what separates the two paths below. - name: Decide whether to publish id: gate env: - EVENT: ${{ github.event_name }} - TAG: ${{ github.event.release.tag_name }} - PRERELEASE: ${{ github.event.release.prerelease }} + TAG: ${{ inputs.tag }} DISPATCH_DEPLOY: ${{ inputs.deploy }} + DISPATCH_MARKER: ${{ inputs.version_marker }} + REF_NAME: ${{ github.ref_name }} + DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} IS_UPSTREAM: ${{ github.repository == 'signalwire/signalwire-python' }} run: | + set -euo pipefail + SEMVER='^v[0-9]+\.[0-9]+\.[0-9]+$' publish=false + marker="" + + # Probe gh-pages rather than trusting checkout's refspec, and keep the + # three states distinct. `ls-remote --exit-code` returns 2 for "no such + # ref" and something else for "could not ask", which is the difference + # between a legitimate bootstrap and a failure we must not read as one. + rc=0 + git ls-remote --exit-code --heads origin gh-pages >/dev/null 2>&1 || rc=$? + case "$rc" in + 0) branch=present ;; + 2) branch=absent ;; + *) branch=unknown ;; + esac + + prev="" + if [ "$branch" = "present" ]; then + # No `|| true` here: an unreadable gh-pages must stop the run rather + # than fall through as "no marker, go ahead". + git fetch --no-tags origin +refs/heads/gh-pages:refs/remotes/origin/gh-pages + if git cat-file -e refs/remotes/origin/gh-pages:version.txt 2>/dev/null; then + prev="$(git show refs/remotes/origin/gh-pages:version.txt | tr -d '[:space:]')" + fi + fi + echo "gh-pages=$branch marker-on-site='${prev}'" + if [ "$IS_UPSTREAM" != "true" ]; then echo "::notice::fork build; not publishing" - elif [ "$EVENT" = "workflow_dispatch" ]; then - publish="$DISPATCH_DEPLOY" - elif [ "$EVENT" = "release" ]; then - if [ "$PRERELEASE" = "true" ]; then - echo "::warning::$TAG is flagged pre-release; not republishing" - # Stable semver only. Actions expressions have no regex, which is why this - # check lives in a step. The prerelease flag is only as good as whoever - # published remembering to tick it, and nothing infers it from the tag name. - elif [[ ! "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + elif [ "$branch" = "unknown" ]; then + echo "::error::could not determine the state of gh-pages; refusing to publish" + elif [ -n "$TAG" ]; then + # Release publish, called from publish-release.yml after its gates. + # publish-release.yml triggers on the `v*` glob, so an rc/beta tag + # does reach here; the shape check is what stops it overwriting the + # stable site. Actions expressions have no regex, hence a step. + if [[ ! "$TAG" =~ $SEMVER ]]; then echo "::warning::$TAG is not stable semver; not republishing" + elif [ "$branch" = "absent" ]; then + echo "::notice::gh-pages does not exist yet; treating $TAG as the first publish" + publish=true + marker="$TAG" + elif [ -z "$prev" ]; then + # Every publish stamps a marker, so a site without one has been + # hand-edited or predates this workflow. Fail closed and make the + # operator repair it deliberately (dispatch with version_marker). + echo "::error::gh-pages carries no readable version.txt; refusing to publish $TAG. Repair with a manual dispatch using the version_marker input." + elif [ "$(printf '%s\n%s\n' "${prev#v}" "${TAG#v}" | sort -V | tail -1)" = "${TAG#v}" ]; then + # Equal versions pass, so re-running a release can republish it. + publish=true + marker="$TAG" + else + echo "::warning::live site is $prev, which is newer than $TAG; not republishing" + fi + else + # Manual dispatch. + if [ "${DISPATCH_DEPLOY:-false}" != "true" ]; then + echo "::notice::preview build; the deploy input was not ticked" + elif [ -z "$DEFAULT_BRANCH" ] || [ "$REF_NAME" != "$DEFAULT_BRANCH" ]; then + # Otherwise any branch in the dropdown could publish itself as the + # official public API reference, running its own code under a + # contents: write token. + echo "::error::refusing to publish from '$REF_NAME'; dispatch a publish from the default branch ('${DEFAULT_BRANCH:-unknown}')" else - # Monotonicity: never replace the live site with an older version. - # A release can be cut from any ref, so a backport tag or a release - # built against an old commit would otherwise force-push older docs - # over newer with nothing left on gh-pages to roll back to. Compare - # against the marker the last successful publish left at the site root. - # Fetch the branch explicitly rather than trusting checkout's refspec. - git fetch --no-tags origin +refs/heads/gh-pages:refs/remotes/origin/gh-pages 2>/dev/null || true - prev="$(git show refs/remotes/origin/gh-pages:version.txt 2>/dev/null | tr -d '[:space:]')" - if [ -z "$prev" ]; then - echo "::notice::no deployed version marker; treating $TAG as the first publish" - publish=true - elif [ "$(printf '%s\n%s\n' "${prev#v}" "${TAG#v}" | sort -V | tail -1)" = "${TAG#v}" ]; then - # Equal versions pass, so re-running a release can republish it. - publish=true + publish=true + # gh-deploy replaces the whole site tree (ghp-import emits + # deleteall), so NOT re-stamping here would erase the marker and + # silently disarm the monotonicity guard for the next release. + if [ -n "$DISPATCH_MARKER" ]; then + if [[ ! "$DISPATCH_MARKER" =~ $SEMVER ]]; then + echo "::error::version_marker '$DISPATCH_MARKER' is not vX.Y.Z" + exit 1 + fi + marker="$DISPATCH_MARKER" + elif [ -n "$prev" ]; then + marker="$prev" else - echo "::warning::live site is $prev, which is newer than $TAG; not republishing" + # Bootstrap floor, so the site always carries a readable marker + # and "missing" stays meaningful as an anomaly. + marker="v0.0.0" fi fi fi + echo "publish=$publish" >> "$GITHUB_OUTPUT" - echo "publish=$publish" + echo "marker=$marker" >> "$GITHUB_OUTPUT" + echo "publish=$publish marker=$marker" + + - uses: actions/setup-python@v6 + with: + python-version: "3.11" + + - name: Install SDK (editable) + doc toolchain + run: | + python -m pip install --upgrade pip + pip install -r reference/requirements.txt + pip install -e . - name: Generate API pages run: bash reference/gen.sh --no-build --no-install - # Leaves the marker the monotonicity check reads on the NEXT run. Must run - # after gen.sh, which does `rm -rf _docs`. Release runs only: a dispatch has - # no tag, and writing a non-version value would corrupt the comparison. + # Must run after gen.sh, which does `rm -rf _docs`. The value goes through + # `env:` rather than inline `${{ }}`: git permits shell metacharacters in + # tag names, and this job holds contents: write. - name: Stamp the version marker - if: github.event_name == 'release' - run: echo "${{ github.event.release.tag_name }}" > reference/_docs/version.txt + if: steps.gate.outputs.marker != '' + env: + MARKER: ${{ steps.gate.outputs.marker }} + run: printf '%s\n' "$MARKER" > reference/_docs/version.txt + # Validates preview runs, and fails a publish before it reaches gh-deploy. + # gh-deploy builds again internally (its --strict is honoured there too), + # so publishing runs do build twice; that is deliberate insurance, not an + # oversight. - name: Build (strict), the gate before any push run: python3 -m mkdocs build --strict --config-file reference/mkdocs.yml From d5b330326d7e57386b8caf082816b99a5f9f6d4e Mon Sep 17 00:00:00 2001 From: August L-R Date: Tue, 18 Aug 2026 20:59:52 +0000 Subject: [PATCH 13/16] ci(reference): scope the PR check and correct what it catches --- .github/workflows/reference-check.yml | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/.github/workflows/reference-check.yml b/.github/workflows/reference-check.yml index 647b9813..fef3058c 100644 --- a/.github/workflows/reference-check.yml +++ b/.github/workflows/reference-check.yml @@ -1,8 +1,15 @@ # API reference docs, PR check. # # Build-only counterpart to reference-docs.yml: no deploy, no write permission. -# Without this, a broken generator, an unimportable module, or a new unresolved -# cross-reference is first exercised on release day against the live site. +# Catches a crashing generator, a root `signalwire` package that will not import +# (gen.sh imports it to enumerate subpackages), and unresolved cross-references, +# on the PR rather than on release day against the live site. +# +# It does NOT catch a submodule whose runtime dependency is missing: mkdocstrings +# analyses statically through griffe, so such a module still renders a clean page. +# Nothing here lints workflow YAML either, so a mistake in reference-docs.yml +# still surfaces at release time. porting-sdk ships scripts/actionlint_gate.py, +# which run-ci.sh does not currently call; wiring it up would close that gap. name: reference-check on: @@ -12,6 +19,9 @@ on: - "reference/**" - "pyproject.toml" - ".github/workflows/reference-check.yml" + # Changing the publish workflow at least re-runs this build. It is not + # validation OF that workflow; see the note above. + - ".github/workflows/reference-docs.yml" permissions: contents: read # never deploys From 6730acd68a18a76794f6749c2e7f095d00441c8a Mon Sep 17 00:00:00 2001 From: August L-R Date: Tue, 18 Aug 2026 21:00:07 +0000 Subject: [PATCH 14/16] docs(reference): correct rollback, marker, and go-live documentation --- reference/README.md | 82 ++++++++++++++++++++++++++++++--------------- 1 file changed, 55 insertions(+), 27 deletions(-) diff --git a/reference/README.md b/reference/README.md index 4634b108..f42326ac 100644 --- a/reference/README.md +++ b/reference/README.md @@ -42,7 +42,7 @@ bash reference/gen.sh # Live preview: regenerates the pages, then serves with autoreload, bound to # 0.0.0.0 so a forwarded port reaches it. PORT defaults to 3001. -bash reference/dev-server.sh [PORT] +bash reference/dev-server.sh # or: bash reference/dev-server.sh 3005 ``` `gen.sh` also takes `--no-build` (generate the pages only) and `--no-install` @@ -66,38 +66,66 @@ Two workflows, both plain `actions/setup-python`, no Docker. `.github/workflows/reference-check.yml` builds on every PR touching `signalwire/`, `reference/`, or `pyproject.toml`. It runs `gen.sh --no-install`, whose strict -`mkdocs build` fails the check on a generator error, an unimportable module, or a -new unresolved cross-reference. Build only: `contents: read`, never deploys. +`mkdocs build` fails the check on a generator error, a root `signalwire` package +that will not import, or a new unresolved cross-reference. It does **not** catch a +submodule with a missing runtime dependency: mkdocstrings analyses statically +through griffe, so that module still renders a clean page. Build only: +`contents: read`, never deploys. `.github/workflows/reference-docs.yml` builds and publishes. It installs from `reference/requirements.txt` plus the SDK editable, runs `gen.sh --no-build --no-install`, builds with `--strict`, and only then runs `mkdocs gh-deploy --force`. -- **Triggers:** published releases, plus `workflow_dispatch` for manual and - fork-preview runs. +- **Triggers:** a reusable `workflow_call` from `publish-release.yml`, which + invokes it after the CI gates and the PyPI upload have succeeded, plus + `workflow_dispatch` for manual and fork-preview runs. There is deliberately no + `release: published` trigger: that release is created with `GITHUB_TOKEN`, and + GitHub raises no workflow-triggering events for that token, so the trigger + would look right and never fire on the normal tag path. - **Publishes only when** the run is on `signalwire/signalwire-python` (not a - fork), the release is not flagged pre-release, the tag is stable semver - (`vX.Y.Z`), and the tag is greater than or equal to the version recorded in - `version.txt` at the root of the live site. That last check exists because - `gh-deploy --force` leaves no prior version on `gh-pages` to roll back to, so - republishing older docs over newer would be unrecoverable. -- A `workflow_dispatch` run builds a preview and publishes only if you tick the - `deploy` input. - -## Manual repo setting required to go live - -One-time, in the GitHub UI: - -> **Settings > Pages > Build and deployment > Source = "Deploy from a branch", -> Branch = `gh-pages` / `(root)`.** - -`mkdocs gh-deploy` pushes the built site to `gh-pages`; Pages then serves it at -`https://signalwire.github.io/signalwire-python/`. - -To create the `gh-pages` branch the first time, run `reference-docs` manually with -the `deploy` input ticked. A dispatch publish writes no `version.txt`, so the next -release finds an empty marker and publishes unconditionally; the monotonicity -check takes effect from the release after that. + fork), the tag is stable semver (`vX.Y.Z`) so an rc tag cannot overwrite the + stable site, and the tag is at least as new as the version recorded in + `version.txt` at the root of the live site. Anything the gate cannot positively + determine, such as an unreadable `gh-pages` or a site with no marker, fails + closed rather than publishing. +- A `workflow_dispatch` run builds a preview, and publishes only if you tick the + `deploy` input **and** dispatch from the default branch. Without that second + condition any branch in the dropdown could publish itself as the official + public reference, running its own code under a `contents: write` token. +- **On rollback:** `gh-deploy` force-pushes but does not discard history. mkdocs + passes `no_history=False`, so ghp-import parents each deploy onto the previous + one and `--force` forces only the push. A bad publish is recoverable by hand + with `git push --force origin gh-pages~1:gh-pages`. The gate exists because + that recovery depends on somebody noticing, not because rollback is impossible. + This is also why `fetch-depth: 0` must stay: it is what fetches + `origin/gh-pages`, and without it the force-push lands a parentless orphan and + the history really is gone. + +## Going live + +Two one-time steps, in this order. The Pages dropdown cannot offer `gh-pages` +until the branch exists, so the dispatch has to come first. + +1. Run `reference-docs` manually from the default branch with the `deploy` input + ticked. That creates `gh-pages` and stamps `version.txt` with the `v0.0.0` + bootstrap floor. +2. In the GitHub UI: **Settings > Pages > Build and deployment > + Source = "Deploy from a branch", Branch = `gh-pages` / `(root)`.** + +Pages then serves the site at `https://signalwire.github.io/signalwire-python/`. + +### The version marker + +`version.txt` at the site root records the version currently published, and the +monotonicity check reads it. **Every** publish stamps it, dispatches included: +`gh-deploy` replaces the whole site tree, so a dispatch that did not re-stamp +would erase the marker and silently disarm the guard for the next release. A +dispatch preserves whatever is already there. + +A site with no readable marker is therefore an anomaly, and the gate refuses to +publish over it. If the marker ever needs repairing, for instance after a typo +tag like `v31.0.0` sorts newest and starts blocking real releases, dispatch a +publish with the `version_marker` input set to the correct `vX.Y.Z`. ## Scope From 256b36e36c04b3ec4e1ed22d4c8c39a6f638c3e8 Mon Sep 17 00:00:00 2001 From: August L-R Date: Tue, 18 Aug 2026 21:00:20 +0000 Subject: [PATCH 15/16] build(reference): correct the empty-page guard rationale, add --help --- reference/gen.sh | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/reference/gen.sh b/reference/gen.sh index f39285e8..f3be6fdf 100755 --- a/reference/gen.sh +++ b/reference/gen.sh @@ -18,11 +18,15 @@ set -euo pipefail NO_BUILD=0 NO_INSTALL=0 +usage() { + sed -n '13,16p' "${BASH_SOURCE[0]}" | sed 's/^# \{0,1\}//' +} for arg in "$@"; do case "$arg" in --no-build) NO_BUILD=1 ;; --no-install) NO_INSTALL=1 ;; - *) echo "gen.sh: unknown option: $arg" >&2; exit 2 ;; + -h|--help) usage; exit 0 ;; + *) echo "gen.sh: unknown option: $arg" >&2; usage >&2; exit 2 ;; esac done @@ -63,8 +67,10 @@ for name in names: fh.write(f"# signalwire.{name}\n\n::: signalwire.{name}\n") written.append(name) -# An unresolvable install yields zero modules, and every command below still -# succeeds, so `set -e` would let a gutted site sail through to deploy. Fail loud. +# The loop above writes nothing when `signalwire` exposes no subpackages, and +# every command below still succeeds, so `set -e` would let a gutted site sail +# through to deploy. (This is NOT an install check: PYTHONPATH points at the +# source tree, so the import resolves with or without the editable install.) if not written: sys.exit("gen.sh: no API pages generated (is the signalwire package importable?)") From 7d3554257fab42c628ef0b5ff03ded28772b8008 Mon Sep 17 00:00:00 2001 From: August L-R Date: Tue, 18 Aug 2026 21:00:43 +0000 Subject: [PATCH 16/16] fix(pom): the console script is pom-tool, not pom_tool --- signalwire/signalwire/pom/pom_tool.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/signalwire/signalwire/pom/pom_tool.py b/signalwire/signalwire/pom/pom_tool.py index 6c970c7d..3b0b1545 100644 --- a/signalwire/signalwire/pom/pom_tool.py +++ b/signalwire/signalwire/pom/pom_tool.py @@ -5,8 +5,8 @@ Usage: ```text -pom_tool [--output=] [--outfile=] [--merge_pom="
:"] -pom_tool (-h | --help) +pom-tool [--output=] [--outfile=] [--merge_pom="
:"] +pom-tool (-h | --help) ``` Options: @@ -91,7 +91,7 @@ def main() -> None: # §6.2-python: argparse (stdlib) replaced the unmaintained docopt — identical CLI # surface (same flags/defaults/usage), one fewer dependency. parser = argparse.ArgumentParser( - prog="pom_tool", + prog="pom-tool", description="POM Tool - work with Prompt Object Model files", ) parser.add_argument("input_file", help="POM file to load (JSON or YAML)")