CI: Windows jobs workflow_dispatch only, PowerShell on Linux, glibc comment #68
5 changed files with 51 additions and 13 deletions
34
.github/workflows/cultmesh-portability.yml
vendored
34
.github/workflows/cultmesh-portability.yml
vendored
|
|
@ -16,12 +16,16 @@ jobs:
|
|||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
# The forge runner is Ubuntu-only: Windows legs run on workflow_dispatch (GitHub or a Windows runner), Ubuntu gates push and PR.
|
||||
# The forge runner (label `ubuntu-latest`) is Linux-only and no Windows runner exists: the Windows leg runs on workflow_dispatch only (GitHub or a Windows runner), the ubuntu-latest leg gates push and PR. Windows push/PR triggers return in the PR that registers a Windows runner.
|
||||
os: ${{ fromJSON(github.event_name == 'workflow_dispatch' && '["windows-latest", "ubuntu-latest"]' || '["ubuntu-latest"]') }}
|
||||
|
||||
steps:
|
||||
- name: Check out CultLib
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
# The declared-dependency-range test builds the admitted releases from their tags.
|
||||
fetch-depth: 0
|
||||
fetch-tags: true
|
||||
|
||||
- name: Set up .NET
|
||||
uses: actions/setup-dotnet@v4
|
||||
|
|
@ -45,6 +49,34 @@ jobs:
|
|||
- name: Install Python CultLib packages
|
||||
run: python -m pip install -e packages/cultcache-py -e packages/cultnet-py -e packages/cultmesh-py
|
||||
|
||||
# The forge runner images carry no cargo either (the cross-runtime store tests build the Rust interop example); GitHub's hosted images do.
|
||||
- name: Install Rust toolchain
|
||||
if: runner.os == 'Linux'
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
if ! command -v cargo >/dev/null && [ ! -x "$HOME/.cargo/bin/cargo" ]; then
|
||||
curl -fsSL https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain stable
|
||||
fi
|
||||
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
|
||||
|
||||
# The forge runner images carry no pwsh; GitHub's Windows and hosted images do.
|
||||
- name: Install PowerShell
|
||||
if: runner.os == 'Linux'
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
if command -v pwsh >/dev/null; then pwsh -Version; exit 0; fi
|
||||
SUDO=""; [ "$(id -u)" -eq 0 ] || SUDO="sudo"
|
||||
PWSH_VERSION=7.4.6
|
||||
curl -fsSL "https://github.com/PowerShell/PowerShell/releases/download/v${PWSH_VERSION}/powershell-${PWSH_VERSION}-linux-x64.tar.gz" -o "${RUNNER_TEMP:-/tmp}/powershell.tar.gz"
|
||||
$SUDO mkdir -p /opt/microsoft/powershell/7
|
||||
$SUDO tar -xzf "${RUNNER_TEMP:-/tmp}/powershell.tar.gz" -C /opt/microsoft/powershell/7
|
||||
$SUDO chmod +x /opt/microsoft/powershell/7/pwsh
|
||||
$SUDO ln -sf /opt/microsoft/powershell/7/pwsh /usr/local/bin/pwsh
|
||||
echo "DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1" >> "$GITHUB_ENV"
|
||||
DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1 pwsh -Version
|
||||
|
||||
- name: Verify explicit reactive scheduling across runtimes
|
||||
shell: pwsh
|
||||
run: ./scripts/verify-reactive-document-scaling.ps1
|
||||
|
|
|
|||
2
.github/workflows/cultnet-interop.yml
vendored
2
.github/workflows/cultnet-interop.yml
vendored
|
|
@ -1,7 +1,7 @@
|
|||
name: CultNet cross-runtime interop
|
||||
|
||||
# workflow_dispatch only: this job is Windows-only (pwsh Kotlin build, setup steps), and the forge
|
||||
# runner is Ubuntu-only, so a push or pull_request trigger would queue a job that can never run.
|
||||
# runner is Ubuntu-only (no Windows runner exists; push and pull_request return in the PR that registers one), so a push or pull_request trigger would queue a job that can never run.
|
||||
# Run it from GitHub or any Windows runner.
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
|
|
|||
11
.github/workflows/quic-native.yml
vendored
11
.github/workflows/quic-native.yml
vendored
|
|
@ -49,11 +49,12 @@ jobs:
|
|||
|
||||
# workflow_dispatch and a cultmesh-quic-native-v* tag run the two builds.
|
||||
# A dry (workflow_dispatch) run uploads artifacts and creates no release.
|
||||
# No Windows runner is registered on the forge, so this job is workflow_dispatch only
|
||||
# (run it on GitHub or a Windows runner). The tag trigger returns in the PR that registers one.
|
||||
# Until then a tag push skips the release job, which needs this build.
|
||||
build-win32-x64:
|
||||
name: Build win32-x64
|
||||
if: >-
|
||||
github.event_name == 'workflow_dispatch' ||
|
||||
(github.event_name == 'push' && startsWith(github.ref, 'refs/tags/cultmesh-quic-native-v'))
|
||||
if: github.event_name == 'workflow_dispatch'
|
||||
runs-on: windows-latest
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
|
|
@ -92,8 +93,8 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
# Q6 A: this pinned Debian 13 container is the only permitted Linux
|
||||
# release builder. The digest is the pin; the `debian:13` tag is only a
|
||||
# label. The artifact links against this image's glibc (2.41); a bare
|
||||
# ubuntu-latest runner carries glibc 2.39, which is not the deploy host's
|
||||
# label. The artifact links against this image's glibc (2.41);
|
||||
# a bare runner's OS image has its own glibc (a GitHub ubuntu-latest image carried 2.39), which is not the deploy host's
|
||||
# OS (docs/typescript-quic-realtime-cut.md:2192-2197).
|
||||
container:
|
||||
image: debian:13@sha256:f324c7ff54321e8d9c588493a20244965938ce0aa50bbd1022d38010e9ffc4b1
|
||||
|
|
|
|||
|
|
@ -2986,8 +2986,9 @@ test("CultMesh TS publishes one registered document to a RUDP catalog", async ()
|
|||
maxFragmentBytes: 1024,
|
||||
maxPendingReliablePackets: 16,
|
||||
connectTimeoutMs: 1_000,
|
||||
flushTimeoutMs: 25,
|
||||
resultWindowMs: 100,
|
||||
// The flush is bounded by the result window, so the window must outlast the transport ack on a loaded
|
||||
// runner: a short one turns a slow ack into local_send_failed, which is not the path this test checks.
|
||||
resultWindowMs: 750,
|
||||
sourceRole: "test-provider",
|
||||
},
|
||||
),
|
||||
|
|
|
|||
|
|
@ -367,6 +367,10 @@ async function bind(): Promise<Socket> {
|
|||
return socket;
|
||||
}
|
||||
const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
|
||||
// Wait for a datagram-driven condition rather than guessing how long loopback delivery takes on a loaded runner.
|
||||
const until = async (condition: () => boolean, limitMs = 2_000) => {
|
||||
for (let waited = 0; !condition() && waited < limitMs; waited += 10) await sleep(10);
|
||||
};
|
||||
|
||||
test("server mode admits a pinned client that restarts on a new port", async () => {
|
||||
const serverSocket = await bind();
|
||||
|
|
@ -385,24 +389,24 @@ test("server mode admits a pinned client that restarts on a new port", async ()
|
|||
try {
|
||||
const first = session(1);
|
||||
a.send(encodeRudpPacket(first.createConnect(0, enc("join"))), port, "127.0.0.1");
|
||||
await sleep(100);
|
||||
await until(() => atA.some((packet) => packet.packetType === "accept"));
|
||||
const accept = atA.find((packet) => packet.packetType === "accept");
|
||||
assert.ok(accept);
|
||||
first.receive(accept, 0);
|
||||
a.send(encodeRudpPacket(first.createAckForReceived(accept.sequence)), port, "127.0.0.1");
|
||||
a.send(encodeRudpPacket(send(first, "hello")), port, "127.0.0.1");
|
||||
await sleep(100);
|
||||
await until(() => frames.length === 1);
|
||||
assert.deepEqual(frames, ["hello"]);
|
||||
|
||||
const second = session(1); // the process restarted on a new port, pinned
|
||||
b.send(encodeRudpPacket(second.createConnect(0, enc("join"))), port, "127.0.0.1");
|
||||
await sleep(100);
|
||||
await until(() => atB.some((packet) => packet.packetType === "accept"));
|
||||
const acceptB = atB.find((packet) => packet.packetType === "accept");
|
||||
assert.ok(acceptB, `the restarted client on a new port was not admitted: ${JSON.stringify(atB.map((packet) => packet.packetType))}`);
|
||||
second.receive(acceptB, 1);
|
||||
assert.ok(second.connected);
|
||||
b.send(encodeRudpPacket(send(second, "after")), port, "127.0.0.1");
|
||||
await sleep(100);
|
||||
await until(() => frames.length === 2);
|
||||
assert.deepEqual(frames, ["hello", "after"]);
|
||||
} finally {
|
||||
server.close();
|
||||
|
|
|
|||
Loading…
Reference in a new issue