Skip to content

Latest commit

 

History

History
152 lines (130 loc) · 6.63 KB

ci.md

File metadata and controls

152 lines (130 loc) · 6.63 KB

Continuous integration

Every first-party native host must compile in pull-request CI. A Racket-only test job, schema check, or package dry run does not prove that WinUI, SwiftUI, or GTK source still compiles. Waiting for a tagged release to perform the first native compilation turns ordinary compiler errors into release incidents.

Use the same runner image class and toolchain family in CI that the release job uses:

  • Windows: windows-latest for the WinUI 3 host;
  • macOS: both macos-latest and macos-15, so current Swift and the pinned Xcode 16 release environment both compile the SwiftUI/AppKit host;
  • Linux: ubuntu-24.04 with GTK 4.10+ development files and an embeddable Racket CS runtime.

raco rivet build is the required host-compilation gate. Add package and verify when the job should also validate the distributable layout. Publisher certificates and notarization credentials do not belong in pull-request CI; use development packaging there and reserve --production for a protected release environment.

Copy-paste GitHub Actions workflow

The following workflow pins Rivet 0.9.0. Update every Rivet package source and the Linux setup action to the same tag (or full commit) in one review. A direct Git source is intentional: the Racket Package Catalog has one current entry for a package name and cannot select an older Rivet release.

name: Native hosts

on:
  pull_request:
  push:
    branches: [main]

permissions:
  contents: read

jobs:
  windows-host:
    runs-on: windows-latest
    steps:
      - uses: actions/checkout@v7
      - uses: Bogdanp/setup-racket@v1.15
        with:
          architecture: x64
          distribution: full
          variant: CS
          version: '9.3'
      - run: raco pkg install --auto --no-docs 'https://github.com/turinglambdaai/rivet.git#v0.9.0'
      - run: raco rivet doctor
      - run: raco rivet schema check rivet-schema.json
      - run: raco rivet build

  macos-host:
    strategy:
      fail-fast: false
      matrix:
        runner: [macos-latest, macos-15]
    runs-on: ${{ matrix.runner }}
    steps:
      - uses: actions/checkout@v7
      - uses: Bogdanp/setup-racket@v1.15
        with:
          architecture: x64
          distribution: full
          variant: CS
          version: '9.3'
      - run: raco pkg install --auto --no-docs 'https://github.com/turinglambdaai/rivet.git#v0.9.0'
      - run: raco rivet doctor
      - run: raco rivet schema check rivet-schema.json
      - run: raco rivet build

  linux-host:
    runs-on: ubuntu-24.04
    steps:
      - uses: actions/checkout@v7
      - name: Set up embeddable Racket CS
        uses: turinglambdaai/rivet/.github/actions/setup-embed-racket@v0.9.0
      - name: Install GTK4 development files
        run: |
          sudo apt-get update
          sudo apt-get install --yes libgtk-4-dev
      - name: Install the matching Rivet package and dependencies
        run: raco pkg install --auto --no-docs 'https://github.com/turinglambdaai/rivet.git#v0.9.0'
      - run: raco rivet doctor
      - run: raco rivet schema check rivet-schema.json
      - run: raco rivet build

The Linux order is load-bearing: install the Rivet package after setup-embed-racket. The action's minimal Racket build intentionally ships without packages; installing Rivet afterward resolves cext-lib, crypto-lib, keel, and the rest of the dependency closure into the package directory that the embeddable runtime actually uses. Installing Rivet earlier under a full Racket distribution can make those dependencies appear satisfied there while leaving the minimal runtime incomplete; a later backend bundle then fails, for example because raco ctool is supplied by cext-lib.

For an intentionally moving development channel, replace the direct Git source with the catalog name rivet and use the setup action from @main. Do not use that pair as a release pin: catalog installation follows the catalog's current checksum and there is no raco pkg install rivet@<version> selector. The standard hold-back form is the tag-pinned Git source shown above. Racket treats the fragment as the Git revision while retaining normal dependency resolution.

Rivet itself additionally launches the generated GTK4 package inside a headless Weston compositor with GDK_BACKEND=wayland. This is a native Wayland gate: DISPLAY is unset, so the application cannot silently pass by using X11 or XWayland. Products supporting Linux should keep an equivalent Wayland launch in their release matrix; see Linux display policy.

Rivet's own Ubuntu jobs run provisioning apt-get commands through .github/scripts/apt-retry.sh. Each attempt is non-interactive, applies APT's network and lock retries, and has a three-minute wall-clock limit; one fresh attempt is allowed before the job fails. Product CI should use the same bounded principle so a stalled package mirror cannot consume the whole native-build budget. Package installation lifecycle tests themselves stay unwrapped because their raw transaction outcome is the behavior under test.

The separate Native UI End-to-End workflow packages the maintained Taskboard and drives its real WinUI 3, SwiftUI/AppKit, and GTK4 accessibility surfaces. It covers activation, an RPC mutation, an Event, State rendering, and orderly close while retaining bounded failure evidence. See native UI end-to-end testing for the application-level extension contract.

For a security-sensitive product, replace the action tag with the full commit SHA for that tag and use the same commit in the package URL fragment. The action downloads the official minimal Racket CS source archive, verifies its SHA-256, builds and caches the static embedding runtime by version/OS/architecture, and exports RIVET_RACKET_INCLUDE, RIVET_RACKET_LIB_DIR, RIVET_RACKET_LIBRARY, and RIVET_RACKET_BOOT_DIR. Product workflows should not copy those discovery rules.

For local Rivet development, a linked checkout remains appropriate. Pin that checkout and the setup action to the same revision in CI. A host compiled against one Rivet revision and released with another is not a useful gate.

Release gate

Before pushing a tag, require all native-host jobs above and the product's Racket tests. The protected release job can then add production packaging, signing, notarization, update-manifest signing, and artifact publication. It should not be the first job that invokes the native compiler.

If the release workflow intentionally pins an older runner or Xcode image, keep that exact image in the pull-request matrix until the release environment is upgraded. Runner labels can change over time; parity with the product's actual release workflow is the contract.