Skip to content
starskiff

CI Setup

Run starskiff tests on GitHub Actions

Prefer images. starskiff is image-first: an instance backed by a usable chain image needs no CI setup at all. Docker is preinstalled on GitHub runners, the image is pulled on demand, and nothing is provisioned.

- run: pnpm install --frozen-lockfile
- run: pnpm vitest run # image-backed instances just work; images pulled on demand

The one built-in exception is the hermes relayer — not a chain node, it runs as a host binary next to the chains, so CI puts it on PATH. Beyond that, provisioning only comes up when a binary is your choice: marood (private, no default image), or any instance you deliberately run with binary: instead of its image. starskiff's own CI uses the image defaults and provisions only hermes, via config/binaries.json.

Provisioning a binary

When you do need one, prefer prebuilt binaries over building from source: a chain binary is a large Go program, and compiling one per CI run spends the startup advantage that makes starskiff worth using. Build (or download) each binary once, store it where CI can fetch it, and every run afterwards pays only a seconds-long download.

Prefer prebuilt over source-build

Many upstreams publish official release binaries you can download straight — the hermes relayer, or e.g. the Hub if you want Instance.gaiad({ binary: 'gaiad' }) on an exact-version build instead of its image:

- name: Download hermes
  env:
    GH_TOKEN: ${{ github.token }}
  run: |
    gh release download v1.13.3 --repo informalsystems/hermes \
      --pattern "hermes-v1.13.3-x86_64-unknown-linux-gnu.tar.gz" --dir /tmp
    tar -xzf /tmp/hermes-*.tar.gz -C /tmp
    mv /tmp/hermes /usr/local/bin/hermes

actions/cache keyed on the binary version works too if you'd rather not manage a release.

Build from source per run

Simplest to set up and always reproducible, but each cold run spends minutes in the Go compiler (the Go module/build cache softens repeat runs):

- uses: actions/setup-go@v6
  with:
    go-version: '1.25'
    cache: true
 
- name: Build gaiad
  run: |
    git clone --depth 1 --branch v27.5.0 https://github.com/cosmos/gaia.git /tmp/gaia
    cd /tmp/gaia && go build -o /usr/local/bin/gaiad ./cmd/gaiad/

Reasonable for a repo that runs CI rarely, or as the bootstrap step that produces the prebuilt assets above.

Split unit and integration jobs

Keep binary-free tests runnable everywhere by splitting vitest projects — a unit project that never touches a chain, and an integration project that boots instances. CI then runs unit on every push and gates integration behind the binary-download job:

jobs:
  ci:
    steps:
      # ... setup, no binaries needed
      - run: pnpm vitest run --project unit
 
  integration:
    needs: ci
    steps:
      # ... setup + binary download
      - run: pnpm vitest run --project integration

Timeouts

CI runners are slower than laptops — first block can take noticeably longer than the local 3–5s. Bump the instance timeout in CI:

const instance = Instance.simd({ chainId: 'test-1' }, { timeout: process.env.CI ? 120_000 : 60_000 });

The same applies to vitest's hookTimeout if you boot instances in beforeAll/globalSetup.