go-lib 0.5.2

rust native goroutines
Documentation
# SPDX-License-Identifier: Apache-2.0
name: CI

on:
  push:
    branches: [ "main" ]
  pull_request:
    branches: [ "main" ]
  workflow_dispatch:

env:
  CARGO_TERM_COLOR: always
  RUST_BACKTRACE: 1

jobs:
  # ── Standard build + test ──────────────────────────────────────────────────
  
  test:
    name: Build & Test
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false   # always run all platforms; don't cancel Windows when macOS fails
      matrix:
        os: [ubuntu-latest, macOS-latest, windows-latest]
        toolchain: [stable]
    continue-on-error: false
    steps:
      - uses: actions/checkout@v4

      - name: Update tool chain
        run: |
          rustup update ${{ matrix.toolchain }}
          rustup default ${{ matrix.toolchain }}

      - name: Cache cargo registry
        uses: actions/cache@v4
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}

      - name: cargo test
        # --nocapture: print test output immediately so crash context is
        # visible in the job log even when the process exits abnormally
        # (e.g. STATUS_ACCESS_VIOLATION on Windows).
        # timeout-minutes: guard against a run_impl park() hang on slow runners.
        timeout-minutes: 10
        run: cargo test --release -- --nocapture

      - name: Print Windows VEH crash file (if present)
        # always(): the crash file matters most when `cargo test` just failed,
        # which would otherwise skip this step entirely.
        if: always() && runner.os == 'Windows'
        shell: pwsh
        # The VEH writes .\go-lib-crash-veh.txt on crash.  Print it so the
        # diagnostics appear in the CI log even when the test binary exits via
        # TerminateProcess (which may race with pipe drain).
        run: |
          if (Test-Path "go-lib-crash-veh.txt") {
            Write-Host "=== go-lib-crash-veh.txt ==="
            Get-Content "go-lib-crash-veh.txt"
          } else {
            Write-Host "(no crash file — process either did not crash or VEH was not reached)"
          }

      - name: cargo run --examples
        timeout-minutes: 10
        # bash on all three platforms so the inverted exit-code check below
        # behaves identically (the default Windows shell is pwsh).
        shell: bash
        run: |
          cargo run --release --example attr_run
          cargo run --release --example cond
          cargo run --release --example hello
          # main_exitcode exits 1 BY DESIGN (it demonstrates returning
          # ExitCode::FAILURE from main).  Assert the non-zero exit instead
          # of failing the job on it.
          if cargo run --release --example main_exitcode; then
            echo "main_exitcode: expected a non-zero exit code"; exit 1
          fi
          cargo run --release --example main_result
          cargo run --release --example pipeline
          cargo run --release --example scope
          cargo run --release --example scope_channel
          cargo run --release --example select_fanin

      - name: stress canary (drain/wake races)
        # Regression canary for the cross-Rt drain/wake races (timer-heap
        # TOCTOU, netpoll harvest, nested RcuGuard deadlock, stale timer
        # entries — see examples/stress_drain_timer.rs).  On the buggy
        # runtime this crashes (malloc abort / NULL deref in chanrecv) or
        # hangs within seconds; the job timeout converts a hang into a
        # failure.  With the singleton scheduler each run_impl leaks only a
        # 16-byte InvState, so the canary can run tens of thousands of
        # iterations in its 15-second window; the per-worker cap just bounds
        # runtime on very fast runners.
        timeout-minutes: 3
        shell: bash
        run: cargo run --release --example stress_drain_timer 15 100000

      - name: cargo doc (no deps, no-run)
        run: cargo doc --no-deps
        
  build:
    name: Build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Update tool chain
        run: |
          rustup update
          rustup default

      - name: Cache cargo registry
        uses: actions/cache@v4
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}

      - name: cargo build
        run: cargo build --all-targets

  # ── Loom concurrency model checker ────────────────────────────────────────
  loom:
    name: Loom model check
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Update tool chain
        run: |
          rustup update
          rustup default

      - name: Cache cargo registry
        uses: actions/cache@v4
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: ${{ runner.os }}-cargo-loom-${{ hashFiles('**/Cargo.lock') }}

      - name: cargo test (loom)
        # --cfg loom: activate loom::sync shims in crate::loom_shim.
        # -- --test-threads 1: loom's model explorer must run serially.
        # LOOM_MAX_PERMUTATIONS: cap the search so CI stays bounded;
        #   increase locally with LOOM_MAX_PERMUTATIONS=0 (unlimited) for
        #   deeper exploration.
        env:
          RUSTFLAGS: "--cfg loom"
          LOOM_MAX_PERMUTATIONS: "10000"
        # --nocapture: surface the async-signal-safe SIGSEGV handler dump
        # in the job log if a test crashes (otherwise libtest swallows it).
        run: cargo test -- --test-threads 1 --nocapture

  coverage:
    name: Coverage
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [ ubuntu-latest ]
        toolchain: [ nightly ]
    steps:
      - uses: actions/checkout@v4
      - name: Update tool chain
        run: |
          rustup update ${{ matrix.toolchain }}
          rustup default ${{ matrix.toolchain }}
          rustup component add llvm-tools-preview --toolchain ${{ matrix.toolchain }}
      - name: Install coverage tool
        run: cargo +stable install cargo-llvm-cov --locked
      - name: Test project and generate coverage report
        run: cargo llvm-cov --remap-path-prefix --show-missing-lines --branch --doctests --lcov --output-path lcov.info
      - name: Publish coverage summary to job summary
        uses: livewing/lcov-job-summary@v1.1.0
        with:
          lcov: lcov.info
      - name: Fail build if coverage below 80%
        uses: bigmeech/gha-simple-coverage@master
        with:
          lcov-file-path: lcov.info
          fail-if-below: 80