Skip to content

Publish Testnode

Publish Testnode #40

name: Publish Testnode
on:
push:
tags:
- "v*"
workflow_dispatch:
inputs:
name:
description: "Testnode name from config/testnodes.json (provides defaults for the inputs below)"
required: false
default: ""
type: string
version:
description: "Pinned testnode image version tag (overrides config/testnodes.json)"
required: false
default: ""
type: string
snapshot-version:
description: "Snapshot release tag to use for every selected variant (overrides config/testnodes.json)"
required: false
default: ""
type: string
snapshot-repo:
description: "GitHub repo in owner/repo form that hosts the tagged snapshot release"
required: false
default: ""
type: string
variant:
description: "Named variant to publish"
required: true
default: "l3-eth"
type: choice
options:
- all
- l2
- l2-timeboost
- l3-eth
- l3-custom-6
- l3-custom-16
- l3-custom-18
- l3-custom-20
nitro-contracts-version:
description: "Nitro contracts version baked into the snapshot"
required: true
default: "v3.2"
type: choice
options:
- all
- v2.1
- v3.2
jobs:
resolve-publish-matrix:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.matrix.outputs.matrix }}
version: ${{ steps.resolve.outputs.version }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Resolve testnode inputs
id: resolve
env:
# On a tag push, publish every variant in every nitro-contracts version
# so we can test against either. Each variant installs its own
# pre-generated snapshot bundle (per-variant snapshotReleaseTag in
# runtime.mjs), so snapshot-version here is unused for publishing and
# passed only to satisfy resolve-testnode.mjs. The matrix builder skips
# variant x version combos that have no snapshot bundle.
TESTNODE_NAME: ${{ github.event_name == 'push' && '' || inputs.name }}
TESTNODE_VERSION: ${{ github.event_name == 'push' && github.ref_name || inputs.version }}
TESTNODE_SNAPSHOT_VERSION: ${{ github.event_name == 'push' && github.ref_name || inputs.snapshot-version }}
TESTNODE_VARIANT: ${{ github.event_name == 'push' && 'all' || inputs.variant }}
TESTNODE_NITRO_CONTRACTS_VERSION: ${{ github.event_name == 'push' && 'all' || inputs.nitro-contracts-version }}
run: >-
node scripts/ci/resolve-testnode.mjs
--name "$TESTNODE_NAME"
--version "$TESTNODE_VERSION"
--snapshot-version "$TESTNODE_SNAPSHOT_VERSION"
--variant "$TESTNODE_VARIANT"
--nitro-contracts-version "$TESTNODE_NITRO_CONTRACTS_VERSION"
- name: Build publish matrix
id: matrix
env:
INPUT_VARIANT: ${{ steps.resolve.outputs.variant }}
INPUT_SNAPSHOT_VERSION: ${{ steps.resolve.outputs.snapshot-version }}
INPUT_CONTRACTS_VERSION: ${{ steps.resolve.outputs.nitro-contracts-version }}
run: >-
node --input-type=module -e
"import { NITRO_CONTRACTS_VERSIONS, VARIANTS, hasVariantSnapshot, resolveVariantSnapshot } from './packages/testnode/src/runtime.mjs';
const names =
process.env.INPUT_VARIANT === 'all'
? Object.keys(VARIANTS)
: [process.env.INPUT_VARIANT];
const contractsVersions =
process.env.INPUT_CONTRACTS_VERSION === 'all'
? Object.keys(NITRO_CONTRACTS_VERSIONS)
: [process.env.INPUT_CONTRACTS_VERSION];
const include = [];
for (const variant of names) {
const config = VARIANTS[variant];
if (!config) throw new Error(\`Unknown variant \${variant}\`);
for (const contractsVersion of contractsVersions) {
if (!hasVariantSnapshot(variant, contractsVersion)) {
console.error(\`Skipping \${variant} x \${contractsVersion}: no snapshot bundle\`);
continue;
}
const snapshot = resolveVariantSnapshot(variant, contractsVersion);
include.push({
variant,
contractsVersion,
snapshotId: snapshot.snapshotId,
snapshotReleaseTag: snapshot.snapshotReleaseTag
});
}
}
const output = process.env.GITHUB_OUTPUT;
if (!output) throw new Error('GITHUB_OUTPUT is required');
const { appendFileSync } = await import('node:fs');
appendFileSync(output, 'matrix=' + JSON.stringify({ include }) + '\\n');"
publish-testnode-image:
needs: resolve-publish-matrix
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.resolve-publish-matrix.outputs.matrix) }}
permissions:
contents: read
packages: write
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
- name: Setup pnpm
uses: pnpm/action-setup@v4
- name: Install dependencies
run: pnpm install --frozen-lockfile
# Install the pre-generated snapshot bundle for this variant. Snapshots are
# generated out of band and published as release bundles (the per-variant
# snapshotReleaseTag lives in runtime.mjs); the publish never runs init.
- name: Install snapshot release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TESTNODE_SNAPSHOT_GH_REPO: ${{ github.repository }}
run: >-
pnpm dev snapshot install --force
--id "${{ matrix.snapshotId }}"
--release-tag "${{ matrix.snapshotReleaseTag }}"
- name: Prepare testnode context
run: >-
node scripts/ci/prepare-testnode-context.mjs
--variant "${{ matrix.variant }}"
--snapshot-id "${{ matrix.snapshotId }}"
--nitro-contracts-version "${{ matrix.contractsVersion }}"
- name: Lowercase owner
id: lower
run: echo "owner=$(echo '${{ github.repository_owner }}' | tr '[:upper:]' '[:lower:]')" >> "$GITHUB_OUTPUT"
- name: Contracts tag
id: nc
run: echo "tag=nc$(echo '${{ matrix.contractsVersion }}' | sed 's/^v//')" >> "$GITHUB_OUTPUT"
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push testnode image
uses: docker/build-push-action@v6
with:
context: .
file: docker/testnode.Dockerfile
push: true
tags: ghcr.io/${{ steps.lower.outputs.owner }}/arbitrum-testnode-ci:${{ needs.resolve-publish-matrix.outputs.version }}-${{ steps.nc.outputs.tag }}-${{ matrix.variant }}