Skip to content

Nightly (heavy doc gates) #49

Nightly (heavy doc gates)

Nightly (heavy doc gates) #49

Workflow file for this run

name: Nightly (heavy doc gates)
# Runs the HEAVY doc-execution gates that per-PR run-ci skips for speed:
# SNIPPET-COMPILE · SNIPPET-RUN · EXAMPLES-RUN (tier=nightly in run-ci.sh)
# via `SW_CI_TIER=nightly bash scripts/run-ci.sh`, which runs the FULL gate set
# (nightly is a superset of the per-PR tier — nothing is only-nightly-untested).
#
# Skip-if-unchanged: the heavy gates depend on three inputs — this port, the
# shared porting-sdk (mocks + gate scripts), and signalwire-python (the oracle).
# The guard fingerprints all three HEAD SHAs into a cache key. A GREEN heavy run
# saves that key; the next nightly's guard does a cache-restore probe on the same
# key — a HIT means the exact (port, porting-sdk, python) triple already passed, so
# the heavy job is skipped. A no-op nightly then costs a cache probe, not ~45 min.
# (Cache, not run-name/API parsing: a job name does not surface as the run's .name,
# so name-based state is unreliable; actions/cache is the GitHub-native state store.)
on:
schedule:
- cron: '17 7 * * *' # 07:17 UTC daily (off the hour to avoid the cron stampede)
workflow_dispatch:
inputs:
force:
description: 'Run even if nothing changed since the last successful nightly'
type: boolean
default: false
concurrency:
group: nightly-${{ github.ref }}
cancel-in-progress: false
permissions:
contents: read
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
jobs:
guard:
runs-on: ubuntu-latest
outputs:
changed: ${{ steps.check.outputs.changed }}
cache_key: ${{ steps.fp.outputs.cache_key }}
steps:
- name: Fingerprint the three input HEAD SHAs (port + porting-sdk + python)
id: fp
env:
GH_TOKEN: ${{ github.token }}
PSDK_TOKEN: ${{ secrets.PORTING_SDK_TOKEN }}
run: |
set -euo pipefail
port_sha='${{ github.sha }}'
# porting-sdk is private → authenticated ref lookup; python is public.
psdk_sha=$(GH_TOKEN="$PSDK_TOKEN" gh api repos/signalwire/porting-sdk/commits/main --jq .sha)
py_sha=$(gh api repos/signalwire/signalwire-python/commits/main --jq .sha)
echo "cache_key=nightly-green-v1-${port_sha}-${psdk_sha}-${py_sha}" >> "$GITHUB_OUTPUT"
echo "inputs → port=$port_sha psdk=$psdk_sha python=$py_sha"
# Probe (restore-only, no save) the green-marker cache for this exact input
# triple. A HIT means these three SHAs already passed the heavy gates.
- name: Probe last-green marker
id: probe
uses: actions/cache/restore@v6
with:
path: .nightly-green-marker
key: ${{ steps.fp.outputs.cache_key }}
lookup-only: true
- name: Decide
id: check
env:
FORCE: ${{ github.event.inputs.force }}
run: |
set -euo pipefail
if [ "$FORCE" = "true" ]; then
echo "force=true → running"; echo "changed=true" >> "$GITHUB_OUTPUT"; exit 0
fi
if [ "${{ steps.probe.outputs.cache-hit }}" = "true" ]; then
echo "this (port, porting-sdk, python) triple already passed a nightly → skipping heavy gates"
echo "changed=false" >> "$GITHUB_OUTPUT"
else
echo "input triple has not passed a nightly yet → running heavy gates"
echo "changed=true" >> "$GITHUB_OUTPUT"
fi
heavy:
needs: guard
if: needs.guard.outputs.changed == 'true'
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout signalwire-typescript
uses: actions/checkout@v7
with:
path: signalwire-typescript
- name: Checkout porting-sdk (mock servers + audit scripts + EMISSION corpus)
uses: actions/checkout@v7
with:
repository: signalwire/porting-sdk
# Coordinated-pass pin: 'main' normally; set the PORTING_SDK_REF repo variable
# to a wave branch to test a coordinated porting-sdk change, declared on the PR
# (see porting-sdk/COORDINATED_PASS.md). No revert commit.
ref: ${{ vars.PORTING_SDK_REF || 'main' }}
path: porting-sdk
token: ${{ secrets.PORTING_SDK_TOKEN }}
- name: Checkout signalwire-python (EMISSION oracle)
uses: actions/checkout@v7
with:
repository: signalwire/signalwire-python
path: signalwire-python
ref: ${{ vars.PORTING_SDK_REF || 'main' }}
- uses: actions/setup-node@v7
with:
node-version: '24'
cache: 'npm'
cache-dependency-path: signalwire-typescript/package-lock.json
- uses: actions/setup-python@v6
with:
python-version: '3.14'
- name: Install Python test harnesses (mock_relay + mock_signalwire)
run: |
python -m pip install --upgrade pip
pip install -e porting-sdk/test_harness/mock_relay \
-e porting-sdk/test_harness/mock_signalwire \
pytest pytest-timeout requests websockets
- name: Install signalwire-python (EMISSION oracle) if not importable
run: pip install -e signalwire-python || true
# SWAIG-HTTP-INVOKE differ drives the python reference through
# starlette.testclient.TestClient, which needs an httpx backend (newest
# starlette: httpx2; older: httpx). Install both so the import resolves.
- name: Install starlette TestClient HTTP backend (SWAIG-HTTP differ)
run: pip install httpx httpx2 || pip install httpx
# ACTIONLINT gate (porting-sdk actionlint_gate.py) needs the actionlint
# binary and fails LOUD when it is absent, so install it before run-ci.
- name: Install actionlint (ACTIONLINT gate)
run: |
bash <(curl -sSfL https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash)
sudo mv ./actionlint /usr/local/bin/actionlint
actionlint --version
- name: npm ci
working-directory: signalwire-typescript
run: npm ci
- name: Run FULL gate set incl. heavy doc gates (SW_CI_TIER=nightly)
working-directory: signalwire-typescript
env:
PORTING_SDK: ${{ github.workspace }}/porting-sdk
SW_CI_TIER: nightly
# COORDINATED-PASS reads the live PR body/labels via 'gh api' to see a
# 'Coordinated-With:' declaration edited after the triggering push.
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: bash scripts/run-ci.sh
# Save the green marker ONLY on success (this step runs only if run-ci passed),
# so the next nightly skips this exact input triple. A failed heavy run saves
# nothing → it re-runs next nightly until it goes green.
- name: Record green marker for this input triple
run: 'echo "$GITHUB_SHA green $(date -u +%FT%TZ)" > .nightly-green-marker'
working-directory: ${{ github.workspace }}
- uses: actions/cache/save@v6
with:
path: .nightly-green-marker
key: ${{ needs.guard.outputs.cache_key }}