Skip to content

ci: migrate from CircleCI to GitHub Actions#166

Merged
Viq111 merged 4 commits into1.xfrom
ci/migrate-to-github-actions
May 1, 2026
Merged

ci: migrate from CircleCI to GitHub Actions#166
Viq111 merged 4 commits into1.xfrom
ci/migrate-to-github-actions

Conversation

@platinummonkey
Copy link
Copy Markdown
Contributor

@platinummonkey platinummonkey commented Apr 29, 2026

Summary

  • Replaces .circleci/config.yml with .github/workflows/ci.yml, preserving all 9 CircleCI jobs (3× Go versions × {default, external-libzstd}, two efence variants, and i386).
  • All third-party actions are pinned to commit SHAs with version comments (actions/checkout@de0fac2e v6.0.2, actions/setup-go@4a360112 v6.4.0).
  • The i386 job preserves the original 32bit/ubuntu:16.04 image and linux32 --32bit i386 ./travis_test_32.sh invocation by running it inside docker run on a standard ubuntu runner.

Notes

  • Branch protection: required status-check names change (ci/circleci: golang-1.24golang-1.24, etc.). The required checks list will need to be re-pinned after this lands.
  • efence runners: the two efence jobs were resource_class: xlarge (8 vCPU) on CircleCI; they now run on default ubuntu-latest (4 vCPU / 16 GB). If memory pressure or runtime regresses, swap to a larger runner label.
  • Behavior preserved verbatim: the asymmetry where golang-1.x-external-libzstd builds/tests without -tags external_libzstd (while golang-efence-external-libzstd does use the tag) is preserved as-is from the original CircleCI config — flag for follow-up if this is a latent bug.
  • Adds a top-level concurrency: group so superseded PR runs are cancelled.

Test plan

  • CI runs green on this PR for all jobs (golang-1.24/1.25/1.26 ± external-libzstd, both efence variants, i386).
  • Confirm efence jobs complete within reasonable time on default runner (no OOM / timeout).
  • After merge, update branch protection to require the new check names.
  • Disable the CircleCI integration on the repo once GHA is the source of truth.

🤖 Generated with Claude Code

platinummonkey and others added 3 commits April 29, 2026 11:30
Replaces .circleci/config.yml with .github/workflows/ci.yml. Preserves
the original 9 CircleCI jobs:

  - golang-{1.24,1.25,1.26} (matrix)
  - golang-{1.24,1.25,1.26}-external-libzstd (matrix)
  - golang-efence
  - golang-efence-external-libzstd
  - golang-i386 (runs travis_test_32.sh inside 32bit/ubuntu:16.04)

All third-party actions are pinned to commit SHAs:
  - actions/checkout@de0fac2e (v6.0.2)
  - actions/setup-go@4a360112  (v6.4.0)

Note: the efence jobs were previously resource_class: xlarge on
CircleCI; they now run on the default ubuntu-latest runner. Required
status-check names will need to be re-pinned in branch protection.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The 32-bit job intermittently crashed with SIGSEGV in a libzstd cgo
call on the GitHub-hosted runner. Modern host kernels randomize the
32-bit address layout differently than the older CircleCI host did,
occasionally placing libzstd's allocations at addresses the legacy
3 GB user-space split doesn't expect. Passing -R (ADDR_NO_RANDOMIZE)
to linux32 makes the layout deterministic; the flag inherits across
fork/exec to the bash script and the Go test binary.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The -R flag broke the i386 job: util-linux 2.27 in 32bit/ubuntu:16.04
parses options after --32bit <arch> in an order-sensitive way and
rejects "-R bash ..." with "i386: Kernel cannot set architecture to
i386". Restoring the previous invocation; the underlying flake will
be addressed separately.

This reverts commit f3b091b.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Collaborator

@Viq111 Viq111 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restoring the previous invocation; the underlying flake will be addressed separately.
Where you able to find a fix for that ? If we don't fix it in this PR, it's unlikely we will find a fix in the future

@platinummonkey
Copy link
Copy Markdown
Contributor Author

Restoring the previous invocation; the underlying flake will be addressed separately.
Where you able to find a fix for that ? If we don't fix it in this PR, it's unlikely we will find a fix in the future

@Viq111 not really. The suggestion was to run with -R to the i386 invocation to disable ASLR in that container so we have a deterministic address layout. Though github did not support this, so I revert that change.

@Viq111
Copy link
Copy Markdown
Collaborator

Viq111 commented Apr 30, 2026

Posted by Claude on Vianney's behalf — model: Opus 4.7 (1M context), effort: xhigh.

Hey Cody — Vianney asked me to drop some thoughts on the i386 job here, since the linux32 -R round-trip suggested the underlying setup is a bit fragile. Not blocking; take or leave.

TL;DR

The current i386 job inherits the CircleCI shape verbatim: spin up 32bit/ubuntu:16.04 (a 9-year-old image) and run travis_test_32.sh, which downloads Go 1.13 i386 to build. That has two compounding issues:

  1. Modern kernel × 2016 userland mismatch. The flaky SIGSEGV is the symptom — modern host kernels lay out the 32-bit address space differently than that image's userland was tuned for, occasionally putting libzstd allocations where the legacy 3GB/1GB split doesn't expect them. linux32 -R couldn't fix it because util-linux 2.27 in the image parses options order-sensitively and rejects the flag. Patching old userland against new kernels is whack-a-mole.
  2. It's not actually testing what users run. go.mod declares go 1.24, but the script installs Go 1.13. The point of the original 32-bit job (Fix tests for 32 bits systems and provide an env to test it #45) was catching 32-bit-specific arithmetic bugs (the int overflow that motivated it), not pinning to ancient Go. Running the suite under Go 1.13 in 2026 mostly catches nothing relevant.

Suggested approach: cross-compile to GOARCH=386 with gcc-multilib, run on the existing amd64 runner

x86_64 Linux runs i386 ELF binaries natively via IA32 compat (default on Ubuntu) — no QEMU, no docker. Install gcc-multilib + libc6-dev-i386, set GOARCH=386 CGO_ENABLED=1 CC="gcc -m32", and go test will compile 32-bit and execute it on the runner. This is the same recipe the Go project itself uses for its 386 builders. It folds neatly into the matrix, eliminates the flake source (modern kernel matched with modern userland, just compiled 32-bit), and tests against the Go version you actually ship.

Concrete drop-in for the i386 job:

  i386:
    name: golang-i386
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
      - name: Setup Go
        uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
        with:
          go-version: "1.26"
      - name: Install 32-bit toolchain
        run: sudo apt-get update && sudo apt-get install -y gcc-multilib libc6-dev-i386
      - name: Download payload
        run: |
          wget https://github.com/DataDog/zstd/files/2246767/mr.zip
          unzip mr.zip
      - name: Build (i386)
        env: { GOARCH: "386", CGO_ENABLED: "1", CC: "gcc -m32" }
        run: go build
      - name: Test (i386)
        env:
          GOARCH: "386"
          CGO_ENABLED: "1"
          CC: "gcc -m32"
          DISABLE_BIG_TESTS: "1"
          PAYLOAD: ${{ github.workspace }}/mr
        run: go test -v

Notes on cgo correctness for this repo

  • Same OS, same toolchain — gcc -m32 from gcc-multilib just emits 32-bit ELF. Cgo honors CC, so all zstd_*.c / huf_*.c / xxhash.c etc. compile as i386. No CXX needed; there's no C++ in the tree.
  • GOARCH=386 flips to cross-compile mode, which disables cgo by default — that's why CGO_ENABLED=1 has to be explicit.
  • The only arch-specific source is huf_decompress_amd64.S. Go's build system auto-excludes files matching *_<GOARCH>.<ext> for other GOARCH values, so it's skipped under GOARCH=386 without any build-tag changes.
  • linux32 wrapper is unnecessary — the binary is genuinely 32-bit ELF; linux32 only changes personality(1) (e.g., uname -m), which the tests don't read. If you ever do want 3GB-AS personality, setarch i386 -3 -R go test ... works fine on a modern util-linux (the PR-166 issue was specifically the 2016 version's broken option ordering).

Side benefits

  • travis_test_32.sh becomes obsolete (delete in the same PR).
  • You can fold i386 into the existing build-test matrix as arch: [amd64, 386] with a conditional toolchain-install step, getting i386 coverage across all three Go versions instead of just one.
  • If you also want external_libzstd × i386: sudo dpkg --add-architecture i386 && sudo apt-get update && sudo apt-get install -y libzstd-dev:i386. Skip if not worth it.

Replaces the docker-in-32bit/ubuntu:16.04 invocation (which downloaded
Go 1.13 and was flaky due to modern kernel × 2016 userland) with a
native cross-compile on ubuntu-latest:

  - actions/setup-go at Go 1.26 (matches the workflow's other jobs)
  - apt: gcc-multilib + libc6-dev-i386 for the 32-bit toolchain
  - GOARCH=386 CGO_ENABLED=1 CC="gcc -m32" so cgo emits 32-bit ELF
  - Linux IA32 compat on the amd64 host runs the resulting binary
    natively — no QEMU, no docker, no linux32 personality dance

The huf_decompress_amd64.S source is auto-excluded by Go's filename
suffix build rule under GOARCH=386. DISABLE_BIG_TESTS=1 is preserved
to keep the prior carve-out for memory-heavy stream tests.

The standalone "go test -bench ." invocation from the old script is
not carried over (benchmarks aren't a correctness gate and the runner
is too noisy for meaningful numbers).

travis_test_32.sh is removed; nothing else referenced it.

Suggested by @Viq111 on the PR.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@platinummonkey
Copy link
Copy Markdown
Contributor Author

@Viq111 :D awesome, applied that suggestion in the latest commit

@Viq111 Viq111 merged commit aad66fa into 1.x May 1, 2026
11 of 12 checks passed
@Viq111 Viq111 deleted the ci/migrate-to-github-actions branch May 1, 2026 13:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants