Nightly (heavy doc gates) #49
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 }} |