Skip to content

Linux arm64

Linux arm64 #286

Workflow file for this run

name: Linux arm64
on:
push:
branches: [main]
tags: ['[0-9]+.[0-9]+.[0-9]+']
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-22.04-arm
# Frozen toolchain, not the runner image: the ubuntu-22.04-arm label
# re-rolls weekly (gcc/glibc/binutils drift). This digest and the
# archive snapshot below are both immutable, so the same commit
# produces the same bytes forever. There is no prebuilt arm64 Nim, so
# setup-nim-action compiles the compiler here too: under the frozen
# gcc that compiler build is itself frozen.
container:
image: ubuntu:22.04@sha256:b8b6ee6aa931ecd9d0d952abc34dc0e5f7c6a30c6bb71b079fe399fde0329c02
steps:
- name: Freeze apt to a pinned archive snapshot
# Runs before checkout: the base image has no git yet. ca-certificates
# comes from the live archive first (it only affects TLS trust, not
# artifact bytes); everything that touches the binary comes from the
# frozen snapshot.
run: |
export DEBIAN_FRONTEND=noninteractive
apt-get update
apt-get install -y --no-install-recommends ca-certificates
sed -i 's|http://archive.ubuntu.com/ubuntu/|https://snapshot.ubuntu.com/ubuntu/20260925T000000Z/|; s|http://security.ubuntu.com/ubuntu/|https://snapshot.ubuntu.com/ubuntu/20260925T000000Z/|' /etc/apt/sources.list
apt-get update
# build-essential: gcc/binutils for nim + the binary; git: checkout
# + config.nims's version probe; curl/xz: nim source download;
# procps: test watchdog ps/pgrep; zstd: actions/cache
apt-get install -y --no-install-recommends build-essential git curl ca-certificates xz-utils procps zstd
- uses: actions/checkout@v4
- name: Trust the checkout
# config.nims runs git (branch/sha/status) for the version define;
# in a container the workspace is owned by a different uid, so
# git would refuse and corrupt the version string.
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
- name: Restore Nim toolchain cache
id: cache-nim
uses: actions/cache@v4
with:
# /opt, not $HOME: job containers don't share the runner's HOME,
# and an absolute path keeps cache hits aligned with the install
# directory below.
path: /opt/nim-toolchain
# Key includes the pinned nim-version: a hit must never resurrect
# a toolchain older/newer than the nim-version input below.
key: ${{ runner.os }}-${{ runner.arch }}-nim-toolchain-2.2.12-${{ hashFiles('*.nimble') }}
restore-keys: |
${{ runner.os }}-${{ runner.arch }}-nim-toolchain-
- uses: jiro4989/setup-nim-action@v2
if: steps.cache-nim.outputs.cache-hit != 'true'
with:
# Exact version, not `stable`: the same commit must compile with
# the same compiler forever. Bump deliberately, together with
# regenerating nimble.lock (its `nim` entry records the version).
nim-version: 2.2.12
repo-token: ${{ secrets.GITHUB_TOKEN }}
parent-nim-install-directory: /opt
nim-install-directory: nim-toolchain
- name: Add Nim to PATH on cache hit
if: steps.cache-nim.outputs.cache-hit == 'true'
run: echo "/opt/nim-toolchain/bin" >> $GITHUB_PATH
- name: Install dependencies
# nimble.lock pins every dependency to an exact revision + checksum;
# install honors it, so rebuilds of the same commit get identical
# dependency trees (bump requires -> `nimble lock` to update).
run: |
nimble install -y --depsOnly
- name: Compute build flags
run: |
if [[ "${GITHUB_REF}" == refs/tags/* ]]; then
# autoupdate on releases only
echo "BUILD_FLAGS=-d:autoUpdate" >> "$GITHUB_ENV"
fi
- name: Build
run: nimble build -y -d:release ${{ env.BUILD_FLAGS }}
- name: Package
# SOURCE_DATE_EPOCH anchors all archive mtimes to the commit, so
# the tarball is byte-identical across rebuilds of one commit.
run: |
export SOURCE_DATE_EPOCH="$(git log -1 --pretty=%ct)"
mkdir -p 3code-linux-arm64
cp 3code 3code-linux-arm64/
# Capture the version from the built binary so it can be checked
# without running the binary on its target OS.
./3code -v > 3code-linux-arm64/VERSION
{
nim --version | head -1
cc --version | head -1
sha256sum 3code | cut -d' ' -f1
echo "SOURCE_DATE_EPOCH=$SOURCE_DATE_EPOCH"
} > 3code-linux-arm64/BUILD_INFO
cp README.md LICENSE 3code-linux-arm64/
pack() {
tar --sort=name --mtime="@${SOURCE_DATE_EPOCH}" --owner=0 --group=0 --numeric-owner \
-cf - 3code-linux-arm64 | gzip -n > 3code-linux-arm64.tar.gz
}
pack
h1=$(sha256sum 3code-linux-arm64.tar.gz | cut -d' ' -f1)
find 3code-linux-arm64 ! -type l -exec touch {} + # perturb mtimes (not symlinks: touch would create dangling targets)
pack
h2=$(sha256sum 3code-linux-arm64.tar.gz | cut -d' ' -f1)
[ "$h1" = "$h2" ] || { echo "archive not reproducible: $h1 vs $h2" >&2; exit 1; }
- name: Upload artifact (GitHub Actions)
uses: actions/upload-artifact@v4
with:
name: 3code-linux-arm64
path: 3code-linux-arm64.tar.gz
- name: Upload artifact to 3code.capocasa.dev
if: github.ref == 'refs/heads/main'
run: |
# --retry: 5xx is transient on the upload endpoint
curl -f --retry 5 --retry-delay 5 -H "Authorization: Bearer ${{ secrets.RELEASE_SECRET }}" -F "file=@3code-linux-arm64.tar.gz" \
https://3code.capocasa.dev/main/builds/upload.nim
test:
# Tests stay on the stock runner: they produce no artifacts, and the
# sandbox/tty tests assume runner-level kernel access (landlock,
# userns, PTYs) that a container's seccomp profile may not allow.
needs: build
runs-on: ubuntu-22.04-arm
steps:
- uses: actions/checkout@v4
- name: Restore Nim toolchain cache
id: cache-nim
uses: actions/cache@v4
with:
path: /home/runner/nim-toolchain
# Key includes the pinned nim-version: a hit must never resurrect
# a toolchain older/newer than the nim-version input above.
key: ${{ runner.os }}-${{ runner.arch }}-nim-toolchain-2.2.12-${{ hashFiles('*.nimble') }}
restore-keys: |
${{ runner.os }}-${{ runner.arch }}-nim-toolchain-
- uses: jiro4989/setup-nim-action@v2
if: steps.cache-nim.outputs.cache-hit != 'true'
with:
nim-version: 2.2.12
repo-token: ${{ secrets.GITHUB_TOKEN }}
parent-nim-install-directory: $HOME
nim-install-directory: nim-toolchain
- name: Add Nim to PATH on cache hit
if: steps.cache-nim.outputs.cache-hit == 'true'
run: echo "$HOME/nim-toolchain/bin" >> $GITHUB_PATH
- name: Install dependencies
# Same lock as the build jobs: what gets tested is what ships.
run: |
nimble install -y --depsOnly
- name: Run tests
# nimble's nimscript task swallows a non-zero testament exit (it
# converts the OSError into a logged exception but still exits 0),
# so a failing test reports green. Call testament directly and
# propagate $? so a test failure actually fails the step.
#
# Run categories sequentially rather than via `all` (which fan-outs
# every category in parallel). The tty PTY tests spawn real
# subprocesses whose render threads are scheduler-sensitive; under
# load the parallel fan-out starves those threads and produces
# load-induced frame mismatches. Sequential `cat` runs the identical
# tests without that contention.
run: sh tests/tools/ci_tests.sh 1500
timeout-minutes: 30